vendor/symfony/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Component\DependencyInjection\Loader;
       
    13 
       
    14 use Symfony\Component\DependencyInjection\DefinitionDecorator;
       
    15 use Symfony\Component\DependencyInjection\Alias;
       
    16 use Symfony\Component\DependencyInjection\ContainerInterface;
       
    17 use Symfony\Component\DependencyInjection\Definition;
       
    18 use Symfony\Component\DependencyInjection\Reference;
       
    19 use Symfony\Component\DependencyInjection\ContainerBuilder;
       
    20 use Symfony\Component\Config\Resource\FileResource;
       
    21 use Symfony\Component\Yaml\Yaml;
       
    22 
       
    23 /**
       
    24  * YamlFileLoader loads YAML files service definitions.
       
    25  *
       
    26  * The YAML format does not support anonymous services (cf. the XML loader).
       
    27  *
       
    28  * @author Fabien Potencier <fabien@symfony.com>
       
    29  */
       
    30 class YamlFileLoader extends FileLoader
       
    31 {
       
    32     /**
       
    33      * Loads a Yaml file.
       
    34      *
       
    35      * @param mixed  $file The resource
       
    36      * @param string $type The resource type
       
    37      */
       
    38     public function load($file, $type = null)
       
    39     {
       
    40         $path = $this->locator->locate($file);
       
    41 
       
    42         $content = $this->loadFile($path);
       
    43 
       
    44         $this->container->addResource(new FileResource($path));
       
    45 
       
    46         // empty file
       
    47         if (null === $content) {
       
    48             return;
       
    49         }
       
    50 
       
    51         // imports
       
    52         $this->parseImports($content, $file);
       
    53 
       
    54         // parameters
       
    55         if (isset($content['parameters'])) {
       
    56             foreach ($content['parameters'] as $key => $value) {
       
    57                 $this->container->setParameter($key, $this->resolveServices($value));
       
    58             }
       
    59         }
       
    60 
       
    61         // extensions
       
    62         $this->loadFromExtensions($content);
       
    63 
       
    64         // services
       
    65         $this->parseDefinitions($content, $file);
       
    66     }
       
    67 
       
    68     /**
       
    69      * Returns true if this class supports the given resource.
       
    70      *
       
    71      * @param mixed  $resource A resource
       
    72      * @param string $type     The resource type
       
    73      *
       
    74      * @return Boolean true if this class supports the given resource, false otherwise
       
    75      */
       
    76     public function supports($resource, $type = null)
       
    77     {
       
    78         return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
       
    79     }
       
    80 
       
    81     /**
       
    82      * Parses all imports
       
    83      *
       
    84      * @param array $content
       
    85      * @param string $file
       
    86      * @return void
       
    87      */
       
    88     private function parseImports($content, $file)
       
    89     {
       
    90         if (!isset($content['imports'])) {
       
    91             return;
       
    92         }
       
    93 
       
    94         foreach ($content['imports'] as $import) {
       
    95             $this->setCurrentDir(dirname($file));
       
    96             $this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
       
    97         }
       
    98     }
       
    99 
       
   100     /**
       
   101      * Parses definitions
       
   102      *
       
   103      * @param array $content
       
   104      * @param string $file
       
   105      * @return void
       
   106      */
       
   107     private function parseDefinitions($content, $file)
       
   108     {
       
   109         if (!isset($content['services'])) {
       
   110             return;
       
   111         }
       
   112 
       
   113         foreach ($content['services'] as $id => $service) {
       
   114             $this->parseDefinition($id, $service, $file);
       
   115         }
       
   116     }
       
   117 
       
   118     /**
       
   119      * Parses a definition.
       
   120      *
       
   121      * @param string $id
       
   122      * @param array $service
       
   123      * @param string $file
       
   124      * @return void
       
   125      */
       
   126     private function parseDefinition($id, $service, $file)
       
   127     {
       
   128         if (is_string($service) && 0 === strpos($service, '@')) {
       
   129             $this->container->setAlias($id, substr($service, 1));
       
   130 
       
   131             return;
       
   132         } else if (isset($service['alias'])) {
       
   133             $public = !array_key_exists('public', $service) || (Boolean) $service['public'];
       
   134             $this->container->setAlias($id, new Alias($service['alias'], $public));
       
   135 
       
   136             return;
       
   137         }
       
   138 
       
   139         if (isset($service['parent'])) {
       
   140             $definition = new DefinitionDecorator($service['parent']);
       
   141         } else {
       
   142             $definition = new Definition();
       
   143         }
       
   144 
       
   145         if (isset($service['class'])) {
       
   146             $definition->setClass($service['class']);
       
   147         }
       
   148 
       
   149         if (isset($service['scope'])) {
       
   150             $definition->setScope($service['scope']);
       
   151         }
       
   152 
       
   153         if (isset($service['synthetic'])) {
       
   154             $definition->setSynthetic($service['synthetic']);
       
   155         }
       
   156 
       
   157         if (isset($service['public'])) {
       
   158             $definition->setPublic($service['public']);
       
   159         }
       
   160 
       
   161         if (isset($service['abstract'])) {
       
   162             $definition->setAbstract($service['abstract']);
       
   163         }
       
   164 
       
   165         if (isset($service['factory_class'])) {
       
   166             $definition->setFactoryClass($service['factory_class']);
       
   167         }
       
   168 
       
   169         if (isset($service['factory_method'])) {
       
   170             $definition->setFactoryMethod($service['factory_method']);
       
   171         }
       
   172 
       
   173         if (isset($service['factory_service'])) {
       
   174             $definition->setFactoryService($service['factory_service']);
       
   175         }
       
   176 
       
   177         if (isset($service['file'])) {
       
   178             $definition->setFile($service['file']);
       
   179         }
       
   180 
       
   181         if (isset($service['arguments'])) {
       
   182             $definition->setArguments($this->resolveServices($service['arguments']));
       
   183         }
       
   184 
       
   185         if (isset($service['properties'])) {
       
   186             $definition->setProperties($this->resolveServices($service['properties']));
       
   187         }
       
   188 
       
   189         if (isset($service['configurator'])) {
       
   190             if (is_string($service['configurator'])) {
       
   191                 $definition->setConfigurator($service['configurator']);
       
   192             } else {
       
   193                 $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
       
   194             }
       
   195         }
       
   196 
       
   197         if (isset($service['calls'])) {
       
   198             foreach ($service['calls'] as $call) {
       
   199                 $definition->addMethodCall($call[0], $this->resolveServices($call[1]));
       
   200             }
       
   201         }
       
   202 
       
   203         if (isset($service['tags'])) {
       
   204             if (!is_array($service['tags'])) {
       
   205                 throw new \InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s.', $id, $file));
       
   206             }
       
   207 
       
   208             foreach ($service['tags'] as $tag) {
       
   209                 if (!isset($tag['name'])) {
       
   210                     throw new \InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
       
   211                 }
       
   212 
       
   213                 $name = $tag['name'];
       
   214                 unset($tag['name']);
       
   215 
       
   216                 $definition->addTag($name, $tag);
       
   217             }
       
   218         }
       
   219 
       
   220         $this->container->setDefinition($id, $definition);
       
   221     }
       
   222 
       
   223     /**
       
   224      * Loads a YAML file.
       
   225      *
       
   226      * @param string $file
       
   227      * @return array The file content
       
   228      */
       
   229     private function loadFile($file)
       
   230     {
       
   231         return $this->validate(Yaml::parse($file), $file);
       
   232     }
       
   233 
       
   234     /**
       
   235      * Validates a YAML file.
       
   236      *
       
   237      * @param mixed $content
       
   238      * @param string $file
       
   239      * @return array
       
   240      *
       
   241      * @throws \InvalidArgumentException When service file is not valid
       
   242      */
       
   243     private function validate($content, $file)
       
   244     {
       
   245         if (null === $content) {
       
   246             return $content;
       
   247         }
       
   248 
       
   249         if (!is_array($content)) {
       
   250             throw new \InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
       
   251         }
       
   252 
       
   253         foreach (array_keys($content) as $namespace) {
       
   254             if (in_array($namespace, array('imports', 'parameters', 'services'))) {
       
   255                 continue;
       
   256             }
       
   257 
       
   258             if (!$this->container->hasExtension($namespace)) {
       
   259                 $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
       
   260                 throw new \InvalidArgumentException(sprintf(
       
   261                     'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
       
   262                     $namespace,
       
   263                     $file,
       
   264                     $namespace,
       
   265                     $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
       
   266                 ));
       
   267             }
       
   268         }
       
   269 
       
   270         return $content;
       
   271     }
       
   272 
       
   273     /**
       
   274      * Resolves services.
       
   275      *
       
   276      * @param string $value
       
   277      * @return Reference
       
   278      */
       
   279     private function resolveServices($value)
       
   280     {
       
   281         if (is_array($value)) {
       
   282             $value = array_map(array($this, 'resolveServices'), $value);
       
   283         } else if (is_string($value) &&  0 === strpos($value, '@')) {
       
   284             if (0 === strpos($value, '@?')) {
       
   285                 $value = substr($value, 2);
       
   286                 $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
       
   287             } else {
       
   288                 $value = substr($value, 1);
       
   289                 $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
       
   290             }
       
   291 
       
   292             if ('=' === substr($value, -1)) {
       
   293                 $value = substr($value, 0, -1);
       
   294                 $strict = false;
       
   295             } else {
       
   296                 $strict = true;
       
   297             }
       
   298 
       
   299             $value = new Reference($value, $invalidBehavior, $strict);
       
   300         }
       
   301 
       
   302         return $value;
       
   303     }
       
   304 
       
   305     /**
       
   306      * Loads from Extensions
       
   307      *
       
   308      * @param array $content
       
   309      * @return void
       
   310      */
       
   311     private function loadFromExtensions($content)
       
   312     {
       
   313         foreach ($content as $namespace => $values) {
       
   314             if (in_array($namespace, array('imports', 'parameters', 'services'))) {
       
   315                 continue;
       
   316             }
       
   317 
       
   318             if (!is_array($values)) {
       
   319                 $values = array();
       
   320             }
       
   321 
       
   322             $this->container->loadFromExtension($namespace, $values);
       
   323         }
       
   324     }
       
   325 }