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

  • ActiveRecord
  • Cache
  • Configs
  • Core
  • DateTime
  • Debug
  • DeleteOperation
  • Errors
  • Event
  • EventHook
  • Events
  • FileCache
  • FormattedString
  • Helpers
  • I18n
  • Image
  • Inflections
  • Inflector
  • Models
  • Module
  • Modules
  • Object
  • Operation
  • PingOperation
  • Prototype
  • Route
  • Routes
  • SaveOperation
  • Session
  • TimeZone
  • TimeZoneLocation
  • Uploaded
  • Vars
  • VarsIterator

Interfaces

  • StorageInterface
  • ToArray
  • ToArrayRecursive

Traits

  • PrototypeTrait
  • ToArrayRecursiveTrait

Exceptions

  • AlreadyAuthenticated
  • AuthenticationRequired
  • Exception
  • ModuleConstructorMissing
  • ModuleIsDisabled
  • ModuleNotDefined
  • OffsetError
  • OffsetNotDefined
  • OffsetNotReadable
  • OffsetNotWritable
  • PermissionRequired
  • PropertyError
  • PropertyIsReserved
  • PropertyNotDefined
  • PropertyNotReadable
  • PropertyNotWritable
  • RouteNotDefined
  • SecurityException

Constants

  • TOKEN_ALPHA
  • TOKEN_ALPHA_UPCASE
  • TOKEN_NUMERIC
  • TOKEN_SYMBOL
  • TOKEN_SYMBOL_WIDE

Functions

  • array_flatten
  • array_insert
  • array_merge_recursive
  • camelize
  • capitalize
  • downcase
  • dump
  • escape
  • escape_all
  • exact_array_merge_recursive
  • excerpt
  • format
  • generate_token
  • generate_token_wide
  • generate_v4_uuid
  • get_autoconfig
  • humanize
  • hyphenate
  • log
  • log_error
  • log_info
  • log_success
  • log_time
  • normalize
  • normalize_namespace_part
  • normalize_url_path
  • pbkdf2
  • pluralize
  • remove_accents
  • shorten
  • singularize
  • sort_by_weight
  • stable_sort
  • strip_root
  • titleize
  • unaccent_compare
  • unaccent_compare_ci
  • underscore
  • upcase
  1 <?php
  2 
  3 /*
  4  * This file is part of the ICanBoogie 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 ICanBoogie;
 13 
 14 use ICanBoogie\ActiveRecord\Connection;
 15 use ICanBoogie\ActiveRecord\Model;
 16 use ICanBoogie\ActiveRecord\ModelNotDefined;
 17 use ICanBoogie\I18n;
 18 
 19 /**
 20  * A module of the framework.
 21  *
 22  * @property-read array $description The description of the module.
 23  * @property-read string $flat_id Underscored identifier.
 24  * @property-read string $id The identifier of the module, defined by {@link T_ID}.
 25  * @property-read Model $model The primary model of the module.
 26  * @property-read Module $parent The parent module, defined by {@link T_EXTENDS}.
 27  * @property-read string $path The path to the module, defined by {@link T_PATH}.
 28  * @property-read string $title The localized title of the module.
 29  */
 30 class Module extends Object
 31 {
 32     /**
 33      * Defines the category for the module.
 34      *
 35      * When modules are listed they are usually grouped by category. The category is also often
 36      * used to create the main navigation menu of the admin interface.
 37      *
 38      * The category of the module is translated within the `module_category` scope.
 39      *
 40      * @var string
 41      */
 42     const T_CATEGORY = 'category';
 43 
 44     /**
 45      * Defines the PHP class of the module.
 46      *
 47      * If the class is not defined it is resolved during indexing using the {@link T_NAMESPACE}
 48      * tag and the following pattern : `<namespace>\Module`.
 49      *
 50      * @var string
 51      */
 52     const T_CLASS = 'class';
 53 
 54     /**
 55      * Defines a short description of what the module do.
 56      *
 57      * @var string
 58      */
 59     const T_DESCRIPTION = 'description';
 60 
 61     /**
 62      * Defines the state of the module.
 63      *
 64      * @var bool
 65      */
 66     const T_DISABLED = 'disabled';
 67 
 68     /**
 69      * Defines the module that the module extends.
 70      *
 71      * @var string|\ICanBoogie\Module
 72      */
 73     const T_EXTENDS = 'extends';
 74 
 75     /**
 76      * Defines the identifier of the module.
 77      *
 78      * If the identifier is not defined the name of the module directory is used instead.
 79      *
 80      * @var string
 81      */
 82     const T_ID = 'id';
 83 
 84     /**
 85      * Defines the state of the module.
 86      *
 87      * Required modules are always enabled.
 88      *
 89      * @var bool
 90      */
 91     const T_REQUIRED = 'required';
 92 
 93     /**
 94      * Defines the modules that the module requires.
 95      *
 96      * The required modules are defined using an array where each key/value pair is the identifier
 97      * of the module and the minimum version required.
 98      *
 99      * @var array[string]string
100      */
101     const T_REQUIRES = 'requires';
102 
103     /**
104      * Defines the models of the module.
105      *
106      * @var array[string]array|string
107      */
108     const T_MODELS = 'models';
109 
110     /**
111      * Defines the namespace of the module.
112      *
113      * This attribute must be defined at construct time.
114      *
115      * @var string
116      */
117     const T_NAMESPACE = 'namespace';
118 
119     /**
120      * Path to the module's directory.
121      *
122      * This tag is resolved when the module is indexed.
123      *
124      * @var string
125      */
126     const T_PATH = 'path';
127 
128     /**
129      * General permission of the module.
130      *
131      * @var string|int
132      */
133     const T_PERMISSION = 'permission';
134 
135     /**
136      * Defines the permissions added by the module.
137      *
138      * @var array[]string
139      */
140     const T_PERMISSIONS = 'permissions';
141 
142     /**
143      * Defines the title of the module.
144      *
145      * The title of the module is translated within the `module_title` scope.
146      *
147      * @var string
148      */
149     const T_TITLE = 'title';
150 
151     /**
152      * Defines the version (and revision) of the module.
153      *
154      * @var string
155      */
156     const T_VERSION = 'version';
157 
158     /**
159      * Defines the weight of the module.
160      *
161      * The weight of the module is resolved during modules indexing according to the
162      * {@link T_EXTENDS} and {@link T_REQUIRES} tags.
163      *
164      * @var int
165      */
166     const T_WEIGHT = 'weight';
167 
168     /*
169      * PERMISSIONS:
170      *
171      * NONE: Well, you can't do anything
172      *
173      * ACCESS: You can access the module and view its records
174      *
175      * CREATE: You can create new records
176      *
177      * MAINTAIN: You can edit the records you created
178      *
179      * MANAGE: You can delete the records you created
180      *
181      * ADMINISTER: You have complete control over the module
182      *
183      */
184     const PERMISSION_NONE = 0;
185     const PERMISSION_ACCESS = 1;
186     const PERMISSION_CREATE = 2;
187     const PERMISSION_MAINTAIN = 3;
188     const PERMISSION_MANAGE = 4;
189     const PERMISSION_ADMINISTER = 5;
190 
191     /**
192      * Defines the name of the operation used to save the records of the module.
193      *
194      * @var string
195      */
196     const OPERATION_SAVE = 'save';
197 
198     /**
199      * Defines the name of the operation used to delete the records of the module.
200      *
201      * @var string
202      */
203     const OPERATION_DELETE = 'delete';
204 
205     /**
206      * Returns the identifier of the module as defined by its descriptor.
207      *
208      * This method is the getter for the {@link $id} magic property.
209      *
210      * @return string
211      */
212     protected function get_id()
213     {
214         return $this->descriptor[self::T_ID];
215     }
216 
217     /**
218      * Returns the path of the module as defined by its descriptor.
219      *
220      * This method is the getter for the {@link $path} magic property.
221      *
222      * @return string
223      */
224     protected function get_path()
225     {
226         return $this->descriptor[self::T_PATH];
227     }
228 
229     /**
230      * The descriptor of the module.
231      *
232      * @var array[string]mixed
233      */
234     protected $descriptor;
235 
236     /**
237      * Returns the descriptor of the module.
238      *
239      * This method is the getter for the {@link $descriptor} magic property.
240      *
241      * @return array[string]mixed
242      */
243     protected function get_descriptor()
244     {
245         return $this->descriptor;
246     }
247 
248     /**
249      * Constructor.
250      *
251      * Initializes the {@link $descriptor} property.
252      *
253      * @param array $descriptor
254      */
255     public function __construct(array $descriptor)
256     {
257         $this->descriptor = $descriptor;
258     }
259 
260     /**
261      * Returns the identifier of the module.
262      *
263      * @return string
264      */
265     public function __toString()
266     {
267         return $this->id;
268     }
269 
270     /**
271      * Returns the _flat_ version of the module's identifier.
272      *
273      * This method is the getter for the {@link $flat_id} magic property.
274      *
275      * @return string
276      */
277     protected function get_flat_id()
278     {
279         return strtr($this->id, [
280 
281             '.' => '_',
282             '-' => '_'
283 
284         ]);
285     }
286 
287     /**
288      * Returns the primary model of the module.
289      *
290      * This is the getter for the {@link $model} magic property.
291      *
292      * @return ActiveRecord\Model
293      */
294     protected function get_model()
295     {
296         return $this->model();
297     }
298 
299     /**
300      * Returns the module title, translated to the current language.
301      *
302      * @return string
303      */
304     protected function get_title()
305     {
306         $default = isset($this->descriptor[self::T_TITLE]) ? $this->descriptor[self::T_TITLE] : 'Undefined';
307 
308         return I18n\t($this->flat_id, [], [ 'scope' => 'module_title', 'default' => $default ]);
309     }
310 
311     /**
312      * Returns the parent module.
313      *
314      * @return Module|null
315      */
316     protected function get_parent()
317     {
318         global $core;
319 
320         $extends = $this->descriptor[self::T_EXTENDS];
321 
322         return $extends ? ($extends instanceof self ? $extends : $core->modules[$extends]) : null;
323     }
324 
325     /**
326      * Checks if the module is installed.
327      *
328      * @param Errors $errors Error collection.
329      *
330      * @return mixed `true` if the module is installed, `false` if the module
331      * (or parts of) is not installed, `null` if the module has no installation.
332      */
333     public function is_installed(Errors $errors)
334     {
335         if (empty($this->descriptor[self::T_MODELS]))
336         {
337             return null;
338         }
339 
340         $rc = true;
341 
342         foreach ($this->descriptor[self::T_MODELS] as $name => $tags)
343         {
344             if (!$this->model($name)->is_installed())
345             {
346                 $rc = false;
347             }
348         }
349 
350         return $rc;
351     }
352 
353     /**
354      * Install the module.
355      *
356      * If the module has models they are installed.
357      *
358      * @param Errors $errors Error collection.
359      *
360      * @return boolean|null true if the module has successfully been installed, false if the
361      * module (or parts of the module) fails to install or null if the module has
362      * no installation process.
363      */
364     public function install(Errors $errors)
365     {
366         if (empty($this->descriptor[self::T_MODELS]))
367         {
368             return null;
369         }
370 
371         $rc = true;
372 
373         foreach ($this->descriptor[self::T_MODELS] as $name => $tags)
374         {
375             $model = $this->model($name);
376 
377             if ($model->is_installed())
378             {
379                 continue;
380             }
381 
382             if (!$model->install())
383             {
384                 $errors[$this->id] = t('Unable to install model %model', [ '%model' => $name ]);
385 
386                 $rc = false;
387             }
388         }
389 
390         return $rc;
391     }
392 
393     /**
394      * Uninstall the module.
395      *
396      * Basically it uninstall the models installed by the module.
397      *
398      * @return boolean|null `true` if the module was successfully uninstalled. `false` if the module
399      * (or parts of the module) failed to uninstall. `null` if there is no uninstall process.
400      */
401     public function uninstall()
402     {
403         if (empty($this->descriptor[self::T_MODELS]))
404         {
405             return;
406         }
407 
408         $rc = true;
409 
410         foreach ($this->descriptor[self::T_MODELS] as $name => $tags)
411         {
412             $model = $this->model($name);
413 
414             if (!$model->is_installed())
415             {
416                 continue;
417             }
418 
419             if (!$model->uninstall())
420             {
421                 $rc = false;
422             }
423         }
424 
425         return $rc;
426     }
427 
428     /**
429      * Cache for loaded models.
430      *
431      * @var array[string]ActiveRecord\Model
432      */
433     protected $models = [];
434 
435     /**
436      * Get a model from the module.
437      *
438      * If the model has not been created yet, it is created on the fly.
439      *
440      * @param string $which The identifier of the model to get.
441      *
442      * @return Model The requested model.
443      *
444      * @throws Exception if the model does not exists.
445      */
446     public function model($which='primary')
447     {
448         if (empty($this->models[$which]))
449         {
450             if (empty($this->descriptor[self::T_MODELS][$which]))
451             {
452                 throw new ModelNotDefined($which);
453             }
454 
455             #
456             # resolve model tags
457             #
458 
459             $callback = "resolve_{$which}_model_tags";
460 
461             if (!method_exists($this, $callback))
462             {
463                 $callback = 'resolve_model_tags';
464             }
465 
466             $attributes = $this->$callback($this->descriptor[self::T_MODELS][$which], $which);
467 
468             #
469             # COMPAT WITH 'inherit'
470             #
471 
472             if ($attributes instanceof Model)
473             {
474                 $this->models[$which] = $attributes;
475 
476                 return $attributes;
477             }
478 
479             #
480             # create model
481             #
482 
483             $class = $attributes[Model::T_CLASS];
484 
485             $this->models[$which] = new $class($attributes);
486         }
487 
488         #
489         # return cached model
490         #
491 
492         return $this->models[$which];
493     }
494 
495     protected function resolve_model_tags($tags, $which)
496     {
497         global $core;
498 
499         #
500         # The model may use another model, in which case the model to use is defined using a
501         # string e.g. 'contents' or 'terms/nodes'
502         #
503 
504         if (is_string($tags))
505         {
506             $model_name = $tags;
507 
508             if ($model_name == 'inherit')
509             {
510                 $class = get_parent_class($this);
511 
512                 foreach ($core->modules->descriptors as $module_id => $descriptor)
513                 {
514                     if ($class != $descriptor['class'])
515                     {
516                         continue;
517                     }
518 
519                     $model_name = $core->models[$module_id];
520 
521                     break;
522                 }
523             }
524 
525             $tags = [ Model::T_EXTENDS => $model_name ];
526         }
527 
528         #
529         # defaults
530         #
531 
532         $id = $this->id;
533 
534         $tags += [
535 
536             Model::CONNECTION => 'primary',
537             Model::ID => $which == 'primary' ? $id : $id . '/' . $which
538 
539         ];
540 
541         if (empty($tags[Model::NAME]))
542         {
543             $tags[Model::NAME] = Modules::format_model_name($id, $which);
544         }
545 
546         #
547         # relations
548         #
549 
550         if (isset($tags[Model::T_EXTENDS]))
551         {
552             $extends = &$tags[Model::T_EXTENDS];
553 
554             if (is_string($extends))
555             {
556                 $extends = $core->models[$extends];
557             }
558 
559             if (!$tags[Model::T_CLASS])
560             {
561                 $tags[Model::T_CLASS] = get_class($extends);
562             }
563         }
564 
565         #
566         #
567         #
568 
569         if (isset($tags[Model::T_IMPLEMENTS]))
570         {
571             $implements =& $tags[Model::T_IMPLEMENTS];
572 
573             foreach ($implements as &$implement)
574             {
575                 if (isset($implement['model']))
576                 {
577                     list($implement_id, $implement_which) = explode('/', $implement['model']) + [ 1 => 'primary' ];
578 
579                     if ($id == $implement_id && $which == $implement_which)
580                     {
581                         throw new Exception('Model %module/%model implements itself !', [ '%module' => $id, '%model' => $which ]);
582                     }
583 
584                     $module = ($implement_id == $id) ? $this : $core->modules[$implement_id];
585 
586                     $implement['table'] = $module->model($implement_which);
587                 }
588                 else if (is_string($implement['table']))
589                 {
590                     throw new Exception('Model %model of module %module implements a table: %table', [
591 
592                         '%model' => $which,
593                         '%module' => $id,
594                         '%table' => $implement['table']
595 
596                     ]);
597 
598                     $implement['table'] = $models[$implement['table']];
599                 }
600             }
601         }
602 
603         #
604         # default class, if none was defined.
605         #
606 
607         if (empty($tags[Model::CLASSNAME]))
608         {
609             $tags[Model::CLASSNAME] = 'ICanBoogie\ActiveRecord\Model';
610         }
611 
612         #
613         # connection
614         #
615 
616         $connection = $tags[Model::CONNECTION];
617 
618         if (!($connection instanceof Connection))
619         {
620             $tags[Model::CONNECTION] = $core->connections[$connection];
621         }
622 
623         return $tags;
624     }
625 
626     /**
627      * Get a block.
628      *
629      * @param string $name The name of the block to get.
630      *
631      * @return mixed Depends on the implementation. Should return a string or object that can be stringified.
632      *
633      * @throws Exception if the block is not defined.
634      */
635     public function getBlock($name)
636     {
637         $args = func_get_args();
638 
639         array_shift($args);
640 
641         $method_name = 'handle_block_' . $name;
642 
643         if (method_exists($this, $method_name))
644         {
645             array_shift($args);
646 
647             return call_user_func_array([ $this, $method_name ], $args);
648         }
649 
650         $callback = 'block_' . $name;
651 
652         if (!method_exists($this, $callback))
653         {
654             throw new Exception('The %method method is missing from the %module module to create block %type.', [
655 
656                 '%method' => $callback,
657                 '%module' => $this->id,
658                 '%type' => $name
659 
660             ]);
661         }
662 
663         return call_user_func_array([ $this, $callback ], $args);
664     }
665 }
Autodoc API documentation generated by ApiGen 2.8.0