* * 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. * * Parameters 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, \ArrayAccess { 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 freezed. */ 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 presense 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[$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) { 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) { if (!is_string($id)) { throw new \InvalidArgumentException(sprintf('A service id should be a string (%s given).', str_replace("\n", '', var_export($id, true)))); } if (isset($this->services[$id])) { return $this->services[$id]; } if (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) { return $this->$method(); } if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { throw new \InvalidArgumentException(sprintf('The service "%s" does not exist.', $id)); } else { return null; } } /** * 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)); } /** * Returns true if the service id is defined (implements the ArrayAccess interface). * * @param string $id The service id * * @return Boolean true if the service id is defined, false otherwise */ public function offsetExists($id) { return $this->has($id); } /** * Gets a service by id (implements the ArrayAccess interface). * * @param string $id The service id * * @return mixed The parameter value */ public function offsetGet($id) { return $this->get($id); } /** * Sets a service (implements the ArrayAccess interface). * * @param string $id The service id * @param object $value The service */ public function offsetSet($id, $value) { $this->set($id, $value); } /** * Removes a service (implements the ArrayAccess interface). * * @param string $id The service id */ public function offsetUnset($id) { throw new \LogicException(sprintf('You can\'t unset a service (%s).', $id)); } /** * Catches unknown methods. * * @param string $method The called method name * @param array $arguments The method arguments * * @return mixed * * @throws \BadMethodCallException When calling to an undefined method */ public function __call($method, $arguments) { if (!preg_match('/^get(.+)Service$/', $method, $match)) { throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s.', get_class($this), $method)); } return $this->get(self::underscore($match[1])); } static public function camelize($id) { return preg_replace(array('/(^|_)+(.)/e', '/\.(.)/e'), array("strtoupper('\\2')", "'_'.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, '_', '.'))); } }