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:  * Component is the base class for all components.
 17:  *
 18:  * Components are objects implementing IComponent. They has parent component and own name.
 19:  *
 20:  * @author     David Grudl
 21:  *
 22:  * @property-read string $name
 23:  * @property IComponentContainer $parent
 24:  * @package Nette
 25:  */
 26: abstract class NComponent extends NObject implements IComponent
 27: {
 28:     /** @var IComponentContainer */
 29:     private $parent;
 30: 
 31:     /** @var string */
 32:     private $name;
 33: 
 34:     /** @var array of [type => [obj, depth, path, is_monitored?]] */
 35:     private $monitors = array();
 36: 
 37: 
 38: 
 39:     /**
 40:      */
 41:     public function __construct(IComponentContainer $parent = NULL, $name = NULL)
 42:     {
 43:         if ($parent !== NULL) {
 44:             $parent->addComponent($this, $name);
 45: 
 46:         } elseif (is_string($name)) {
 47:             $this->name = $name;
 48:         }
 49:     }
 50: 
 51: 
 52: 
 53:     /**
 54:      * Lookup hierarchy for component specified by class or interface name.
 55:      * @param  string class/interface type
 56:      * @param  bool   throw exception if component doesn't exist?
 57:      * @return IComponent
 58:      */
 59:     public function lookup($type, $need = TRUE)
 60:     {
 61:         if ($a = strrpos($type, '\\')) $type = substr($type, $a + 1); // fix namespace
 62:         if (!isset($this->monitors[$type])) { // not monitored or not processed yet
 63:             $obj = $this->parent;
 64:             $path = self::NAME_SEPARATOR . $this->name;
 65:             $depth = 1;
 66:             while ($obj !== NULL) {
 67:                 if ($obj instanceof $type) break;
 68:                 $path = self::NAME_SEPARATOR . $obj->getName() . $path;
 69:                 $depth++;
 70:                 $obj = $obj->getParent(); // IComponent::getParent()
 71:                 if ($obj === $this) $obj = NULL; // prevent cycling
 72:             }
 73: 
 74:             if ($obj) {
 75:                 $this->monitors[$type] = array($obj, $depth, substr($path, 1), FALSE);
 76: 
 77:             } else {
 78:                 $this->monitors[$type] = array(NULL, NULL, NULL, FALSE); // not found
 79:             }
 80:         }
 81: 
 82:         if ($need && $this->monitors[$type][0] === NULL) {
 83:             throw new InvalidStateException("Component '$this->name' is not attached to '$type'.");
 84:         }
 85: 
 86:         return $this->monitors[$type][0];
 87:     }
 88: 
 89: 
 90: 
 91:     /**
 92:      * Lookup for component specified by class or interface name. Returns backtrace path.
 93:      * A path is the concatenation of component names separated by self::NAME_SEPARATOR.
 94:      * @param  string class/interface type
 95:      * @param  bool   throw exception if component doesn't exist?
 96:      * @return string
 97:      */
 98:     public function lookupPath($type, $need = TRUE)
 99:     {
100:         if ($a = strrpos($type, '\\')) $type = substr($type, $a + 1); // fix namespace
101:         $this->lookup($type, $need);
102:         return $this->monitors[$type][2];
103:     }
104: 
105: 
106: 
107:     /**
108:      * Starts monitoring.
109:      * @param  string class/interface type
110:      * @return void
111:      */
112:     public function monitor($type)
113:     {
114:         if ($a = strrpos($type, '\\')) $type = substr($type, $a + 1); // fix namespace
115:         if (empty($this->monitors[$type][3])) {
116:             if ($obj = $this->lookup($type, FALSE)) {
117:                 $this->attached($obj);
118:             }
119:             $this->monitors[$type][3] = TRUE; // mark as monitored
120:         }
121:     }
122: 
123: 
124: 
125:     /**
126:      * Stops monitoring.
127:      * @param  string class/interface type
128:      * @return void
129:      */
130:     public function unmonitor($type)
131:     {
132:         if ($a = strrpos($type, '\\')) $type = substr($type, $a + 1); // fix namespace
133:         unset($this->monitors[$type]);
134:     }
135: 
136: 
137: 
138:     /**
139:      * This method will be called when the component (or component's parent)
140:      * becomes attached to a monitored object. Do not call this method yourself.
141:      * @param  IComponent
142:      * @return void
143:      */
144:     protected function attached($obj)
145:     {
146:     }
147: 
148: 
149: 
150:     /**
151:      * This method will be called before the component (or component's parent)
152:      * becomes detached from a monitored object. Do not call this method yourself.
153:      * @param  IComponent
154:      * @return void
155:      */
156:     protected function detached($obj)
157:     {
158:     }
159: 
160: 
161: 
162:     /********************* interface IComponent ****************d*g**/
163: 
164: 
165: 
166:     /**
167:      * @return string
168:      */
169:     final public function getName()
170:     {
171:         return $this->name;
172:     }
173: 
174: 
175: 
176:     /**
177:      * Returns the container if any.
178:      * @return IComponentContainer|NULL
179:      */
180:     final public function getParent()
181:     {
182:         return $this->parent;
183:     }
184: 
185: 
186: 
187:     /**
188:      * Sets the parent of this component. This method is managed by containers and should.
189:      * not be called by applications
190:      * @param  IComponentContainer  New parent or null if this component is being removed from a parent
191:      * @param  string
192:      * @return NComponent  provides a fluent interface
193:      * @throws InvalidStateException
194:      */
195:     public function setParent(IComponentContainer $parent = NULL, $name = NULL)
196:     {
197:         if ($parent === NULL && $this->parent === NULL && $name !== NULL) {
198:             $this->name = $name; // just rename
199:             return $this;
200: 
201:         } elseif ($parent === $this->parent && $name === NULL) {
202:             return $this; // nothing to do
203:         }
204: 
205:         // A component cannot be given a parent if it already has a parent.
206:         if ($this->parent !== NULL && $parent !== NULL) {
207:             throw new InvalidStateException("Component '$this->name' already has a parent.");
208:         }
209: 
210:         // remove from parent?
211:         if ($parent === NULL) {
212:             $this->refreshMonitors(0);
213:             $this->parent = NULL;
214: 
215:         } else { // add to parent
216:             $this->validateParent($parent);
217:             $this->parent = $parent;
218:             if ($name !== NULL) $this->name = $name;
219: 
220:             $tmp = array();
221:             $this->refreshMonitors(0, $tmp);
222:         }
223:         return $this;
224:     }
225: 
226: 
227: 
228:     /**
229:      * Is called by a component when it is about to be set new parent. Descendant can
230:      * override this method to disallow a parent change by throwing an InvalidStateException
231:      * @param  IComponentContainer
232:      * @return void
233:      * @throws InvalidStateException
234:      */
235:     protected function validateParent(IComponentContainer $parent)
236:     {
237:     }
238: 
239: 
240: 
241:     /**
242:      * Refreshes monitors.
243:      * @param  int
244:      * @param  array|NULL (array = attaching, NULL = detaching)
245:      * @param  array
246:      * @return void
247:      */
248:     private function refreshMonitors($depth, & $missing = NULL, & $listeners = array())
249:     {
250:         if ($this instanceof IComponentContainer) {
251:             foreach ($this->getComponents() as $component) {
252:                 if ($component instanceof NComponent) {
253:                     $component->refreshMonitors($depth + 1, $missing, $listeners);
254:                 }
255:             }
256:         }
257: 
258:         if ($missing === NULL) { // detaching
259:             foreach ($this->monitors as $type => $rec) {
260:                 if (isset($rec[1]) && $rec[1] > $depth) {
261:                     if ($rec[3]) { // monitored
262:                         $this->monitors[$type] = array(NULL, NULL, NULL, TRUE);
263:                         $listeners[] = array($this, $rec[0]);
264:                     } else { // not monitored, just randomly cached
265:                         unset($this->monitors[$type]);
266:                     }
267:                 }
268:             }
269: 
270:         } else { // attaching
271:             foreach ($this->monitors as $type => $rec) {
272:                 if (isset($rec[0])) { // is in cache yet
273:                     continue;
274: 
275:                 } elseif (!$rec[3]) { // not monitored, just randomly cached
276:                     unset($this->monitors[$type]);
277: 
278:                 } elseif (isset($missing[$type])) { // known from previous lookup
279:                     $this->monitors[$type] = array(NULL, NULL, NULL, TRUE);
280: 
281:                 } else {
282:                     $this->monitors[$type] = NULL; // forces re-lookup
283:                     if ($obj = $this->lookup($type, FALSE)) {
284:                         $listeners[] = array($this, $obj);
285:                     } else {
286:                         $missing[$type] = TRUE;
287:                     }
288:                     $this->monitors[$type][3] = TRUE; // mark as monitored
289:                 }
290:             }
291:         }
292: 
293:         if ($depth === 0) { // call listeners
294:             $method = $missing === NULL ? 'detached' : 'attached';
295:             foreach ($listeners as $item) {
296:                 $item[0]->$method($item[1]);
297:             }
298:         }
299:     }
300: 
301: 
302: 
303:     /********************* cloneable, serializable ****************d*g**/
304: 
305: 
306: 
307:     /**
308:      * Object cloning.
309:      */
310:     public function __clone()
311:     {
312:         if ($this->parent === NULL) {
313:             return;
314: 
315:         } elseif ($this->parent instanceof NComponentContainer) {
316:             $this->parent = $this->parent->_isCloning();
317:             if ($this->parent === NULL) { // not cloning
318:                 $this->refreshMonitors(0);
319:             }
320: 
321:         } else {
322:             $this->parent = NULL;
323:             $this->refreshMonitors(0);
324:         }
325:     }
326: 
327: 
328: 
329:     /**
330:      * Prevents unserialization.
331:      */
332:     final public function __wakeup()
333:     {
334:         throw new NotImplementedException;
335:     }
336: 
337: }
338: 
Nette Framework 0.9.7 (for PHP 5.2) API documentation generated by ApiGen 2.3.0