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