Beispiel #1
0
 /**
  * Resolve a parameter if it references other parameters.
  *
  * Works recursively.
  * 
  * @param  mixed $parameter Parameter value to be resolved.
  * @return mixed
  */
 public function resolve($parameter)
 {
     // allow for deep resolving
     if (is_array($parameter)) {
         foreach ($parameter as $key => $value) {
             $parameter[$key] = $this->resolve($value);
         }
         return $parameter;
     }
     if (!is_string($parameter)) {
         return $parameter;
     }
     // only bother with resolving when there are at least two %
     $parameterLength = mb_strlen($parameter);
     $firstDelimeter = strpos($parameter, '%');
     $secondDelimeter = strpos($parameter, '%', min((int) $firstDelimeter + 1, $parameterLength));
     if ($firstDelimeter === false || $secondDelimeter === false || $firstDelimeter === $secondDelimeter) {
         return $parameter;
     }
     // special case when fully referencing another parameter, to avoid regex
     // but also handle cases where referencing an array parameter
     // (otherwise preg_replace_callback below will trigger array to string conversion)
     if ($firstDelimeter === 0 && $secondDelimeter === $parameterLength - 1) {
         $referenced = mb_substr($parameter, 1, -1);
         return $this->container->hasParameter($referenced) ? $this->container->getParameter($referenced) : $parameter;
     }
     $container = $this->container;
     $original = $parameter;
     $parameter = preg_replace_callback('#(%%|%)([\\w\\d_\\.]+)%#i', function ($matches) use($container, $original) {
         if ($matches[1] === '%%') {
             return '%' . $matches[2];
         }
         $name = $matches[2];
         if ($container->hasParameter($name)) {
             $param = $container->getParameter($name);
             // only scalar types can be referenced like that
             if (!is_scalar($param)) {
                 throw new InvalidParameterException('Invalid parameter construction - cannot reference non-scalar type parameter in "' . $original . '".');
             }
             return $container->getParameter($name);
         }
         return '%' . $name . '%';
     }, $parameter);
     return $parameter;
 }
Beispiel #2
0
 /**
  * Reroutes notifications from one service name to another.
  *
  * This is especially used when a notification was referring to its target by an alias and the alias's target
  * has just become known to the container.
  * 
  * @param  string $from Original notifications target.
  * @param  string $to   New notifications target.
  */
 public function rerouteNotifications($from, $to)
 {
     if (!isset($this->notifications[$from])) {
         return;
     }
     // $to might also be an alias, so lets dig deeper
     $to = $this->container->resolveServiceName($to);
     foreach ($this->notifications[$from] as $notification) {
         $this->notifications[$to][] = $notification;
     }
 }
Beispiel #3
0
 /**
  * Resolves function arguments to applicable arguments.
  *
  * This method will resolve all parameters in arguments as well as references to
  * other services (in the form of `@service_name`).
  * 
  * @param  array|mixed $argument   Either an array of arguments or a single argument.
  * @param  string $selfServiceName If the arguments can reference "self service name", the name of
  *                                 such references service should be passed here. It can be referenced
  *                                 in arguments as "@=". Default: `null`.
  * @return array|mixed
  */
 public function resolve($argument, $selfServiceName = null)
 {
     // deeply resolve arguments
     if (is_array($argument)) {
         foreach ($argument as $i => $arg) {
             $argument[$i] = $this->resolve($arg, $selfServiceName);
         }
         return $argument;
     }
     // possible parameter argument
     if (is_string($argument)) {
         $argument = $this->parametersResolver->resolve($argument);
     }
     // if possible to reference self in arguments then do it
     // (reference by name instead of getting the service now)
     if ($selfServiceName !== null && $argument === '@') {
         $argument = '@' . $selfServiceName;
     }
     // if possible to reference self name in arguments then do it
     if ($selfServiceName !== null && $argument === '@=') {
         $argument = $selfServiceName;
     }
     // and maybe referencing a different service?
     if (is_string($argument) && mb_substr($argument, 0, 1) === '@') {
         $serviceName = mb_substr($argument, 1);
         $optional = mb_substr($argument, -1) === '?';
         $serviceName = $optional ? mb_substr($serviceName, 0, -1) : $serviceName;
         try {
             $argument = $this->container->get($serviceName);
         } catch (ServiceNotFoundException $e) {
             if ($optional) {
                 $argument = null;
             } else {
                 throw new ServiceNotFoundException('Could not find service "' . $serviceName . '" when resolving a non-optional argument.', 0, $e);
             }
         }
     }
     return $argument;
 }
Beispiel #4
0
 public function get($name)
 {
     $instance = parent::get($name);
     // if already loaded from cache, then don't do anything
     if ($this->loadedFromCache) {
         return $instance;
     }
     // if cache hasn't been loaded yet, then keep reference to this
     // resolved service so that on cache load we can deliver all
     // notifications to it
     $realName = $this->resolveServiceName($name);
     $this->preCacheServices[$realName] = array('name' => $realName, 'instance' => $instance);
     return $instance;
 }
Beispiel #5
0
 /**
  * Instantiate the service and perform constructor injection if necessary.
  * 
  * @param  Service $service Service definition.
  * @return object
  */
 protected function instantiateService(Service $service)
 {
     $name = $service->name;
     // if already resolved the definition, then just call the resolved closure factory
     if (isset($this->instantiateClosuresCache[$name])) {
         $instantiateClosure = $this->instantiateClosuresCache[$name];
         return $instantiateClosure();
     }
     // deal with closure services
     if ($service instanceof ClosureService) {
         $serviceClosure = $service->closure;
         return $serviceClosure($this->container);
     }
     // deal with object services
     if ($service instanceof ObjectService) {
         return $service->getInstance();
     }
     // deal with factory services
     if ($service instanceof FactoryService) {
         try {
             $factoryServiceName = $this->parametersResolver->resolve($service->factoryService);
             $factoryServiceDefinition = $this->container->getDefinition($factoryServiceName);
             $factoryService = $this->container->get($factoryServiceName);
             return $this->callMethod($factoryServiceDefinition, $service->factoryMethod, $service->factoryArguments, $factoryService);
         } catch (Exception $e) {
             throw new InvalidServiceException('Could not instantiate service "' . $name . '" due to: ' . $e->getMessage(), 0, $e);
         }
     }
     // class can be defined as a parameter
     $class = $this->parametersResolver->resolve($service->class);
     if (!class_exists($class)) {
         throw new InvalidServiceException('Could not instantiate service "' . $name . '" because class ' . $class . ' was not found.');
     }
     $instantiateClosure = $this->createInstantiationClosure($class, $service->arguments);
     // cache this closure
     $this->instantiateClosuresCache[$name] = $instantiateClosure;
     // and finally call it
     return $instantiateClosure();
 }
Beispiel #6
0
 public function testDumpServices()
 {
     $container = new Container();
     $container->setParameter('collection.class', $this->collectionServiceClass);
     $container->register('simple', $this->simpleServiceClass);
     $container->register('simple.alias', array('alias' => 'simple'));
     $container->register('called_service', array('class' => $this->calledServiceClass, 'arguments' => array('asd', 3)));
     $container->register('simple_factory', $this->simpleFactoryClass);
     $container->register('simple_factory.product.one', array('factory' => array('@simple_factory', 'get'), 'aliases' => array('factoried_service')));
     $container->register('collection', '%collection.class%');
     $this->assertEquals(array('container' => array('name' => 'container', 'class' => 'Splot\\DependencyInjection\\Container'), 'service_container' => array('name' => 'service_container', 'alias' => 'container'), 'services_container' => array('name' => 'services_container', 'alias' => 'container'), 'di_container' => array('name' => 'di_container', 'alias' => 'container'), 'simple' => array('name' => 'simple', 'class' => $this->simpleServiceClass), 'simple.alias' => array('name' => 'simple.alias', 'alias' => 'simple'), 'called_service' => array('name' => 'called_service', 'class' => $this->calledServiceClass), 'simple_factory' => array('name' => 'simple_factory', 'class' => $this->simpleFactoryClass), 'simple_factory.product.one' => array('name' => 'simple_factory.product.one'), 'factoried_service' => array('name' => 'factoried_service', 'alias' => 'simple_factory.product.one'), 'collection' => array('name' => 'collection', 'class' => $this->collectionServiceClass)), $container->dump());
 }
Beispiel #7
0
 public function testEscapingParameterSign()
 {
     $container = new Container();
     $container->setParameter('lorem', 'ipsum');
     $container->setParameter('dolor', 'sit.amet');
     $container->setParameter('adipiscit.elit', '%lorem%%dolor%');
     $container->setParameter('lipsum', '%%lorem%%');
     $container->setParameter('lipsum.com', 'it.%dolor%%%lorem%%');
     $this->assertEquals('ipsumsit.amet', $container->getParameter('adipiscit.elit'));
     $this->assertEquals('%lorem%', $container->getParameter('lipsum'));
     $this->assertEquals('it.sit.amet%lorem%', $container->getParameter('lipsum.com'));
 }