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 trait PrototypeTrait
 15 {
 16     private $prototype;
 17 
 18     /**
 19      * Returns the prototype associated with the class.
 20      *
 21      * @return Prototype
 22      */
 23     protected function get_prototype()
 24     {
 25         if (!$this->prototype)
 26         {
 27             $this->prototype = Prototype::from($this);
 28         }
 29 
 30         return $this->prototype;
 31     }
 32 
 33     /**
 34      * The method returns an array of key/key pairs.
 35      *
 36      * Properties for which a lazy getter is defined are discarted. For instance, if the property
 37      * `next` is defined and the class of the instance defines the getter `lazy_get_next()`, the
 38      * property is discarted.
 39      *
 40      * Note that façade properties are also included.
 41      *
 42      * Warning: The code used to export private properties seams to produce frameless exception on
 43      * session close. If you encounter this problem you might want to override the method. Don't
 44      * forget to remove the prototype property!
 45      *
 46      * @return array
 47      */
 48     public function __sleep()
 49     {
 50         $keys = array_keys(get_object_vars($this));
 51 
 52         if ($keys)
 53         {
 54             $keys = array_combine($keys, $keys);
 55 
 56             unset($keys['prototype']);
 57 
 58             foreach ($keys as $key)
 59             {
 60                 #
 61                 # we don't use {@link has_method()} because using prototype during session write
 62                 # seams to corrupt PHP (tested with PHP 5.3.3).
 63                 #
 64 
 65                 if (method_exists($this, 'lazy_get_' . $key))
 66                 {
 67                     unset($keys[$key]);
 68                 }
 69             }
 70         }
 71 
 72         foreach (Object::resolve_facade_properties($this) as $name => $property)
 73         {
 74             $keys[$name] = "\x00" . $property->class . "\x00" . $name;
 75         }
 76 
 77         return $keys;
 78     }
 79 
 80     /**
 81      * Unsets null properties for which a getter is defined so that it is called when the property
 82      * is accessed.
 83      */
 84     public function __wakeup()
 85     {
 86         $vars = get_object_vars($this);
 87 
 88         foreach ($vars as $key => $value)
 89         {
 90             if ($value !== null)
 91             {
 92                 continue;
 93             }
 94 
 95             if ($this->has_method('lazy_get_' . $key))
 96             {
 97                 unset($this->$key);
 98             }
 99         }
100     }
101 
102     /**
103      * If a property exists with the name specified by `$method` and holds an object which class
104      * implements `__invoke` then the object is called with the arguments. Otherwise, calls are
105      * forwarded to the {@link $prototype}.
106      *
107      * @param string $method
108      * @param array $arguments
109      *
110      * @return mixed
111      */
112     public function __call($method, $arguments)
113     {
114         if (isset($this->$method) && is_callable([ $this->$method, '__invoke' ]))
115         {
116             return call_user_func_array($this->$method, $arguments);
117         }
118 
119         array_unshift($arguments, $this);
120 
121         $prototype = $this->prototype ?: $this->get_prototype();
122 
123         return call_user_func_array($prototype[$method], $arguments);
124     }
125 
126     /**
127      * Returns the value of an inaccessible property.
128      *
129      * Multiple callbacks are tried in order to retrieve the value of the property:
130      *
131      * 1. `get_<property>`: Get and return the value of the property.
132      * 2. `lazy_get_<property>`: Get, set and return the value of the property. Because new
133      * properties are created as public the callback is only called once which is ideal for lazy
134      * loading.
135      * 3. The prototype is queried for callbacks for the `get_<property>` and
136      * `lazy_get_<property>` methods.
137      * 4. Finally, the `ICanBoogie\Object::property` event is fired to try and retrieve the value
138      * of the property.
139      *
140      * @param string $property
141      *
142      * @throws PropertyNotReadable when the property has a protected or private scope and
143      * no suitable callback could be found to retrieve its value.
144      *
145      * @throws PropertyNotDefined when the property is undefined and there is no suitable
146      * callback to retrieve its values.
147      *
148      * @return mixed The value of the inaccessible property.
149      */
150     public function __get($property)
151     {
152         $method = 'get_' . $property;
153 
154         if (method_exists($this, $method))
155         {
156             return $this->$method();
157         }
158 
159         $method = 'lazy_get_' . $property;
160 
161         if (method_exists($this, $method))
162         {
163             return $this->$property = $this->$method();
164         }
165 
166         #
167         # we didn't find a suitable method in the class, maybe the prototype has one.
168         #
169 
170         $prototype = $this->prototype ?: $this->get_prototype();
171 
172         $method = 'get_' . $property;
173 
174         if (isset($prototype[$method]))
175         {
176             return call_user_func($prototype[$method], $this, $property);
177         }
178 
179         $method  = 'lazy_get_' . $property;
180 
181         if (isset($prototype[$method]))
182         {
183             return $this->$property = call_user_func($prototype[$method], $this, $property);
184         }
185 
186         $success = false;
187         $value = $this->last_chance_get($property, $success);
188 
189         if ($success)
190         {
191             return $value;
192         }
193 
194         #
195         # We tried, but the property really is unaccessible.
196         #
197 
198         $reflexion_class = new \ReflectionClass($this);
199 
200         try
201         {
202             $reflexion_property = $reflexion_class->getProperty($property);
203 
204             if (!$reflexion_property->isPublic())
205             {
206                 throw new PropertyNotReadable([ $property, $this ]);
207             }
208         }
209         catch (\ReflectionException $e) { }
210 
211         if ($this->has_method('set_' . $property))
212         {
213             throw new PropertyNotReadable([ $property, $this ]);
214         }
215 
216         $properties = array_keys(get_object_vars($this));
217 
218         if ($properties)
219         {
220             throw new PropertyNotDefined(sprintf('Unknown or inaccessible property "%s" for object of class "%s" (available properties: %s).', $property, get_class($this), implode(', ', $properties)));
221         }
222 
223         throw new PropertyNotDefined([ $property, $this ]);
224     }
225 
226     /**
227      * Sets the value of an inaccessible property.
228      *
229      * The method is called because the property does not exists, it's visibility is
230      * "protected" or "private", or because although its visibility is "public" is was unset
231      * and is now inaccessible.
232      *
233      * The method only sets the property if it isn't defined by the class or its visibility is
234      * "public", but one can provide setters to override this behaviour:
235      *
236      * The `set_<property>` setter can be used to set properties that are protected or private,
237      * which can be used to make properties write-only for example.
238      *
239      * The `volatile_set_<property>` setter can be used the handle virtual properties e.g. a
240      * `minute` property that would alter a `second` property for example.
241      *
242      * The setters can be defined by the class or its prototype.
243      *
244      * Note: Permission is granted if a `lazy_get_<property>` getter is defined by the class or
245      * its prototype.
246      *
247      * @param string $property
248      * @param mixed $value
249      *
250      * @throws PropertyNotWritable if the property is not writable.
251      */
252     public function __set($property, $value)
253     {
254         $method = 'set_' . $property;
255 
256         if ($this->has_method($method))
257         {
258             return $this->$method($value);
259         }
260 
261         $method = 'lazy_set_' . $property;
262 
263         if ($this->has_method($method))
264         {
265             return $this->$property = $this->$method($value);
266         }
267 
268         $success = false;
269         $this->last_chance_set($property, $value, $success);
270 
271         if ($success)
272         {
273             return;
274         }
275 
276         #
277         # We tried, but the property really is unaccessible.
278         #
279 
280         if (property_exists($this, $property) && !$this->has_method('lazy_get_' . $property))
281         {
282             $reflection = new \ReflectionObject($this);
283             $property_reflection = $reflection->getProperty($property);
284 
285             if (!$property_reflection->isPublic())
286             {
287                 throw new PropertyNotWritable([ $property, $this ]);
288             }
289 
290             $this->$property = $value;
291 
292             return;
293         }
294 
295         if ($this->has_method('get_' . $property))
296         {
297             throw new PropertyNotWritable([ $property, $this ]);
298         }
299 
300         $this->$property = $value;
301     }
302 
303     /**
304      * Checks if the object has the specified property.
305      *
306      * The difference with the `property_exists()` function is that this method also checks for
307      * getters defined by the class or the prototype.
308      *
309      * @param string $property The property to check.
310      *
311      * @return bool true if the object has the property, false otherwise.
312      */
313     public function has_property($property)
314     {
315         if (property_exists($this, $property))
316         {
317             return true;
318         }
319 
320         if ($this->has_method('get_' . $property) || $this->has_method('lazy_get_' . $property))
321         {
322             return true;
323         }
324 
325         $success = false;
326         $this->last_chance_get($property, $success);
327 
328         return $success;
329     }
330 
331     /**
332      * Checks whether this object supports the specified method.
333      *
334      * The method checks for method defined by the class and the prototype.
335      *
336      * @param string $method Name of the method.
337      *
338      * @return bool
339      */
340     public function has_method($method)
341     {
342         if (method_exists($this, $method))
343         {
344             return true;
345         }
346 
347         $prototype = $this->prototype ?: $this->get_prototype();
348 
349         return isset($prototype[$method]);
350     }
351 
352     /**
353      * The method is invoked as a last chance to get a property,
354      * just before an exception is thrown.
355      *
356      * The method uses the helper {@link Prototype\last_chance_get()}.
357      *
358      * @param string $property Property to get.
359      * @param bool $success If the _last chance get_ was successful.
360      *
361      * @return mixed
362      */
363     protected function last_chance_get($property, &$success)
364     {
365         return Prototype\last_chance_get($this, $property, $success);
366     }
367 
368     /**
369      * The method is invoked as a last chance to set a property,
370      * just before an exception is thrown.
371      *
372      * The method uses the helper {@link Prototype\last_chance_set()}.
373      *
374      * @param string $property Property to set.
375      * @param mixed $value Value of the property.
376      * @param bool $success If the _last chance set_ was successful.
377      */
378     protected function last_chance_set($property, $value, &$success)
379     {
380         Prototype\last_chance_set($this, $property, $value, $success);
381     }
382 }
Autodoc API documentation generated by ApiGen 2.8.0