Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

RegisterControllerArgumentLocatorsPass.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 8.29 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\HttpKernel\DependencyInjection;
013   
014  use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
015  use Symfony\Component\DependencyInjection\ChildDefinition;
016  use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
017  use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
018  use Symfony\Component\DependencyInjection\ContainerAwareInterface;
019  use Symfony\Component\DependencyInjection\ContainerBuilder;
020  use Symfony\Component\DependencyInjection\ContainerInterface;
021  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
022  use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
023  use Symfony\Component\DependencyInjection\Reference;
024  use Symfony\Component\DependencyInjection\TypedReference;
025  use Symfony\Component\HttpFoundation\Request;
026   
027  /**
028   * Creates the service-locators required by ServiceValueResolver.
029   *
030   * @author Nicolas Grekas <p@tchwork.com>
031   */
032  class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
033  {
034      private $resolverServiceId;
035      private $controllerTag;
036   
037      public function __construct($resolverServiceId = 'argument_resolver.service', $controllerTag = 'controller.service_arguments')
038      {
039          $this->resolverServiceId = $resolverServiceId;
040          $this->controllerTag = $controllerTag;
041      }
042   
043      public function process(ContainerBuilder $container)
044      {
045          if (false === $container->hasDefinition($this->resolverServiceId)) {
046              return;
047          }
048   
049          $parameterBag = $container->getParameterBag();
050          $controllers = [];
051   
052          foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) {
053              $def = $container->getDefinition($id);
054              $def->setPublic(true);
055              $class = $def->getClass();
056              $autowire = $def->isAutowired();
057              $bindings = $def->getBindings();
058   
059              // resolve service class, taking parent definitions into account
060              while ($def instanceof ChildDefinition) {
061                  $def = $container->findDefinition($def->getParent());
062                  $class = $class ?: $def->getClass();
063                  $bindings += $def->getBindings();
064              }
065              $class = $parameterBag->resolveValue($class);
066   
067              if (!$r = $container->getReflectionClass($class)) {
068                  throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
069              }
070              $isContainerAware = $r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class);
071   
072              // get regular public methods
073              $methods = [];
074              $arguments = [];
075              foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) {
076                  if ('setContainer' === $r->name && $isContainerAware) {
077                      continue;
078                  }
079                  if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) {
080                      $methods[strtolower($r->name)] = [$r, $r->getParameters()];
081                  }
082              }
083   
084              // validate and collect explicit per-actions and per-arguments service references
085              foreach ($tags as $attributes) {
086                  if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) {
087                      $autowire = true;
088                      continue;
089                  }
090                  foreach (['action', 'argument', 'id'] as $k) {
091                      if (!isset($attributes[$k][0])) {
092                          throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "%s" %s for service "%s".', $k, $this->controllerTag, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id));
093                      }
094                  }
095                  if (!isset($methods[$action = strtolower($attributes['action'])])) {
096                      throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "%s" for service "%s": no public "%s()" method found on class "%s".', $this->controllerTag, $id, $attributes['action'], $class));
097                  }
098                  list($r, $parameters) = $methods[$action];
099                  $found = false;
100   
101                  foreach ($parameters as $p) {
102                      if ($attributes['argument'] === $p->name) {
103                          if (!isset($arguments[$r->name][$p->name])) {
104                              $arguments[$r->name][$p->name] = $attributes['id'];
105                          }
106                          $found = true;
107                          break;
108                      }
109                  }
110   
111                  if (!$found) {
112                      throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $this->controllerTag, $id, $r->name, $attributes['argument'], $class));
113                  }
114              }
115   
116              foreach ($methods as list($r, $parameters)) {
117                  /** @var \ReflectionMethod $r */
118   
119                  // create a per-method map of argument-names to service/type-references
120                  $args = [];
121                  foreach ($parameters as $p) {
122                      /** @var \ReflectionParameter $p */
123                      $type = $target = ProxyHelper::getTypeHint($r, $p, true);
124                      $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
125   
126                      if (isset($arguments[$r->name][$p->name])) {
127                          $target = $arguments[$r->name][$p->name];
128                          if ('?' !== $target[0]) {
129                              $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
130                          } elseif ('' === $target = (string) substr($target, 1)) {
131                              throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id));
132                          } elseif ($p->allowsNull() && !$p->isOptional()) {
133                              $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
134                          }
135                      } elseif (isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) {
136                          $binding = $bindings[$bindingName];
137   
138                          list($bindingValue, $bindingId) = $binding->getValues();
139   
140                          if (!$bindingValue instanceof Reference) {
141                              continue;
142                          }
143   
144                          $binding->setValues([$bindingValue, $bindingId, true]);
145                          $args[$p->name] = $bindingValue;
146   
147                          continue;
148                      } elseif (!$type || !$autowire) {
149                          continue;
150                      }
151   
152                      if (Request::class === $type) {
153                          continue;
154                      }
155   
156                      if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) {
157                          $message = sprintf('Cannot determine controller argument for "%s::%s()": the $%s argument is type-hinted with the non-existent class or interface: "%s".', $class, $r->name, $p->name, $type);
158   
159                          // see if the type-hint lives in the same namespace as the controller
160                          if (0 === strncmp($type, $class, strrpos($class, '\\'))) {
161                              $message .= ' Did you forget to add a use statement?';
162                          }
163   
164                          throw new InvalidArgumentException($message);
165                      }
166   
167                      $args[$p->name] = $type ? new TypedReference($target, $type, $r->class, $invalidBehavior) : new Reference($target, $invalidBehavior);
168                  }
169                  // register the maps as a per-method service-locators
170                  if ($args) {
171                      $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args);
172                  }
173              }
174          }
175   
176          $container->getDefinition($this->resolverServiceId)
177              ->replaceArgument(0, ServiceLocatorTagPass::register($container, $controllers));
178      }
179  }
180