* * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ /** * Container is a dependency injection container. * * It gives access to object instances (services). * * Services and parameters are simple key/pair stores. * * Parameter and service keys are case insensitive. * * A service id can contain lowercased letters, digits, underscores, and dots. * Underscores are used to separate words, and dots to group services * under namespaces: * * * * A service can also be defined by creating a method named * getXXXService(), where XXX is the camelized version of the id: * * * * 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) * * @author Fabien Potencier */ class Container implements ContainerInterface { protected $parameterBag; protected $services; /** * Constructor. * * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance */ public function __construct(ParameterBagInterface $parameterBag = null) { $this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag; $this->services = array(); $this->set('service_container', $this); } /** * Freezes the container. * * This method does two things: * * * Parameter values are resolved; * * The parameter bag is frozen. */ public function freeze() { $this->parameterBag->resolve(); $this->parameterBag = new FrozenParameterBag($this->parameterBag->all()); } /** * Returns true if the container parameter bag are frozen. * * @return Boolean true if the container parameter bag are frozen, false otherwise */ public function isFrozen() { return $this->parameterBag instanceof FrozenParameterBag; } /** * Gets the service container parameter bag. * * @return ParameterBagInterface A ParameterBagInterface instance */ public function getParameterBag() { return $this->parameterBag; } /** * Gets a parameter. * * @param string $name The parameter name * * @return mixed The parameter value * * @throws \InvalidArgumentException if the parameter is not defined */ public function getParameter($name) { return $this->parameterBag->get($name); } /** * Checks if a parameter exists. * * @param string $name The parameter name * * @return boolean The presence of parameter in container */ public function hasParameter($name) { return $this->parameterBag->has($name); } /** * Sets a parameter. * * @param string $name The parameter name * @param mixed $parameters The parameter value */ public function setParameter($name, $value) { $this->parameterBag->set($name, $value); } /** * Sets a service. * * @param string $id The service identifier * @param object $service The service instance */ public function set($id, $service) { $this->services[strtolower($id)] = $service; } /** * Returns true if the given service is defined. * * @param string $id The service identifier * * @return Boolean true if the service is defined, false otherwise */ public function has($id) { $id = strtolower($id); return isset($this->services[$id]) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service'); } /** * Gets a service. * * If a service is both defined through a set() method and * with a set*Service() method, the former has always precedence. * * @param string $id The service identifier * @param int $invalidBehavior The behavior when the service does not exist * * @return object The associated service * * @throws \InvalidArgumentException if the service is not defined * * @see Reference */ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) { static $loading = array(); $id = strtolower($id); if (isset($this->services[$id])) { return $this->services[$id]; } if (isset($loading[$id])) { throw new \LogicException(sprintf('Circular reference detected for service "%s" (services currently loading: %s).', $id, implode(', ', array_keys($loading)))); } if (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) { $loading[$id] = true; $service = $this->$method(); unset($loading[$id]); return $service; } if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { throw new \InvalidArgumentException(sprintf('The service "%s" does not exist.', $id)); } } /** * Gets all service ids. * * @return array An array of all defined service ids */ public function getServiceIds() { $ids = array(); $r = new \ReflectionClass($this); foreach ($r->getMethods() as $method) { if (preg_match('/^get(.+)Service$/', $name = $method->getName(), $match)) { $ids[] = self::underscore($match[1]); } } return array_merge($ids, array_keys($this->services)); } static public function camelize($id) { return preg_replace(array('/(?:^|_)+(.)/e', '/\.(.)/e'), array("strtoupper('\\1')", "'_'.strtoupper('\\1')"), $id); } static public function underscore($id) { return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.'))); } }