Autodoc
  • Namespace
  • Class
  • Tree

Namespaces

  • BlueTihi
    • Context
  • Brickrouge
    • Element
      • Nodes
    • Renderer
    • Widget
  • ICanBoogie
    • ActiveRecord
    • AutoConfig
    • CLDR
    • Composer
    • Core
    • Event
    • Exception
    • HTTP
      • Dispatcher
      • Request
    • I18n
      • Translator
    • Mailer
    • Modules
      • Taxonomy
        • Support
      • Thumbnailer
        • Versions
    • Object
    • Operation
      • Dispatcher
    • Prototype
    • Routes
    • Routing
      • Dispatcher
    • Session
  • Icybee
    • ActiveRecord
      • Model
    • ConfigOperation
    • Document
    • EditBlock
    • Element
      • ActionbarContextual
      • ActionbarSearch
      • ActionbarToolbar
    • FormBlock
    • Installer
    • ManageBlock
    • Modules
      • Articles
      • Cache
        • Collection
        • ManageBlock
      • Comments
        • ManageBlock
      • Contents
        • ManageBlock
      • Dashboard
      • Editor
        • Collection
      • Files
        • File
        • ManageBlock
      • Forms
        • Form
        • ManageBlock
      • I18n
      • Images
        • ManageBlock
      • Members
      • Modules
        • ManageBlock
      • Nodes
        • ManageBlock
        • Module
      • Pages
        • BreadcrumbElement
        • LanguagesElement
        • ManageBlock
        • NavigationBranchElement
        • NavigationElement
        • Page
        • PageController
      • Registry
      • Search
      • Seo
      • Sites
        • ManageBlock
      • Taxonomy
        • Terms
          • ManageBlock
        • Vocabulary
          • ManageBlock
      • Users
        • ManageBlock
        • NonceLogin
        • Roles
      • Views
        • ActiveRecordProvider
        • Collection
        • View
    • Operation
      • ActiveRecord
      • Constructor
      • Module
      • Widget
    • Rendering
  • None
  • Patron
  • PHP

Classes

  • Blueprint
  • BlueprintNode
  • BreadcrumbElement
  • Content
  • ContentModel
  • CopyOperation
  • DeleteOperation
  • EditBlock
  • ExportBlock
  • ExportOperation
  • Hooks
  • ImportOperation
  • LanguagesElement
  • ListView
  • ManageBlock
  • Model
  • Module
  • NavigationBranchElement
  • NavigationElement
  • NavigationExcludeOperation
  • NavigationIncludeOperation
  • Page
  • PageController
  • PopPage
  • PopTemplate
  • QueryOperationOperation
  • SaveOperation
  • TemplateEditorsOperation
  • UpdateTreeOperation
  1 <?php
  2 
  3 /*
  4  * This file is part of the Icybee package.
  5  *
  6  * (c) Olivier Laviale <olivier.laviale@gmail.com>
  7  *
  8  * For the full copyright and license information, please view the LICENSE
  9  * file that was distributed with this source code.
 10  */
 11 
 12 namespace Icybee\Modules\Pages;
 13 
 14 use ICanBoogie\ActiveRecord\Query;
 15 use ICanBoogie\PropertyNotDefined;
 16 
 17 /**
 18  * A simplified data structure representing the relashionship between pages.
 19  *
 20  * @property-read array[]Page $ordered_records Records ordered according to their position and
 21  * relation. See: {@link get_ordered_records()}.
 22  *
 23  * @see BlueprintNode
 24  */
 25 class Blueprint
 26 {
 27     /**
 28      * Creates a {@link Blueprint} instance from an {@link ActiveRecord\Query}.
 29      *
 30      * @param Query $query
 31      *
 32      * @return Blueprint
 33      */
 34     static public function from(Query $query)
 35     {
 36         $query->mode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\BluePrintNode');
 37 
 38         $relation = array();
 39         $children = array();
 40         $index = array();
 41 
 42         foreach ($query as $row)
 43         {
 44             $row->parent = null;
 45             $row->depth = null;
 46             $row->children = array();
 47 
 48             $nid = $row->nid;
 49             $parent_id = $row->parentid;
 50             $index[$nid] = $row;
 51             $relation[$nid] = $parent_id;
 52             $children[$parent_id][$nid] = $nid;
 53         }
 54 
 55         $tree = array();
 56 
 57         foreach ($index as $nid => $page)
 58         {
 59             if (!$page->parentid || empty($index[$page->parentid]))
 60             {
 61                 $tree[$nid] = $page;
 62 
 63                 continue;
 64             }
 65 
 66             $page->parent = $index[$page->parentid];
 67             $page->parent->children[$nid] = $page;
 68         }
 69 
 70         self::set_depth($tree);
 71 
 72         return new static($query->model, $relation, $children, $index, $tree);
 73     }
 74 
 75     /**
 76      * Set the depth of the nodes of the specified branch.
 77      *
 78      * @param array $branch
 79      * @param number $depth Starting depth.
 80      */
 81     static private function set_depth(array $branch, $depth=0)
 82     {
 83         foreach ($branch as $node)
 84         {
 85             $node->depth = $depth;
 86 
 87             if (!$node->children)
 88             {
 89                 continue;
 90             }
 91 
 92             self::set_depth($node->children, $depth + 1);
 93         }
 94     }
 95 
 96     /**
 97      * The child/parent relation.
 98      *
 99      * An array where each key/value is the identifier of a node and the idenfier of its parent,
100      * or zero if the node has no parent.
101      *
102      * @var array[int]int
103      */
104     public $relation;
105 
106     /**
107      * The parent/children relation.
108      *
109      * An array where each key/value is the identifier of a parent and an array made of the
110      * identifiers of its children. Each key/value pair of the children value is made of the
111      * child identifier.
112      *
113      * @var array[int]array
114      */
115     public $children;
116 
117     /**
118      * Index of the blueprint nodes.
119      *
120      * Blueprint nodes are instances of the {@link BlueprintNode} class. The key of the index is
121      * the identifier of the node, while the value is the node instance.
122      *
123      * @var array[int]BlueprintNode
124      */
125     public $index;
126 
127     /**
128      * Pages nested as a tree.
129      *
130      * @var array[int]BlueprintNode
131      */
132     public $tree;
133 
134     /**
135      * Model associated with the blueprint.
136      *
137      * @var \ICanBoogie\ActiveRecord\Model
138      */
139     public $model;
140 
141     /**
142      * The blueprint is usualy constructed by the {@link Model::blueprint()} method or the
143      * {@link subset()} method.
144      *
145      * @param Model $model
146      * @param array $relation The child/parent relations.
147      * @param array $children The parent/children relations.
148      * @param array $index Pages index.
149      * @param array $tree Pages nested as a tree.
150      */
151     protected function __construct(Model $model, array $relation, array $children, array $index, array $tree)
152     {
153         $this->relation = $relation;
154         $this->children = $children;
155         $this->index = $index;
156         $this->tree = $tree;
157         $this->model = $model;
158     }
159 
160     /**
161      * Support for the {@link $ordered_records} property.
162      *
163      * @param string $property
164      *
165      * @throws PropertyNotDefined in attempt to get a property that is not defined or supported.
166      *
167      * @return mixed
168      */
169     public function __get($property)
170     {
171         switch ($property)
172         {
173             case 'ordered_nodes';
174 
175                 return $this->get_ordered_nodes();
176 
177             case 'ordered_records':
178 
179                 return $this->get_ordered_records();
180         }
181 
182         throw new PropertyNotDefined(array($property, $this));
183     }
184 
185     protected function get_ordered_nodes()
186     {
187         $nodes = array();
188 
189         $ordering = function(array $branch) use(&$ordering, &$nodes) {
190 
191             foreach ($branch as $node)
192             {
193                 $nodes[$node->nid] = $node;
194 
195                 if ($node->children)
196                 {
197                     $ordering($node->children);
198                 }
199             }
200         };
201 
202         $ordering($this->tree);
203 
204         return $nodes;
205     }
206 
207     /**
208      * Returns the records of the blueprint ordered according to their position and relation.
209      *
210      * Note: The blueprint is populated with records if needed.
211      *
212      * @return array[int]ActiveRecord
213      */
214     protected function get_ordered_records()
215     {
216         $records = array();
217 
218         $ordering = function(array $branch) use(&$ordering, &$records) {
219 
220             foreach ($branch as $node)
221             {
222                 $records[$node->nid] = $node->record;
223 
224                 if ($node->children)
225                 {
226                     $ordering($node->children);
227                 }
228             }
229         };
230 
231         $node = current($this->index);
232 
233         if (empty($node->record))
234         {
235             $this->populate();
236         }
237 
238         $ordering($this->tree);
239 
240         return $records;
241     }
242 
243     /**
244      * Checks if a branch has children.
245      *
246      * @param int $nid Identifier of the parent record.
247      *
248      * @return boolean
249      */
250     public function has_children($nid)
251     {
252         return !empty($this->children[$nid]);
253     }
254 
255     /**
256      * Returns the number of children of a branch.
257      *
258      * @param int $nid The identifier of the parent record.
259      *
260      * @return int
261      */
262     public function children_count($nid)
263     {
264         return $this->has_children($nid) ? count($this->children[$nid]) : 0;
265     }
266 
267     /**
268      * Create a subset of the blueprint.
269      *
270      * A filter can be specified to filter out the nodes of the subset. The function returns `true`
271      * to discart a node. The callback function have the following signature:
272      *
273      *     function(BlueprintNode $node)
274      *
275      * The following example demonstrate how offline nodes cen be filtered out.
276      *
277      * <pre>
278      * <?php
279      *
280      * use Icybee\Modules\Pages\BlueprintNode;
281      *
282      * $subset = $core->models['pages']
283      * ->blueprint($site_id = 1)
284      * ->subset(null, null, function(BlueprintNode $node) {
285      *
286      *     return !$node->is_online;
287      *
288      * });
289      * </pre>
290      *
291      * @param int $nid Identifier of the starting branch.
292      * @param int $depth Maximum depth of the subset.
293      * @param callable $filter The filter callback.
294      *
295      * @return Blueprint
296      */
297     public function subset($nid=null, $depth=null, $filter=null)
298     {
299         $relation = array();
300         $children = array();
301         $index = array();
302 
303         $iterator = function(array $branch) use(&$iterator, &$filter, &$depth, &$relation, &$children, &$index)
304         {
305             $pages = array();
306 
307             foreach ($branch as $nid => $node)
308             {
309                 $node_children = $node->children;
310                 $node = clone $node;
311                 $node->children = array();
312 
313                 if ($node_children && ($depth === null || $node->depth < $depth))
314                 {
315                     $node->children = $iterator($node_children);
316                 }
317 
318                 if ($filter && $filter($node))
319                 {
320                     continue;
321                 }
322 
323                 $parentid = $node->parentid;
324 
325                 $relation[$nid] = $parentid;
326                 $children[$parentid][] = $nid;
327                 $pages[$nid] = $node;
328                 $index[$nid] = $node;
329             }
330 
331             return $pages;
332         };
333 
334         $tree = $iterator($nid ? $this->index[$nid]->children : $this->tree);
335 
336         return new static($this->model, $relation, $children, $index, $tree);
337     }
338 
339     /**
340      * Populates the blueprint by loading the associated records.
341      *
342      * The method adds the `record` property to the blueprint nodes.
343      *
344      * @return array[int]\Icybee\Modules\Pages\Page
345      */
346     public function populate()
347     {
348         if (!$this->index)
349         {
350             return array();
351         }
352 
353         $records = $this->model->find(array_keys($this->index));
354 
355         foreach ($records as $nid => $record)
356         {
357             $this->index[$nid]->record = $record;
358         }
359 
360         return $records;
361     }
362 }
363 
364 /**
365  * A node of the blueprint.
366  *
367  * @property-read int $children_count The number of children.
368  * @property-read array[int]ActiveRecord $descendents The descendents ordered according to their
369  * position and relation.
370  * @property-read int $descendents_count The number of descendents.
371  *
372  * @see Blueprint
373  */
374 class BlueprintNode
375 {
376     /**
377      * The identifier of the page.
378      *
379      * @var int
380      */
381     public $nid;
382 
383     /**
384      * Depth of the node is the tree.
385      *
386      * @var int
387      */
388     public $depth;
389 
390     /**
391      * The identifier of the parent of the page.
392      *
393      * @var int
394      */
395     public $parentid;
396 
397     /**
398      * Blueprint node of the parent of the page.
399      *
400      * @var BlueprintNode
401      */
402     public $parent;
403 
404     /**
405      * The children of the node.
406      *
407      * @var array[int]BlueprintNode
408      */
409     public $children;
410 
411     /**
412      * Inaccessible properties are obtained from the record.
413      *
414      * @param string $property
415      */
416     public function __get($property)
417     {
418         switch ($property)
419         {
420             case 'children_count': return count($this->children);
421             case 'descendents': return $this->get_descendents();
422             case 'descendents_count': return $this->get_descendents_count();
423         }
424 
425         return $this->record->$property;
426     }
427 
428     /**
429      * Return the descendent nodes of the node.
430      *
431      * @return int
432      */
433     protected function get_descendents()
434     {
435         $descendents = array();
436 
437         foreach ($this->children as $nid => $child)
438         {
439             $descendents[$nid] = $child;
440             $descendents += $child->descendents;
441         }
442 
443         return $descendents;
444     }
445 
446     /**
447      * Return the number of descendents.
448      *
449      * @return int
450      */
451     protected function get_descendents_count()
452     {
453         $n = 0;
454 
455         foreach ($this->children as $child)
456         {
457             $n += 1 + $child->descendents_count;
458         }
459 
460         return $n;
461     }
462 
463     /**
464      * Forwards calls to the record.
465      *
466      * @param string $method
467      * @param array $arguments
468      *
469      * @return mixed
470      */
471     public function __call($method, $arguments)
472     {
473         return call_user_func_array($this->record, $method, $arguments);
474     }
475 }
Autodoc API documentation generated by ApiGen 2.8.0