Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • NComponent
  • NComponentContainer

Interfaces

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