Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
html.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Document
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 jimport('joomla.utilities.utility');
13 
14 /**
15  * DocumentHTML class, provides an easy interface to parse and display a HTML document
16  *
17  * @package Joomla.Platform
18  * @subpackage Document
19  * @since 11.1
20  */
21 class JDocumentHTML extends JDocument
22 {
23  /**
24  * Array of Header <link> tags
25  *
26  * @var array
27  * @since 11.1
28  */
29  public $_links = array();
30 
31  /**
32  * Array of custom tags
33  *
34  * @var array
35  * @since 11.1
36  */
37  public $_custom = array();
38 
39  /**
40  * Name of the template
41  *
42  * @var string
43  * @since 11.1
44  */
45  public $template = null;
46 
47  /**
48  * Base url
49  *
50  * @var string
51  * @since 11.1
52  */
53  public $baseurl = null;
54 
55  /**
56  * Array of template parameters
57  *
58  * @var array
59  * @since 11.1
60  */
61  public $params = null;
62 
63  /**
64  * File name
65  *
66  * @var array
67  * @since 11.1
68  */
69  public $_file = null;
70 
71  /**
72  * String holding parsed template
73  *
74  * @var string
75  * @since 11.1
76  */
77  protected $_template = '';
78 
79  /**
80  * Array of parsed template JDoc tags
81  *
82  * @var array
83  * @since 11.1
84  */
85  protected $_template_tags = array();
86 
87  /**
88  * Integer with caching setting
89  *
90  * @var integer
91  * @since 11.1
92  */
93  protected $_caching = null;
94 
95  /**
96  * Set to true when the document should be output as HTML%
97  *
98  * @var boolean
99  * @since 12.1
100  */
101  private $_html5 = null;
102 
103  /**
104  * Class constructor
105  *
106  * @param array $options Associative array of options
107  *
108  * @since 11.1
109  */
110  public function __construct($options = array())
111  {
112  parent::__construct($options);
113 
114  // Set document type
115  $this->_type = 'html';
116 
117  // Set default mime type and document metadata (meta data syncs with mime type by default)
118  $this->setMimeEncoding('text/html');
119  }
120 
121  /**
122  * Get the HTML document head data
123  *
124  * @return array The document head data in array form
125  *
126  * @since 11.1
127  */
128  public function getHeadData()
129  {
130  $data = array();
131  $data['title'] = $this->title;
132  $data['description'] = $this->description;
133  $data['link'] = $this->link;
134  $data['metaTags'] = $this->_metaTags;
135  $data['links'] = $this->_links;
136  $data['styleSheets'] = $this->_styleSheets;
137  $data['style'] = $this->_style;
138  $data['scripts'] = $this->_scripts;
139  $data['script'] = $this->_script;
140  $data['custom'] = $this->_custom;
141  $data['scriptText'] = JText::script();
142  return $data;
143  }
144 
145  /**
146  * Set the HTML document head data
147  *
148  * @param array $data The document head data in array form
149  *
150  * @return JDocumentHTML instance of $this to allow chaining
151  *
152  * @since 11.1
153  */
154  public function setHeadData($data)
155  {
156  if (empty($data) || !is_array($data))
157  {
158  return;
159  }
160 
161  $this->title = (isset($data['title']) && !empty($data['title'])) ? $data['title'] : $this->title;
162  $this->description = (isset($data['description']) && !empty($data['description'])) ? $data['description'] : $this->description;
163  $this->link = (isset($data['link']) && !empty($data['link'])) ? $data['link'] : $this->link;
164  $this->_metaTags = (isset($data['metaTags']) && !empty($data['metaTags'])) ? $data['metaTags'] : $this->_metaTags;
165  $this->_links = (isset($data['links']) && !empty($data['links'])) ? $data['links'] : $this->_links;
166  $this->_styleSheets = (isset($data['styleSheets']) && !empty($data['styleSheets'])) ? $data['styleSheets'] : $this->_styleSheets;
167  $this->_style = (isset($data['style']) && !empty($data['style'])) ? $data['style'] : $this->_style;
168  $this->_scripts = (isset($data['scripts']) && !empty($data['scripts'])) ? $data['scripts'] : $this->_scripts;
169  $this->_script = (isset($data['script']) && !empty($data['script'])) ? $data['script'] : $this->_script;
170  $this->_custom = (isset($data['custom']) && !empty($data['custom'])) ? $data['custom'] : $this->_custom;
171 
172  if (isset($data['scriptText']) && !empty($data['scriptText']))
173  {
174  foreach ($data['scriptText'] as $key => $string)
175  {
176  JText::script($key, $string);
177  }
178  }
179 
180  return $this;
181  }
182 
183  /**
184  * Merge the HTML document head data
185  *
186  * @param array $data The document head data in array form
187  *
188  * @return JDocumentHTML instance of $this to allow chaining
189  *
190  * @since 11.1
191  */
192  public function mergeHeadData($data)
193  {
194 
195  if (empty($data) || !is_array($data))
196  {
197  return;
198  }
199 
200  $this->title = (isset($data['title']) && !empty($data['title']) && !stristr($this->title, $data['title']))
201  ? $this->title . $data['title']
202  : $this->title;
203  $this->description = (isset($data['description']) && !empty($data['description']) && !stristr($this->description, $data['description']))
204  ? $this->description . $data['description']
205  : $this->description;
206  $this->link = (isset($data['link'])) ? $data['link'] : $this->link;
207 
208  if (isset($data['metaTags']))
209  {
210  foreach ($data['metaTags'] as $type1 => $data1)
211  {
212  $booldog = $type1 == 'http-equiv' ? true : false;
213  foreach ($data1 as $name2 => $data2)
214  {
215  $this->setMetaData($name2, $data2, $booldog);
216  }
217  }
218  }
219 
220  $this->_links = (isset($data['links']) && !empty($data['links']) && is_array($data['links']))
221  ? array_unique(array_merge($this->_links, $data['links']))
222  : $this->_links;
223  $this->_styleSheets = (isset($data['styleSheets']) && !empty($data['styleSheets']) && is_array($data['styleSheets']))
224  ? array_merge($this->_styleSheets, $data['styleSheets'])
225  : $this->_styleSheets;
226 
227  if (isset($data['style']))
228  {
229  foreach ($data['style'] as $type => $stdata)
230  {
231  if (!isset($this->_style[strtolower($type)]) || !stristr($this->_style[strtolower($type)], $stdata))
232  {
233  $this->addStyleDeclaration($stdata, $type);
234  }
235  }
236  }
237 
238  $this->_scripts = (isset($data['scripts']) && !empty($data['scripts']) && is_array($data['scripts']))
239  ? array_merge($this->_scripts, $data['scripts'])
240  : $this->_scripts;
241 
242  if (isset($data['script']))
243  {
244  foreach ($data['script'] as $type => $sdata)
245  {
246  if (!isset($this->_script[strtolower($type)]) || !stristr($this->_script[strtolower($type)], $sdata))
247  {
248  $this->addScriptDeclaration($sdata, $type);
249  }
250  }
251  }
252 
253  $this->_custom = (isset($data['custom']) && !empty($data['custom']) && is_array($data['custom']))
254  ? array_unique(array_merge($this->_custom, $data['custom']))
255  : $this->_custom;
256 
257  return $this;
258  }
259 
260  /**
261  * Adds <link> tags to the head of the document
262  *
263  * $relType defaults to 'rel' as it is the most common relation type used.
264  * ('rev' refers to reverse relation, 'rel' indicates normal, forward relation.)
265  * Typical tag: <link href="index.php" rel="Start">
266  *
267  * @param string $href The link that is being related.
268  * @param string $relation Relation of link.
269  * @param string $relType Relation type attribute. Either rel or rev (default: 'rel').
270  * @param array $attribs Associative array of remaining attributes.
271  *
272  * @return JDocumentHTML instance of $this to allow chaining
273  *
274  * @since 11.1
275  */
276  public function addHeadLink($href, $relation, $relType = 'rel', $attribs = array())
277  {
278  $this->_links[$href]['relation'] = $relation;
279  $this->_links[$href]['relType'] = $relType;
280  $this->_links[$href]['attribs'] = $attribs;
281 
282  return $this;
283  }
284 
285  /**
286  * Adds a shortcut icon (favicon)
287  *
288  * This adds a link to the icon shown in the favorites list or on
289  * the left of the url in the address bar. Some browsers display
290  * it on the tab, as well.
291  *
292  * @param string $href The link that is being related.
293  * @param string $type File type
294  * @param string $relation Relation of link
295  *
296  * @return JDocumentHTML instance of $this to allow chaining
297  *
298  * @since 11.1
299  */
300  public function addFavicon($href, $type = 'image/vnd.microsoft.icon', $relation = 'shortcut icon')
301  {
302  $href = str_replace('\\', '/', $href);
303  $this->addHeadLink($href, $relation, 'rel', array('type' => $type));
304 
305  return $this;
306  }
307 
308  /**
309  * Adds a custom HTML string to the head block
310  *
311  * @param string $html The HTML to add to the head
312  *
313  * @return JDocumentHTML instance of $this to allow chaining
314  *
315  * @since 11.1
316  */
317  public function addCustomTag($html)
318  {
319  $this->_custom[] = trim($html);
320 
321  return $this;
322  }
323 
324  /**
325  * Returns whether the document is set up to be output as HTML5
326  *
327  * @return Boolean true when HTML5 is used
328  *
329  * @since 12.1
330  */
331  public function isHtml5()
332  {
333  return $this->_html5;
334  }
335 
336  /**
337  * Sets whether the document should be output as HTML5
338  *
339  * @param bool $state True when HTML5 should be output
340  *
341  * @return void
342  *
343  * @since 12.1
344  */
345  public function setHtml5($state)
346  {
347  if (is_bool($state))
348  {
349  $this->_html5 = $state;
350  }
351  }
352 
353  /**
354  * Get the contents of a document include
355  *
356  * @param string $type The type of renderer
357  * @param string $name The name of the element to render
358  * @param array $attribs Associative array of remaining attributes.
359  *
360  * @return The output of the renderer
361  *
362  * @since 11.1
363  */
364  public function getBuffer($type = null, $name = null, $attribs = array())
365  {
366  // If no type is specified, return the whole buffer
367  if ($type === null)
368  {
369  return parent::$_buffer;
370  }
371 
372  $title = (isset($attribs['title'])) ? $attribs['title'] : null;
373  if (isset(parent::$_buffer[$type][$name][$title]))
374  {
375  return parent::$_buffer[$type][$name][$title];
376  }
377 
378  $renderer = $this->loadRenderer($type);
379  if ($this->_caching == true && $type == 'modules')
380  {
381  $cache = JFactory::getCache('com_modules', '');
382  $hash = md5(serialize(array($name, $attribs, null, $renderer)));
383  $cbuffer = $cache->get('cbuffer_' . $type);
384 
385  if (isset($cbuffer[$hash]))
386  {
387  return JCache::getWorkarounds($cbuffer[$hash], array('mergehead' => 1));
388  }
389  else
390  {
391  $options = array();
392  $options['nopathway'] = 1;
393  $options['nomodules'] = 1;
394  $options['modulemode'] = 1;
395 
396  $this->setBuffer($renderer->render($name, $attribs, null), $type, $name);
397  $data = parent::$_buffer[$type][$name][$title];
398 
399  $tmpdata = JCache::setWorkarounds($data, $options);
400 
401  $cbuffer[$hash] = $tmpdata;
402 
403  $cache->store($cbuffer, 'cbuffer_' . $type);
404  }
405  }
406  else
407  {
408  $this->setBuffer($renderer->render($name, $attribs, null), $type, $name, $title);
409  }
410 
411  return parent::$_buffer[$type][$name][$title];
412  }
413 
414  /**
415  * Set the contents a document includes
416  *
417  * @param string $content The content to be set in the buffer.
418  * @param array $options Array of optional elements.
419  *
420  * @return JDocumentHTML instance of $this to allow chaining
421  *
422  * @since 11.1
423  */
424  public function setBuffer($content, $options = array())
425  {
426  // The following code is just for backward compatibility.
427  if (func_num_args() > 1 && !is_array($options))
428  {
429  $args = func_get_args();
430  $options = array();
431  $options['type'] = $args[1];
432  $options['name'] = (isset($args[2])) ? $args[2] : null;
433  $options['title'] = (isset($args[3])) ? $args[3] : null;
434  }
435 
436  parent::$_buffer[$options['type']][$options['name']][$options['title']] = $content;
437 
438  return $this;
439  }
440 
441  /**
442  * Parses the template and populates the buffer
443  *
444  * @param array $params Parameters for fetching the template
445  *
446  * @return JDocumentHTML instance of $this to allow chaining
447  *
448  * @since 11.1
449  */
450  public function parse($params = array())
451  {
452  return $this->_fetchTemplate($params)->_parseTemplate();
453  }
454 
455  /**
456  * Outputs the template to the browser.
457  *
458  * @param boolean $caching If true, cache the output
459  * @param array $params Associative array of attributes
460  *
461  * @return The rendered data
462  *
463  * @since 11.1
464  */
465  public function render($caching = false, $params = array())
466  {
467  $this->_caching = $caching;
468 
469  if (!empty($this->_template))
470  {
471  $data = $this->_renderTemplate();
472  }
473  else
474  {
475  $this->parse($params);
476  $data = $this->_renderTemplate();
477  }
478 
479  parent::render();
480  return $data;
481  }
482 
483  /**
484  * Count the modules based on the given condition
485  *
486  * @param string $condition The condition to use
487  *
488  * @return integer Number of modules found
489  *
490  * @since 11.1
491  */
492  public function countModules($condition)
493  {
494  $operators = '(\+|\-|\*|\/|==|\!=|<>|<|>|<=|>=|and|or|xor)';
495  $words = preg_split('# ' . $operators . ' #', $condition, null, PREG_SPLIT_DELIM_CAPTURE);
496  for ($i = 0, $n = count($words); $i < $n; $i += 2)
497  {
498  // Odd parts (modules)
499  $name = strtolower($words[$i]);
500  $words[$i] = ((isset(parent::$_buffer['modules'][$name])) && (parent::$_buffer['modules'][$name] === false))
501  ? 0
502  : count(JModuleHelper::getModules($name));
503  }
504 
505  $str = 'return ' . implode(' ', $words) . ';';
506 
507  return eval($str);
508  }
509 
510  /**
511  * Count the number of child menu items
512  *
513  * @return integer Number of child menu items
514  *
515  * @since 11.1
516  */
517  public function countMenuChildren()
518  {
519  static $children;
520 
521  if (!isset($children))
522  {
523  $db = JFactory::getDbo();
524  $app = JFactory::getApplication();
525  $menu = $app->getMenu();
526  $active = $menu->getActive();
527  if ($active)
528  {
529  $query = $db->getQuery(true)
530  ->select('COUNT(*)')
531  ->from('#__menu')
532  ->where('parent_id = ' . $active->id)
533  ->where('published = 1');
534  $db->setQuery($query);
535  $children = $db->loadResult();
536  }
537  else
538  {
539  $children = 0;
540  }
541  }
542 
543  return $children;
544  }
545 
546  /**
547  * Load a template file
548  *
549  * @param string $directory The name of the template
550  * @param string $filename The actual filename
551  *
552  * @return string The contents of the template
553  *
554  * @since 11.1
555  */
556  protected function _loadTemplate($directory, $filename)
557  {
558  // @todo remove code: $component = JApplicationHelper::getComponentName();
559 
560  $contents = '';
561 
562  // Check to see if we have a valid template file
563  if (file_exists($directory . '/' . $filename))
564  {
565  // Store the file path
566  $this->_file = $directory . '/' . $filename;
567 
568  // Get the file content
569  ob_start();
570  require $directory . '/' . $filename;
571  $contents = ob_get_contents();
572  ob_end_clean();
573  }
574 
575  // Try to find a favicon by checking the template and root folder
576  $path = $directory . '/';
577  $dirs = array($path, JPATH_BASE . '/');
578  foreach ($dirs as $dir)
579  {
580  $icon = $dir . 'favicon.ico';
581  if (file_exists($icon))
582  {
583  $path = str_replace(JPATH_BASE . '/', '', $dir);
584  $path = str_replace('\\', '/', $path);
585  $this->addFavicon(JUri::base(true) . '/' . $path . 'favicon.ico');
586  break;
587  }
588  }
589 
590  return $contents;
591  }
592 
593  /**
594  * Fetch the template, and initialise the params
595  *
596  * @param array $params Parameters to determine the template
597  *
598  * @return JDocumentHTML instance of $this to allow chaining
599  *
600  * @since 11.1
601  */
602  protected function _fetchTemplate($params = array())
603  {
604  // Check
605  $directory = isset($params['directory']) ? $params['directory'] : 'templates';
606  $filter = JFilterInput::getInstance();
607  $template = $filter->clean($params['template'], 'cmd');
608  $file = $filter->clean($params['file'], 'cmd');
609 
610  if (!file_exists($directory . '/' . $template . '/' . $file))
611  {
612  $template = 'system';
613  }
614 
615  // Load the language file for the template
616  $lang = JFactory::getLanguage();
617 
618  // 1.5 or core then 1.6
619  $lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
620  || $lang->load('tpl_' . $template, $directory . '/' . $template, null, false, false)
621  || $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
622  || $lang->load('tpl_' . $template, $directory . '/' . $template, $lang->getDefault(), false, false);
623 
624  // Assign the variables
625  $this->template = $template;
626  $this->baseurl = JUri::base(true);
627  $this->params = isset($params['params']) ? $params['params'] : new JRegistry;
628 
629  // Load
630  $this->_template = $this->_loadTemplate($directory . '/' . $template, $file);
631 
632  return $this;
633  }
634 
635  /**
636  * Parse a document template
637  *
638  * @return JDocumentHTML instance of $this to allow chaining
639  *
640  * @since 11.1
641  */
642  protected function _parseTemplate()
643  {
644  $matches = array();
645 
646  if (preg_match_all('#<jdoc:include\ type="([^"]+)"(.*)\/>#iU', $this->_template, $matches))
647  {
648  $template_tags_first = array();
649  $template_tags_last = array();
650 
651  // Step through the jdocs in reverse order.
652  for ($i = count($matches[0]) - 1; $i >= 0; $i--)
653  {
654  $type = $matches[1][$i];
655  $attribs = empty($matches[2][$i]) ? array() : JUtility::parseAttributes($matches[2][$i]);
656  $name = isset($attribs['name']) ? $attribs['name'] : null;
657 
658  // Separate buffers to be executed first and last
659  if ($type == 'module' || $type == 'modules')
660  {
661  $template_tags_first[$matches[0][$i]] = array('type' => $type, 'name' => $name, 'attribs' => $attribs);
662  }
663  else
664  {
665  $template_tags_last[$matches[0][$i]] = array('type' => $type, 'name' => $name, 'attribs' => $attribs);
666  }
667  }
668  // Reverse the last array so the jdocs are in forward order.
669  $template_tags_last = array_reverse($template_tags_last);
670 
671  $this->_template_tags = $template_tags_first + $template_tags_last;
672  }
673 
674  return $this;
675  }
676 
677  /**
678  * Render pre-parsed template
679  *
680  * @return string rendered template
681  *
682  * @since 11.1
683  */
684  protected function _renderTemplate()
685  {
686  $replace = array();
687  $with = array();
688 
689  foreach ($this->_template_tags as $jdoc => $args)
690  {
691  $replace[] = $jdoc;
692  $with[] = $this->getBuffer($args['type'], $args['name'], $args['attribs']);
693  }
694 
695  return str_replace($replace, $with, $this->_template);
696  }
697 }