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

  • BeforeRenderEvent
  • RenderEvent
  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\AuthenticationRequired;
 15 use ICanBoogie\Exception;
 16 use ICanBoogie\HTTP\NotFound;
 17 use ICanBoogie\HTTP\RedirectResponse;
 18 use ICanBoogie\HTTP\Request;
 19 use ICanBoogie\HTTP\Response;
 20 use ICanBoogie\HTTP\ServiceUnavailable;
 21 use ICanBoogie\I18n;
 22 use ICanBoogie\Routing\Pattern;
 23 
 24 use Icybee\Modules\Sites\Site;
 25 
 26 define(__NAMESPACE__ . '\PageController\CSS_DOCUMENT_PLACEHOLDER', uniqid());
 27 define(__NAMESPACE__ . '\PageController\JS_DOCUMENT_PLACEHOLDER', uniqid());
 28 
 29 class PageController
 30 {
 31     const DOCUMENT_JS_PLACEHOLDER = '<!-- $document.js -->';
 32 
 33     public function __invoke(Request $request)
 34     {
 35         global $core;
 36 
 37         try
 38         {
 39             $request->context->page = $page = $this->resolve_page($request);
 40 
 41             if (!$page)
 42             {
 43                 return;
 44             }
 45 
 46             if ($page instanceof Response)
 47             {
 48                 return $page;
 49             }
 50 
 51             return $this->resolve_response($page, $request);
 52         }
 53         catch (\Exception $e) // TODO-20130812: This shouldn't be handled by the class, but by Icybee or the user.
 54         {
 55             $code = $e->getCode();
 56             $pathname = \ICanBoogie\DOCUMENT_ROOT . "protected/all/templates/$code.html";
 57 
 58             if (file_exists($pathname))
 59             {
 60                 $request->context->page = $page = Page::from([
 61 
 62                     'siteid' => $core->site_id,
 63                     'title' => I18n\t($e->getCode(), [], [ 'scope' => 'exception' ]),
 64                     'body' => I18n\t($e->getMessage(), [], [ 'scope' => 'exception' ])
 65 
 66                 ]);
 67 
 68                 $template = file_get_contents($pathname);
 69                 $engine = $this->resolve_engine($template);
 70 
 71                 return new Response($engine($template, $page), $code);
 72             }
 73 
 74             throw $e;
 75         }
 76     }
 77 
 78     /**
 79      * Resolve the specified Page and Request into a Response.
 80      *
 81      * @param Page $page
 82      * @param Request $request
 83      *
 84      * @return \ICanBoogie\HTTP\Response
 85      */
 86     protected function resolve_response(Page $page, Request $request)
 87     {
 88         global $core;
 89 
 90         $template = $this->resolve_template($page->template);
 91         $document = $core->document;
 92         $engine = $this->resolve_engine($template);
 93         $engine->context['page'] = $page;
 94         $engine->context['document'] = $document;
 95 
 96         new PageController\BeforeRenderEvent($this, $request, $page, $engine->context);
 97 
 98         #
 99         # The page body is rendered before the template is parsed.
100         #
101 
102         if ($page->body && is_callable(array($page->body, 'render')))
103         {
104             $page->body->render();
105         }
106 
107         $html = $engine($template, $page, [ 'file' => $page->template ]);
108 
109         new PageController\RenderEvent($this, $request, $page, $html);
110 
111         #
112         # late replace
113         #
114 
115         $pos = strpos($html, self::DOCUMENT_JS_PLACEHOLDER);
116 
117         if ($pos !== false)
118         {
119             $html = substr($html, 0, $pos)
120             . $document->js
121             . substr($html, $pos + strlen(self::DOCUMENT_JS_PLACEHOLDER));
122         }
123         else
124         {
125             $html = str_replace('</body>', PHP_EOL . PHP_EOL . $document->js . PHP_EOL . '</body>', $html);
126         }
127 
128         return new Response($html, 200, [
129 
130             'Content-Type' => 'text/html; charset=utf-8'
131 
132         ]);
133     }
134 
135     /**
136      * Resolves a request into a page.
137      *
138      * @param Request $request
139      *
140      * @return Page|Response
141      */
142     protected function resolve_page(Request $request)
143     {
144         global $core;
145 
146         /* TODO-20130812: Move the following code section in the Sites module. */
147 
148         $site = $request->context->site;
149 
150         if (!$site->siteid)
151         {
152             throw new NotFound('Unable to find matching website.');
153         }
154 
155         $status = $site->status;
156 
157         switch ($status)
158         {
159             case Site::STATUS_UNAUTHORIZED: throw new AuthenticationRequired();
160             case Site::STATUS_NOT_FOUND: throw new NotFound
161             (
162                 \ICanBoogie\format("The requested URL does not exists: %uri", [
163 
164                     'uri' => $request->uri
165 
166                 ])
167             );
168 
169             case Site::STATUS_UNAVAILABLE: throw new ServiceUnavailable();
170         }
171 
172         /* /TODO */
173 
174         $path = $request->path;
175         $page = $core->models['pages']->find_by_path($request->path);
176 
177         if (!$page)
178         {
179             return;
180         }
181 
182         if ($page->location)
183         {
184             return new RedirectResponse($page->location->url, 301, [
185 
186                 'Icybee-Redirected-By' => __FILE__ . '::' . __LINE__
187 
188             ]);
189         }
190 
191         #
192         # We make sure that a normalized URL is used. For instance, "/fr" is redirected to
193         # "/fr/".
194         #
195 
196         $url_pattern = Pattern::from($page->url_pattern);
197 
198         if (!$url_pattern->params && $page->url != $path)
199         {
200             $query_string = $request->query_string;
201 
202             return new RedirectResponse($page->url . ($query_string ? '?' . $query_string : ''), 301, [
203 
204                 'Icybee-Redirected-By' => __FILE__ . '::' . __LINE__
205 
206             ]);
207         }
208 
209         if (!$page->is_online || $page->site->status != Site::STATUS_OK)
210         {
211             #
212             # Offline pages are displayed if the user has ownership, otherwise an HTTP exception
213             # with code 401 (Authentication) is thrown. We add the "✎" marker to the title of the
214             # page to indicate that the page is offline but displayed as a preview for the user.
215             #
216 
217             if (!$core->user->has_ownership('pages', $page))
218             {
219                 throw new AuthenticationRequired
220                 (
221                     \ICanBoogie\format('The requested URL %url requires authentication.', [
222 
223                         'url' => $path
224 
225                     ])
226                 );
227             }
228 
229             $page->title .= ' ✎';
230         }
231 
232         if (isset($page->url_variables))
233         {
234             $request->path_params = array_merge($request->path_params, $page->url_variables);
235             $request->params = array_merge($request->params, $page->url_variables);
236         }
237 
238         return $page;
239     }
240 
241     protected function resolve_template($name)
242     {
243         global $core;
244 
245         $root = \ICanBoogie\DOCUMENT_ROOT;
246         $pathname = $core->site->resolve_path('templates/' . $name);
247 
248         if (!$pathname)
249         {
250             throw new Exception('Unable to resolve path for template: %template', [ '%template' => $pathname ]);
251         }
252 
253         return file_get_contents($root . $pathname, true);
254     }
255 
256     protected function resolve_engine($template)
257     {
258         return new \Patron\Engine;
259     }
260 }
261 
262 namespace Icybee\Modules\Pages\PageController;
263 
264 use ICanBoogie\HTTP\Request;
265 
266 use Icybee\Modules\Pages\Page;
267 
268 /**
269  * Event class for the 'Icybee\Modules\Pages\PageController::render:before'.
270  */
271 class BeforeRenderEvent extends \ICanBoogie\Event
272 {
273     /**
274      * Request.
275      *
276      * @var \ICanBoogie\HTTP\Request
277      */
278     public $request;
279 
280     /**
281      * Response.
282      *
283      * @var \ICanBoogie\HTTP\Response
284      */
285     public $response;
286 
287     /**
288      * Rendering context.
289      *
290      * @var mixed
291      */
292     public $context;
293 
294     /**
295      * The event is constructed with the type `render:before`.
296      *
297      * @param \Icybee\Modules\Pages\PageController $target
298      * @param array $payload
299      */
300     public function __construct(\Icybee\Modules\Pages\PageController $target, Request $request, Page $page, &$context)
301     {
302         $this->request = $request;
303         $this->page = $page;
304         $this->context = &$context;
305 
306         parent::__construct($target, 'render:before');
307     }
308 }
309 
310 /**
311  * Event class for the `Icybee\Modules\Pages\PageController::render` event.
312  */
313 class RenderEvent extends \ICanBoogie\Event
314 {
315     /**
316      * The request.
317      *
318      * @var \ICanBoogie\HTTP\Request
319      */
320     public $request;
321 
322     /**
323      * The page being rendered.
324      *
325      * @var \Icybee\Modules\Pages\Page
326      */
327     public $page;
328 
329     /**
330      * The rendered HTML.
331      *
332      * @var string
333      */
334     public $html;
335 
336     /**
337      * The event is constructed with the type `render`.
338      *
339      * @param \Icybee\Modules\Pages\PageController $target
340      * @param array $payload
341      */
342     public function __construct(\Icybee\Modules\Pages\PageController $target, Request $request, Page $page, &$html)
343     {
344         $this->request = $request;
345         $this->page = $page;
346         $this->html = &$html;
347 
348         parent::__construct($target, 'render');
349     }
350 }
Autodoc API documentation generated by ApiGen 2.8.0