ConfigDriver.php 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <?php
  2. namespace JMS\SecurityExtraBundle\Metadata\Driver;
  3. use JMS\SecurityExtraBundle\Security\Authorization\Expression\Expression;
  4. use JMS\SecurityExtraBundle\Metadata\MethodMetadata;
  5. use JMS\SecurityExtraBundle\Metadata\ClassMetadata;
  6. use Metadata\Driver\DriverInterface;
  7. /**
  8. * Uses Symfony2 DI configuration for metadata.
  9. *
  10. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  11. */
  12. class ConfigDriver implements DriverInterface
  13. {
  14. private $bundles;
  15. private $config;
  16. public function __construct(array $bundles, array $config)
  17. {
  18. uasort($bundles, function($a, $b) {
  19. return strlen($b) - strlen($a);
  20. });
  21. foreach ($bundles as $name => $namespace) {
  22. $bundles[$name] = substr($namespace, 0, strrpos($namespace, '\\'));
  23. }
  24. $this->bundles = $bundles;
  25. $this->config = $config;
  26. }
  27. public function loadMetadataForClass(\ReflectionClass $class)
  28. {
  29. $metadata = new ClassMetadata($class->name);
  30. foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
  31. if ($method->getDeclaringClass()->name !== $class->name) {
  32. continue;
  33. }
  34. $expression = null;
  35. if (null !== $notation = $this->getControllerNotation($method)) {
  36. $expression = $this->getExpressionForSignature($notation);
  37. }
  38. if (null === $expression && null === $expression =
  39. $this->getExpressionForSignature($method->class.'::'.$method->name)) {
  40. continue;
  41. }
  42. $methodMetadata = new MethodMetadata($method->class, $method->name);
  43. $methodMetadata->roles = array(new Expression($expression));
  44. $metadata->addMethodMetadata($methodMetadata);
  45. }
  46. if (!$metadata->methodMetadata) {
  47. return null;
  48. }
  49. return $metadata;
  50. }
  51. private function getExpressionForSignature($signature)
  52. {
  53. foreach ($this->config as $pattern => $expr) {
  54. if (!preg_match('#'.$pattern.'#i', $signature)) {
  55. continue;
  56. }
  57. return $expr;
  58. }
  59. return null;
  60. }
  61. // TODO: Is it feasible to reverse-engineer the notation for service controllers?
  62. private function getControllerNotation(\ReflectionMethod $method)
  63. {
  64. $signature = $method->class.'::'.$method->name;
  65. // check if class is a controller
  66. if (0 === preg_match('#\\\\Controller\\\\([^\\\\]+)Controller::(.+)Action$#', $signature, $match)) {
  67. return null;
  68. }
  69. foreach ($this->bundles as $name => $namespace) {
  70. if (0 !== strpos($method->class, $namespace)) {
  71. continue;
  72. }
  73. // controller notation (AcmeBundle:Foo:foo)
  74. return $name.':'.$match[1].':'.$match[2];
  75. }
  76. return null;
  77. }
  78. }