1<?php 2/** 3 * Joomla! Content Management System 4 * 5 * @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved. 6 * @license GNU General Public License version 2 or later; see LICENSE.txt 7 */ 8 9namespace Joomla\CMS\Document; 10 11defined('JPATH_PLATFORM') or die; 12 13use Joomla\CMS\Date\Date; 14 15/** 16 * Document class, provides an easy interface to parse and display a document 17 * 18 * @since 1.7.0 19 */ 20class Document 21{ 22 /** 23 * Document title 24 * 25 * @var string 26 * @since 1.7.0 27 */ 28 public $title = ''; 29 30 /** 31 * Document description 32 * 33 * @var string 34 * @since 1.7.0 35 */ 36 public $description = ''; 37 38 /** 39 * Document full URL 40 * 41 * @var string 42 * @since 1.7.0 43 */ 44 public $link = ''; 45 46 /** 47 * Document base URL 48 * 49 * @var string 50 * @since 1.7.0 51 */ 52 public $base = ''; 53 54 /** 55 * Contains the document language setting 56 * 57 * @var string 58 * @since 1.7.0 59 */ 60 public $language = 'en-gb'; 61 62 /** 63 * Contains the document direction setting 64 * 65 * @var string 66 * @since 1.7.0 67 */ 68 public $direction = 'ltr'; 69 70 /** 71 * Document generator 72 * 73 * @var string 74 * @since 1.7.0 75 */ 76 public $_generator = 'Joomla! - Open Source Content Management'; 77 78 /** 79 * Document modified date 80 * 81 * @var string|Date 82 * @since 1.7.0 83 */ 84 public $_mdate = ''; 85 86 /** 87 * Tab string 88 * 89 * @var string 90 * @since 1.7.0 91 */ 92 public $_tab = "\11"; 93 94 /** 95 * Contains the line end string 96 * 97 * @var string 98 * @since 1.7.0 99 */ 100 public $_lineEnd = "\12"; 101 102 /** 103 * Contains the character encoding string 104 * 105 * @var string 106 * @since 1.7.0 107 */ 108 public $_charset = 'utf-8'; 109 110 /** 111 * Document mime type 112 * 113 * @var string 114 * @since 1.7.0 115 */ 116 public $_mime = ''; 117 118 /** 119 * Document namespace 120 * 121 * @var string 122 * @since 1.7.0 123 */ 124 public $_namespace = ''; 125 126 /** 127 * Document profile 128 * 129 * @var string 130 * @since 1.7.0 131 */ 132 public $_profile = ''; 133 134 /** 135 * Array of linked scripts 136 * 137 * @var array 138 * @since 1.7.0 139 */ 140 public $_scripts = array(); 141 142 /** 143 * Array of scripts placed in the header 144 * 145 * @var array 146 * @since 1.7.0 147 */ 148 public $_script = array(); 149 150 /** 151 * Array of scripts options 152 * 153 * @var array 154 */ 155 protected $scriptOptions = array(); 156 157 /** 158 * Array of linked style sheets 159 * 160 * @var array 161 * @since 1.7.0 162 */ 163 public $_styleSheets = array(); 164 165 /** 166 * Array of included style declarations 167 * 168 * @var array 169 * @since 1.7.0 170 */ 171 public $_style = array(); 172 173 /** 174 * Array of meta tags 175 * 176 * @var array 177 * @since 1.7.0 178 */ 179 public $_metaTags = array(); 180 181 /** 182 * The rendering engine 183 * 184 * @var object 185 * @since 1.7.0 186 */ 187 public $_engine = null; 188 189 /** 190 * The document type 191 * 192 * @var string 193 * @since 1.7.0 194 */ 195 public $_type = null; 196 197 /** 198 * Array of buffered output 199 * 200 * @var mixed (depends on the renderer) 201 * @since 1.7.0 202 */ 203 public static $_buffer = null; 204 205 /** 206 * Document instances container. 207 * 208 * @var array 209 * @since 1.7.3 210 */ 211 protected static $instances = array(); 212 213 /** 214 * Media version added to assets 215 * 216 * @var string 217 * @since 3.2 218 */ 219 protected $mediaVersion = null; 220 221 /** 222 * Class constructor. 223 * 224 * @param array $options Associative array of options 225 * 226 * @since 1.7.0 227 */ 228 public function __construct($options = array()) 229 { 230 if (array_key_exists('lineend', $options)) 231 { 232 $this->setLineEnd($options['lineend']); 233 } 234 235 if (array_key_exists('charset', $options)) 236 { 237 $this->setCharset($options['charset']); 238 } 239 240 if (array_key_exists('language', $options)) 241 { 242 $this->setLanguage($options['language']); 243 } 244 245 if (array_key_exists('direction', $options)) 246 { 247 $this->setDirection($options['direction']); 248 } 249 250 if (array_key_exists('tab', $options)) 251 { 252 $this->setTab($options['tab']); 253 } 254 255 if (array_key_exists('link', $options)) 256 { 257 $this->setLink($options['link']); 258 } 259 260 if (array_key_exists('base', $options)) 261 { 262 $this->setBase($options['base']); 263 } 264 265 if (array_key_exists('mediaversion', $options)) 266 { 267 $this->setMediaVersion($options['mediaversion']); 268 } 269 } 270 271 /** 272 * Returns the global Document object, only creating it 273 * if it doesn't already exist. 274 * 275 * @param string $type The document type to instantiate 276 * @param array $attributes Array of attributes 277 * 278 * @return object The document object. 279 * 280 * @since 1.7.0 281 */ 282 public static function getInstance($type = 'html', $attributes = array()) 283 { 284 $signature = serialize(array($type, $attributes)); 285 286 if (empty(self::$instances[$signature])) 287 { 288 $type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type); 289 $ntype = null; 290 291 // Determine the path and class 292 $class = __NAMESPACE__ . '\\' . ucfirst($type) . 'Document'; 293 294 if (!class_exists($class)) 295 { 296 $class = 'JDocument' . ucfirst($type); 297 } 298 299 if (!class_exists($class)) 300 { 301 // @deprecated 4.0 - Document objects should be autoloaded instead 302 $path = __DIR__ . '/' . $type . '/' . $type . '.php'; 303 304 \JLoader::register($class, $path); 305 306 if (class_exists($class)) 307 { 308 \JLog::add('Non-autoloadable Document subclasses are deprecated, support will be removed in 4.0.', \JLog::WARNING, 'deprecated'); 309 } 310 // Default to the raw format 311 else 312 { 313 $ntype = $type; 314 $class = 'JDocumentRaw'; 315 } 316 } 317 318 $instance = new $class($attributes); 319 self::$instances[$signature] = $instance; 320 321 if (!is_null($ntype)) 322 { 323 // Set the type to the Document type originally requested 324 $instance->setType($ntype); 325 } 326 } 327 328 return self::$instances[$signature]; 329 } 330 331 /** 332 * Set the document type 333 * 334 * @param string $type Type document is to set to 335 * 336 * @return Document instance of $this to allow chaining 337 * 338 * @since 1.7.0 339 */ 340 public function setType($type) 341 { 342 $this->_type = $type; 343 344 return $this; 345 } 346 347 /** 348 * Returns the document type 349 * 350 * @return string 351 * 352 * @since 1.7.0 353 */ 354 public function getType() 355 { 356 return $this->_type; 357 } 358 359 /** 360 * Get the contents of the document buffer 361 * 362 * @return mixed 363 * 364 * @since 1.7.0 365 */ 366 public function getBuffer() 367 { 368 return self::$_buffer; 369 } 370 371 /** 372 * Set the contents of the document buffer 373 * 374 * @param string $content The content to be set in the buffer. 375 * @param array $options Array of optional elements. 376 * 377 * @return Document instance of $this to allow chaining 378 * 379 * @since 1.7.0 380 */ 381 public function setBuffer($content, $options = array()) 382 { 383 self::$_buffer = $content; 384 385 return $this; 386 } 387 388 /** 389 * Gets a meta tag. 390 * 391 * @param string $name Name of the meta HTML tag 392 * @param string $attribute Attribute to use in the meta HTML tag 393 * 394 * @return string 395 * 396 * @since 1.7.0 397 */ 398 public function getMetaData($name, $attribute = 'name') 399 { 400 // B/C old http_equiv parameter. 401 if (!is_string($attribute)) 402 { 403 $attribute = $attribute == true ? 'http-equiv' : 'name'; 404 } 405 406 if ($name == 'generator') 407 { 408 $result = $this->getGenerator(); 409 } 410 elseif ($name == 'description') 411 { 412 $result = $this->getDescription(); 413 } 414 else 415 { 416 $result = isset($this->_metaTags[$attribute]) && isset($this->_metaTags[$attribute][$name]) ? $this->_metaTags[$attribute][$name] : ''; 417 } 418 419 return $result; 420 } 421 422 /** 423 * Sets or alters a meta tag. 424 * 425 * @param string $name Name of the meta HTML tag 426 * @param mixed $content Value of the meta HTML tag as array or string 427 * @param string $attribute Attribute to use in the meta HTML tag 428 * 429 * @return Document instance of $this to allow chaining 430 * 431 * @since 1.7.0 432 */ 433 public function setMetaData($name, $content, $attribute = 'name') 434 { 435 // Pop the element off the end of array if target function expects a string or this http_equiv parameter. 436 if (is_array($content) && (in_array($name, array('generator', 'description')) || !is_string($attribute))) 437 { 438 $content = array_pop($content); 439 } 440 441 // B/C old http_equiv parameter. 442 if (!is_string($attribute)) 443 { 444 $attribute = $attribute == true ? 'http-equiv' : 'name'; 445 } 446 447 if ($name == 'generator') 448 { 449 $this->setGenerator($content); 450 } 451 elseif ($name == 'description') 452 { 453 $this->setDescription($content); 454 } 455 else 456 { 457 $this->_metaTags[$attribute][$name] = $content; 458 } 459 460 return $this; 461 } 462 463 /** 464 * Adds a linked script to the page 465 * 466 * @param string $url URL to the linked script. 467 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9') 468 * @param array $attribs Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1) 469 * 470 * @return Document instance of $this to allow chaining 471 * 472 * @since 1.7.0 473 * @deprecated 4.0 The (url, mime, defer, async) method signature is deprecated, use (url, options, attributes) instead. 474 */ 475 public function addScript($url, $options = array(), $attribs = array()) 476 { 477 // B/C before 3.7.0 478 if (!is_array($options) && (!is_array($attribs) || $attribs === array())) 479 { 480 \JLog::add('The addScript method signature used has changed, use (url, options, attributes) instead.', \JLog::WARNING, 'deprecated'); 481 482 $argList = func_get_args(); 483 $options = array(); 484 $attribs = array(); 485 486 // Old mime type parameter. 487 if (!empty($argList[1])) 488 { 489 $attribs['mime'] = $argList[1]; 490 } 491 492 // Old defer parameter. 493 if (isset($argList[2]) && $argList[2]) 494 { 495 $attribs['defer'] = true; 496 } 497 498 // Old async parameter. 499 if (isset($argList[3]) && $argList[3]) 500 { 501 $attribs['async'] = true; 502 } 503 } 504 505 // Default value for type. 506 if (!isset($attribs['type']) && !isset($attribs['mime'])) 507 { 508 $attribs['type'] = 'text/javascript'; 509 } 510 511 $this->_scripts[$url] = isset($this->_scripts[$url]) ? array_replace($this->_scripts[$url], $attribs) : $attribs; 512 $this->_scripts[$url]['options'] = isset($this->_scripts[$url]['options']) ? array_replace($this->_scripts[$url]['options'], $options) : $options; 513 514 return $this; 515 } 516 517 /** 518 * Adds a linked script to the page with a version to allow to flush it. Ex: myscript.js?54771616b5bceae9df03c6173babf11d 519 * If not specified Joomla! automatically handles versioning 520 * 521 * @param string $url URL to the linked script. 522 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9') 523 * @param array $attribs Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1) 524 * 525 * @return Document instance of $this to allow chaining 526 * 527 * @since 3.2 528 * @deprecated 4.0 This method is deprecated, use addScript(url, options, attributes) instead. 529 */ 530 public function addScriptVersion($url, $options = array(), $attribs = array()) 531 { 532 \JLog::add('The method is deprecated, use addScript(url, attributes, options) instead.', \JLog::WARNING, 'deprecated'); 533 534 // B/C before 3.7.0 535 if (!is_array($options) && (!is_array($attribs) || $attribs === array())) 536 { 537 $argList = func_get_args(); 538 $options = array(); 539 $attribs = array(); 540 541 // Old version parameter. 542 $options['version'] = isset($argList[1]) && !is_null($argList[1]) ? $argList[1] : 'auto'; 543 544 // Old mime type parameter. 545 if (!empty($argList[2])) 546 { 547 $attribs['mime'] = $argList[2]; 548 } 549 550 // Old defer parameter. 551 if (isset($argList[3]) && $argList[3]) 552 { 553 $attribs['defer'] = true; 554 } 555 556 // Old async parameter. 557 if (isset($argList[4]) && $argList[4]) 558 { 559 $attribs['async'] = true; 560 } 561 } 562 // Default value for version. 563 else 564 { 565 $options['version'] = 'auto'; 566 } 567 568 return $this->addScript($url, $options, $attribs); 569 } 570 571 /** 572 * Adds a script to the page 573 * 574 * @param string $content Script 575 * @param string $type Scripting mime (defaults to 'text/javascript') 576 * 577 * @return Document instance of $this to allow chaining 578 * 579 * @since 1.7.0 580 */ 581 public function addScriptDeclaration($content, $type = 'text/javascript') 582 { 583 if (!isset($this->_script[strtolower($type)])) 584 { 585 $this->_script[strtolower($type)] = $content; 586 } 587 else 588 { 589 $this->_script[strtolower($type)] .= chr(13) . $content; 590 } 591 592 return $this; 593 } 594 595 /** 596 * Add option for script 597 * 598 * @param string $key Name in Storage 599 * @param mixed $options Scrip options as array or string 600 * @param bool $merge Whether merge with existing (true) or replace (false) 601 * 602 * @return Document instance of $this to allow chaining 603 * 604 * @since 3.5 605 */ 606 public function addScriptOptions($key, $options, $merge = true) 607 { 608 if (empty($this->scriptOptions[$key])) 609 { 610 $this->scriptOptions[$key] = array(); 611 } 612 613 if ($merge && is_array($options)) 614 { 615 $this->scriptOptions[$key] = array_replace_recursive($this->scriptOptions[$key], $options); 616 } 617 else 618 { 619 $this->scriptOptions[$key] = $options; 620 } 621 622 return $this; 623 } 624 625 /** 626 * Get script(s) options 627 * 628 * @param string $key Name in Storage 629 * 630 * @return array Options for given $key, or all script options 631 * 632 * @since 3.5 633 */ 634 public function getScriptOptions($key = null) 635 { 636 if ($key) 637 { 638 return (empty($this->scriptOptions[$key])) ? array() : $this->scriptOptions[$key]; 639 } 640 else 641 { 642 return $this->scriptOptions; 643 } 644 } 645 646 /** 647 * Adds a linked stylesheet to the page 648 * 649 * @param string $url URL to the linked style sheet 650 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9') 651 * @param array $attribs Array of attributes. Example: array('id' => 'stylesheet', 'data-test' => 1) 652 * 653 * @return Document instance of $this to allow chaining 654 * 655 * @since 1.7.0 656 * @deprecated 4.0 The (url, mime, media, attribs) method signature is deprecated, use (url, options, attributes) instead. 657 */ 658 public function addStyleSheet($url, $options = array(), $attribs = array()) 659 { 660 // B/C before 3.7.0 661 if (is_string($options)) 662 { 663 \JLog::add('The addStyleSheet method signature used has changed, use (url, options, attributes) instead.', \JLog::WARNING, 'deprecated'); 664 665 $argList = func_get_args(); 666 $options = array(); 667 $attribs = array(); 668 669 // Old mime type parameter. 670 if (!empty($argList[1])) 671 { 672 $attribs['type'] = $argList[1]; 673 } 674 675 // Old media parameter. 676 if (isset($argList[2]) && $argList[2]) 677 { 678 $attribs['media'] = $argList[2]; 679 } 680 681 // Old attribs parameter. 682 if (isset($argList[3]) && $argList[3]) 683 { 684 $attribs = array_replace($attribs, $argList[3]); 685 } 686 } 687 688 // Default value for type. 689 if (!isset($attribs['type']) && !isset($attribs['mime'])) 690 { 691 $attribs['type'] = 'text/css'; 692 } 693 694 $this->_styleSheets[$url] = isset($this->_styleSheets[$url]) ? array_replace($this->_styleSheets[$url], $attribs) : $attribs; 695 696 if (isset($this->_styleSheets[$url]['options'])) 697 { 698 $this->_styleSheets[$url]['options'] = array_replace($this->_styleSheets[$url]['options'], $options); 699 } 700 else 701 { 702 $this->_styleSheets[$url]['options'] = $options; 703 } 704 705 return $this; 706 } 707 708 /** 709 * Adds a linked stylesheet version to the page. Ex: template.css?54771616b5bceae9df03c6173babf11d 710 * If not specified Joomla! automatically handles versioning 711 * 712 * @param string $url URL to the linked style sheet 713 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9') 714 * @param array $attribs Array of attributes. Example: array('id' => 'stylesheet', 'data-test' => 1) 715 * 716 * @return Document instance of $this to allow chaining 717 * 718 * @since 3.2 719 * @deprecated 4.0 This method is deprecated, use addStyleSheet(url, options, attributes) instead. 720 */ 721 public function addStyleSheetVersion($url, $options = array(), $attribs = array()) 722 { 723 \JLog::add('The method is deprecated, use addStyleSheet(url, attributes, options) instead.', \JLog::WARNING, 'deprecated'); 724 725 // B/C before 3.7.0 726 if (!is_array($options) && (!is_array($attribs) || $attribs === array())) 727 { 728 $argList = func_get_args(); 729 $options = array(); 730 $attribs = array(); 731 732 // Old version parameter. 733 $options['version'] = isset($argList[1]) && !is_null($argList[1]) ? $argList[1] : 'auto'; 734 735 // Old mime type parameter. 736 if (!empty($argList[2])) 737 { 738 $attribs['mime'] = $argList[2]; 739 } 740 741 // Old media parameter. 742 if (isset($argList[3]) && $argList[3]) 743 { 744 $attribs['media'] = $argList[3]; 745 } 746 747 // Old attribs parameter. 748 if (isset($argList[4]) && $argList[4]) 749 { 750 $attribs = array_replace($attribs, $argList[4]); 751 } 752 } 753 // Default value for version. 754 else 755 { 756 $options['version'] = 'auto'; 757 } 758 759 return $this->addStyleSheet($url, $options, $attribs); 760 } 761 762 /** 763 * Adds a stylesheet declaration to the page 764 * 765 * @param string $content Style declarations 766 * @param string $type Type of stylesheet (defaults to 'text/css') 767 * 768 * @return Document instance of $this to allow chaining 769 * 770 * @since 1.7.0 771 */ 772 public function addStyleDeclaration($content, $type = 'text/css') 773 { 774 if (!isset($this->_style[strtolower($type)])) 775 { 776 $this->_style[strtolower($type)] = $content; 777 } 778 else 779 { 780 $this->_style[strtolower($type)] .= chr(13) . $content; 781 } 782 783 return $this; 784 } 785 786 /** 787 * Sets the document charset 788 * 789 * @param string $type Charset encoding string 790 * 791 * @return Document instance of $this to allow chaining 792 * 793 * @since 1.7.0 794 */ 795 public function setCharset($type = 'utf-8') 796 { 797 $this->_charset = $type; 798 799 return $this; 800 } 801 802 /** 803 * Returns the document charset encoding. 804 * 805 * @return string 806 * 807 * @since 1.7.0 808 */ 809 public function getCharset() 810 { 811 return $this->_charset; 812 } 813 814 /** 815 * Sets the global document language declaration. Default is English (en-gb). 816 * 817 * @param string $lang The language to be set 818 * 819 * @return Document instance of $this to allow chaining 820 * 821 * @since 1.7.0 822 */ 823 public function setLanguage($lang = 'en-gb') 824 { 825 $this->language = strtolower($lang); 826 827 return $this; 828 } 829 830 /** 831 * Returns the document language. 832 * 833 * @return string 834 * 835 * @since 1.7.0 836 */ 837 public function getLanguage() 838 { 839 return $this->language; 840 } 841 842 /** 843 * Sets the global document direction declaration. Default is left-to-right (ltr). 844 * 845 * @param string $dir The language direction to be set 846 * 847 * @return Document instance of $this to allow chaining 848 * 849 * @since 1.7.0 850 */ 851 public function setDirection($dir = 'ltr') 852 { 853 $this->direction = strtolower($dir); 854 855 return $this; 856 } 857 858 /** 859 * Returns the document direction declaration. 860 * 861 * @return string 862 * 863 * @since 1.7.0 864 */ 865 public function getDirection() 866 { 867 return $this->direction; 868 } 869 870 /** 871 * Sets the title of the document 872 * 873 * @param string $title The title to be set 874 * 875 * @return Document instance of $this to allow chaining 876 * 877 * @since 1.7.0 878 */ 879 public function setTitle($title) 880 { 881 $this->title = $title; 882 883 return $this; 884 } 885 886 /** 887 * Return the title of the document. 888 * 889 * @return string 890 * 891 * @since 1.7.0 892 */ 893 public function getTitle() 894 { 895 return $this->title; 896 } 897 898 /** 899 * Set the assets version 900 * 901 * @param string $mediaVersion Media version to use 902 * 903 * @return Document instance of $this to allow chaining 904 * 905 * @since 3.2 906 */ 907 public function setMediaVersion($mediaVersion) 908 { 909 $this->mediaVersion = strtolower($mediaVersion); 910 911 return $this; 912 } 913 914 /** 915 * Return the media version 916 * 917 * @return string 918 * 919 * @since 3.2 920 */ 921 public function getMediaVersion() 922 { 923 return $this->mediaVersion; 924 } 925 926 /** 927 * Sets the base URI of the document 928 * 929 * @param string $base The base URI to be set 930 * 931 * @return Document instance of $this to allow chaining 932 * 933 * @since 1.7.0 934 */ 935 public function setBase($base) 936 { 937 $this->base = $base; 938 939 return $this; 940 } 941 942 /** 943 * Return the base URI of the document. 944 * 945 * @return string 946 * 947 * @since 1.7.0 948 */ 949 public function getBase() 950 { 951 return $this->base; 952 } 953 954 /** 955 * Sets the description of the document 956 * 957 * @param string $description The description to set 958 * 959 * @return Document instance of $this to allow chaining 960 * 961 * @since 1.7.0 962 */ 963 public function setDescription($description) 964 { 965 $this->description = $description; 966 967 return $this; 968 } 969 970 /** 971 * Return the description of the document. 972 * 973 * @return string 974 * 975 * @since 1.7.0 976 */ 977 public function getDescription() 978 { 979 return $this->description; 980 } 981 982 /** 983 * Sets the document link 984 * 985 * @param string $url A url 986 * 987 * @return Document instance of $this to allow chaining 988 * 989 * @since 1.7.0 990 */ 991 public function setLink($url) 992 { 993 $this->link = $url; 994 995 return $this; 996 } 997 998 /** 999 * Returns the document base url 1000 * 1001 * @return string 1002 * 1003 * @since 1.7.0 1004 */ 1005 public function getLink() 1006 { 1007 return $this->link; 1008 } 1009 1010 /** 1011 * Sets the document generator 1012 * 1013 * @param string $generator The generator to be set 1014 * 1015 * @return Document instance of $this to allow chaining 1016 * 1017 * @since 1.7.0 1018 */ 1019 public function setGenerator($generator) 1020 { 1021 $this->_generator = $generator; 1022 1023 return $this; 1024 } 1025 1026 /** 1027 * Returns the document generator 1028 * 1029 * @return string 1030 * 1031 * @since 1.7.0 1032 */ 1033 public function getGenerator() 1034 { 1035 return $this->_generator; 1036 } 1037 1038 /** 1039 * Sets the document modified date 1040 * 1041 * @param string|Date $date The date to be set 1042 * 1043 * @return Document instance of $this to allow chaining 1044 * 1045 * @since 1.7.0 1046 * @throws \InvalidArgumentException 1047 */ 1048 public function setModifiedDate($date) 1049 { 1050 if (!is_string($date) && !($date instanceof Date)) 1051 { 1052 throw new \InvalidArgumentException( 1053 sprintf( 1054 'The $date parameter of %1$s must be a string or a %2$s instance, a %3$s was given.', 1055 __METHOD__ . '()', 1056 'Joomla\\CMS\\Date\\Date', 1057 gettype($date) === 'object' ? (get_class($date) . ' instance') : gettype($date) 1058 ) 1059 ); 1060 } 1061 1062 $this->_mdate = $date; 1063 1064 return $this; 1065 } 1066 1067 /** 1068 * Returns the document modified date 1069 * 1070 * @return string|Date 1071 * 1072 * @since 1.7.0 1073 */ 1074 public function getModifiedDate() 1075 { 1076 return $this->_mdate; 1077 } 1078 1079 /** 1080 * Sets the document MIME encoding that is sent to the browser. 1081 * 1082 * This usually will be text/html because most browsers cannot yet 1083 * accept the proper mime settings for XHTML: application/xhtml+xml 1084 * and to a lesser extent application/xml and text/xml. See the W3C note 1085 * ({@link http://www.w3.org/TR/xhtml-media-types/ 1086 * http://www.w3.org/TR/xhtml-media-types/}) for more details. 1087 * 1088 * @param string $type The document type to be sent 1089 * @param boolean $sync Should the type be synced with HTML? 1090 * 1091 * @return Document instance of $this to allow chaining 1092 * 1093 * @since 1.7.0 1094 * 1095 * @link http://www.w3.org/TR/xhtml-media-types 1096 */ 1097 public function setMimeEncoding($type = 'text/html', $sync = true) 1098 { 1099 $this->_mime = strtolower($type); 1100 1101 // Syncing with metadata 1102 if ($sync) 1103 { 1104 $this->setMetaData('content-type', $type . '; charset=' . $this->_charset, true); 1105 } 1106 1107 return $this; 1108 } 1109 1110 /** 1111 * Return the document MIME encoding that is sent to the browser. 1112 * 1113 * @return string 1114 * 1115 * @since 1.7.0 1116 */ 1117 public function getMimeEncoding() 1118 { 1119 return $this->_mime; 1120 } 1121 1122 /** 1123 * Sets the line end style to Windows, Mac, Unix or a custom string. 1124 * 1125 * @param string $style "win", "mac", "unix" or custom string. 1126 * 1127 * @return Document instance of $this to allow chaining 1128 * 1129 * @since 1.7.0 1130 */ 1131 public function setLineEnd($style) 1132 { 1133 switch ($style) 1134 { 1135 case 'win': 1136 $this->_lineEnd = "\15\12"; 1137 break; 1138 case 'unix': 1139 $this->_lineEnd = "\12"; 1140 break; 1141 case 'mac': 1142 $this->_lineEnd = "\15"; 1143 break; 1144 default: 1145 $this->_lineEnd = $style; 1146 } 1147 1148 return $this; 1149 } 1150 1151 /** 1152 * Returns the lineEnd 1153 * 1154 * @return string 1155 * 1156 * @since 1.7.0 1157 */ 1158 public function _getLineEnd() 1159 { 1160 return $this->_lineEnd; 1161 } 1162 1163 /** 1164 * Sets the string used to indent HTML 1165 * 1166 * @param string $string String used to indent ("\11", "\t", ' ', etc.). 1167 * 1168 * @return Document instance of $this to allow chaining 1169 * 1170 * @since 1.7.0 1171 */ 1172 public function setTab($string) 1173 { 1174 $this->_tab = $string; 1175 1176 return $this; 1177 } 1178 1179 /** 1180 * Returns a string containing the unit for indenting HTML 1181 * 1182 * @return string 1183 * 1184 * @since 1.7.0 1185 */ 1186 public function _getTab() 1187 { 1188 return $this->_tab; 1189 } 1190 1191 /** 1192 * Load a renderer 1193 * 1194 * @param string $type The renderer type 1195 * 1196 * @return DocumentRenderer 1197 * 1198 * @since 1.7.0 1199 * @throws \RuntimeException 1200 */ 1201 public function loadRenderer($type) 1202 { 1203 // Determine the path and class 1204 $class = __NAMESPACE__ . '\\Renderer\\' . ucfirst($this->getType()) . '\\' . ucfirst($type) . 'Renderer'; 1205 1206 if (!class_exists($class)) 1207 { 1208 $class = 'JDocumentRenderer' . ucfirst($this->getType()) . ucfirst($type); 1209 } 1210 1211 if (!class_exists($class)) 1212 { 1213 // "Legacy" class name structure 1214 $class = 'JDocumentRenderer' . $type; 1215 1216 if (!class_exists($class)) 1217 { 1218 // @deprecated 4.0 - Non-autoloadable class support is deprecated, only log a message though if a file is found 1219 $path = __DIR__ . '/' . $this->getType() . '/renderer/' . $type . '.php'; 1220 1221 if (!file_exists($path)) 1222 { 1223 throw new \RuntimeException('Unable to load renderer class', 500); 1224 } 1225 1226 \JLoader::register($class, $path); 1227 1228 \JLog::add('Non-autoloadable JDocumentRenderer subclasses are deprecated, support will be removed in 4.0.', \JLog::WARNING, 'deprecated'); 1229 1230 // If the class still doesn't exist after including the path, we've got issues 1231 if (!class_exists($class)) 1232 { 1233 throw new \RuntimeException('Unable to load renderer class', 500); 1234 } 1235 } 1236 } 1237 1238 return new $class($this); 1239 } 1240 1241 /** 1242 * Parses the document and prepares the buffers 1243 * 1244 * @param array $params The array of parameters 1245 * 1246 * @return Document instance of $this to allow chaining 1247 * 1248 * @since 1.7.0 1249 */ 1250 public function parse($params = array()) 1251 { 1252 return $this; 1253 } 1254 1255 /** 1256 * Outputs the document 1257 * 1258 * @param boolean $cache If true, cache the output 1259 * @param array $params Associative array of attributes 1260 * 1261 * @return void The rendered data 1262 * 1263 * @since 1.7.0 1264 */ 1265 public function render($cache = false, $params = array()) 1266 { 1267 $app = \JFactory::getApplication(); 1268 1269 if ($mdate = $this->getModifiedDate()) 1270 { 1271 if (!($mdate instanceof Date)) 1272 { 1273 $mdate = new Date($mdate); 1274 } 1275 1276 $app->modifiedDate = $mdate; 1277 } 1278 1279 $app->mimeType = $this->_mime; 1280 $app->charSet = $this->_charset; 1281 } 1282} 1283