2017-01-17 20:04:53 +00:00
< ? 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\Compiler ;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface ;
use Symfony\Component\DependencyInjection\ContainerBuilder ;
2017-04-04 14:48:08 +01:00
use Symfony\Component\DependencyInjection\Definition ;
use Symfony\Component\DependencyInjection\Exception\RuntimeException ;
use Symfony\Component\DependencyInjection\Reference ;
2017-01-17 20:04:53 +00:00
/**
* @ author Nicolas Grekas < p @ tchwork . com >
*/
abstract class AbstractRecursivePass implements CompilerPassInterface
{
2017-09-22 18:54:05 +01:00
/**
* @ var ContainerBuilder
*/
2017-01-17 20:04:53 +00:00
protected $container ;
protected $currentId ;
/**
* { @ inheritdoc }
*/
public function process ( ContainerBuilder $container )
{
$this -> container = $container ;
try {
$this -> processValue ( $container -> getDefinitions (), true );
} finally {
$this -> container = null ;
}
}
/**
* Processes a value found in a definition tree .
*
* @ param mixed $value
* @ param bool $isRoot
*
* @ return mixed The processed value
*/
protected function processValue ( $value , $isRoot = false )
{
2018-01-20 08:34:19 +00:00
if ( \is_array ( $value )) {
2017-01-17 20:04:53 +00:00
foreach ( $value as $k => $v ) {
if ( $isRoot ) {
$this -> currentId = $k ;
}
if ( $v !== $processedValue = $this -> processValue ( $v , $isRoot )) {
$value [ $k ] = $processedValue ;
}
}
} elseif ( $value instanceof ArgumentInterface ) {
$value -> setValues ( $this -> processValue ( $value -> getValues ()));
} elseif ( $value instanceof Definition ) {
$value -> setArguments ( $this -> processValue ( $value -> getArguments ()));
$value -> setProperties ( $this -> processValue ( $value -> getProperties ()));
$value -> setMethodCalls ( $this -> processValue ( $value -> getMethodCalls ()));
2017-04-05 13:12:51 +01:00
$changes = $value -> getChanges ();
if ( isset ( $changes [ 'factory' ])) {
$value -> setFactory ( $this -> processValue ( $value -> getFactory ()));
2017-01-17 20:04:53 +00:00
}
2017-04-05 13:12:51 +01:00
if ( isset ( $changes [ 'configurator' ])) {
$value -> setConfigurator ( $this -> processValue ( $value -> getConfigurator ()));
2017-01-17 20:04:53 +00:00
}
}
return $value ;
}
2017-04-04 14:48:08 +01:00
/**
* @ param Definition $definition
* @ param bool $required
*
* @ return \ReflectionFunctionAbstract | null
*
* @ throws RuntimeException
*/
protected function getConstructor ( Definition $definition , $required )
{
if ( is_string ( $factory = $definition -> getFactory ())) {
if ( ! function_exists ( $factory )) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": function "%s" does not exist.' , $this -> currentId , $factory ));
2017-04-04 14:48:08 +01:00
}
$r = new \ReflectionFunction ( $factory );
if ( false !== $r -> getFileName () && file_exists ( $r -> getFileName ())) {
$this -> container -> fileExists ( $r -> getFileName ());
}
return $r ;
}
if ( $factory ) {
list ( $class , $method ) = $factory ;
if ( $class instanceof Reference ) {
$class = $this -> container -> findDefinition (( string ) $class ) -> getClass ();
} elseif ( null === $class ) {
$class = $definition -> getClass ();
}
if ( '__construct' === $method ) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": "__construct()" cannot be used as a factory method.' , $this -> currentId ));
2017-04-04 14:48:08 +01:00
}
return $this -> getReflectionMethod ( new Definition ( $class ), $method );
}
$class = $definition -> getClass ();
if ( ! $r = $this -> container -> getReflectionClass ( $class )) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": class "%s" does not exist.' , $this -> currentId , $class ));
2017-04-04 14:48:08 +01:00
}
if ( ! $r = $r -> getConstructor ()) {
if ( $required ) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": class%s has no constructor.' , $this -> currentId , sprintf ( $class !== $this -> currentId ? ' "%s"' : '' , $class )));
2017-04-04 14:48:08 +01:00
}
} elseif ( ! $r -> isPublic ()) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": %s must be public.' , $this -> currentId , sprintf ( $class !== $this -> currentId ? 'constructor of class "%s"' : 'its constructor' , $class )));
2017-04-04 14:48:08 +01:00
}
return $r ;
}
/**
* @ param Definition $definition
* @ param string $method
*
* @ throws RuntimeException
*
* @ return \ReflectionFunctionAbstract
*/
protected function getReflectionMethod ( Definition $definition , $method )
{
if ( '__construct' === $method ) {
return $this -> getConstructor ( $definition , true );
}
if ( ! $class = $definition -> getClass ()) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": the class is not set.' , $this -> currentId ));
2017-04-04 14:48:08 +01:00
}
if ( ! $r = $this -> container -> getReflectionClass ( $class )) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": class "%s" does not exist.' , $this -> currentId , $class ));
2017-04-04 14:48:08 +01:00
}
if ( ! $r -> hasMethod ( $method )) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": method "%s()" does not exist.' , $this -> currentId , $class !== $this -> currentId ? $class . '::' . $method : $method ));
2017-04-04 14:48:08 +01:00
}
$r = $r -> getMethod ( $method );
if ( ! $r -> isPublic ()) {
2017-09-23 23:04:06 +01:00
throw new RuntimeException ( sprintf ( 'Invalid service "%s": method "%s()" must be public.' , $this -> currentId , $class !== $this -> currentId ? $class . '::' . $method : $method ));
2017-04-04 14:48:08 +01:00
}
return $r ;
}
2017-01-17 20:04:53 +00:00
}