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

Новые заметки:

Про что мы забываем когда делаем оценку задачи по времени

Список вопросов для собеседования разработчика по телефону

Symfony2 авторизация без Doctrine2 для чайника

Phpstorm7 LiveEdit

Жесткий хабр или не хабр, тогда кто?

Яндекс.Деньги мошенничество

Как узнать какие страницы в поиске яндекса или это секрет

Последние комменты:

Yapro CMS:

Здравствуйте, Гость | Войти | Регистрация | Карта сайта | RSS ленты | Ошибка в тексте? Выделите её мышкой и нажмите: Ctrl + Enter

youtube.com/watch?v=7hFivbgIEqk

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

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