Namespaces

  • 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

  • Component
  • Container

Interfaces

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