Hawk - PHP documentation
  • Namespace
  • Class
  • Tree

Namespaces

  • Hawk
    • View
      • Plugins

Classes

  • Hawk\App
  • Hawk\ButtonInput
  • Hawk\Cache
  • Hawk\CheckboxInput
  • Hawk\ColorInput
  • Hawk\Conf
  • Hawk\Controller
  • Hawk\Crypto
  • Hawk\DatabaseSessionHandler
  • Hawk\DatetimeInput
  • Hawk\DB
  • Hawk\DBExample
  • Hawk\DeleteInput
  • Hawk\Dialogbox
  • Hawk\EmailInput
  • Hawk\ErrorHandler
  • Hawk\Event
  • Hawk\FileInput
  • Hawk\FileSystem
  • Hawk\FloatInput
  • Hawk\Form
  • Hawk\FormFieldset
  • Hawk\FormInput
  • Hawk\GenericModel
  • Hawk\GifImage
  • Hawk\HawkApi
  • Hawk\HawkUpdater
  • Hawk\HiddenInput
  • Hawk\HtmlInput
  • Hawk\HTTPRequest
  • Hawk\Icon
  • Hawk\Image
  • Hawk\IntegerInput
  • Hawk\ItemList
  • Hawk\ItemListField
  • Hawk\JpegImage
  • Hawk\Lang
  • Hawk\Language
  • Hawk\LeftSidebarTab
  • Hawk\Less
  • Hawk\Logger
  • Hawk\Mail
  • Hawk\MenuItem
  • Hawk\Model
  • Hawk\NoSidebarTab
  • Hawk\NumberInput
  • Hawk\ObjectInput
  • Hawk\Option
  • Hawk\Panel
  • Hawk\PasswordInput
  • Hawk\Permission
  • Hawk\Plugin
  • Hawk\PluginInstaller
  • Hawk\PngImage
  • Hawk\ProfileQuestion
  • Hawk\ProfileQuestionValue
  • Hawk\RadioInput
  • Hawk\Request
  • Hawk\Response
  • Hawk\RightSidebarTab
  • Hawk\Role
  • Hawk\RolePermission
  • Hawk\Route
  • Hawk\Router
  • Hawk\SelectInput
  • Hawk\Session
  • Hawk\Singleton
  • Hawk\SubmitInput
  • Hawk\Tabs
  • Hawk\TextareaInput
  • Hawk\TextInput
  • Hawk\Theme
  • Hawk\TimeInput
  • Hawk\Upload
  • Hawk\User
  • Hawk\View
  • Hawk\View\Plugins\Accordion
  • Hawk\View\Plugins\Button
  • Hawk\View\Plugins\Form
  • Hawk\View\Plugins\Icon
  • Hawk\View\Plugins\Import
  • Hawk\View\Plugins\Panel
  • Hawk\View\Plugins\Tabs
  • Hawk\View\Plugins\Text
  • Hawk\View\Plugins\Uri
  • Hawk\View\Plugins\Widget
  • Hawk\ViewPlugin
  • Hawk\Widget
  • Hawk\WysiwygInput

Traits

  • Hawk\Utils

Exceptions

  • Hawk\AppStopException
  • Hawk\DBExampleException
  • Hawk\DBException
  • Hawk\FileSystemException
  • Hawk\HawkApiException
  • Hawk\ImageException
  • Hawk\MailException
  • Hawk\UploadException
  • Hawk\ViewException
  1 <?php
  2 /**
  3  * View.php
  4  *
  5  * @author  Elvyrra SAS
  6  * @license http://rem.mit-license.org/ MIT
  7  */
  8 
  9 namespace Hawk;
 10 
 11 /**
 12  * This class describes the behavior of views
 13  *
 14  * @package View
 15  */
 16 class View{
 17     /**
 18      * The source file of the view
 19      */
 20     private $file,
 21 
 22     /**
 23      * The content of the source template
 24      *
 25      * @var string
 26      */
 27     $content,
 28 
 29     /**
 30      * The data injected in the view for generation
 31      *
 32      * @var array
 33      */
 34     $data,
 35 
 36     /**
 37      * Defines if the view already cached or not
 38      *
 39      * @var boolean
 40      */
 41     $cached = false;
 42 
 43     /**
 44      * The instanced views
 45      */
 46     private static $instances = array();
 47 
 48     /**
 49      * The directory containing the views plugins
 50      */
 51     const PLUGINS_VIEW = 'view-plugins/';
 52 
 53     /**
 54      * The regular expression to match control structure openings
 55      */
 56     const BLOCK_START_REGEX = '#\{(if|elseif|else|for|foreach|while)\s*(\(.+?\))?\s*\}#i';
 57 
 58     /**
 59      * The regular expression to match control structure closings
 60      */
 61     const BLOCK_END_REGEX = '#\{\/(if|for|foreach|while)\s*\}#is';
 62 
 63     /**
 64      * The regular expression to echo a variable
 65      */
 66     const ECHO_REGEX = '#\{{2}\s*(.+?)\}{2}#is';
 67 
 68     /**
 69      * The regular expression for assignations
 70      */
 71     const ASSIGN_REGEX = '#\{assign\s+name=(["\'])(\w+)\\1\s*\}(.*?)\{\/assign\}#ims';
 72 
 73     /**
 74      * The regular expression to match views plugins
 75      */
 76     const PLUGIN_REGEX = '#\{(\w+)((\s+[\w\-]+\=([\'"])((?:[^\4\\\\]|\\\\.)*?)\4)*?)\s*\}#sm';
 77 
 78     /**
 79      * The regular expression to match view plugins attributes
 80      */
 81     const PLUGIN_ARGUMENTS_REGEX = '#([\w\-]+)\=([\'"])(\{?)((?:[^\2\\\\]|\\\\.)*?)(\}?)\\2#sm';
 82 
 83     /**
 84      * The regular expresison to match translations
 85      */
 86     const TRANSLATION_REGEX = '#{(?!if)([a-zA-Z]{2})}(.*?){/\\1}#ism';
 87 
 88 
 89     /**
 90      * Constructor
 91      *
 92      * @param string $file The template file to parse
 93      */
 94     public function __construct($file){
 95         if(!is_file($file)) {
 96             // The source file does not exist
 97             throw new ViewException(ViewException::TYPE_FILE_NOT_FOUND, $file);
 98         }
 99 
100         $this->file = $file;
101 
102         // Get the cache file containing the precompiled
103         $this->cacheFile = 'views/' . str_replace(array(ROOT_DIR, '/'), array('', '-'), realpath($this->file)) . '.php';
104 
105         if(! App::cache()->isCached($this->file, $this->cacheFile)) {
106             $this->content = file_get_contents($this->file);
107             $this->parse();
108             App::cache()->save($this->cacheFile, $this->parsed);
109         }
110 
111         self::$instances[realpath($this->file)] = $this;
112     }
113 
114 
115     /**
116      * Set data to display in the view
117      *
118      * @param array $data The data to insert in the view. The keys of the data will become variables in the view
119      *
120      * @return View The view itself
121      */
122     public function setData($data = array()){
123         $this->data = $data;
124         return $this;
125     }
126 
127 
128     /**
129      * Add data to display in the view
130      *
131      * @param array $data The data to add in the view
132      *
133      * @return View The view itself
134      */
135     public function addData($data = array()){
136         $this->data = array_merge($this->data, $data);
137         return $this;
138     }
139 
140 
141     /**
142      * Get the data pushed in the view
143      *
144      * @return array The view data
145      */
146     public function getData(){
147         return $this->data;
148     }
149 
150 
151     /**
152      * Parse the view into a PHP file
153      *
154      * @return View The view itself, to permit chained expressions
155      */
156     private function parse(){
157         // Parse PHP Structures
158         $replaces = array(
159             // structure starts
160             self::BLOCK_START_REGEX => "<?php $1 $2 : ?>",
161 
162             // structures ends
163             self::BLOCK_END_REGEX   => "<?php end$1; ?>",
164 
165             // echo
166             self::ECHO_REGEX        => "<?= $1 ?>",
167 
168             // Support translations in views
169             self::TRANSLATION_REGEX => "<?php if(LANGUAGE == '$1'): ?>$2<?php endif; ?>",
170 
171             // assign template part in variable
172             self::ASSIGN_REGEX      => "<?php ob_start(); ?>$3<?php \$$2 = ob_get_clean(); ?>"
173         );
174 
175         $this->parsed = preg_replace(array_keys($replaces), $replaces, $this->content);
176 
177         // Parse view plugins
178         $this->parsed = $this->parsePlugin($this->parsed);
179 
180         $this->parsed = '<?php namespace ' . __NAMESPACE__ . '; ?>' . $this->parsed;
181 
182         return $this;
183     }
184 
185 
186     /**
187      * Parse plugins in a view
188      *
189      * @param string $content  The content to parse
190      * @param string $inPlugin Internal variable that indicates if the plugin is another plugin (as  attribute value)
191      *
192      * @return string The parsed PHP instruction to inject in the view compilation
193      */
194     private function parsePlugin($content, $inPlugin = false){
195         return preg_replace_callback(
196             self::PLUGIN_REGEX, function ($matches) use ($inPlugin) {
197                 list($l, $component, $arguments) = $matches;
198                 $componentClass = '\\Hawk\\View\\Plugins\\' . ucfirst($component);
199 
200                 if(!class_exists($componentClass)) {
201                     return $matches[0];
202                 }
203                 try{
204 
205                     $parameters = array();
206 
207                     while(preg_match(self::PLUGIN_ARGUMENTS_REGEX, $arguments, $m)){
208                         list($whole, $name, $quote, $lbrace, $value, $rbrace) = $m;
209                         if($lbrace && $rbrace) {
210                             $subPlugin = $lbrace . stripslashes($value) . $rbrace;
211                             if(preg_match(self::PLUGIN_REGEX, $subPlugin)) {
212                                 // The value is a view plugin
213                                 $value = $this->parsePlugin($subPlugin, true);
214                             }
215 
216                             // That is a PHP expression to evaluate => nothing to do
217                         }
218                         else{
219                             // The value is a static string
220                             $value = '\'' .addcslashes($lbrace . $value . $rbrace, '\\\'') . '\'';
221                         }
222 
223                         $parameters[$name] = '\'' . $name . '\' => ' . $value;
224 
225                         // Remove the argument from the arguments list
226                         $arguments = str_replace($m[0], '', $arguments);
227                     }
228 
229                     if(! $inPlugin) {
230                         return '<?= new ' . $componentClass . '("' . $this->file . '", $_viewData, array(' . implode(',', $parameters) . ') ) ?>';
231                     }
232                     else{
233                         return '(new ' . $componentClass . '("' . $this->file . '", $_viewData, array(' . implode(',', $parameters) . ')))->display()';
234                     }
235                 }
236                 catch(\Exception $e){
237                     return $matches[0];
238                 }
239             }, $content
240         );
241     }
242 
243 
244     /**
245      * Replace the keys in the template and display it
246      *
247      * @return string The HTML result of the view, applied with the data
248      */
249     public function display(){
250         extract($this->data);
251         $_viewData = $this->data;
252         ob_start();
253 
254         include App::cache()->getCacheFilePath($this->cacheFile);
255 
256         return ob_get_clean();
257     }
258 
259 
260     /**
261      * Generate a view result
262      *
263      * @param string $file The filename of the template
264      * @param array  $data The data to apply to the view
265      *
266      * @return string The HTML result of the view
267      */
268     public static function make($file, $data = array()){
269         $view = new self($file);
270         $view->setData($data);
271         return $view->display();
272     }
273 
274 
275     /**
276      * Generate a view from a string
277      *
278      * @param string $content The string of the origin template
279      * @param array  $data    The data to apply to the view
280      *
281      * @return string The HTML result of the string
282      */
283     public static function makeFromString($content, $data = array()){
284         $file = tempnam(TMP_DIR, '');
285         file_put_contents($file, $content);
286 
287         // calculate the view
288         $view = new self($file);
289         $view->setData($data);
290         $result = $view->display();
291 
292         // Remove temporary files
293         unlink($file);
294         App::cache()->clear($view->cacheFile);
295 
296         return $result;
297     }
298 }
299 
300 
301 
302 
303 /**
304  * This class describes the View exceptions
305  *
306  * @package Exceptions
307  */
308 class ViewException extends \Exception{
309     /**
310      * Error type : source file not found
311      */
312     const TYPE_FILE_NOT_FOUND = 1;
313 
314     /**
315      * Error type : view evaluation failed
316      */
317     const TYPE_EVAL = 2;
318 
319     /**
320      * Constructor
321      *
322      * @param int       $type     The type of exception
323      * @param string    $file     The source file that caused this exception
324      * @param Exception $previous The previous exception that caused that one
325      */
326     public function __construct($type, $file, $previous = null){
327         $code = $type;
328         switch($type){
329             case self::TYPE_FILE_NOT_FOUND:
330                 $message = "Error creating a view from template file $file : No such file or directory";
331                 break;
332 
333             case self::TYPE_EVAL:
334                 $trace = array_map(
335                     function ($t) {
336                         return $t['file'] . ':' . $t['line'];
337                     }, $previous->getTrace()
338                 );
339 
340                 $message = "An error occured while building the view from file $file : " . $previous->getMessage() . PHP_EOL . implode(PHP_EOL, $trace);
341                 break;
342         }
343 
344         parent::__construct($message, $code, $previous);
345     }
346 }
347 
Hawk - PHP documentation API documentation generated by ApiGen