Symfony2 — это веб-фреймворк, который появился совсем недавно. Соответственно, разработчики просто не успели написать к нему стоящую документацию. В одном из текущих проектов используется MongoDB, и ACL прикрутить нему можно, нужно всего лишь написать свой ACL-провайдер. Но я решил пойти своим путём. Итак, вот что примерно у нас получится:
Как видно, здесь аннотации route и template — стандартны и я не буду о них рассказывать. Нас же интересует собственная аннотация Permissions.
Ну что ж, приступим.
Для начала нужно создать класс аннотаций, который будет показывать ядру, что у нас теперь есть новая аннотация:
Таким образом, аннотация будет типа @Permissions(perm=«some_value»)
Следующим нашим шагом будет создания сервиса, в которым мы будем читать аннотации и выполнять какие-то действия, в зависимости от их значений.
Прошу заметить, что используем мы читалку аннотаций из доктрины. Но доктрина сегодня стала неотъемлемой частью symfony2.
Да. И последний шаг, но не менее важный. Теперь нам нужно зарегистрировать свой хук контролеера, или, если правильно назвать его: EventListener
Вот, собственно, и всё! Теперь наши аннотации готовы к использованию.
P.S. Для использования своих аннотаций в своих бандлах и контролерах нужно подключить только класс с аннотациями:
UPD: Сделал нормальную подсветку кода, спасибо sHinE
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