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 .
2010-01-04 14:26:20 +00:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-01-04 14:26:20 +00:00
*
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-01-04 14:26:20 +00:00
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Component\DependencyInjection ;
2016-08-12 19:34:27 +01:00
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException ;
2011-12-04 23:51:22 +00:00
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException ;
2011-05-17 15:26:08 +01:00
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException ;
2011-05-25 08:46:30 +01:00
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException ;
2011-01-15 13:29:43 +00:00
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface ;
2016-08-12 19:34:27 +01:00
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag ;
2011-01-15 13:29:43 +00:00
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag ;
2010-01-04 14:26:20 +00:00
/**
* Container is a dependency injection container .
*
2010-06-27 17:28:29 +01:00
* It gives access to object instances ( services ) .
2010-01-04 14:26:20 +00:00
*
* Services and parameters are simple key / pair stores .
*
2011-01-03 08:07:06 +00:00
* Parameter and service keys are case insensitive .
2010-01-04 14:26:20 +00:00
*
* A service id can contain lowercased letters , digits , underscores , and dots .
* Underscores are used to separate words , and dots to group services
* under namespaces :
*
* < ul >
* < li > request </ li >
* < li > mysql_session_storage </ li >
* < li > symfony . mysql_session_storage </ li >
* </ ul >
*
* A service can also be defined by creating a method named
* getXXXService (), where XXX is the camelized version of the id :
*
* < ul >
* < li > request -> getRequestService () </ li >
* < li > mysql_session_storage -> getMysqlSessionStorageService () </ li >
* < li > symfony . mysql_session_storage -> getSymfony_MysqlSessionStorageService () </ li >
* </ ul >
*
* The container can have three possible behaviors when a service does not exist :
*
* * EXCEPTION_ON_INVALID_REFERENCE : Throws an exception ( the default )
* * NULL_ON_INVALID_REFERENCE : Returns null
* * IGNORE_ON_INVALID_REFERENCE : Ignores the wrapping command asking for the reference
* ( for instance , ignore a setter if the service does not exist )
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2011-01-17 22:28:59 +00:00
* @ author Johannes M . Schmitt < schmittjoh @ gmail . com >
2010-01-04 14:26:20 +00:00
*/
2015-07-23 11:18:12 +01:00
class Container implements ResettableContainerInterface
2010-01-04 14:26:20 +00:00
{
2012-11-01 15:08:59 +00:00
/**
* @ var ParameterBagInterface
*/
2010-06-27 17:28:29 +01:00
protected $parameterBag ;
2012-11-01 15:08:59 +00:00
2013-11-10 17:06:47 +00:00
protected $services = array ();
protected $methodMap = array ();
2016-06-22 21:01:50 +01:00
protected $privates = array ();
2013-11-10 17:06:47 +00:00
protected $aliases = array ();
2011-01-18 15:07:12 +00:00
protected $loading = array ();
2010-05-06 12:25:53 +01:00
2017-01-10 07:04:52 +00:00
/**
* @ internal
*/
protected $normalizedIds = array ();
2015-05-15 13:54:35 +01:00
private $underscoreMap = array ( '_' => '' , '.' => '_' , '\\' => '_' );
2016-08-12 19:34:27 +01:00
private $envCache = array ();
2015-05-15 13:54:35 +01:00
2010-05-06 12:25:53 +01:00
/**
2010-07-27 14:33:28 +01:00
* @ param ParameterBagInterface $parameterBag A ParameterBagInterface instance
2010-05-06 12:25:53 +01:00
*/
2010-06-27 17:28:29 +01:00
public function __construct ( ParameterBagInterface $parameterBag = null )
2010-01-04 14:26:20 +00:00
{
2016-08-12 19:34:27 +01:00
$this -> parameterBag = $parameterBag ? : new EnvPlaceholderParameterBag ();
2010-01-04 14:26:20 +00:00
}
2010-05-06 12:25:53 +01:00
/**
2011-01-16 07:12:36 +00:00
* Compiles the container .
2010-07-16 08:15:22 +01:00
*
* This method does two things :
*
* * Parameter values are resolved ;
2011-01-14 17:43:51 +00:00
* * The parameter bag is frozen .
2010-05-06 12:25:53 +01:00
*/
2011-01-16 07:12:36 +00:00
public function compile ()
2010-05-06 12:25:53 +01:00
{
2010-07-16 08:15:22 +01:00
$this -> parameterBag -> resolve ();
2010-06-27 17:28:29 +01:00
$this -> parameterBag = new FrozenParameterBag ( $this -> parameterBag -> all ());
2010-05-06 12:25:53 +01:00
}
/**
2010-06-27 17:28:29 +01:00
* Returns true if the container parameter bag are frozen .
2010-05-06 12:25:53 +01:00
*
2014-11-30 13:33:44 +00:00
* @ return bool true if the container parameter bag are frozen , false otherwise
2010-05-06 12:25:53 +01:00
*/
2010-06-27 17:28:29 +01:00
public function isFrozen ()
2010-05-06 12:25:53 +01:00
{
2010-06-27 17:28:29 +01:00
return $this -> parameterBag instanceof FrozenParameterBag ;
2010-05-06 12:25:53 +01:00
}
/**
2010-06-27 17:28:29 +01:00
* Gets the service container parameter bag .
2010-05-06 12:25:53 +01:00
*
2010-07-27 14:33:28 +01:00
* @ return ParameterBagInterface A ParameterBagInterface instance
2010-05-06 12:25:53 +01:00
*/
2010-06-27 17:28:29 +01:00
public function getParameterBag ()
2010-05-06 12:25:53 +01:00
{
2010-06-27 17:28:29 +01:00
return $this -> parameterBag ;
2010-05-06 12:25:53 +01:00
}
/**
2010-06-27 17:28:29 +01:00
* Gets a parameter .
2010-05-06 12:25:53 +01:00
*
2012-05-15 21:19:31 +01:00
* @ param string $name The parameter name
2010-05-06 12:25:53 +01:00
*
2014-11-30 13:33:44 +00:00
* @ return mixed The parameter value
2010-05-06 12:25:53 +01:00
*
2011-12-04 23:51:22 +00:00
* @ throws InvalidArgumentException if the parameter is not defined
2010-05-06 12:25:53 +01:00
*/
public function getParameter ( $name )
{
2010-06-27 17:28:29 +01:00
return $this -> parameterBag -> get ( $name );
2010-05-06 12:25:53 +01:00
}
2010-08-25 23:30:10 +01:00
/**
* Checks if a parameter exists .
*
2012-05-15 21:19:31 +01:00
* @ param string $name The parameter name
2010-08-25 23:30:10 +01:00
*
2014-11-30 13:33:44 +00:00
* @ return bool The presence of parameter in container
2010-08-25 23:30:10 +01:00
*/
public function hasParameter ( $name )
{
return $this -> parameterBag -> has ( $name );
}
2010-05-06 12:25:53 +01:00
/**
2010-06-27 17:28:29 +01:00
* Sets a parameter .
2010-05-06 12:25:53 +01:00
*
2011-04-23 16:05:44 +01:00
* @ param string $name The parameter name
* @ param mixed $value The parameter value
2010-05-06 12:25:53 +01:00
*/
public function setParameter ( $name , $value )
{
2010-06-27 17:28:29 +01:00
$this -> parameterBag -> set ( $name , $value );
2010-05-06 12:25:53 +01:00
}
/**
* Sets a service .
*
2013-07-25 16:13:34 +01:00
* Setting a service to null resets the service : has () returns false and get ()
* behaves in the same way as if the service was never created .
*
2010-05-06 12:25:53 +01:00
* @ param string $id The service identifier
* @ param object $service The service instance
*/
2015-09-04 20:54:37 +01:00
public function set ( $id , $service )
2010-01-04 14:26:20 +00:00
{
2017-01-10 07:04:52 +00:00
$id = $this -> normalizeId ( $id );
2011-01-17 22:28:59 +00:00
2014-07-19 19:07:52 +01:00
if ( 'service_container' === $id ) {
2015-04-01 03:23:52 +01:00
throw new InvalidArgumentException ( 'You cannot set service "service_container".' );
2014-07-19 19:07:52 +01:00
}
2015-04-01 03:23:52 +01:00
2016-02-09 19:58:01 +00:00
if ( isset ( $this -> aliases [ $id ])) {
unset ( $this -> aliases [ $id ]);
}
2011-01-17 22:28:59 +00:00
$this -> services [ $id ] = $service ;
2013-02-06 20:42:01 +00:00
2013-07-25 16:13:34 +01:00
if ( null === $service ) {
unset ( $this -> services [ $id ]);
}
2016-06-22 21:01:50 +01:00
if ( isset ( $this -> privates [ $id ])) {
if ( null === $service ) {
@ trigger_error ( sprintf ( 'Unsetting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
2016-08-22 17:57:59 +01:00
unset ( $this -> privates [ $id ]);
2016-06-22 21:01:50 +01:00
} else {
2017-01-14 09:13:01 +00:00
@ trigger_error ( sprintf ( 'Setting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
}
} elseif ( isset ( $this -> methodMap [ $id ])) {
if ( null === $service ) {
@ trigger_error ( sprintf ( 'Unsetting the "%s" pre-defined service is deprecated since Symfony 3.3 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
} else {
@ trigger_error ( sprintf ( 'Setting the "%s" pre-defined service is deprecated since Symfony 3.3 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
2016-06-22 21:01:50 +01:00
}
}
2010-01-04 14:26:20 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns true if the given service is defined .
*
2012-05-15 21:19:31 +01:00
* @ param string $id The service identifier
2010-05-06 12:25:53 +01:00
*
2014-11-30 13:33:44 +00:00
* @ return bool true if the service is defined , false otherwise
2010-05-06 12:25:53 +01:00
*/
2010-06-27 17:28:29 +01:00
public function has ( $id )
2010-01-19 12:29:28 +00:00
{
2015-05-15 13:54:35 +01:00
for ( $i = 2 ;;) {
2017-01-12 12:28:30 +00:00
if ( 'service_container' === $id ) {
return true ;
}
if ( isset ( $this -> aliases [ $id ])) {
$id = $this -> aliases [ $id ];
}
if ( isset ( $this -> services [ $id ])) {
2015-05-15 13:54:35 +01:00
return true ;
}
2016-09-30 22:26:24 +01:00
if ( isset ( $this -> privates [ $id ])) {
@ trigger_error ( sprintf ( 'Checking for the existence of the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
}
if ( isset ( $this -> methodMap [ $id ])) {
return true ;
}
2017-01-10 07:04:52 +00:00
if ( -- $i && $id !== $normalizedId = $this -> normalizeId ( $id )) {
$id = $normalizedId ;
2016-09-30 22:26:24 +01:00
continue ;
}
// We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
// and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
if ( ! $this -> methodMap && ! $this instanceof ContainerBuilder && __CLASS__ !== static :: class && method_exists ( $this , 'get' . strtr ( $id , $this -> underscoreMap ) . 'Service' )) {
@ trigger_error ( 'Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.' , E_USER_DEPRECATED );
2016-06-22 21:01:50 +01:00
2016-09-30 22:26:24 +01:00
return true ;
2015-05-15 13:54:35 +01:00
}
2016-09-30 22:26:24 +01:00
return false ;
2014-07-19 19:07:52 +01:00
}
2010-01-19 12:29:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Gets a service .
*
2012-07-01 11:35:01 +01:00
* If a service is defined both through a set () method and
* with a get { $id } Service () method , the former has always precedence .
2010-05-06 12:25:53 +01:00
*
2014-11-30 13:33:44 +00:00
* @ param string $id The service identifier
* @ param int $invalidBehavior The behavior when the service does not exist
2010-05-06 12:25:53 +01:00
*
* @ return object The associated service
*
2012-09-07 23:56:45 +01:00
* @ throws ServiceCircularReferenceException When a circular reference is detected
2014-07-26 13:09:47 +01:00
* @ throws ServiceNotFoundException When the service is not defined
* @ throws \Exception if an exception has been thrown when the service has been resolved
2010-05-06 12:25:53 +01:00
*
* @ see Reference
*/
2010-06-27 17:28:29 +01:00
public function get ( $id , $invalidBehavior = self :: EXCEPTION_ON_INVALID_REFERENCE )
2010-01-04 14:26:20 +00:00
{
2013-09-01 13:17:20 +01:00
// Attempt to retrieve the service by checking first aliases then
// available services. Service IDs are case insensitive, however since
// this method can be called thousands of times during a request, avoid
2017-01-10 07:04:52 +00:00
// calling $this->normalizeId($id) unless necessary.
2015-05-15 13:54:35 +01:00
for ( $i = 2 ;;) {
2014-07-19 19:07:52 +01:00
if ( 'service_container' === $id ) {
return $this ;
}
2013-09-01 13:17:20 +01:00
if ( isset ( $this -> aliases [ $id ])) {
$id = $this -> aliases [ $id ];
}
// Re-use shared service instance if it exists.
2016-08-21 13:01:27 +01:00
if ( isset ( $this -> services [ $id ])) {
2013-09-01 13:17:20 +01:00
return $this -> services [ $id ];
}
2010-05-06 12:25:53 +01:00
2015-05-15 13:54:35 +01:00
if ( isset ( $this -> loading [ $id ])) {
throw new ServiceCircularReferenceException ( $id , array_keys ( $this -> loading ));
}
2011-01-06 13:18:28 +00:00
2015-05-15 13:54:35 +01:00
if ( isset ( $this -> methodMap [ $id ])) {
$method = $this -> methodMap [ $id ];
2017-01-10 07:04:52 +00:00
} elseif ( -- $i && $id !== $normalizedId = $this -> normalizeId ( $id )) {
$id = $normalizedId ;
2015-05-15 13:54:35 +01:00
continue ;
2016-09-30 22:26:24 +01:00
} elseif ( ! $this -> methodMap && ! $this instanceof ContainerBuilder && __CLASS__ !== static :: class && method_exists ( $this , $method = 'get' . strtr ( $id , $this -> underscoreMap ) . 'Service' )) {
// We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
// and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
@ trigger_error ( 'Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.' , E_USER_DEPRECATED );
2015-05-15 13:54:35 +01:00
// $method is set to the right value, proceed
} else {
if ( self :: EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior ) {
if ( ! $id ) {
throw new ServiceNotFoundException ( $id );
}
2012-10-07 19:46:50 +01:00
2015-05-15 13:54:35 +01:00
$alternatives = array ();
2016-08-20 09:07:04 +01:00
foreach ( $this -> getServiceIds () as $knownId ) {
$lev = levenshtein ( $id , $knownId );
if ( $lev <= strlen ( $id ) / 3 || false !== strpos ( $knownId , $id )) {
$alternatives [] = $knownId ;
2015-05-15 13:54:35 +01:00
}
2013-05-05 11:11:01 +01:00
}
2015-05-15 13:54:35 +01:00
throw new ServiceNotFoundException ( $id , null , null , $alternatives );
2013-03-21 16:34:16 +00:00
}
2015-05-15 13:54:35 +01:00
return ;
2011-03-09 14:38:02 +00:00
}
2016-06-22 21:01:50 +01:00
if ( isset ( $this -> privates [ $id ])) {
@ trigger_error ( sprintf ( 'Requesting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.' , $id ), E_USER_DEPRECATED );
}
2011-01-06 13:18:28 +00:00
2015-05-15 13:54:35 +01:00
$this -> loading [ $id ] = true ;
2010-05-06 12:25:53 +01:00
2015-05-15 13:54:35 +01:00
try {
$service = $this -> $method ();
} catch ( \Exception $e ) {
2015-11-26 16:15:31 +00:00
unset ( $this -> services [ $id ]);
2013-05-05 11:11:01 +01:00
2015-05-15 13:54:35 +01:00
throw $e ;
2015-11-26 16:15:31 +00:00
} finally {
unset ( $this -> loading [ $id ]);
2013-04-30 18:55:25 +01:00
}
2015-05-15 13:54:35 +01:00
return $service ;
}
2010-01-04 14:26:20 +00:00
}
2012-05-01 13:46:26 +01:00
2012-04-18 18:26:58 +01:00
/**
2014-12-21 17:00:50 +00:00
* Returns true if the given service has actually been initialized .
2012-04-18 18:26:58 +01:00
*
2012-05-15 21:19:31 +01:00
* @ param string $id The service identifier
2012-04-18 18:26:58 +01:00
*
2014-11-30 13:33:44 +00:00
* @ return bool true if service has already been initialized , false otherwise
2012-04-18 18:26:58 +01:00
*/
public function initialized ( $id )
{
2017-01-10 07:04:52 +00:00
$id = $this -> normalizeId ( $id );
2013-10-30 08:30:20 +00:00
2014-07-19 19:07:52 +01:00
if ( 'service_container' === $id ) {
2015-04-01 03:23:52 +01:00
return false ;
2014-07-19 19:07:52 +01:00
}
2014-11-25 09:00:53 +00:00
if ( isset ( $this -> aliases [ $id ])) {
$id = $this -> aliases [ $id ];
}
2016-08-21 13:01:27 +01:00
return isset ( $this -> services [ $id ]);
2012-04-18 18:26:58 +01:00
}
2010-01-04 14:26:20 +00:00
2015-07-02 23:05:34 +01:00
/**
* { @ inheritdoc }
*/
public function reset ()
{
$this -> services = array ();
}
2010-05-06 12:25:53 +01:00
/**
* Gets all service ids .
*
* @ return array An array of all defined service ids
*/
public function getServiceIds ()
2010-01-04 14:26:20 +00:00
{
2010-05-06 12:25:53 +01:00
$ids = array ();
2016-09-30 22:26:24 +01:00
if ( ! $this -> methodMap && ! $this instanceof ContainerBuilder && __CLASS__ !== static :: class ) {
// We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
// and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
@ trigger_error ( 'Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.' , E_USER_DEPRECATED );
foreach ( get_class_methods ( $this ) as $method ) {
if ( preg_match ( '/^get(.+)Service$/' , $method , $match )) {
$ids [] = self :: underscore ( $match [ 1 ]);
}
2010-05-06 12:25:53 +01:00
}
}
2014-07-19 19:07:52 +01:00
$ids [] = 'service_container' ;
2010-05-06 12:25:53 +01:00
2016-09-30 22:26:24 +01:00
return array_unique ( array_merge ( $ids , array_keys ( $this -> methodMap ), array_keys ( $this -> services )));
2010-01-04 14:26:20 +00:00
}
2011-02-13 18:06:41 +00:00
/**
* Camelizes a string .
*
* @ param string $id A string to camelize
2011-12-13 07:50:54 +00:00
*
2011-02-13 18:06:41 +00:00
* @ return string The camelized string
*/
2012-07-09 13:50:58 +01:00
public static function camelize ( $id )
2010-05-06 12:25:53 +01:00
{
2013-11-25 14:21:26 +00:00
return strtr ( ucwords ( strtr ( $id , array ( '_' => ' ' , '.' => '_ ' , '\\' => '_ ' ))), array ( ' ' => '' ));
2010-05-06 12:25:53 +01:00
}
2011-02-13 18:06:41 +00:00
/**
* A string to underscore .
*
* @ param string $id The string to underscore
2011-12-13 07:50:54 +00:00
*
2011-02-13 18:06:41 +00:00
* @ return string The underscored string
*/
2012-07-09 13:50:58 +01:00
public static function underscore ( $id )
2010-05-06 12:25:53 +01:00
{
2016-01-06 13:34:50 +00:00
return strtolower ( preg_replace ( array ( '/([A-Z]+)([A-Z][a-z])/' , '/([a-z\d])([A-Z])/' ), array ( '\\1_\\2' , '\\1_\\2' ), str_replace ( '_' , '.' , $id )));
2010-05-06 12:25:53 +01:00
}
2015-07-16 09:25:41 +01:00
2016-08-12 19:34:27 +01:00
/**
* Fetches a variable from the environment .
*
* @ param string The name of the environment variable
*
* @ return scalar The value to use for the provided environment variable name
*
* @ throws EnvNotFoundException When the environment variable is not found and has no default value
*/
protected function getEnv ( $name )
{
if ( isset ( $this -> envCache [ $name ]) || array_key_exists ( $name , $this -> envCache )) {
return $this -> envCache [ $name ];
}
if ( isset ( $_ENV [ $name ])) {
return $this -> envCache [ $name ] = $_ENV [ $name ];
}
if ( false !== $env = getenv ( $name )) {
return $this -> envCache [ $name ] = $env ;
}
if ( ! $this -> hasParameter ( " env( $name ) " )) {
throw new EnvNotFoundException ( $name );
}
return $this -> envCache [ $name ] = $this -> getParameter ( " env( $name ) " );
}
2017-01-10 07:04:52 +00:00
/**
* Returns the case sensitive id used at registration time .
*
* @ param string $id
*
* @ return string
*
* @ internal
*/
public function normalizeId ( $id )
{
if ( ! is_string ( $id )) {
$type = is_object ( $id ) ? get_class ( $id ) : gettype ( $id );
$id = ( string ) $id ;
@ trigger_error ( sprintf ( 'Non-string service identifiers are deprecated since Symfony 3.3 and won\'t be supported in 4.0 for service "%s" ("%s" given.) Cast it to string beforehand.' , $id , $type ), E_USER_DEPRECATED );
}
if ( isset ( $this -> normalizedIds [ $normalizedId = strtolower ( $id )])) {
$normalizedId = $this -> normalizedIds [ $normalizedId ];
if ( $id !== $normalizedId ) {
@ trigger_error ( sprintf ( 'Service identifiers will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since version 3.3.' , $id , $normalizedId ), E_USER_DEPRECATED );
}
} else {
$normalizedId = $this -> normalizedIds [ $normalizedId ] = $id ;
}
return $normalizedId ;
}
2015-07-16 09:25:41 +01:00
private function __clone ()
{
}
2010-01-04 14:26:20 +00:00
}