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;
 15 use ICanBoogie\Event;
 16 use ICanBoogie\FileCache;
 17 use ICanBoogie\HTTP\Dispatcher;
 18 use ICanBoogie\HTTP\Request;
 19 use ICanBoogie\HTTP\Response;
 20 
 21 use Brickrouge\Element;
 22 
 23 use Icybee\Modules\Files\File;
 24 use Icybee\Modules\Sites\Site;
 25 
 26 class Hooks
 27 {
 28     /**
 29      * Adds the `pages` dispatcher, which serves pages managed by the module.
 30      *
 31      * @param Dispatcher\AlterEvent $event
 32      * @param Dispatcher $target
 33      */
 34     static public function on_http_dispatcher_alter(Dispatcher\AlterEvent $event, Dispatcher $target)
 35     {
 36         // TODO-20130812: This should be either moved to a Dispatcher class, or used as an event hook
 37         // to the Routing dispatcher.
 38         $target['pages'] = function(Request $request)
 39         {
 40             global $core; // used in user-startup.php
 41 
 42             require_once \ICanBoogie\DOCUMENT_ROOT . 'user-startup.php';
 43 
 44             $controller = new PageController();
 45             $response = $controller($request);
 46 
 47             if (!$response)
 48             {
 49                 return;
 50             }
 51 
 52             if (!($response instanceof Response))
 53             {
 54                 $response = new Response($response);
 55             }
 56 
 57             $response->cache_control = 'private, no-cache, no-store, must-revalidate';
 58 
 59             return $response;
 60         };
 61     }
 62 
 63     /**
 64      * The callback is called when the `Icybee\Modules\Files\File::move` event is triggered,
 65      * allowing us to update content to the changed path of resource.
 66      *
 67      * @param File\MoveEvent $event
 68      * @param File $target
 69      */
 70     static public function on_file_move(File\MoveEvent $event, File $target)
 71     {
 72         global $core;
 73 
 74         $core->models['pages/contents']->execute
 75         (
 76             'UPDATE {self} SET content = REPLACE(content, ?, ?)', array($event->from, $event->to)
 77         );
 78     }
 79 
 80     /**
 81      * The callback is called when the `Icybee\Modules\Pages\Page::move` event is triggered,
 82      * allowing us to update content to the changed url of the page.
 83      *
 84      * Note that *only* url within something that looks like a HTML attribute are updated, the
 85      * matching pattern is ~="<url>("|/)~
 86      *
 87      * @param Page\MoveEvent $event
 88      * @param Page $target
 89      */
 90     static public function on_page_move(Page\MoveEvent $event, Page $target)
 91     {
 92         global $core;
 93 
 94         try
 95         {
 96             $model = $core->models['pages/contents'];
 97         }
 98         catch (\Exception $e) { return; }
 99 
100         $old = $event->from;
101         $new = $event->to;
102 
103         if (!$old)
104         {
105             return;
106         }
107 
108         foreach ($model->where('content LIKE ?', '%' . $old . '%') as $record)
109         {
110             $content = $record->content;
111             $content = preg_replace('~=\"' . preg_quote($old, '~') . '(\"|\/)~', '="' . $new . '$1', $content);
112 
113             if ($content == $record->content)
114             {
115                 continue;
116             }
117 
118             $model->execute
119             (
120                 'UPDATE {self} SET content = ? WHERE pageid = ? AND contentid = ?', array
121                 (
122                     $content, $record->pageid, $record->contentid
123                 )
124             );
125         }
126     }
127 
128     /**
129      * An operation (save, delete, online, offline) has invalidated the cache, thus we have to
130      * reset it.
131      */
132     static public function invalidate_cache()
133     {
134         global $core;
135 
136         $cache = new FileCache
137         (
138             array
139             (
140                 FileCache::T_REPOSITORY => $core->config['repository.cache'] . '/pages'
141             )
142         );
143 
144         return $cache->clear();
145     }
146 
147     /**
148      * Returns the current page.
149      *
150      * This getter is a shortcut for the `request->context->page` property.
151      *
152      * @param \ICanBoogie\Core $core
153      *
154      * @return Page
155      */
156     static public function get_page(\ICanBoogie\Core $core)
157     {
158         return $core->request->context->page;
159     }
160 
161     /**
162      * Returns the home page of the target site.
163      *
164      * @param \Icybee\Modules\Sites\Site $site
165      *
166      * @return Page|null The home page of the target site or `null` if there is none.
167      */
168     static public function get_home(Site $site)
169     {
170         global $core;
171 
172         return $core->models['pages']->find_home($site->siteid);
173     }
174 
175     static public function before_document_render_title(\Icybee\Document\BeforeRenderTitleEvent $event)
176     {
177         global $core;
178 
179         $page = $core->request->context->page;
180 
181         $event->separator = ' − ';
182         $event->title = $page->title . $event->separator . $page->site->title;
183     }
184 
185     /*
186      * Markups
187      */
188 
189     static public function markup_page_region(array $args, \Patron\Engine $patron, $template)
190     {
191         global $core;
192 
193         $id = $args['id'];
194         $page = $core->request->context->page;
195         $element = new Element('div', array('id' => $id, 'class' => "region region-$id"));
196         $html = null;
197 
198         new Page\RenderRegionEvent
199         (
200             $page, array
201             (
202                 'id' => $id,
203                 'page' => $page,
204                 'element' => $element,
205                 'html' => &$html
206             )
207         );
208 
209         if (!$html)
210         {
211             return;
212         }
213 
214         $element[Element::INNER_HTML] = $html;
215 
216         return $element;
217     }
218 
219     static public function markup_page_title(array $args, $engine, $template)
220     {
221         global $core;
222 
223         $page = $core->request->context->page;
224         $title = $page->title;
225         $html = \ICanBoogie\escape($title);
226 
227         new Page\RenderTitleEvent($page, array('title' => $title, 'html' => &$html));
228 
229         return $template ? $engine($template, $html) : $html;
230     }
231 
232     /**
233      * Defines an editable page content in a template.
234      *
235      * <pre>
236      * <p:page:content
237      *     id = qname
238      *     title = string
239      *     editor = string
240      *     inherit = boolean>
241      *     <!-- Content: with-param*, template? -->
242      * </p:page:content>
243      * </pre>
244      *
245      * The `id` attribute specifies the identifier of the content, it is required and must be
246      * unique in the template. The `title` attribute specifies the label of the editor in the
247      * page editor, it is required. The `editor` attribute specifies the editor to use to edit
248      * the content, it is optional. The `inherit` attribute specifies that the content can be
249      * inherited.
250      *
251      * Example:
252      *
253      * <pre>
254      * <p:page:content id="body" title="Page body" />
255      *
256      * <p:page:content id="picture" title="Decorating picture" editor="image" inherit="inherit">
257      * <img src="#{@path}" alt="#{@alt}" />
258      * </p>
259      *
260      * </pre>
261      *
262      * @param array $args
263      * @param \Patron\Engine $patron
264      * @param mixed $template
265      *
266      * @return mixed
267      */
268     static public function markup_page_content(array $args, \Patron\Engine $patron, $template)
269     {
270         global $core;
271 
272         $render = $args['render'];
273 
274         if ($render === 'none')
275         {
276             return;
277         }
278 
279         $page = $core->request->context->page;
280         $contentid = $args['id'];
281         $contents = array_key_exists($contentid, $page->contents) ? $page->contents[$contentid] : null;
282 
283         if (!$contents && !empty($args['inherit']))
284         {
285             $node = $page->parent;
286 
287             while ($node)
288             {
289                 $node_contents = $node->contents;
290 
291                 if (empty($node_contents[$contentid]))
292                 {
293                     $node = $node->parent;
294 
295                     continue;
296                 }
297 
298                 $contents = $node_contents[$contentid];
299 
300                 break;
301             }
302 
303             #
304             # maybe the home page define the contents, but because the home page is not the parent
305             # of pages on single language sites, we have to check it now.
306             #
307 
308             if (!$contents)
309             {
310                 $node_contents = $page->home->contents;
311 
312                 if (isset($node_contents[$contentid]))
313                 {
314                     $contents = $node_contents[$contentid];
315                 }
316             }
317         }
318 
319         $editor = null;
320         $rendered = null;
321 
322         if (is_string($contents))
323         {
324             $rendered = $contents;
325         }
326         else if ($contents)
327         {
328             $editor = $contents->editor;
329             $rendered = $contents->render();
330         }
331 
332         if (!$rendered)
333         {
334             return;
335         }
336 
337         $element = new Element('div', [
338 
339             'id' => 'content-' . $contentid,
340             'class' => 'editor-' . \ICanBoogie\normalize($editor)
341 
342         ]);
343 
344         $patron->context['self']['element'] = $element;
345 
346         $rc = $template ? $patron($template, $rendered) : $rendered;
347 
348         if (!$rc)
349         {
350             return;
351         }
352 
353         if (preg_match('#\.html$#', $page->template) && empty($args['no-wrapper']))
354         {
355             $element[Element::INNER_HTML] = $rc;
356             $rc = $element;
357         }
358 
359         $rc = self::handle_external_anchors($rc);
360 
361         return $rc;
362     }
363 
364     /**
365      * Adds a blank target to external href.
366      *
367      * @param string $html
368      */
369     static protected function handle_external_anchors($html)
370     {
371         return preg_replace_callback
372         (
373             '#<a\s+[^>]+>#', function($matches)
374             {
375                 $str = array_shift($matches);
376 
377                 preg_match_all('#([a-zA-Z0-9\-]+)\="([^"]+)#', $str, $matches, 0, PREG_SET_ORDER);
378 
379                 if (empty($matches[1]))
380                 {
381                     return $str;
382                 }
383 
384                 $attributes = array_combine($matches[1], $matches[2]);
385 
386                 if (isset($attributes['href']))
387                 {
388                     if (preg_match('#^http(s)?://#', $attributes['href']))
389                     {
390                         $attributes['target'] = '_blank';
391                     }
392                 }
393 
394                 $str = '<a';
395 
396                 foreach ($attributes as $attribute => $value)
397                 {
398                     $str .= ' ' . $attribute . '="' . $value . '"';
399                 }
400 
401                 $str .= '>';
402 
403                 return $str;
404             },
405 
406             $html
407         );
408     }
409 }
410 
411 namespace Icybee\Modules\Pages\Page;
412 
413 use Icybee\Modules\Pages\Page;
414 
415 class RenderTitleEvent extends \ICanBoogie\Event
416 {
417     /**
418      * Title of the page.
419      *
420      * @var string
421      */
422     public $title;
423 
424     /**
425      * Reference to the rendered title of the page.
426      *
427      * @var string
428      */
429     public $html;
430 
431     /**
432      * The event is constructed with the type `render_title`.
433      *
434      * @param Page $target
435      * @param array $payload
436      */
437     public function __construct(Page $target, array $payload)
438     {
439         parent::__construct($target, 'render_title', $payload);
440     }
441 }
442 
443 class RenderRegionEvent extends \ICanBoogie\Event
444 {
445     /**
446      * Identifier of the region.
447      *
448      * @var string
449      */
450     public $id;
451 
452     /**
453      * Page where the region is rendered.
454      *
455      * @var Page
456      */
457     public $page;
458 
459     /**
460      * The region element.
461      *
462      * @var Element
463      */
464     public $element;
465 
466     /**
467      * Reference to the rendered HTML of the region.
468      *
469      * @var string
470      */
471     public $html;
472 
473     /**
474      * The event is constructed with the type `render_region`.
475      *
476      * @param Page $target
477      * @param array $payload
478      */
479     public function __construct(Page $target, array $payload)
480     {
481         parent::__construct($target, 'render_region', $payload);
482     }
483 }
Autodoc API documentation generated by ApiGen 2.8.0