Pull to refresh

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

Reading time3 min
Views12K
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
Tags:
Hubs:
+19
Comments34

Articles

Change theme settings