Кастомные аннотации в Symfony 2

Symfony2 — это веб-фреймворк, который появился совсем недавно. Соответственно, разработчики просто не успели написать к нему стоящую документацию. В одном из текущих проектов используется MongoDB, и ACL прикрутить нему можно, нужно всего лишь написать свой ACL-провайдер. Но я решил пойти своим путём. Итак, вот что примерно у нас получится:
class DefaultController extends Controller
{

    /**
    * Dashboard page.
    * @Permissions(perm="dashboard_view")
    * @Route("/", name="ITEDashboardBundle_index")
    * @Template()
    * @return array
    */
    public function indexAction()
    {.......



Как видно, здесь аннотации route и template — стандартны и я не буду о них рассказывать. Нас же интересует собственная аннотация Permissions.

Ну что ж, приступим.
Для начала нужно создать класс аннотаций, который будет показывать ядру, что у нас теперь есть новая аннотация:
namespace SomeNameSpace\SomeBundle\Annotations;
/**
* @Annotation
*/
class Permissions
{
    public $perm;
}

Таким образом, аннотация будет типа @Permissions(perm=«some_value»)
Следующим нашим шагом будет создания сервиса, в которым мы будем читать аннотации и выполнять какие-то действия, в зависимости от их значений.
namespace SomeNamespace\SomeBundle\Annotations\Driver;

use Doctrine\Common\Annotations\Reader;//Вот эта штука как раз и читает аннотации
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;//Подключаем нужный компонент ядра
use SomeNamespace\SomeBundle\Annotations;//Юзаем свою аннотацию
use SomeNamespace\SomeBundle\Security\Permission; //В этом классе я проверяю соответствие permission to user
use Symfony\Component\HttpFoundation\Response; // В нашем примере я просто буду выводить 403, если нет доступа

use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class AnnotationDriver{

    private $reader;

    public function __construct($reader)
    {
        $this->reader = $reader;//Получаем читалку аннотаций
    }
    /**
    * Это событие возникнет при вызове любого контроллера
    */
    public function onKernelController(FilterControllerEvent $event)
    {

        if (!is_array($controller = $event->getController())) { //Выходим, если нет контроллера
            return;
        }

        $object = new \ReflectionObject($controller[0]);// Получаем контроллер
        $method = $object->getMethod($controller[1]);// Получаем метод

        foreach ($this->reader->getMethodAnnotations($method) as $configuration) { //Начинаем читать аннотации
            if(isset($configuration->perm)){//Если прочитанная аннотация наша, то выполняем код ниже
                $perm = new Permission($controller[0]->get('doctrine.odm.mongodb.document_manager'));
                $userName = $controller[0]->get('security.context')->getToken()->getUser()->getUserName();
                if(!$perm->isAccess($userName,$configuration->perm)){
                           //Если после проверки доступа нет, то выдаём 403
                           throw new AccessDeniedHttpException();

                }

             }
         }
    }
}


Прошу заметить, что используем мы читалку аннотаций из доктрины. Но доктрина сегодня стала неотъемлемой частью symfony2.
Да. И последний шаг, но не менее важный. Теперь нам нужно зарегистрировать свой хук контролеера, или, если правильно назвать его: EventListener
# SomeBundle\config\services.yml
services:
    some_annotation_driver:
        class: SomeNamespace\SomeBundle\Annotations\Driver\AnnotationDriver #Указываем класс
        tags: [{name: kernel.event_listener, event: kernel.controller, method: onKernelController}]          #Указываем по какому событию вызывать этот сервис
        arguments: [@annotation_reader] # Передаём annotation_reader в конструктор нашего сервиса


Вот, собственно, и всё! Теперь наши аннотации готовы к использованию.
P.S. Для использования своих аннотаций в своих бандлах и контролерах нужно подключить только класс с аннотациями:
namespace SomeNamespace\SomeBundle\Controller;

use SomeNamespace\SomeBundle\Annotations\Permissions;

/**
* Dashboard controller.
*
* @Route("/dashboard")
*/
class DefaultController extends Controller
{

    /**
    * Dashboard page.
    * @Permissions(perm="dashboard_view")
    * @Route("/", name="ITEDashboardBundle_index")
    * @Template()
    * @return array
    */
    public function indexAction()
    {...}
}

UPD: Сделал нормальную подсветку кода, спасибо sHinE
+19
23 ноября 2011, 19:30
38

комментарии (34)

–6
altdesign #
не удержусь… «Кастомные» — это по русски?
+1
sam0delkin #
Думаю, нет. Но ведь всё понятно, не так-ли?
+11
sam0delkin #
А вообще, меня очень печалит, что на хабре очень мало статей о Symfony 2. Ведь framework действительно стоящий, а большинство статей либо дважды два, либо просто перевод документации. Попытался просто помочь сообществу, надеюсь кому-то это нужно.
0
TigranAM #
Спасибо Вам большое, недавно начал изучать Symfony2 (кстати первую версию не знаю), и любая статья на эту тему неоценима :)
0
sam0delkin #
Всегда рад помочь!
0
Fedcomp #
Гм, тоже не знаю первую версию :) начал сразу со второй.
+1
Davert #
Не знаю, зачем они назвали новый фреймворк Symfony2, но суть в том, что он не имеет ничего общего с первой симфони. Так что, скорее всего, это плюс, что с ней незнакомы )
0
everzet #
Та же идеология, тот же разработчик, то же коммюнити?
0
psylosss #
Возможно, разработчик тот же, но остальные два — нет
+1
everzet #
Найдите мне активного члена symfony1 коммюнити, который не является членом Symfony2 коммюнити.
Найдите мне пункт идеологии первой симфонии, который не подойдет ко второй.
0
psylosss #
1. на его комментарий вы только что ответили

2. обратное тоже верно? если да, то полагаю, что общего меньше, чем различий.
0
everzet #
1. У нас разные представления об активности :-)
2. Мы все еще говорим об идеологии фреймворка? Различий в чем? Вы так и не ответили на изначальный вопрос.
0
psylosss #
На изначальный вопрос я ответил двумя комментариями выше. Спор бессмысленный, без четкой цели и сомнительной ценности. Предлагаю прекратить.
0
nightstalker #
Затем что symfony это довольно известный бренд. Вкладывать деньги в раскрутку нового глупо.
0
pentium133 #
о, то что надо, спасибо.
0
zaartix #
Спасибо за статью. А вообще да, статей про вторую симфонию маловато.
0
FractalizeR #
Было бы неплохо реализовать кеширование аннотаций. А то читать их каждый раз долговато, мне кажется. Доктрина ведь их сама не кеширует?
+3
chEbba #
Там из коробки кэш есть в ридере (по дефолту ArrayCache). Симфони, кажется, используется по дефолту файловый кэш для аннотаций.
0
chEbba #
*использует
+1
centuri0n #
«Соответственно, разработчики просто не успели написать к нему стоящую документацию.»
Позвольте не согласится. Нормальной документации более чем достаточно. Практических примеров использования типа Askeet or Jobeet действительно пока нет. За статью спасибо.
0
centuri0n #
ться конечно-же.
0
sam0delkin #
Друзья, я не хочу, что бы вы здесь спорили! Я написал эту статью лишь для того, чтобы помочь сообществу. Я очень хочу, что бы Symfony была популярной среди разработчиков. И очень хочу, чтобы разработчики знали как под неё писать. Если кому-то она действительна интересна, то я могу написать ещё статей.
0
centuri0n #
Очень даже интересна. С удовольствием почитаю.
0
sam0delkin #
Ну тогда ждите статью про расширение стандартного контроллера. А ещё, надеюсь, статью про репозитории доктрины.
0
sam0delkin #
Но последняя статья уже будет не от меня. Есть единомышленники.
0
centuri0n #
Я могу конечно ошибаться, но все-таки выскажу свое мнение. На мой взгляд, порог входа в симфони несколько выше чем у других фреймворков. Отчасти виновата в этом документация. Не то чтобы ее было мало, просто она не так лаконична и предметна как у того же Codeigniter. Для первой версии симфони большим подспорьем было наличие практических примеров в виде аскита и джобита, в которых наглядно показаны возможности фреймворка и то, как правильно с ним работать. К чему я все это говорю?! Вы хотите популяризировать симфони, что конечно же очень хорошо. Однако темы ваших предполагаемых статей — это материал для людей, которые уже работают или работали с фреймворком. Т.е. те, кому уже популяризировать не нужно :). Мне кажется для большинства не имевших дела с с2 было бы важно узнать основы идеологии: container, di. А может быть и простой обзор компонентов, которые как известно можно использовать и отдельно от фреймворка. Как бы там ни было, решать вам, я с удовольствием почитаю ваши статьи.
0
sam0delkin #
основы идеологии: di, container, по-моему, уже давно должны стать основой идеологии любого фреймворка. Порог входа большой, да. Но это ничего не меняет.
0
sam0delkin #
хотя, можно, конечно и статьи для новичков, типа основы идеи контейнера и инъектирования зависимостей)
0
lu4e3ar #
–1
diostm #
Каждый раз когда вижу «аннотации» в PHP тянет прослезиться. Очередная не очень удачная попытка походить на «Большого брата».

P.S. А теперь минусуйте.
+2
centuri0n #
Да ладно, лучше прослезитесь раз тянет :).
0
nfx #
Аннотации более сильны, когда использовать CompilerPass и генерацию кода, вобщем, то… вот MageConf 2011 будет доклад как раз об етом.
0
Silverstorm #
А вам не кажется что комментарий к коду для таких аннотаций не предназначен. Не хочу пальцем показывать на какой язык я перешел но это неявное поведени совсем уж надоело. Ну раз есть возможность ретроспекции сигнатур функций то давайте кодить прямо в них, в сигнатурах. И пофиг что этого от нас никто не ожидает!
0
sam0delkin #
Давайте

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.