Блог

PHP/Symfony2: аннотации

Я уверен, что если вы используете Symfony2 то использовали аннотаций или видели в документации, понятие аннотаций в PHP/Symfony2 пришло от Python/Django и Java. Благодаря Doctrine2 теперь вы можете писать пользовательские аннотации без особых проблем.

Настройка

Для создания аннотаций вам нужен пакет doctrine/annotations, это должно быть включено по умолчанию с Symfony2, если нету, то просто добавьте пакет composer require doctrine/annotations.

Создание класса аннотаций

После того как вы получили пакет, с помощью которого вы можете начать создавать аннотации. Во-первых Вам нужно будет создать класс аннотации, который будет содержать свойства аннотации, это можно рассматривать как мета-класс, который будет привязываться к целевому классу. Вы будете иметь возможность использовать методы, чтобы вытащить его настройки.

Класс аннотации просто держатель параметров для настройки, заданные в аннотации, например:

<?php
namespace DemoBundle\Annotations;

use Doctrine\Common\Annotations\Annotation;

/**
*
* @Annotation
* @Target("CLASS")
* @Attributes({
*     @Attribute("resource", type="string"),
* })
*/
final class ExampleMeta extends Annotation
{
	public $resource;
}

Приведенный выше код является примером класса аннотаций, а именно в стиле Doctrine2 сущность аннотаций. Так вы можете создавать аннотации для классов, функций и свойств. Единственное различие между этими типами аннотаций является значение “@Target” в описании аннотаций.

Расширение класса аннотаций не является обязательным, это конструктор просто берет на себя все параметры, указанные в аннотации и добавляет их в качестве свойств к экземпляру аннотаций. Таким образом, в приведенном ниже примере вы сможете использовать ресурс, чтобы извлечь значение ресурса для конкретного объекта.

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use AppBunle\Annotations\ExampleMeta;

/**
 *
 * @ExampleMeta(resource="example")
 */
class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction(Request $request)
    {
        // replace this example code with whatever you need
        return $this->render('default/index.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
        ]);
    }
}

Чтение класса аннотации

Когда создали класс аннотации теперь нужен класс который будет читать аннотации. Для считывания параметров аннотаций, нужен класс чтения, используя читателя вы можете вытащить любые аннотаций, которые были описаны в классе, свойстве или функции.

В приведенном ниже примере, получает пространство имен объекта для загрузки, она передает экземпляр класса в ReflectionClass в функцию AnnotationReader::getClassAnnotation, указывая конкретную аннотацию, которую я хочу получить в качестве второго аргумента. Вы можете также использовать функцию ‘getClassAnnotations’ только с экземпляром ReflectionClass, чтобы вытащить все аннотации, связанные с классом.

Вот пример кода для использования чтения Аннотации:

<?php

namespace DemoBundle\Annotations\Reader;

use Doctrine\Common\Annotations\AnnotationReader;

class ExampleReader
{
	public function get($object)
	{
		$reader = new AnnotationReader();
		$annotation = $reader->getClassAnnotation(new \ReflectionClass(new $object), \AppBundle\Annotations\ExampleMeta::class);
		if(!$annotation) {
			throw new Exception(sprintf('%s does not have required annotation ExampleMeta', $entityClass));
		}

		$resource = strtolower($annotation->resource);
                dump($resource);exit;
	}
}

После того, как экземпляр аннотаций был получен вы можете получить доступ к его свойствам, как и к обычному классу.

Пример использования

Вы можете прочитать больше о пакет doctrine/annotations в официальной документации. Как уже упоминалось ранее вы можете аннотировать классы, свойства и методы, вот некоторые примеры из них.

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Annotations\ExampleClass;

/**
 *
 * @ExampleClass(resource="example_class")
 */
class DefaultController extends Controller
{
    /**
     *
     * @Route("/", name="homepage")
     * @ExampleClass(resource="example_action")
     */
    public function indexAction(Request $request)
    {
        // replace this example code with whatever you need
        return $this->render('default/index.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
        ]);
    }
}

Пример использование залит на github.com