$30 off During Our Annual Pro Sale. View Details »

Custom annotations in Symfony2

Joshua Thijssen
March 06, 2014
1.4k

Custom annotations in Symfony2

Joshua Thijssen

March 06, 2014
Tweet

Transcript

  1. Symfony2 custom annotations
    1
    Joshua Thijssen
    jaytaph NL UG

    View Slide

  2. 2
    Joshua Thijssen
    Freelance consultant, developer and
    trainer @ NoxLogic
    Founder of the Dutch Web Alliance
    Development in PHP, Python, C, Java.
    Lead developer of Saffire.
    Blog: http://adayinthelifeof.nl
    Email: [email protected]
    Twitter: @jaytaph

    View Slide

  3. 3
    Annotations

    View Slide

  4. What’s an annotation?
    4

    View Slide

  5. Ask Rafael Dohms
    5
    http://www.slideshare.net/rdohms/annotations-in-php-they-exist

    View Slide

  6. 6
    Metadata attached to code
    that can be read at runtime!

    View Slide

  7. 7
    ➡ @ - notation, cause other languages do too :)
    ➡ Userland only :(
    ➡ Reflection :(
    ➡ Different readers :(

    View Slide

  8. /**
    * @Annotation
    */
    8

    View Slide

  9. /**
    *
    */
    9
    docblock
    T_DOC_COMMENT
    http://www.php.net/manual/en/tokens.php

    View Slide

  10. /*
    *
    */
    10
    comment
    T_COMMENT
    //
    #
    http://www.php.net/manual/en/tokens.php

    View Slide

  11. /***
    *
    */
    11
    T_COMMENT
    http://www.php.net/manual/en/tokens.php
    ???

    View Slide

  12. 12
    Doctrine\Common

    View Slide

  13. 13
    annotation library
    http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html

    View Slide

  14. 14
    ➡ Read / parse annotations from classes /
    methods / properties.
    ➡ Places them in data objects (POPOs)
    ➡ Caching etc.

    View Slide

  15. 15
    1 2
    3 // vendor/NoxLogic/Annotations/Append.php
    4
    5 namespace NoxLogic\Annotations;
    6 use Doctrine\Common\Annotations\Annotation;
    7
    8 /**
    9 * @Annotation
    10 */
    11 class Append {
    12 public $value;
    13 public $repeat = 8;
    14 public $priority = 99;
    15 }
    16
    simple annotation based on public properties

    View Slide

  16. 16
    1 2
    3 // vendor/NoxLogic/Annotations/Append.php
    4
    5 namespace NoxLogic\Annotations;
    6 use Doctrine\Common\Annotations\Annotation;
    7
    8 /**
    9 * @Annotation
    10 */
    11 class Append {
    12 protected $value;
    13 protected $repeats;
    14 protected $priority;
    15
    16 function __construct($options) {
    17 $this->value = $options['value'];
    18 $this->repeats = isset($options['repeat']) ? $options['repeat'] : 1;
    19 $this->priority = isset($options['priority']) ? $options['priority'] : 100;
    20 }
    21
    22 }
    23
    simple annotation based on __construct values

    View Slide

  17. 17
    1 2
    3 // vendor/NoxLogic/Annotations/Prepend.php
    4
    5 namespace NoxLogic\Annotations;
    6 use Doctrine\Common\Annotations\Annotation;
    7
    8 /**
    9 * @Annotation
    10 * @Target({"METHOD"})
    11 */
    12 class Prepend extends Annotation {
    13 public $value;
    14 protected $repeat = 1;
    15 protected $priority = 100;
    16
    17 function setValue($value) {
    18 $this->value = $value;
    19 }
    20
    21 function setRepeat($repeat) {
    22 $this->repeats = $repeat;
    23 }
    24
    25 function setPriority($priority) {
    26 $this->priority = $priority;
    27 }
    28
    29 }
    30
    simple annotation based on getters/setters

    View Slide

  18. 18
    1 2
    3 // vendor/NoxLogic/Foo.php
    4
    5 namespace NoxLogic;
    6
    7 use \NoxLogic\Annotations as NoxAnnotations;
    8
    9 class Foo {
    10
    11 /**
    12 * @author Joshua Thijssen
    13 *
    14 * @NoxAnnotations\Prepend("text before", repeat = 3)
    15 * @NoxAnnotations\Prepend("more text before")
    16 * @NoxAnnotations\Append("some text after")
    17 */
    18 function output($string) {
    19 return "[".$string."]";
    20 }
    21
    22 }
    annotation usage

    View Slide

  19. 19
    1 2
    3 use Doctrine\Common\Annotations\AnnotationReader;
    4 use Doctrine\Common\Annotations\AnnotationRegistry;
    5
    6 require_once "vendor/autoload.php";
    7
    8
    9 AnnotationRegistry::registerAutoloadNamespace("\\NoxLogic\\", "vendor");
    10 $reader = new AnnotationReader();
    11
    12
    13 $class = new ReflectionClass("\\NoxLogic\\Foo");
    14 foreach ($class->getMethods() as $method) {
    15
    16 $annotations = $reader->getMethodAnnotations($method);
    17 foreach ($annotations as $annotation) {
    18 print_r ($annotation);
    19 }
    20 }
    21
    main application
    Can’t be PSR0 loader.
    Need silence!

    View Slide

  20. 20
    1 $ php annotations.php
    2 NoxLogic\Annotations\Prepend Object
    3 (
    4 [value] => text before
    5 [repeat:protected] => 3
    6 [priority:protected] => 100
    7 )
    8 NoxLogic\Annotations\Prepend Object
    9 (
    10 [value] => more text before
    11 [repeat:protected] => 1
    12 [priority:protected] => 100
    13 )
    14 NoxLogic\Annotations\Append Object
    15 (
    16 [value:protected] => some text after
    17 [repeats:protected] => 1
    18 [priority:protected] => 100
    19 )

    View Slide

  21. 21
    1 2
    3 // vendor/NoxLogic/Foo.php
    4
    5 namespace NoxLogic;
    6
    7 use \NoxLogic\Annotations as NoxAnnotations;
    8
    9 class Foo {
    10
    11 /**
    12 * @author Joshua Thijssen
    13 *
    14 * @NoxAnnotations\Prepend("text before", repeat = 3)
    15 * @NoxAnnotations\Prepend("more text before")
    16 * @NoxAnnotations\Append("some text after")
    17 */
    18 function output($string) {
    19 return "[".$string."]";
    20 }
    21
    22 }
    annotation usage
    Add use statements!
    (can mess up your IDE)
    Ignored Annotations

    View Slide

  22. 22
    private static $globalIgnoredNames = array(
    'access'=> true, 'author'=> true, 'copyright'=> true, 'deprecated'=> true,
    'example'=> true, 'ignore'=> true, 'internal'=> true, 'link'=> true, 'see'=> true,
    'since'=> true, 'tutorial'=> true, 'version'=> true, 'package'=> true,
    'subpackage'=> true, 'name'=> true, 'global'=> true, 'param'=> true,
    'return'=> true, 'staticvar'=> true, 'category'=> true, 'staticVar'=> true,
    'static'=> true, 'var'=> true, 'throws'=> true, 'inheritdoc'=> true,
    'inheritDoc'=> true, 'license'=> true, 'todo'=> true, 'TODO'=> true,
    'deprec'=> true, 'property' => true, 'method' => true,
    'abstract'=> true, 'exception'=> true, 'magic' => true, 'api' => true,
    'final'=> true, 'filesource'=> true, 'throw' => true, 'uses' => true,
    'usedby'=> true, 'private' => true, 'Annotation' => true, 'override' => true,
    'codeCoverageIgnore' => true, 'codeCoverageIgnoreStart' => true, 'codeCoverageIgnoreEnd' => true,
    'Required' => true, 'Attribute' => true, 'Attributes' => true,
    'Target' => true, 'SuppressWarnings' => true,
    'ingroup' => true, 'code' => true, 'endcode' => true,
    'package_version' => true, 'fixme' => true
    );
    Doctrine\Common\Annotations\AnnotationReader

    View Slide

  23. 23
    1 $ php annotations.php
    2 NoxLogic\Annotations\Prepend Object
    3 (
    4 [value] => text before
    5 [repeat:protected] => 3
    6 [priority:protected] => 100
    7 )
    8 NoxLogic\Annotations\Prepend Object
    9 (
    10 [value] => more text before
    11 [repeat:protected] => 1
    12 [priority:protected] => 100
    13 )
    14 NoxLogic\Annotations\Append Object
    15 (
    16 [value:protected] => some text after
    17 [repeats:protected] => 1
    18 [priority:protected] => 100
    19 )

    View Slide

  24. ➡ Does NOT contain logic to does “magic”
    execution.
    ➡ “Prepend” and “Append” are just names.
    24

    View Slide

  25. Enter
    25
    v2.4.x

    View Slide

  26. 26
    Controllers

    View Slide

  27. 1. Create annotation class
    2. Create event listener(s)
    3. Service configuration
    4. ???
    5. Profit!
    27
    World Domination Plan (v5.3 beta)

    View Slide

  28. 28
    1 2
    3 namespace NoxLogic\DemoBundle\Service\Annotation;
    4
    5 /**
    6 * @Annotation
    7 */
    8 class Reverse {
    9
    10 }
    simple annotation without data values

    View Slide

  29. 29
    1 2
    3 namespace NoxLogic\DemoBundle\EventListener;
    4
    5 use NoxLogic\DemoBundle\Service\Annotation\Reverse;
    6 use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
    7
    8 class AnnotationListener {
    9
    10 /** @var \Doctrine\Common\Annotations\Reader */
    11 protected $reader;
    12
    13 function __construct(\Doctrine\Common\Annotations\Reader $reader) {
    14 // Inject a annotation reader
    15 $this->reader = $reader;
    16 }
    17
    ...
    annotation listener 1/2

    View Slide

  30. 30
    ....
    18 public function onKernelController(FilterControllerEvent $event) {
    19 // Skip if we aren't a controller
    20 if (! is_array($controller = $event->getController())) {
    21 return;
    22 }
    23
    24 $object = new \ReflectionObject($controller[0]);
    25 $method = $object->getMethod($controller[1]);
    26
    27 foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
    28 if ($annotation instanceof Reverse) {
    29 $r = new \ReflectionMethod($object, $method);
    30 foreach ($r->getParameters() as $param) {
    31 $name = $param->getName();
    32
    33 $request = $event->getRequest();
    34 $request->attributes->set($name,
    strrev($request->attributes->get($name)));
    35 }
    36 }
    37 }
    38 }
    39
    40 }
    annotation listener 2/2

    View Slide

  31. 31
    1 parameters:
    2 noxlogic_demo_bundle.annotation.listener.class:
    NoxLogic\DemoBundle\EventListener\AnnotationListener
    3
    4 services:
    5 noxlogic_demo_bundle.annotation.listener:
    6 class : %noxlogic_demo_bundle.annotation.listener.class%
    7 arguments: [ @annotation_reader ]
    8 tags:
    9 - { name: kernel.event_listener, event: kernel.controller,
    method: onKernelController, priority: 10 }
    service configuration

    View Slide

  32. 32
    1 2
    3 namespace NoxLogic\DemoBundle\Controller;
    4
    5 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    6 use NoxLogic\DemoBundle\Service\Annotation as NoxAnnotation;
    7
    8 class DefaultController extends Controller
    9 {
    10
    11 /**
    12 * @NoxAnnotation\Reverse()
    13 */
    14 public function indexAction($name)
    15 {
    16 return $this->render('NoxLogicDemoBundle:Default:index.html.twig',
    array('name' => $name));
    17 }
    18 }
    hello dlrow
    controller

    View Slide

  33. 33
    1 2
    3 namespace NoxLogic\DemoBundle\Controller;
    4
    5 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    6 use NoxLogic\DemoBundle\Service\Annotation as NoxAnnotation;
    7
    8 class DefaultController extends Controller
    9 {
    10
    11 /**
    12 * @NoxAnnotation\Reverse()
    13 * @NoxAnnotation\Reverse()
    14 */
    15 public function indexAction($name)
    16 {
    17 return $this->render('NoxLogicDemoBundle:Default:index.html.twig',
    array('name' => $name));
    18 }
    19 }
    hello world
    multiple annotations

    View Slide

  34. 34
    1 foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
    2 if ($annotation instanceof Reverse) {
    3 $r = new \ReflectionMethod($controller[0], $controller[1]);
    4 foreach ($r->getParameters() as $param) {
    5 $name = $param->getName();
    6
    7 $request = $event->getRequest();
    8 $request->attributes->set($name,
    strrev($request->attributes->get($name)));
    9 }
    10 }
    11
    12 if ($annotation instanceof Uppercase) {
    13 $r = new \ReflectionMethod($controller[0], $controller[1]);
    14 foreach ($r->getParameters() as $param) {
    15 $name = $param->getName();
    16
    17 $request = $event->getRequest();
    18 $request->attributes->set($name,
    strtoupper($request->attributes->get($name)));
    19 }
    20 }
    21
    22 if ($annotation instanceof ....
    complex listener

    View Slide

  35. 35
    Moving code

    View Slide

  36. 36
    ➡ Move annotations to separate listeners
    ➡ Uppercase Listener
    ➡ Reverse Listener
    ➡ Move “business logic” away into separate
    services (upperCaseService,
    reverseService, transformService)

    View Slide

  37. 37
    @header
    (Adds additional headers to your response)

    View Slide

  38. 38
    1 2
    3 namespace NoxLogic\DemoBundle\Controller;
    4
    5 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    6 use NoxLogic\DemoBundle\Service\Annotation as NoxAnnotations;
    7
    8 class DefaultController extends Controller
    9 {
    10
    11 /**
    12 * @NoxAnnotations\Header(name="X-Some-Header", value="Data");
    13 * @NoxAnnotations\Header(name="X-AnotherHeader", value="123456");
    14 */
    15 public function indexAction($name)
    16 {
    17 return $this->render('NoxLogicDemoBundle:Default:index.html.twig',
    array('name' => $name));
    18 }
    19 }
    header annotation usage

    View Slide

  39. ➡ onKernelResponse (kernel.response)
    ➡ FilterResponseEvent $event
    ➡ But.. no $event->getController
    ➡ How to “iterate” our annotations?
    39

    View Slide

  40. ➡ use onKernelController()
    (kernel.controller)
    ➡ store annotations inside request
    ➡ read back inside onKernelResponse
    40

    View Slide

  41. 41
    1 public function onKernelController(FilterControllerEvent $event) {
    2 // Skip if we aren't a controller
    3 if (! is_array($controller = $event->getController())) {
    4 return;
    5 }
    6
    7 $object = new \ReflectionObject($controller[0]);
    8 $method = $object->getMethod($controller[1]);
    9
    10 foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
    11 if (! $annotation instanceof Header) continue;
    12
    13 $request = $event->getRequest();
    14 $request->attributes->set('_header', $annotation);
    15 }
    16 }
    storing the annotation inside the $request

    View Slide

  42. 42
    1 public function onKernelResponse(FilterResponseEvent $event) {
    2 $request = $event->getRequest();
    3
    4 $annotation = $request->attributes->get('_header', null);
    5 if (! $annotation) return;
    6
    7 $response = $event->getResponse();
    8 $response->headers->set($annotation->getName(), $annotation->getValue());
    9 }
    retrieving the annotation from the $request

    View Slide

  43. 43
    Symfony2 makes
    it easier:
    (actually, FrameworkExtraBundle)

    View Slide

  44. 44
    1 /**
    2 * @Annotation
    3 */
    4 class Header extends ConfigurationAnnotation {
    5
    6 protected $name;
    7 protected $value;
    8
    9 public function getAliasName()
    10 {
    11 return "header";
    12 }
    13
    14 public function allowArray()
    15 {
    16 return true;
    17 }
    using sensioFrameworkExtraBundle configurationAnnotation
    Calls setName() setValue(), stores annotation info inside request
    attribute field named “_header” and allows multiple annotations.

    View Slide

  45. 45
    1 public function onKernelResponse(FilterResponseEvent $event) {
    2 $request = $event->getRequest();
    3
    4 $annotations = $request->attributes->get('_header', null);
    5 if (! $annotations) return;
    6
    7 $response = $event->getResponse();
    8 foreach ($annotations as $annotation) {
    9 $response->headers->set($annotation->getName(), $annotation->getValue());
    10 }
    11 }
    auto injects (multiple) annotations inside $request

    View Slide

  46. ➡ Uses kernel.controller (prio: 0)
    ➡ Does work when kernel.controller has
    been called.
    ➡ Does not work on kernel.request etc.
    46

    View Slide

  47. 47
    Services

    View Slide

  48. 48
    ➡ Modifies mostly setup of a service.
    ➡ Tagging, injection of services, security
    permissions etc.
    ➡ Pretty much you are changing the
    Dependency Injection Container.

    View Slide

  49. 1. Create annotation class
    2. Add compiler pass that checks and
    tags annotated services.
    3. Add compiler pass that collects
    tagged services and does the magic
    49
    World Domination Plan (v5.3 beta)

    View Slide

  50. 50
    ➡ JMSDiExtraBundle
    ➡ @inject, @service, @tag, @formtype ...

    View Slide

  51. ➡ Let’s try it (the hard way)
    51

    View Slide

  52. ➡ @SecurityLevel(“PUBLIC”)
    ➡ @SecurityLevel(“SECRET”)
    ➡ @SecurityLevel(“TOP SECRET”)
    52

    View Slide

  53. ➡ Cannot inject TOP_SECRET into
    PUBLIC or SECRET.
    ➡ Can inject PUBLIC or SECRET into
    TOP_SECRET.
    ➡ Not annotated, we can inject it in any
    securitylevel.
    53

    View Slide

  54. 1 2
    3 namespace NoxLogic\DefaultBundle\Service;
    4
    5 use \NoxLogic\DefaultBundle\Annotation\SecurityLevel;
    6
    7 /**
    8 * @SecurityLevel("PUBLIC")
    9 */
    10 class PublicService {
    11
    12 /**
    13 * AnotherPublicService
    14 */
    15 public $anotherPublicService;
    16
    17 /**
    18 * PrivateService // This should not be able to work!
    19 */
    20 public $privateService;
    21
    22 }
    54

    View Slide

  55. 1 2
    3 namespace NoxLogic\DefaultBundle\Service;
    4
    5 use \NoxLogic\DefaultBundle\Annotation\SecurityLevel;
    6
    7 /**
    8 * @SecurityLevel("PUBLIC")
    9 */
    10 class AnotherPublicService {
    11
    12 /**
    13 * PublicService
    14 */
    15 protected $publicService;
    16
    17
    18 function setPublicService($publicService) {
    19 $this->publicService = $publicService;
    20 }
    21
    22 }
    55

    View Slide

  56. 1 2
    3 /*
    4 * Everything in this service is highly classified!
    5 */
    6
    7 namespace NoxLogic\DefaultBundle\Service;
    8
    9 use \NoxLogic\DefaultBundle\Annotation\SecurityLevel;
    10
    11 /**
    12 * @SecurityLevel("TOP SECRET")
    13 */
    14 class PrivateService {
    15
    16 /**
    17 * @var anotherPrivateService
    18 */
    19 public $anotherPrivateService;
    20 }
    56

    View Slide

  57. 1 2
    3 namespace NoxLogic\DefaultBundle\Service;
    4
    5 use \NoxLogic\DefaultBundle\Annotation\SecurityLevel;
    6
    7 /**
    8 * @SecurityLevel("SECRET")
    9 */
    10 class AnotherPrivateService {
    11
    12 /**
    13 * PublicService
    14 */
    15 protected $publicService;
    16
    17 function __construct($publicService) {
    18 $this->publicService = $publicService;
    19 }
    20
    21 }
    57

    View Slide

  58. 1 parameters:
    2 noxlogic.default.service.public.class: NoxLogic\DefaultBundle\Service\PublicService
    3 noxlogic.default.service.anotherpublic.class: NoxLogic\DefaultBundle\Service\AnotherPublicService
    4 noxlogic.default.service.private.class: NoxLogic\DefaultBundle\Service\PrivateClass
    5 noxlogic.default.service.anotherprivate.class: NoxLogic\DefaultBundle\Service\AnotherPrivateService
    6
    7 services:
    8 noxlogic.default.service.public:
    9 class: %noxlogic.default.service.public.class%
    10 properties:
    11 anotherPublicService: @noxlogic.default.service.anotherpublic
    12 privateService: @noxlogic.default.service.private
    13
    14 noxlogic.default.service.anotherpublic:
    15 class: %noxlogic.default.service.anotherpublic.class%
    16 calls:
    17 - [ setPublicService, [ @noxlogic.default.service.public ] ]
    18
    19 noxlogic.default.service.private:
    20 class: %noxlogic.default.service.private.class%
    21 properties:
    22 anotherPrivateService: @noxlogic.default.service.anotherprivate
    23
    24 noxlogic.default.service.anotherprivate:
    25 class: %noxlogic.default.service.anotherprivate.class%
    26 arguments: [ @noxlogic.default.service.public ]
    58
    Services using other services, constructor, setter and
    property injection

    View Slide

  59. ➡ Create annotation
    ➡ Create securityLevelCollectorPass
    ➡ Create securityLevelCheckerPass
    ➡ Add compiler passes
    59

    View Slide

  60. 60
    1 /**
    2 * @Annotation
    3 * @Target("CLASS")
    4 */
    5 class SecurityLevel {
    6
    7 const LEVEL_PUBLIC = 1;
    8 const LEVEL_SECRET = 2;
    9 const LEVEL_TOP_SECRET = 4;
    10
    11 protected $mapping = array(
    12 "PUBLIC" => self::LEVEL_PUBLIC,
    13 "SECRET" => self::LEVEL_SECRET,
    14 "TOP SECRET" => self::LEVEL_TOP_SECRET,
    15 );
    16
    17 protected $level = 0;
    18
    19 public function __construct($value) {
    20 $value = array_shift($value);
    21 if (array_key_exists($value, $this->mapping)) {
    22 $this->level = $this->mapping[$value];
    23 } else {
    24 throw new \Exception("Unknown security level specified. Use: PUBLIC, SECRET or
    TOP_SECRET");
    25 }
    26 }
    27
    28 function getLevel() {
    29 return $this->level;
    30 }
    31
    32 }

    View Slide

  61. 61
    1 class SecurityLevelCollectorPass implements CompilerPassInterface
    2 {
    3
    4 public function process(ContainerBuilder $container)
    5 {
    6 // Can't inject?
    7 $reader = $container->get("annotation_reader");
    8
    9 foreach ($container->getDefinitions() as $id => $definition) {
    10 try {
    11 $class = new \ReflectionClass($definition->getClass());
    12 } catch (\ReflectionException $e) {
    13 continue;
    14 }
    15
    16 foreach ($reader->getClassAnnotations($class) as $annotation) {
    17 if (! $annotation instanceOf \NoxLogic\DefaultBundle\Annotation\SecurityLevel) {
    18 continue;
    19 }
    20
    21 $definition->securityLevel = $annotation;
    22 }
    23 }
    24 }

    View Slide

  62. 62
    1 class SecurityLevelCheckerPass implements CompilerPassInterface
    2 {
    3 /** @var ContainerBuilder */
    4 protected $container;
    5
    6 public function process(ContainerBuilder $container)
    7 {
    8 $this->container = $container;
    9
    10 foreach ($this->container->getDefinitions() as $id => $definition) {
    11 if (! property_exists($definition, 'securityLevel')) continue;
    12
    13 $this->checkSecurityClearance($definition, $definition->getArguments());
    14 $this->checkSecurityClearance($definition, $definition->getMethodCalls());
    15 $this->checkSecurityClearance($definition, $definition->getProperties());
    16 }
    17 }
    ...

    View Slide

  63. 63
    1 function checkSecurityClearanceForArgument(Definition $definition,
    Reference $reference, Definition $targetDefinition) {
    2 // No target is ok
    3 if (! $targetDefinition) return;
    4
    5 // No securitylevel on the target is ok
    6 if (! isset($targetDefinition->securityLevel)) {
    7 return;
    8 }
    9
    10 if ($definition->securityLevel->getLevel() > $targetDefinition->securityLevel->getLevel()) {
    11 throw new SecurityLevelException("You cannot inject " .
    $targetDefinition->getClass() . " into the more secured service " .
    $definition->getClass());
    12 }
    13 }

    View Slide

  64. 64
    1 2
    3 namespace NoxLogic\DefaultBundle;
    4
    5 use NoxLogic\DefaultBundle\DependencyInjection\Compiler\SecurityLevelCheckerPass;
    6 use NoxLogic\DefaultBundle\DependencyInjection\Compiler\SecurityLevelCollectorPass;
    7 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
    8 use Symfony\Component\DependencyInjection\ContainerBuilder;
    9 use Symfony\Component\HttpKernel\Bundle\Bundle;
    10
    11 class NoxLogicDefaultBundle extends Bundle
    12 {
    13 public function build(ContainerBuilder $container)
    14 {
    15 $config = $container->getCompiler()->getPassConfig();
    16 $config->addPass(new SecurityLevelCollectorPass(), PassConfig::TYPE_AFTER_REMOVING);
    17 $config->addPass(new SecurityLevelCheckerPass(), PassConfig::TYPE_AFTER_REMOVING);
    18 }
    19 }

    View Slide

  65. 65

    View Slide

  66. ➡ More info:
    ➡ http://php-and-symfony.matthiasnoback.nl/2012/12/
    prevent-controller-execution-with-annotations-and-
    return-a-custom-response/
    ➡ https://github.com/jaytaph/MultiParamBundle
    ➡ http://jmsyst.com/bundles/JMSDiExtraBundle
    66

    View Slide

  67. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg 67

    View Slide

  68. 68
    Find me on twitter: @jaytaph
    Find me for consultancy and training: www.noxlogic.nl
    Find me on email: [email protected]
    Find me for blogs: www.adayinthelifeof.nl

    View Slide