Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

334 lines (281 sloc) 10.034 kb
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads YAML files service definitions.
*
* The YAML format does not support anonymous services (cf. the XML loader).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class YamlFileLoader extends FileLoader
{
/**
* Loads a Yaml file.
*
* @param mixed $file The resource
* @param string $type The resource type
*/
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$content = $this->loadFile($path);
$this->container->addResource(new FileResource($path));
// empty file
if (null === $content) {
return;
}
// imports
$this->parseImports($content, $file);
// parameters
if (isset($content['parameters'])) {
foreach ($content['parameters'] as $key => $value) {
$this->container->setParameter($key, $this->resolveServices($value));
}
}
// extensions
$this->loadFromExtensions($content);
// services
$this->parseDefinitions($content, $file);
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean true if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
}
/**
* Parses all imports
*
* @param array $content
* @param string $file
*/
private function parseImports($content, $file)
{
if (!isset($content['imports'])) {
return;
}
foreach ($content['imports'] as $import) {
$this->setCurrentDir(dirname($file));
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
}
}
/**
* Parses definitions
*
* @param array $content
* @param string $file
*/
private function parseDefinitions($content, $file)
{
if (!isset($content['services'])) {
return;
}
foreach ($content['services'] as $id => $service) {
$this->parseDefinition($id, $service, $file);
}
}
/**
* Parses a definition.
*
* @param string $id
* @param array $service
* @param string $file
*
* @throws InvalidArgumentException When tags are invalid
*/
private function parseDefinition($id, $service, $file)
{
if (is_string($service) && 0 === strpos($service, '@')) {
$this->container->setAlias($id, substr($service, 1));
return;
} elseif (isset($service['alias'])) {
$public = !array_key_exists('public', $service) || (Boolean) $service['public'];
$this->container->setAlias($id, new Alias($service['alias'], $public));
return;
}
if (isset($service['parent'])) {
$definition = new DefinitionDecorator($service['parent']);
} else {
$definition = new Definition();
}
if (isset($service['class'])) {
$definition->setClass($service['class']);
}
if (isset($service['scope'])) {
$definition->setScope($service['scope']);
}
if (isset($service['synthetic'])) {
$definition->setSynthetic($service['synthetic']);
}
if (isset($service['public'])) {
$definition->setPublic($service['public']);
}
if (isset($service['abstract'])) {
$definition->setAbstract($service['abstract']);
}
if (isset($service['factory_class'])) {
$definition->setFactoryClass($service['factory_class']);
}
if (isset($service['factory_method'])) {
$definition->setFactoryMethod($service['factory_method']);
}
if (isset($service['factory_service'])) {
$definition->setFactoryService($service['factory_service']);
}
if (isset($service['file'])) {
$definition->setFile($service['file']);
}
if (isset($service['arguments'])) {
$definition->setArguments($this->resolveServices($service['arguments']));
}
if (isset($service['properties'])) {
$definition->setProperties($this->resolveServices($service['properties']));
}
if (isset($service['configurator'])) {
if (is_string($service['configurator'])) {
$definition->setConfigurator($service['configurator']);
} else {
$definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
}
}
if (isset($service['calls'])) {
foreach ($service['calls'] as $call) {
$args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
$definition->addMethodCall($call[0], $args);
}
}
if (isset($service['tags'])) {
if (!is_array($service['tags'])) {
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s.', $id, $file));
}
foreach ($service['tags'] as $tag) {
if (!isset($tag['name'])) {
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
}
$name = $tag['name'];
unset($tag['name']);
foreach ($tag as $attribute => $value) {
if (!is_scalar($value)) {
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s" in %s.', $id, $name, $file));
}
}
$definition->addTag($name, $tag);
}
}
$this->container->setDefinition($id, $definition);
}
/**
* Loads a YAML file.
*
* @param string $file
*
* @return array The file content
*/
private function loadFile($file)
{
return $this->validate(Yaml::parse($file), $file);
}
/**
* Validates a YAML file.
*
* @param mixed $content
* @param string $file
*
* @return array
*
* @throws InvalidArgumentException When service file is not valid
*/
private function validate($content, $file)
{
if (null === $content) {
return $content;
}
if (!is_array($content)) {
throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
}
foreach (array_keys($content) as $namespace) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}
if (!$this->container->hasExtension($namespace)) {
$extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
throw new InvalidArgumentException(sprintf(
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
$namespace,
$file,
$namespace,
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
));
}
}
return $content;
}
/**
* Resolves services.
*
* @param string $value
*
* @return Reference
*/
private function resolveServices($value)
{
if (is_array($value)) {
$value = array_map(array($this, 'resolveServices'), $value);
} elseif (is_string($value) && 0 === strpos($value, '@')) {
if (0 === strpos($value, '@?')) {
$value = substr($value, 2);
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
} else {
$value = substr($value, 1);
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
}
if ('=' === substr($value, -1)) {
$value = substr($value, 0, -1);
$strict = false;
} else {
$strict = true;
}
$value = new Reference($value, $invalidBehavior, $strict);
}
return $value;
}
/**
* Loads from Extensions
*
* @param array $content
*/
private function loadFromExtensions($content)
{
foreach ($content as $namespace => $values) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}
if (!is_array($values)) {
$values = array();
}
$this->container->loadFromExtension($namespace, $values);
}
}
}
Jump to Line
Something went wrong with that request. Please try again.