Symfony теги

Статья рассказывает о том, как использовать теги в своих сервисах и о Compiler Passes, но для начала о возможностях Symfony.

Чтобы переоперделить/расширить сервисы, в Symfony существует 2 способа.

Первый способ - вы можете установить ваш собственный класс как параметр к классу сервиса в app/config/config.yml. Этот способ возможен только если имя класса определено как параметр в конфигурации бандла. Например, чтобы переопределить класс для Symfony сервиса translator, вы можете переопределить параметр translator.class (для translator, параметр определен и используется в Resources/config/translation.xml в ядре FrameworkBundle):

# app/config/config.yml
parameters:
    translator.class: Acme\HelloBundle\Translation\Translator

* иногда чтобы найти какой-то параметр - надо немного погуглить. 

Второй способ - используется, если класс не определен как параметр (в конфигурации). Вам придется переопределить класс определенного сервиса во время компиляции сервис-контейрена:

<?php
// src/Acme/DemoBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php
namespace Acme\DemoBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class OverrideServiceCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $definition = $container->getDefinition('original-service-id');
        $definition->setClass('Acme\DemoBundle\YourService');
    }
}

* 2 примера выше не относятся к коду ниже и приведены лишь в качестве демонстрации способов.

Задача

Создать сервис acme_mailer.transport_chain, который будет пытаться отправлять письмо несколькими способами (если одним способом не получилось - пытается следующим способом).

Как пример добавим следующие методы доставки (smtp, sendmail) в качестве сервисов:

# src/Acme/MailerBundle/Resources/config/services.yml
services:
    acme_mailer.transport.smtp:
        class: \Swift_SmtpTransport
        arguments:
            - %mailer_host%
        tags:
            -  { name: acme_mailer.transport }
    acme_mailer.transport.sendmail:
        class: \Swift_SendmailTransport
        tags:
            -  { name: acme_mailer.transport }

Теги

Как видите, сервисам мы указали свои теги и благодаря Symfony Compiler Passes мы обработаем эти теги.

Обратите внимание на тег acme_mailer.transport. Мы хотим чтобы бандл автоматически определял эти способы доставки и добавлял их в цепочку. Для того, чтобы этого добиться, надо добавить метод build() в класс AcmeMailerBundle:

<?php

namespace Acme\MailerBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Acme\MailerBundle\DependencyInjection\Compiler\TransportCompilerPass;

class AcmeMailerBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new TransportCompilerPass());
    }
}

Вы наверняка заметили упоминание несуществующего пока класса TransportCompilerPass, давайте напишем его:

<?php

namespace Acme\MailerBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;

class TransportCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (false === $container->hasDefinition('acme_mailer.transport_chain')) {
            return;
        }

        $definition = $container->getDefinition('acme_mailer.transport_chain');

        foreach ($container->findTaggedServiceIds('acme_mailer.transport') as $id => $attributes) {
            $definition->addMethodCall('addTransport', array(new Reference($id)));
        }
    }
}

Обратите внимание - сервисы, у которых есть тег acme_mailer.transport при помощи метода addTransport() добавились в реестр сервиса acme_mailer.transport_chain

acme_mailer.transport_chain - сервис отправки почты, такой же как Symfony2 сервис mailer, но, который является реестром (коллекцией) классов (сервисов) которые реализовали интерфейс \Swift_Transport библиотеки Swift Mailer (библиотека отправки электронных писем, в Symfony2 она представлена как сервис mailer). Давайте объявим этот сервис:

# src/Acme/MailerBundle/Resources/config/services.yml
services:
    acme_mailer.transport_chain:
        class: Acme\MailerBundle\TransportChain

Теперь нам осталось реализовать TransportChain (транспортную цепочку - реестр).

<?php

namespace Acme\MailerBundle;

class TransportChain
{
    private $transports;

    public function __construct()
    {
        $this->transports = array();
    }

    public function addTransport(\Swift_Transport $transport)
    {
        $this->transports[] = $transport;
    }

    public function send(Swift_Mime_Message $message, &$failedRecipients = null)
    {
        /** @var \Swift_Transport $service */
        foreach ($this->transports as $service) {
            if ($service->send($message , $failedRecipients)) {
                return 1;
            }
        }
    }
}

Вот и все, теперь в своем контроллере Вы можете использовать данный сервис, как обычный сервис mailer:

$this->get('acme_mailer.transport_chain')->send($message);

Надеюсь, все хорошо разжевал, удачки.

p.s.

Подробности:

По соглашению, имена тегов должны начинаться с названия бандла (нижний регистр, подчеркивание в качестве разделителя), затем должна стоять точка, а в конце - “настоящее” название. Так, тег “transport” в бандле AcmeMailerBundle должен выглядеть следующим образом: acme_mailer.transport

Объявление скомпилированного сервиса

После пропуска через компилятор, в окончательной версии оболочки сервиса, появятся следующие строки. Если вы используете среду dev, то загляните в файл /cache/dev/appDevDebugProjectContainer.php и найдите там метод getTransportChainService(). Если вы всё сделали правильно, то он должен выглядеть следующим образом:

protected function getAcmeMailer_TransportChainService()
{
    $this->services['acme_mailer.transport_chain'] = $instance = new \Acme\MailerBundle\TransportChain();

    $instance->addTransport($this->get('acme_mailer.transport.smtp'));
    $instance->addTransport($this->get('acme_mailer.transport.sendmail'));

    return $instance;
}

Источник: 1 

Оцени публикацию:
  • 0,0
Оценили человек: 0

Похожие статьи:

Справочники и учебники:


Предложения и пожелания:
Ваше имя:
Ваш E-mail:
Сколько будет Οдин + Τри
Главная
X

youtube.com/watch?v=7hFivbgIEqk

При полном или частичном использовании материалов данного сайта, ссылка на сайт "yapro.ru" обязательна как на источник информации.
Автоматический импорт материалов и информации с сайта запрещен.
Copyrights © 2007 - 2017 YaPro.Ru

Главная » Веб-мастеру » PHP »