2010-01-04 14:26:20 +00:00
< ? php
2011-01-15 13:29:43 +00:00
/*
* This file is part of the Symfony package .
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2011-01-15 13:29:43 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2010-08-20 22:09:55 +01:00
namespace Symfony\Component\DependencyInjection\Loader ;
2010-01-04 14:26:20 +00:00
2012-08-30 20:32:42 +01:00
use Symfony\Component\Config\Resource\FileResource ;
2012-10-30 11:08:35 +00:00
use Symfony\Component\Config\Util\XmlUtils ;
2011-01-26 23:14:31 +00:00
use Symfony\Component\DependencyInjection\DefinitionDecorator ;
2011-01-17 22:28:59 +00:00
use Symfony\Component\DependencyInjection\ContainerInterface ;
2011-01-07 14:44:29 +00:00
use Symfony\Component\DependencyInjection\Alias ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\DependencyInjection\Definition ;
use Symfony\Component\DependencyInjection\Reference ;
2011-12-04 23:51:22 +00:00
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException ;
use Symfony\Component\DependencyInjection\Exception\RuntimeException ;
2013-10-19 15:07:47 +01:00
use Symfony\Component\ExpressionLanguage\Expression ;
2010-01-04 14:26:20 +00:00
/**
* XmlFileLoader loads XML files service definitions .
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2010-01-04 14:26:20 +00:00
*/
class XmlFileLoader extends FileLoader
{
2013-10-19 15:07:47 +01:00
const NS = 'http://symfony.com/schema/dic/services' ;
2010-05-06 12:25:53 +01:00
/**
2014-10-13 20:09:32 +01:00
* { @ inheritdoc }
2010-05-06 12:25:53 +01:00
*/
2014-10-13 20:09:32 +01:00
public function load ( $resource , $type = null )
2010-05-06 12:25:53 +01:00
{
2014-10-13 20:09:32 +01:00
$path = $this -> locator -> locate ( $resource );
2010-01-17 10:21:31 +00:00
2013-10-19 15:07:47 +01:00
$xml = $this -> parseFileToDOM ( $path );
2010-01-04 14:26:20 +00:00
2010-07-16 08:12:58 +01:00
$this -> container -> addResource ( new FileResource ( $path ));
2010-01-04 14:26:20 +00:00
2010-05-06 12:25:53 +01:00
// anonymous services
2012-05-07 11:17:20 +01:00
$this -> processAnonymousServices ( $xml , $path );
2010-01-04 14:26:20 +00:00
2010-05-06 12:25:53 +01:00
// imports
2011-05-28 09:29:32 +01:00
$this -> parseImports ( $xml , $path );
2010-01-04 14:26:20 +00:00
2010-06-22 16:27:49 +01:00
// parameters
2015-07-15 22:26:13 +01:00
$this -> parseParameters ( $xml );
2010-06-22 16:27:49 +01:00
2010-12-13 00:20:21 +00:00
// extensions
$this -> loadFromExtensions ( $xml );
2010-06-22 16:27:49 +01:00
// services
2011-05-28 09:29:32 +01:00
$this -> parseDefinitions ( $xml , $path );
2010-01-04 14:26:20 +00:00
}
2010-07-18 10:26:47 +01:00
/**
2014-10-13 20:09:32 +01:00
* { @ inheritdoc }
2010-07-18 10:26:47 +01:00
*/
2011-02-10 15:15:51 +00:00
public function supports ( $resource , $type = null )
2010-07-18 10:26:47 +01:00
{
return is_string ( $resource ) && 'xml' === pathinfo ( $resource , PATHINFO_EXTENSION );
}
2011-02-13 18:06:41 +00:00
/**
2014-12-21 17:00:50 +00:00
* Parses parameters .
2011-02-13 18:06:41 +00:00
*
2013-10-19 15:07:47 +01:00
* @ param \DOMDocument $xml
2011-02-13 18:06:41 +00:00
*/
2015-07-22 11:08:40 +01:00
private function parseParameters ( \DOMDocument $xml )
2010-01-04 14:26:20 +00:00
{
2013-10-19 15:07:47 +01:00
if ( $parameters = $this -> getChildren ( $xml -> documentElement , 'parameters' )) {
$this -> container -> getParameterBag () -> add ( $this -> getArgumentsAsPhp ( $parameters [ 0 ], 'parameter' ));
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:26:20 +00:00
}
2011-02-13 18:06:41 +00:00
/**
2014-12-21 17:00:50 +00:00
* Parses imports .
2011-02-13 18:06:41 +00:00
*
2013-10-19 15:07:47 +01:00
* @ param \DOMDocument $xml
* @ param string $file
2011-02-13 18:06:41 +00:00
*/
2013-10-19 15:07:47 +01:00
private function parseImports ( \DOMDocument $xml , $file )
2010-01-04 14:26:20 +00:00
{
2013-10-19 15:07:47 +01:00
$xpath = new \DOMXPath ( $xml );
$xpath -> registerNamespace ( 'container' , self :: NS );
if ( false === $imports = $xpath -> query ( '//container:imports/container:import' )) {
2011-02-15 21:06:52 +00:00
return ;
}
2016-01-06 13:34:50 +00:00
$defaultDirectory = dirname ( $file );
2011-02-15 09:09:58 +00:00
foreach ( $imports as $import ) {
2016-01-06 13:34:50 +00:00
$this -> setCurrentDir ( $defaultDirectory );
2014-04-16 09:08:40 +01:00
$this -> import ( $import -> getAttribute ( 'resource' ), null , ( bool ) XmlUtils :: phpize ( $import -> getAttribute ( 'ignore-errors' )), $file );
2010-05-06 12:25:53 +01:00
}
}
2010-01-17 11:20:47 +00:00
2011-02-13 18:06:41 +00:00
/**
2014-12-21 17:00:50 +00:00
* Parses multiple definitions .
2011-02-13 18:06:41 +00:00
*
2013-10-19 15:07:47 +01:00
* @ param \DOMDocument $xml
* @ param string $file
2011-02-13 18:06:41 +00:00
*/
2013-10-19 15:07:47 +01:00
private function parseDefinitions ( \DOMDocument $xml , $file )
2010-01-04 14:26:20 +00:00
{
2013-10-19 15:07:47 +01:00
$xpath = new \DOMXPath ( $xml );
$xpath -> registerNamespace ( 'container' , self :: NS );
if ( false === $services = $xpath -> query ( '//container:services/container:service' )) {
2011-02-15 21:06:52 +00:00
return ;
}
2011-02-15 09:09:58 +00:00
foreach ( $services as $service ) {
2015-03-23 18:17:24 +00:00
if ( null !== $definition = $this -> parseDefinition ( $service , $file )) {
$this -> container -> setDefinition (( string ) $service -> getAttribute ( 'id' ), $definition );
}
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:26:20 +00:00
}
2011-02-13 18:06:41 +00:00
/**
2014-12-21 17:00:50 +00:00
* Parses an individual Definition .
2011-02-13 18:06:41 +00:00
*
2013-10-19 15:07:47 +01:00
* @ param \DOMElement $service
2015-05-31 09:14:49 +01:00
* @ param string $file
2015-03-23 18:17:24 +00:00
*
* @ return Definition | null
2011-02-13 18:06:41 +00:00
*/
2015-05-31 09:14:49 +01:00
private function parseDefinition ( \DOMElement $service , $file )
2010-01-04 14:26:20 +00:00
{
2013-10-19 15:07:47 +01:00
if ( $alias = $service -> getAttribute ( 'alias' )) {
2016-01-09 18:39:03 +00:00
$this -> validateAlias ( $service , $file );
2011-01-07 14:44:29 +00:00
$public = true ;
2013-10-19 15:07:47 +01:00
if ( $publicAttr = $service -> getAttribute ( 'public' )) {
$public = XmlUtils :: phpize ( $publicAttr );
2011-01-07 14:44:29 +00:00
}
2015-03-23 18:17:24 +00:00
$this -> container -> setAlias (( string ) $service -> getAttribute ( 'id' ), new Alias ( $alias , $public ));
2010-01-04 14:26:20 +00:00
2010-05-06 12:25:53 +01:00
return ;
}
2010-01-04 14:26:20 +00:00
2013-10-19 15:07:47 +01:00
if ( $parent = $service -> getAttribute ( 'parent' )) {
$definition = new DefinitionDecorator ( $parent );
2011-01-26 23:14:31 +00:00
} else {
$definition = new Definition ();
}
2010-01-04 14:26:20 +00:00
2015-07-01 21:40:29 +01:00
foreach ( array ( 'class' , 'shared' , 'public' , 'synthetic' , 'lazy' , 'abstract' ) as $key ) {
2013-10-19 15:07:47 +01:00
if ( $value = $service -> getAttribute ( $key )) {
2016-10-27 09:29:18 +01:00
$method = 'set' . $key ;
2013-10-19 15:07:47 +01:00
$definition -> $method ( XmlUtils :: phpize ( $value ));
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:26:20 +00:00
}
2010-05-06 12:25:53 +01:00
2015-08-24 02:36:41 +01:00
if ( $value = $service -> getAttribute ( 'autowire' )) {
$definition -> setAutowired ( XmlUtils :: phpize ( $value ));
}
2013-10-19 15:07:47 +01:00
if ( $files = $this -> getChildren ( $service , 'file' )) {
$definition -> setFile ( $files [ 0 ] -> nodeValue );
2010-01-04 14:26:20 +00:00
}
2015-08-10 13:35:12 +01:00
if ( $deprecated = $this -> getChildren ( $service , 'deprecated' )) {
2016-07-26 17:22:37 +01:00
$definition -> setDeprecated ( true , $deprecated [ 0 ] -> nodeValue ? : null );
2015-08-10 13:35:12 +01:00
}
2013-10-19 15:07:47 +01:00
$definition -> setArguments ( $this -> getArgumentsAsPhp ( $service , 'argument' ));
$definition -> setProperties ( $this -> getArgumentsAsPhp ( $service , 'property' ));
2010-01-04 14:26:20 +00:00
2014-04-13 16:18:39 +01:00
if ( $factories = $this -> getChildren ( $service , 'factory' )) {
$factory = $factories [ 0 ];
if ( $function = $factory -> getAttribute ( 'function' )) {
$definition -> setFactory ( $function );
} else {
2015-03-23 18:17:24 +00:00
$factoryService = $this -> getChildren ( $factory , 'service' );
if ( isset ( $factoryService [ 0 ])) {
2015-05-31 09:14:49 +01:00
$class = $this -> parseDefinition ( $factoryService [ 0 ], $file );
2015-03-23 18:17:24 +00:00
} elseif ( $childService = $factory -> getAttribute ( 'service' )) {
2014-04-13 16:18:39 +01:00
$class = new Reference ( $childService , ContainerInterface :: EXCEPTION_ON_INVALID_REFERENCE , false );
} else {
$class = $factory -> getAttribute ( 'class' );
}
$definition -> setFactory ( array ( $class , $factory -> getAttribute ( 'method' )));
}
}
2013-10-19 15:07:47 +01:00
if ( $configurators = $this -> getChildren ( $service , 'configurator' )) {
$configurator = $configurators [ 0 ];
if ( $function = $configurator -> getAttribute ( 'function' )) {
$definition -> setConfigurator ( $function );
2010-05-07 15:09:11 +01:00
} else {
2015-03-23 18:17:24 +00:00
$configuratorService = $this -> getChildren ( $configurator , 'service' );
if ( isset ( $configuratorService [ 0 ])) {
2015-05-31 09:14:49 +01:00
$class = $this -> parseDefinition ( $configuratorService [ 0 ], $file );
2015-03-23 18:17:24 +00:00
} elseif ( $childService = $configurator -> getAttribute ( 'service' )) {
2013-10-19 15:07:47 +01:00
$class = new Reference ( $childService , ContainerInterface :: EXCEPTION_ON_INVALID_REFERENCE , false );
2010-05-07 15:09:11 +01:00
} else {
2013-10-19 15:07:47 +01:00
$class = $configurator -> getAttribute ( 'class' );
2010-05-06 12:25:53 +01:00
}
2013-10-19 15:07:47 +01:00
$definition -> setConfigurator ( array ( $class , $configurator -> getAttribute ( 'method' )));
2010-05-06 12:25:53 +01:00
}
}
2010-01-04 14:26:20 +00:00
2013-10-19 15:07:47 +01:00
foreach ( $this -> getChildren ( $service , 'call' ) as $call ) {
$definition -> addMethodCall ( $call -> getAttribute ( 'method' ), $this -> getArgumentsAsPhp ( $call , 'argument' ));
2010-02-09 08:45:23 +00:00
}
2013-10-19 15:07:47 +01:00
foreach ( $this -> getChildren ( $service , 'tag' ) as $tag ) {
2010-05-06 12:25:53 +01:00
$parameters = array ();
2013-10-19 15:07:47 +01:00
foreach ( $tag -> attributes as $name => $node ) {
2010-05-08 14:32:30 +01:00
if ( 'name' === $name ) {
2010-05-06 12:25:53 +01:00
continue ;
}
2013-11-10 19:01:46 +00:00
if ( false !== strpos ( $name , '-' ) && false === strpos ( $name , '_' ) && ! array_key_exists ( $normalizedName = str_replace ( '-' , '_' , $name ), $parameters )) {
2013-10-19 15:07:47 +01:00
$parameters [ $normalizedName ] = XmlUtils :: phpize ( $node -> nodeValue );
2013-11-10 19:01:46 +00:00
}
2015-10-04 14:03:24 +01:00
// keep not normalized key
2014-04-02 16:31:05 +01:00
$parameters [ $name ] = XmlUtils :: phpize ( $node -> nodeValue );
2010-05-06 12:25:53 +01:00
}
2016-01-31 07:56:20 +00:00
if ( '' === $tag -> getAttribute ( 'name' )) {
throw new InvalidArgumentException ( sprintf ( 'The tag name for service "%s" in %s must be a non-empty string.' , ( string ) $service -> getAttribute ( 'id' ), $file ));
2015-12-10 21:20:42 +00:00
}
2010-05-06 12:25:53 +01:00
2013-10-19 15:07:47 +01:00
$definition -> addTag ( $tag -> getAttribute ( 'name' ), $parameters );
2010-05-06 12:25:53 +01:00
}
2010-02-09 08:45:23 +00:00
2015-08-24 02:36:41 +01:00
foreach ( $this -> getChildren ( $service , 'autowiring-type' ) as $type ) {
$definition -> addAutowiringType ( $type -> textContent );
}
2014-04-02 16:31:05 +01:00
if ( $value = $service -> getAttribute ( 'decorates' )) {
$renameId = $service -> hasAttribute ( 'decoration-inner-name' ) ? $service -> getAttribute ( 'decoration-inner-name' ) : null ;
2015-07-31 02:41:40 +01:00
$priority = $service -> hasAttribute ( 'decoration-priority' ) ? $service -> getAttribute ( 'decoration-priority' ) : 0 ;
$definition -> setDecoratedService ( $value , $renameId , $priority );
2014-03-31 16:58:40 +01:00
}
2015-03-23 18:17:24 +00:00
return $definition ;
2010-02-09 08:45:23 +00:00
}
2013-10-19 15:07:47 +01:00
/**
2015-05-31 09:14:49 +01:00
* Parses a XML file to a \DOMDocument .
2013-10-19 15:07:47 +01:00
*
* @ param string $file Path to a file
*
* @ return \DOMDocument
*
* @ throws InvalidArgumentException When loading of XML file returns error
*/
2014-04-02 16:31:05 +01:00
private function parseFileToDOM ( $file )
2010-01-04 14:26:20 +00:00
{
2012-10-30 11:08:35 +00:00
try {
$dom = XmlUtils :: loadFile ( $file , array ( $this , 'validateSchema' ));
} catch ( \InvalidArgumentException $e ) {
2013-03-20 08:16:15 +00:00
throw new InvalidArgumentException ( sprintf ( 'Unable to parse file "%s".' , $file ), $e -> getCode (), $e );
2012-08-27 18:10:00 +01:00
}
2012-10-30 11:08:35 +00:00
$this -> validateExtensions ( $dom , $file );
2010-01-04 14:26:20 +00:00
2013-10-19 15:07:47 +01:00
return $dom ;
2010-01-04 14:26:20 +00:00
}
2011-02-13 18:06:41 +00:00
/**
2014-12-21 17:00:50 +00:00
* Processes anonymous services .
2011-02-13 18:06:41 +00:00
*
2013-10-19 15:07:47 +01:00
* @ param \DOMDocument $xml
* @ param string $file
2011-02-13 18:06:41 +00:00
*/
2013-10-19 15:07:47 +01:00
private function processAnonymousServices ( \DOMDocument $xml , $file )
2010-01-04 14:26:20 +00:00
{
2010-05-06 12:25:53 +01:00
$definitions = array ();
$count = 0 ;
2010-01-04 14:26:20 +00:00
2013-10-19 15:07:47 +01:00
$xpath = new \DOMXPath ( $xml );
$xpath -> registerNamespace ( 'container' , self :: NS );
2012-05-07 11:25:27 +01:00
// anonymous services as arguments/properties
2013-10-19 15:07:47 +01:00
if ( false !== $nodes = $xpath -> query ( '//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]' )) {
2012-05-07 11:23:07 +01:00
foreach ( $nodes as $node ) {
// give it a unique name
2013-07-30 13:08:17 +01:00
$id = sprintf ( '%s_%d' , hash ( 'sha256' , $file ), ++ $count );
2013-10-19 15:07:47 +01:00
$node -> setAttribute ( 'id' , $id );
2010-09-02 11:16:20 +01:00
2013-10-19 15:07:47 +01:00
if ( $services = $this -> getChildren ( $node , 'service' )) {
$definitions [ $id ] = array ( $services [ 0 ], $file , false );
$services [ 0 ] -> setAttribute ( 'id' , $id );
2016-05-04 20:53:17 +01:00
2016-05-06 10:19:28 +01:00
// anonymous services are always private
// we could not use the constant false here, because of XML parsing
$services [ 0 ] -> setAttribute ( 'public' , 'false' );
2013-10-19 15:07:47 +01:00
}
2012-05-07 11:23:07 +01:00
}
2010-09-02 11:16:20 +01:00
}
// anonymous services "in the wild"
2013-10-19 15:07:47 +01:00
if ( false !== $nodes = $xpath -> query ( '//container:services/container:service[not(@id)]' )) {
2012-05-07 11:23:07 +01:00
foreach ( $nodes as $node ) {
// give it a unique name
2013-07-30 13:08:17 +01:00
$id = sprintf ( '%s_%d' , hash ( 'sha256' , $file ), ++ $count );
2013-10-19 15:07:47 +01:00
$node -> setAttribute ( 'id' , $id );
2016-04-09 15:46:37 +01:00
$definitions [ $id ] = array ( $node , $file , true );
2012-05-07 11:23:07 +01:00
}
2010-05-06 12:25:53 +01:00
}
2010-01-11 14:56:49 +00:00
2010-05-06 12:25:53 +01:00
// resolve definitions
krsort ( $definitions );
2015-08-11 05:26:47 +01:00
foreach ( $definitions as $id => list ( $domElement , $file , $wild )) {
2015-03-23 18:17:24 +00:00
if ( null !== $definition = $this -> parseDefinition ( $domElement , $file )) {
$this -> container -> setDefinition ( $id , $definition );
}
2010-02-13 09:39:35 +00:00
2014-08-14 00:29:31 +01:00
if ( true === $wild ) {
$tmpDomElement = new \DOMElement ( '_services' , null , self :: NS );
$domElement -> parentNode -> replaceChild ( $tmpDomElement , $domElement );
$tmpDomElement -> setAttribute ( 'id' , $id );
2010-09-02 11:16:20 +01:00
} else {
2014-08-14 00:29:31 +01:00
$domElement -> parentNode -> removeChild ( $domElement );
2010-09-02 11:16:20 +01:00
}
2010-02-13 09:39:35 +00:00
}
2010-01-11 14:56:49 +00:00
}
2013-10-19 15:07:47 +01:00
/**
* Returns arguments as valid php types .
*
* @ param \DOMElement $node
* @ param string $name
2014-04-16 09:09:01 +01:00
* @ param bool $lowercase
2013-10-19 15:07:47 +01:00
*
* @ return mixed
*/
private function getArgumentsAsPhp ( \DOMElement $node , $name , $lowercase = true )
{
$arguments = array ();
foreach ( $this -> getChildren ( $node , $name ) as $arg ) {
2014-04-03 11:22:56 +01:00
if ( $arg -> hasAttribute ( 'name' )) {
$arg -> setAttribute ( 'key' , $arg -> getAttribute ( 'name' ));
2013-10-19 15:07:47 +01:00
}
// this is used by DefinitionDecorator to overwrite a specific
// argument of the parent definition
2014-04-03 11:22:56 +01:00
if ( $arg -> hasAttribute ( 'index' )) {
$key = 'index_' . $arg -> getAttribute ( 'index' );
2016-11-16 17:59:59 +00:00
} elseif ( ! $arg -> hasAttribute ( 'key' )) {
// Append an empty argument, then fetch its key to overwrite it later
$arguments [] = null ;
$keys = array_keys ( $arguments );
$key = array_pop ( $keys );
} else {
$key = $arg -> getAttribute ( 'key' );
// parameter keys are case insensitive
if ( 'parameter' == $name && $lowercase ) {
$key = strtolower ( $key );
}
2013-10-19 15:07:47 +01:00
}
switch ( $arg -> getAttribute ( 'type' )) {
case 'service' :
$onInvalid = $arg -> getAttribute ( 'on-invalid' );
$invalidBehavior = ContainerInterface :: EXCEPTION_ON_INVALID_REFERENCE ;
if ( 'ignore' == $onInvalid ) {
$invalidBehavior = ContainerInterface :: IGNORE_ON_INVALID_REFERENCE ;
} elseif ( 'null' == $onInvalid ) {
$invalidBehavior = ContainerInterface :: NULL_ON_INVALID_REFERENCE ;
}
if ( $strict = $arg -> getAttribute ( 'strict' )) {
$strict = XmlUtils :: phpize ( $strict );
} else {
$strict = true ;
}
$arguments [ $key ] = new Reference ( $arg -> getAttribute ( 'id' ), $invalidBehavior , $strict );
break ;
case 'expression' :
$arguments [ $key ] = new Expression ( $arg -> nodeValue );
break ;
case 'collection' :
$arguments [ $key ] = $this -> getArgumentsAsPhp ( $arg , $name , false );
break ;
case 'string' :
$arguments [ $key ] = $arg -> nodeValue ;
break ;
case 'constant' :
2016-10-19 19:16:43 +01:00
$arguments [ $key ] = constant ( trim ( $arg -> nodeValue ));
2013-10-19 15:07:47 +01:00
break ;
default :
$arguments [ $key ] = XmlUtils :: phpize ( $arg -> nodeValue );
}
}
return $arguments ;
}
/**
2015-05-31 09:14:49 +01:00
* Get child elements by name .
2013-10-19 15:07:47 +01:00
*
* @ param \DOMNode $node
* @ param mixed $name
*
* @ return array
*/
private function getChildren ( \DOMNode $node , $name )
{
$children = array ();
foreach ( $node -> childNodes as $child ) {
if ( $child instanceof \DOMElement && $child -> localName === $name && $child -> namespaceURI === self :: NS ) {
$children [] = $child ;
}
}
return $children ;
}
2010-05-06 12:25:53 +01:00
/**
2011-02-13 18:06:41 +00:00
* Validates a documents XML schema .
*
* @ param \DOMDocument $dom
*
2014-04-16 11:30:19 +01:00
* @ return bool
2012-12-16 12:02:54 +00:00
*
2012-10-30 11:08:35 +00:00
* @ throws RuntimeException When extension references a non - existent XSD file
2010-05-06 12:25:53 +01:00
*/
2012-10-30 11:08:35 +00:00
public function validateSchema ( \DOMDocument $dom )
2010-05-06 12:25:53 +01:00
{
2011-03-06 11:40:06 +00:00
$schemaLocations = array ( 'http://symfony.com/schema/dic/services' => str_replace ( '\\' , '/' , __DIR__ . '/schema/dic/services/services-1.0.xsd' ));
2010-05-06 12:25:53 +01:00
2010-05-07 15:09:11 +01:00
if ( $element = $dom -> documentElement -> getAttributeNS ( 'http://www.w3.org/2001/XMLSchema-instance' , 'schemaLocation' )) {
2010-05-06 12:25:53 +01:00
$items = preg_split ( '/\s+/' , $element );
2010-05-07 15:09:11 +01:00
for ( $i = 0 , $nb = count ( $items ); $i < $nb ; $i += 2 ) {
2010-07-16 08:12:58 +01:00
if ( ! $this -> container -> hasExtension ( $items [ $i ])) {
continue ;
}
if (( $extension = $this -> container -> getExtension ( $items [ $i ])) && false !== $extension -> getXsdValidationBasePath ()) {
2010-06-27 17:54:03 +01:00
$path = str_replace ( $extension -> getNamespace (), str_replace ( '\\' , '/' , $extension -> getXsdValidationBasePath ()) . '/' , $items [ $i + 1 ]);
2010-05-06 12:25:53 +01:00
2011-08-29 14:28:03 +01:00
if ( ! is_file ( $path )) {
2011-12-04 23:51:22 +00:00
throw new RuntimeException ( sprintf ( 'Extension "%s" references a non-existent XSD file "%s"' , get_class ( $extension ), $path ));
2010-05-06 12:25:53 +01:00
}
$schemaLocations [ $items [ $i ]] = $path ;
}
}
}
2011-01-06 21:37:24 +00:00
$tmpfiles = array ();
2010-05-06 12:25:53 +01:00
$imports = '' ;
2010-05-07 15:09:11 +01:00
foreach ( $schemaLocations as $namespace => $location ) {
2010-05-21 15:18:29 +01:00
$parts = explode ( '/' , $location );
2011-09-05 14:06:29 +01:00
if ( 0 === stripos ( $location , 'phar://' )) {
2011-01-06 21:37:24 +00:00
$tmpfile = tempnam ( sys_get_temp_dir (), 'sf2' );
if ( $tmpfile ) {
2011-09-05 14:06:29 +01:00
copy ( $location , $tmpfile );
2011-01-06 21:37:24 +00:00
$tmpfiles [] = $tmpfile ;
$parts = explode ( '/' , str_replace ( '\\' , '/' , $tmpfile ));
}
}
2010-07-19 23:38:44 +01:00
$drive = '\\' === DIRECTORY_SEPARATOR ? array_shift ( $parts ) . '/' : '' ;
2010-05-21 15:18:29 +01:00
$location = 'file:///' . $drive . implode ( '/' , array_map ( 'rawurlencode' , $parts ));
2010-05-06 12:25:53 +01:00
$imports .= sprintf ( ' <xsd:import namespace="%s" schemaLocation="%s" />' . " \n " , $namespace , $location );
}
$source = <<< EOF
2010-01-11 14:56:49 +00:00
< ? xml version = " 1.0 " encoding = " utf-8 " ?>
2011-03-06 11:40:06 +00:00
< xsd : schema xmlns = " http://symfony.com/schema "
2010-01-11 14:56:49 +00:00
xmlns : xsd = " http://www.w3.org/2001/XMLSchema "
2011-03-06 11:40:06 +00:00
targetNamespace = " http://symfony.com/schema "
2010-01-11 14:56:49 +00:00
elementFormDefault = " qualified " >
2010-05-06 12:25:53 +01:00
< xsd : import namespace = " http://www.w3.org/XML/1998/namespace " />
2010-01-11 14:56:49 +00:00
$imports
</ xsd : schema >
EOF
2010-05-06 12:25:53 +01:00
;
2010-01-11 14:56:49 +00:00
2016-05-29 11:39:28 +01:00
$disableEntities = libxml_disable_entity_loader ( false );
2012-07-04 16:22:26 +01:00
$valid = @ $dom -> schemaValidateSource ( $source );
2016-05-29 11:39:28 +01:00
libxml_disable_entity_loader ( $disableEntities );
2012-08-28 08:54:04 +01:00
2011-01-06 21:37:24 +00:00
foreach ( $tmpfiles as $tmpfile ) {
@ unlink ( $tmpfile );
}
2012-10-30 11:08:35 +00:00
return $valid ;
2010-01-04 14:26:20 +00:00
}
2010-05-06 12:25:53 +01:00
2016-01-09 18:39:03 +00:00
/**
* Validates an alias .
*
* @ param \DOMElement $alias
* @ param string $file
*/
private function validateAlias ( \DOMElement $alias , $file )
{
foreach ( $alias -> attributes as $name => $node ) {
if ( ! in_array ( $name , array ( 'alias' , 'id' , 'public' ))) {
2016-10-07 12:16:58 +01:00
@ trigger_error ( sprintf ( 'Using the attribute "%s" is deprecated for the service "%s" which is defined as an alias in "%s". Allowed attributes for service aliases are "alias", "id" and "public". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.' , $name , $alias -> getAttribute ( 'id' ), $file ), E_USER_DEPRECATED );
2016-01-09 18:39:03 +00:00
}
}
foreach ( $alias -> childNodes as $child ) {
if ( $child instanceof \DOMElement && $child -> namespaceURI === self :: NS ) {
2016-10-07 12:16:58 +01:00
@ trigger_error ( sprintf ( 'Using the element "%s" is deprecated for the service "%s" which is defined as an alias in "%s". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported elements.' , $child -> localName , $alias -> getAttribute ( 'id' ), $file ), E_USER_DEPRECATED );
2016-01-09 18:39:03 +00:00
}
}
}
2010-05-06 12:25:53 +01:00
/**
2011-02-13 18:06:41 +00:00
* Validates an extension .
*
* @ param \DOMDocument $dom
2012-05-18 18:41:48 +01:00
* @ param string $file
2011-02-13 18:06:41 +00:00
*
2011-12-04 23:51:22 +00:00
* @ throws InvalidArgumentException When no extension is found corresponding to a tag
2010-05-06 12:25:53 +01:00
*/
2011-03-11 13:50:46 +00:00
private function validateExtensions ( \DOMDocument $dom , $file )
2010-01-04 14:26:20 +00:00
{
2010-05-07 15:09:11 +01:00
foreach ( $dom -> documentElement -> childNodes as $node ) {
2011-03-06 11:40:06 +00:00
if ( ! $node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node -> namespaceURI ) {
2010-05-06 12:25:53 +01:00
continue ;
}
// can it be handled by an extension?
2010-07-16 08:12:58 +01:00
if ( ! $this -> container -> hasExtension ( $node -> namespaceURI )) {
2011-07-06 14:26:08 +01:00
$extensionNamespaces = array_filter ( array_map ( function ( $ext ) { return $ext -> getNamespace (); }, $this -> container -> getExtensions ()));
2011-12-04 23:51:22 +00:00
throw new InvalidArgumentException ( sprintf (
2011-07-05 23:08:33 +01:00
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s' ,
$node -> tagName ,
$file ,
$node -> namespaceURI ,
2011-07-06 14:26:08 +01:00
$extensionNamespaces ? sprintf ( '"%s"' , implode ( '", "' , $extensionNamespaces )) : 'none'
2011-07-05 23:08:33 +01:00
));
2010-05-06 12:25:53 +01:00
}
}
2010-01-04 14:26:20 +00:00
}
2011-02-13 18:06:41 +00:00
/**
* Loads from an extension .
*
2013-10-19 15:07:47 +01:00
* @ param \DOMDocument $xml
2011-02-13 18:06:41 +00:00
*/
2013-10-19 15:07:47 +01:00
private function loadFromExtensions ( \DOMDocument $xml )
2010-01-04 14:26:20 +00:00
{
2013-10-19 15:07:47 +01:00
foreach ( $xml -> documentElement -> childNodes as $node ) {
if ( ! $node instanceof \DOMElement || $node -> namespaceURI === self :: NS ) {
2010-05-06 12:25:53 +01:00
continue ;
}
2010-01-04 14:26:20 +00:00
2010-05-06 12:25:53 +01:00
$values = static :: convertDomElementToArray ( $node );
2010-06-07 06:57:01 +01:00
if ( ! is_array ( $values )) {
$values = array ();
}
2010-02-12 16:44:52 +00:00
2011-02-05 18:42:07 +00:00
$this -> container -> loadFromExtension ( $node -> namespaceURI , $values );
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:26:20 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Converts a \DomElement object to a PHP array .
*
* The following rules applies during the conversion :
*
* * Each tag is converted to a key value or an array
* if there is more than one " value "
*
* * The content of a tag is set under a " value " key ( < foo > bar </ foo > )
* if the tag also has some nested tags
*
* * The attributes are converted to keys ( < foo foo = " bar " /> )
*
* * The nested - tags are converted to keys ( < foo >< foo > bar </ foo ></ foo > )
*
* @ param \DomElement $element A \DomElement instance
*
* @ return array A PHP array
*/
2016-07-22 15:17:18 +01:00
public static function convertDomElementToArray ( \DOMElement $element )
2010-01-04 14:26:20 +00:00
{
2012-10-30 11:08:35 +00:00
return XmlUtils :: convertDomElementToArray ( $element );
2010-01-04 14:26:20 +00:00
}
}