Packages

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

Classes

  • NArrayTools
  • NCallback
  • NComponent
  • NComponentContainer
  • NConfigurator
  • NDateTime53
  • NDebug
  • NEnvironment
  • NFramework
  • NFreezableObject
  • NGenericRecursiveIterator
  • NImage
  • NImageMagick
  • NInstanceFilterIterator
  • NObject
  • NObjectMixin
  • NPaginator
  • NRecursiveComponentIterator
  • NServiceLocator
  • NSmartCachingIterator
  • NString
  • NTools

Interfaces

  • IComponent
  • IComponentContainer
  • IDebuggable
  • IServiceLocator
  • ITranslator

Exceptions

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