2017-02-21 22:24:03 +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\ContainerInterface ;
use Symfony\Component\DependencyInjection\Definition ;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException ;
use Symfony\Component\DependencyInjection\Reference ;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface ;
use Symfony\Component\DependencyInjection\TypedReference ;
/**
* Compiler pass to register tagged services that require a service locator .
*
* @ author Nicolas Grekas < p @ tchwork . com >
*/
class RegisterServiceSubscribersPass extends AbstractRecursivePass
{
private $serviceLocator ;
protected function processValue ( $value , $isRoot = false )
{
if ( $value instanceof Reference && $this -> serviceLocator && 'container' === ( string ) $value ) {
return new Reference ( $this -> serviceLocator );
}
if ( ! $value instanceof Definition || $value -> isAbstract () || $value -> isSynthetic () || ! $value -> hasTag ( 'container.service_subscriber' )) {
return parent :: processValue ( $value , $isRoot );
}
$serviceMap = array ();
foreach ( $value -> getTag ( 'container.service_subscriber' ) as $attributes ) {
if ( ! $attributes ) {
continue ;
}
ksort ( $attributes );
if ( array () !== array_diff ( array_keys ( $attributes ), array ( 'id' , 'key' ))) {
throw new InvalidArgumentException ( sprintf ( 'The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".' , implode ( '", "' , array_keys ( $attributes )), $this -> currentId ));
}
if ( ! array_key_exists ( 'id' , $attributes )) {
throw new InvalidArgumentException ( sprintf ( 'Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".' , $attributes [ 'key' ], $this -> currentId ));
}
if ( ! array_key_exists ( 'key' , $attributes )) {
$attributes [ 'key' ] = $attributes [ 'id' ];
}
if ( isset ( $serviceMap [ $attributes [ 'key' ]])) {
continue ;
}
$serviceMap [ $attributes [ 'key' ]] = new Reference ( $attributes [ 'id' ]);
}
$class = $value -> getClass ();
if ( ! is_subclass_of ( $class , ServiceSubscriberInterface :: class )) {
if ( ! class_exists ( $class , false )) {
throw new InvalidArgumentException ( sprintf ( 'Class "%s" used for service "%s" cannot be found.' , $class , $this -> currentId ));
}
throw new InvalidArgumentException ( sprintf ( 'Service "%s" must implement interface "%s".' , $this -> currentId , ServiceSubscriberInterface :: class ));
}
$this -> container -> addObjectResource ( $class );
$subscriberMap = array ();
foreach ( $class :: getSubscribedServices () as $key => $type ) {
if ( ! is_string ( $type ) || ! preg_match ( '/^\??[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/' , $type )) {
throw new InvalidArgumentException ( sprintf ( '%s::getSubscribedServices() must return valid PHP types for service "%s" key "%s", "%s" returned.' , $class , $this -> currentId , $key , is_string ( $type ) ? $type : gettype ( $type )));
}
if ( $optionalBehavior = '?' === $type [ 0 ]) {
$type = substr ( $type , 1 );
$optionalBehavior = ContainerInterface :: IGNORE_ON_INVALID_REFERENCE ;
}
if ( is_int ( $key )) {
$key = $type ;
}
if ( ! isset ( $serviceMap [ $key ])) {
$serviceMap [ $key ] = new Reference ( $type );
}
2017-03-27 12:10:12 +01:00
$subscriberMap [ $key ] = new TypedReference (( string ) $serviceMap [ $key ], $type , $optionalBehavior ? : ContainerInterface :: EXCEPTION_ON_INVALID_REFERENCE );
2017-02-21 22:24:03 +00:00
unset ( $serviceMap [ $key ]);
}
if ( $serviceMap = array_keys ( $serviceMap )) {
2017-03-27 19:07:18 +01:00
$message = sprintf ( 1 < count ( $serviceMap ) ? 'keys "%s" do' : 'key "%s" does' , str_replace ( '%' , '%%' , implode ( '", "' , $serviceMap )));
throw new InvalidArgumentException ( sprintf ( 'Service %s not exist in the map returned by %s::getSubscribedServices() for service "%s".' , $message , $class , $this -> currentId ));
2017-02-21 22:24:03 +00:00
}
$serviceLocator = $this -> serviceLocator ;
2017-03-27 12:10:12 +01:00
$this -> serviceLocator = ( string ) ServiceLocatorTagPass :: register ( $this -> container , $subscriberMap , $value -> getAutowired ());
2017-02-21 22:24:03 +00:00
try {
return parent :: processValue ( $value );
} finally {
$this -> serviceLocator = $serviceLocator ;
}
}
}