Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • ArrayTools
  • Callback
  • Component
  • ComponentContainer
  • Configurator
  • DateTime
  • Debug
  • Environment
  • Framework
  • FreezableObject
  • GenericRecursiveIterator
  • Image
  • ImageMagick
  • InstanceFilterIterator
  • Object
  • ObjectMixin
  • Paginator
  • RecursiveComponentIterator
  • ServiceLocator
  • SmartCachingIterator
  • String
  • Tools

Interfaces

  • IComponent
  • IComponentContainer
  • IDebuggable
  • IServiceLocator
  • ITranslator

Exceptions

  • AmbiguousServiceException
  • Overview
  • Namespace
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18: /**
 19:  * Service locator pattern implementation.
 20:  *
 21:  * @author     David Grudl
 22:  */
 23: class ServiceLocator extends Object implements IServiceLocator
 24: {
 25:     /** @var IServiceLocator */
 26:     private $parent;
 27: 
 28:     /** @var array  storage for shared objects */
 29:     private $registry = array();
 30: 
 31:     /** @var array  storage for service factories */
 32:     private $factories = array();
 33: 
 34: 
 35: 
 36:     /**
 37:      * @param  IServiceLocator
 38:      */
 39:     public function __construct(IServiceLocator $parent = NULL)
 40:     {
 41:         $this->parent = $parent;
 42:     }
 43: 
 44: 
 45: 
 46:     /**
 47:      * Adds the specified service to the service container.
 48:      * @param  string service name
 49:      * @param  mixed  object, class name or factory callback
 50:      * @param  bool   is singleton?
 51:      * @param  array  factory options
 52:      * @return void
 53:      */
 54:     public function addService($name, $service, $singleton = TRUE, array $options = NULL)
 55:     {
 56:         if (!is_string($name) || $name === '') {
 57:             throw new \InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
 58:         }
 59: 
 60:         $lower = strtolower($name);
 61:         if (isset($this->registry[$lower])) { // only for instantiated services?
 62:             throw new AmbiguousServiceException("Service named '$name' has been already registered.");
 63:         }
 64: 
 65:         if (is_object($service) && !($service instanceof \Closure || $service instanceof Callback)) {
 66:             if (!$singleton || $options) {
 67:                 throw new \InvalidArgumentException("Service named '$name' is an instantiated object and must therefore be singleton without options.");
 68:             }
 69:             $this->registry[$lower] = $service;
 70: 
 71:         } else {
 72:             if (!$service) {
 73:                 throw new \InvalidArgumentException("Service named '$name' is empty.");
 74:             }
 75:             $this->factories[$lower] = array($service, $singleton, $options);
 76:         }
 77:     }
 78: 
 79: 
 80: 
 81:     /**
 82:      * Removes the specified service type from the service container.
 83:      * @return void
 84:      */
 85:     public function removeService($name)
 86:     {
 87:         if (!is_string($name) || $name === '') {
 88:             throw new \InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
 89:         }
 90: 
 91:         $lower = strtolower($name);
 92:         unset($this->registry[$lower], $this->factories[$lower]);
 93:     }
 94: 
 95: 
 96: 
 97:     /**
 98:      * Gets the service object of the specified type.
 99:      * @param  string service name
100:      * @param  array  options in case service is not singleton
101:      * @return mixed
102:      */
103:     public function getService($name, array $options = NULL)
104:     {
105:         if (!is_string($name) || $name === '') {
106:             throw new \InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
107:         }
108: 
109:         $lower = strtolower($name);
110: 
111:         if (isset($this->registry[$lower])) { // instantiated singleton
112:             if ($options) {
113:                 throw new \InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
114:             }
115:             return $this->registry[$lower];
116: 
117:         } elseif (isset($this->factories[$lower])) {
118:             list($factory, $singleton, $defOptions) = $this->factories[$lower];
119: 
120:             if ($singleton && $options) {
121:                 throw new \InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
122: 
123:             } elseif ($defOptions) {
124:                 $options = $options ? $options + $defOptions : $defOptions;
125:             }
126: 
127:             if (is_string($factory) && strpos($factory, ':') === FALSE) { // class name
128:                 if (!class_exists($factory)) {
129:                     throw new AmbiguousServiceException("Cannot instantiate service '$name', class '$factory' not found.");
130:                 }
131:                 $service = new $factory;
132:                 if ($options) {
133:                     if (method_exists($service, 'setOptions')) {
134:                         $service->setOptions($options); // TODO: better!
135:                     } else {
136:                         throw new \InvalidStateException("Unable to set options, method $factory::setOptions() is missing.");
137:                     }
138:                 }
139: 
140:             } else { // factory callback
141:                 $factory = callback($factory);
142:                 if (!$factory->isCallable()) {
143:                     throw new \InvalidStateException("Cannot instantiate service '$name', handler '$factory' is not callable.");
144:                 }
145:                 $service = $factory($options);
146:                 if (!is_object($service)) {
147:                     throw new AmbiguousServiceException("Cannot instantiate service '$name', value returned by '$factory' is not object.");
148:                 }
149:             }
150: 
151:             if ($singleton) {
152:                 $this->registry[$lower] = $service;
153:                 unset($this->factories[$lower]);
154:             }
155:             return $service;
156:         }
157: 
158:         if ($this->parent !== NULL) {
159:             return $this->parent->getService($name, $options);
160: 
161:         } else {
162:             throw new \InvalidStateException("Service '$name' not found.");
163:         }
164:     }
165: 
166: 
167: 
168:     /**
169:      * Exists the service?
170:      * @param  string service name
171:      * @param  bool   must be created yet?
172:      * @return bool
173:      */
174:     public function hasService($name, $created = FALSE)
175:     {
176:         if (!is_string($name) || $name === '') {
177:             throw new \InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
178:         }
179: 
180:         $lower = strtolower($name);
181:         return isset($this->registry[$lower]) || (!$created && isset($this->factories[$lower])) || ($this->parent !== NULL && $this->parent->hasService($name, $created));
182:     }
183: 
184: 
185: 
186:     /**
187:      * Returns the parent container if any.
188:      * @return IServiceLocator|NULL
189:      */
190:     public function getParent()
191:     {
192:         return $this->parent;
193:     }
194: 
195: }
196: 
197: 
198: 
199: /**
200:  * Ambiguous service resolution exception.
201:  *
202:  * @author     David Grudl
203:  */
204: class AmbiguousServiceException extends \Exception
205: {
206: }
207: 
Nette Framework 0.9.7 API documentation generated by ApiGen 2.3.0