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\Form; 10 11defined('JPATH_PLATFORM') or die; 12 13use Joomla\CMS\Layout\FileLayout; 14use Joomla\String\Normalise; 15use Joomla\String\StringHelper; 16 17/** 18 * Abstract Form Field class for the Joomla Platform. 19 * 20 * @since 1.7.0 21 */ 22abstract class FormField 23{ 24 /** 25 * The description text for the form field. Usually used in tooltips. 26 * 27 * @var string 28 * @since 1.7.0 29 */ 30 protected $description; 31 32 /** 33 * The hint text for the form field used to display hint inside the field. 34 * 35 * @var string 36 * @since 3.2 37 */ 38 protected $hint; 39 40 /** 41 * The autocomplete state for the form field. If 'off' element will not be automatically 42 * completed by browser. 43 * 44 * @var mixed 45 * @since 3.2 46 */ 47 protected $autocomplete = 'on'; 48 49 /** 50 * The spellcheck state for the form field. 51 * 52 * @var boolean 53 * @since 3.2 54 */ 55 protected $spellcheck = true; 56 57 /** 58 * The autofocus request for the form field. If true element will be automatically 59 * focused on document load. 60 * 61 * @var boolean 62 * @since 3.2 63 */ 64 protected $autofocus = false; 65 66 /** 67 * The SimpleXMLElement object of the `<field>` XML element that describes the form field. 68 * 69 * @var \SimpleXMLElement 70 * @since 1.7.0 71 */ 72 protected $element; 73 74 /** 75 * The Form object of the form attached to the form field. 76 * 77 * @var Form 78 * @since 1.7.0 79 */ 80 protected $form; 81 82 /** 83 * The form control prefix for field names from the JForm object attached to the form field. 84 * 85 * @var string 86 * @since 1.7.0 87 */ 88 protected $formControl; 89 90 /** 91 * The hidden state for the form field. 92 * 93 * @var boolean 94 * @since 1.7.0 95 */ 96 protected $hidden = false; 97 98 /** 99 * True to translate the field label string. 100 * 101 * @var boolean 102 * @since 1.7.0 103 */ 104 protected $translateLabel = true; 105 106 /** 107 * True to translate the field description string. 108 * 109 * @var boolean 110 * @since 1.7.0 111 */ 112 protected $translateDescription = true; 113 114 /** 115 * True to translate the field hint string. 116 * 117 * @var boolean 118 * @since 3.2 119 */ 120 protected $translateHint = true; 121 122 /** 123 * The document id for the form field. 124 * 125 * @var string 126 * @since 1.7.0 127 */ 128 protected $id; 129 130 /** 131 * The input for the form field. 132 * 133 * @var string 134 * @since 1.7.0 135 */ 136 protected $input; 137 138 /** 139 * The label for the form field. 140 * 141 * @var string 142 * @since 1.7.0 143 */ 144 protected $label; 145 146 /** 147 * The multiple state for the form field. If true then multiple values are allowed for the 148 * field. Most often used for list field types. 149 * 150 * @var boolean 151 * @since 1.7.0 152 */ 153 protected $multiple = false; 154 155 /** 156 * Allows extensions to create repeat elements 157 * 158 * @var mixed 159 * @since 3.2 160 */ 161 public $repeat = false; 162 163 /** 164 * The pattern (Reg Ex) of value of the form field. 165 * 166 * @var string 167 * @since 1.7.0 168 */ 169 protected $pattern; 170 171 /** 172 * The validation text of invalid value of the form field. 173 * 174 * @var string 175 * @since 4.0 176 */ 177 protected $validationtext; 178 179 /** 180 * The name of the form field. 181 * 182 * @var string 183 * @since 1.7.0 184 */ 185 protected $name; 186 187 /** 188 * The name of the field. 189 * 190 * @var string 191 * @since 1.7.0 192 */ 193 protected $fieldname; 194 195 /** 196 * The group of the field. 197 * 198 * @var string 199 * @since 1.7.0 200 */ 201 protected $group; 202 203 /** 204 * The required state for the form field. If true then there must be a value for the field to 205 * be considered valid. 206 * 207 * @var boolean 208 * @since 1.7.0 209 */ 210 protected $required = false; 211 212 /** 213 * The disabled state for the form field. If true then the field will be disabled and user can't 214 * interact with the field. 215 * 216 * @var boolean 217 * @since 3.2 218 */ 219 protected $disabled = false; 220 221 /** 222 * The readonly state for the form field. If true then the field will be readonly. 223 * 224 * @var boolean 225 * @since 3.2 226 */ 227 protected $readonly = false; 228 229 /** 230 * The form field type. 231 * 232 * @var string 233 * @since 1.7.0 234 */ 235 protected $type; 236 237 /** 238 * The validation method for the form field. This value will determine which method is used 239 * to validate the value for a field. 240 * 241 * @var string 242 * @since 1.7.0 243 */ 244 protected $validate; 245 246 /** 247 * The value of the form field. 248 * 249 * @var mixed 250 * @since 1.7.0 251 */ 252 protected $value; 253 254 /** 255 * The default value of the form field. 256 * 257 * @var mixed 258 * @since 1.7.0 259 */ 260 protected $default; 261 262 /** 263 * The size of the form field. 264 * 265 * @var integer 266 * @since 3.2 267 */ 268 protected $size; 269 270 /** 271 * The class of the form field 272 * 273 * @var mixed 274 * @since 3.2 275 */ 276 protected $class; 277 278 /** 279 * The label's CSS class of the form field 280 * 281 * @var mixed 282 * @since 1.7.0 283 */ 284 protected $labelclass; 285 286 /** 287 * The javascript onchange of the form field. 288 * 289 * @var string 290 * @since 3.2 291 */ 292 protected $onchange; 293 294 /** 295 * The javascript onclick of the form field. 296 * 297 * @var string 298 * @since 3.2 299 */ 300 protected $onclick; 301 302 /** 303 * The conditions to show/hide the field. 304 * 305 * @var string 306 * @since 3.7.0 307 */ 308 protected $showon; 309 310 /** 311 * The count value for generated name field 312 * 313 * @var integer 314 * @since 1.7.0 315 */ 316 protected static $count = 0; 317 318 /** 319 * The string used for generated fields names 320 * 321 * @var string 322 * @since 1.7.0 323 */ 324 protected static $generated_fieldname = '__field'; 325 326 /** 327 * Name of the layout being used to render the field 328 * 329 * @var string 330 * @since 3.5 331 */ 332 protected $layout; 333 334 /** 335 * Layout to render the form field 336 * 337 * @var string 338 */ 339 protected $renderLayout = 'joomla.form.renderfield'; 340 341 /** 342 * Layout to render the label 343 * 344 * @var string 345 */ 346 protected $renderLabelLayout = 'joomla.form.renderlabel'; 347 348 /** 349 * Method to instantiate the form field object. 350 * 351 * @param Form $form The form to attach to the form field object. 352 * 353 * @since 1.7.0 354 */ 355 public function __construct($form = null) 356 { 357 // If there is a form passed into the constructor set the form and form control properties. 358 if ($form instanceof Form) 359 { 360 $this->form = $form; 361 $this->formControl = $form->getFormControl(); 362 } 363 364 // Detect the field type if not set 365 if (!isset($this->type)) 366 { 367 $parts = Normalise::fromCamelCase(get_called_class(), true); 368 369 if ($parts[0] == 'J') 370 { 371 $this->type = StringHelper::ucfirst($parts[count($parts) - 1], '_'); 372 } 373 else 374 { 375 $this->type = StringHelper::ucfirst($parts[0], '_') . StringHelper::ucfirst($parts[count($parts) - 1], '_'); 376 } 377 } 378 } 379 380 /** 381 * Method to get certain otherwise inaccessible properties from the form field object. 382 * 383 * @param string $name The property name for which to get the value. 384 * 385 * @return mixed The property value or null. 386 * 387 * @since 1.7.0 388 */ 389 public function __get($name) 390 { 391 switch ($name) 392 { 393 case 'description': 394 case 'hint': 395 case 'formControl': 396 case 'hidden': 397 case 'id': 398 case 'multiple': 399 case 'name': 400 case 'required': 401 case 'type': 402 case 'validate': 403 case 'value': 404 case 'class': 405 case 'layout': 406 case 'labelclass': 407 case 'size': 408 case 'onchange': 409 case 'onclick': 410 case 'fieldname': 411 case 'group': 412 case 'disabled': 413 case 'readonly': 414 case 'autofocus': 415 case 'autocomplete': 416 case 'spellcheck': 417 case 'validationtext': 418 case 'showon': 419 return $this->$name; 420 421 case 'input': 422 // If the input hasn't yet been generated, generate it. 423 if (empty($this->input)) 424 { 425 $this->input = $this->getInput(); 426 } 427 428 return $this->input; 429 430 case 'label': 431 // If the label hasn't yet been generated, generate it. 432 if (empty($this->label)) 433 { 434 $this->label = $this->getLabel(); 435 } 436 437 return $this->label; 438 439 case 'title': 440 return $this->getTitle(); 441 } 442 443 return; 444 } 445 446 /** 447 * Method to set certain otherwise inaccessible properties of the form field object. 448 * 449 * @param string $name The property name for which to set the value. 450 * @param mixed $value The value of the property. 451 * 452 * @return void 453 * 454 * @since 3.2 455 */ 456 public function __set($name, $value) 457 { 458 switch ($name) 459 { 460 case 'class': 461 // Removes spaces from left & right and extra spaces from middle 462 $value = preg_replace('/\s+/', ' ', trim((string) $value)); 463 464 case 'description': 465 case 'hint': 466 case 'value': 467 case 'labelclass': 468 case 'layout': 469 case 'onchange': 470 case 'onclick': 471 case 'validate': 472 case 'pattern': 473 case 'validationtext': 474 case 'group': 475 case 'showon': 476 case 'default': 477 $this->$name = (string) $value; 478 break; 479 480 case 'id': 481 $this->id = $this->getId((string) $value, $this->fieldname); 482 break; 483 484 case 'fieldname': 485 $this->fieldname = $this->getFieldName((string) $value); 486 break; 487 488 case 'name': 489 $this->fieldname = $this->getFieldName((string) $value); 490 $this->name = $this->getName($this->fieldname); 491 break; 492 493 case 'multiple': 494 // Allow for field classes to force the multiple values option. 495 $value = (string) $value; 496 $value = $value === '' && isset($this->forceMultiple) ? (string) $this->forceMultiple : $value; 497 498 case 'required': 499 case 'disabled': 500 case 'readonly': 501 case 'autofocus': 502 case 'hidden': 503 $value = (string) $value; 504 $this->$name = ($value === 'true' || $value === $name || $value === '1'); 505 break; 506 507 case 'autocomplete': 508 $value = (string) $value; 509 $value = ($value == 'on' || $value == '') ? 'on' : $value; 510 $this->$name = ($value === 'false' || $value === 'off' || $value === '0') ? false : $value; 511 break; 512 513 case 'spellcheck': 514 case 'translateLabel': 515 case 'translateDescription': 516 case 'translateHint': 517 $value = (string) $value; 518 $this->$name = !($value === 'false' || $value === 'off' || $value === '0'); 519 break; 520 521 case 'translate_label': 522 $value = (string) $value; 523 $this->translateLabel = $this->translateLabel && !($value === 'false' || $value === 'off' || $value === '0'); 524 break; 525 526 case 'translate_description': 527 $value = (string) $value; 528 $this->translateDescription = $this->translateDescription && !($value === 'false' || $value === 'off' || $value === '0'); 529 break; 530 531 case 'size': 532 $this->$name = (int) $value; 533 break; 534 535 default: 536 if (property_exists(__CLASS__, $name)) 537 { 538 \JLog::add("Cannot access protected / private property $name of " . __CLASS__); 539 } 540 else 541 { 542 $this->$name = $value; 543 } 544 } 545 } 546 547 /** 548 * Method to attach a JForm object to the field. 549 * 550 * @param Form $form The JForm object to attach to the form field. 551 * 552 * @return FormField The form field object so that the method can be used in a chain. 553 * 554 * @since 1.7.0 555 */ 556 public function setForm(Form $form) 557 { 558 $this->form = $form; 559 $this->formControl = $form->getFormControl(); 560 561 return $this; 562 } 563 564 /** 565 * Method to attach a JForm object to the field. 566 * 567 * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. 568 * @param mixed $value The form field value to validate. 569 * @param string $group The field name group control value. This acts as as an array container for the field. 570 * For example if the field has name="foo" and the group value is set to "bar" then the 571 * full field name would end up being "bar[foo]". 572 * 573 * @return boolean True on success. 574 * 575 * @since 1.7.0 576 */ 577 public function setup(\SimpleXMLElement $element, $value, $group = null) 578 { 579 // Make sure there is a valid JFormField XML element. 580 if ((string) $element->getName() != 'field') 581 { 582 return false; 583 } 584 585 // Reset the input and label values. 586 $this->input = null; 587 $this->label = null; 588 589 // Set the XML element object. 590 $this->element = $element; 591 592 // Set the group of the field. 593 $this->group = $group; 594 595 $attributes = array( 596 'multiple', 'name', 'id', 'hint', 'class', 'description', 'labelclass', 'onchange', 'onclick', 'validate', 'pattern', 'validationtext', 'default', 597 'required', 'disabled', 'readonly', 'autofocus', 'hidden', 'autocomplete', 'spellcheck', 'translateHint', 'translateLabel', 598 'translate_label', 'translateDescription', 'translate_description', 'size', 'showon'); 599 600 $this->default = isset($element['value']) ? (string) $element['value'] : $this->default; 601 602 // Set the field default value. 603 if ($element['multiple'] && is_string($value) && is_array(json_decode($value, true))) 604 { 605 $this->value = (array) json_decode($value); 606 } 607 else 608 { 609 $this->value = $value; 610 } 611 612 foreach ($attributes as $attributeName) 613 { 614 $this->__set($attributeName, $element[$attributeName]); 615 } 616 617 // Allow for repeatable elements 618 $repeat = (string) $element['repeat']; 619 $this->repeat = ($repeat == 'true' || $repeat == 'multiple' || (!empty($this->form->repeat) && $this->form->repeat == 1)); 620 621 // Set the visibility. 622 $this->hidden = ($this->hidden || (string) $element['type'] == 'hidden'); 623 624 $this->layout = !empty($this->element['layout']) ? (string) $this->element['layout'] : $this->layout; 625 626 // Add required to class list if field is required. 627 if ($this->required) 628 { 629 $this->class = trim($this->class . ' required'); 630 } 631 632 return true; 633 } 634 635 /** 636 * Simple method to set the value 637 * 638 * @param mixed $value Value to set 639 * 640 * @return void 641 * 642 * @since 3.2 643 */ 644 public function setValue($value) 645 { 646 $this->value = $value; 647 } 648 649 /** 650 * Method to get the id used for the field input tag. 651 * 652 * @param string $fieldId The field element id. 653 * @param string $fieldName The field element name. 654 * 655 * @return string The id to be used for the field input tag. 656 * 657 * @since 1.7.0 658 */ 659 protected function getId($fieldId, $fieldName) 660 { 661 $id = ''; 662 663 // If there is a form control set for the attached form add it first. 664 if ($this->formControl) 665 { 666 $id .= $this->formControl; 667 } 668 669 // If the field is in a group add the group control to the field id. 670 if ($this->group) 671 { 672 // If we already have an id segment add the group control as another level. 673 if ($id) 674 { 675 $id .= '_' . str_replace('.', '_', $this->group); 676 } 677 else 678 { 679 $id .= str_replace('.', '_', $this->group); 680 } 681 } 682 683 // If we already have an id segment add the field id/name as another level. 684 if ($id) 685 { 686 $id .= '_' . ($fieldId ? $fieldId : $fieldName); 687 } 688 else 689 { 690 $id .= ($fieldId ? $fieldId : $fieldName); 691 } 692 693 // Clean up any invalid characters. 694 $id = preg_replace('#\W#', '_', $id); 695 696 // If this is a repeatable element, add the repeat count to the ID 697 if ($this->repeat) 698 { 699 $repeatCounter = empty($this->form->repeatCounter) ? 0 : $this->form->repeatCounter; 700 $id .= '-' . $repeatCounter; 701 702 if (strtolower($this->type) == 'radio') 703 { 704 $id .= '-'; 705 } 706 } 707 708 return $id; 709 } 710 711 /** 712 * Method to get the field input markup. 713 * 714 * @return string The field input markup. 715 * 716 * @since 1.7.0 717 */ 718 protected function getInput() 719 { 720 if (empty($this->layout)) 721 { 722 throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); 723 } 724 725 return $this->getRenderer($this->layout)->render($this->getLayoutData()); 726 } 727 728 /** 729 * Method to get the field title. 730 * 731 * @return string The field title. 732 * 733 * @since 1.7.0 734 */ 735 protected function getTitle() 736 { 737 $title = ''; 738 739 if ($this->hidden) 740 { 741 return $title; 742 } 743 744 // Get the label text from the XML element, defaulting to the element name. 745 $title = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name']; 746 $title = $this->translateLabel ? \JText::_($title) : $title; 747 748 return $title; 749 } 750 751 /** 752 * Method to get the field label markup. 753 * 754 * @return string The field label markup. 755 * 756 * @since 1.7.0 757 */ 758 protected function getLabel() 759 { 760 if ($this->hidden) 761 { 762 return ''; 763 } 764 765 $data = $this->getLayoutData(); 766 767 // Forcing the Alias field to display the tip below 768 $position = $this->element['name'] == 'alias' ? ' data-placement="bottom" ' : ''; 769 770 // Here mainly for B/C with old layouts. This can be done in the layouts directly 771 $extraData = array( 772 'text' => $data['label'], 773 'for' => $this->id, 774 'classes' => explode(' ', $data['labelclass']), 775 'position' => $position, 776 ); 777 778 return $this->getRenderer($this->renderLabelLayout)->render(array_merge($data, $extraData)); 779 } 780 781 /** 782 * Method to get the name used for the field input tag. 783 * 784 * @param string $fieldName The field element name. 785 * 786 * @return string The name to be used for the field input tag. 787 * 788 * @since 1.7.0 789 */ 790 protected function getName($fieldName) 791 { 792 // To support repeated element, extensions can set this in plugin->onRenderSettings 793 794 $name = ''; 795 796 // If there is a form control set for the attached form add it first. 797 if ($this->formControl) 798 { 799 $name .= $this->formControl; 800 } 801 802 // If the field is in a group add the group control to the field name. 803 if ($this->group) 804 { 805 // If we already have a name segment add the group control as another level. 806 $groups = explode('.', $this->group); 807 808 if ($name) 809 { 810 foreach ($groups as $group) 811 { 812 $name .= '[' . $group . ']'; 813 } 814 } 815 else 816 { 817 $name .= array_shift($groups); 818 819 foreach ($groups as $group) 820 { 821 $name .= '[' . $group . ']'; 822 } 823 } 824 } 825 826 // If we already have a name segment add the field name as another level. 827 if ($name) 828 { 829 $name .= '[' . $fieldName . ']'; 830 } 831 else 832 { 833 $name .= $fieldName; 834 } 835 836 // If the field should support multiple values add the final array segment. 837 if ($this->multiple) 838 { 839 switch (strtolower((string) $this->element['type'])) 840 { 841 case 'text': 842 case 'textarea': 843 case 'email': 844 case 'password': 845 case 'radio': 846 case 'calendar': 847 case 'editor': 848 case 'hidden': 849 break; 850 default: 851 $name .= '[]'; 852 } 853 } 854 855 return $name; 856 } 857 858 /** 859 * Method to get the field name used. 860 * 861 * @param string $fieldName The field element name. 862 * 863 * @return string The field name 864 * 865 * @since 1.7.0 866 */ 867 protected function getFieldName($fieldName) 868 { 869 if ($fieldName) 870 { 871 return $fieldName; 872 } 873 else 874 { 875 self::$count = self::$count + 1; 876 877 return self::$generated_fieldname . self::$count; 878 } 879 } 880 881 /** 882 * Method to get an attribute of the field 883 * 884 * @param string $name Name of the attribute to get 885 * @param mixed $default Optional value to return if attribute not found 886 * 887 * @return mixed Value of the attribute / default 888 * 889 * @since 3.2 890 */ 891 public function getAttribute($name, $default = null) 892 { 893 if ($this->element instanceof \SimpleXMLElement) 894 { 895 $attributes = $this->element->attributes(); 896 897 // Ensure that the attribute exists 898 if ($attributes->$name !== null) 899 { 900 return (string) $attributes->$name; 901 } 902 } 903 904 return $default; 905 } 906 907 /** 908 * Method to get a control group with label and input. 909 * 910 * @return string A string containing the html for the control group 911 * 912 * @since 3.2 913 * @deprecated 3.2.3 Use renderField() instead 914 */ 915 public function getControlGroup() 916 { 917 \JLog::add('FormField->getControlGroup() is deprecated use FormField->renderField().', \JLog::WARNING, 'deprecated'); 918 919 return $this->renderField(); 920 } 921 922 /** 923 * Render a layout of this field 924 * 925 * @param string $layoutId Layout identifier 926 * @param array $data Optional data for the layout 927 * 928 * @return string 929 * 930 * @since 3.5 931 */ 932 public function render($layoutId, $data = array()) 933 { 934 $data = array_merge($this->getLayoutData(), $data); 935 936 return $this->getRenderer($layoutId)->render($data); 937 } 938 939 /** 940 * Method to get a control group with label and input. 941 * 942 * @param array $options Options to be passed into the rendering of the field 943 * 944 * @return string A string containing the html for the control group 945 * 946 * @since 3.2 947 */ 948 public function renderField($options = array()) 949 { 950 if ($this->hidden) 951 { 952 return $this->getInput(); 953 } 954 955 if (!isset($options['class'])) 956 { 957 $options['class'] = ''; 958 } 959 960 $options['rel'] = ''; 961 962 if (empty($options['hiddenLabel']) && $this->getAttribute('hiddenLabel')) 963 { 964 $options['hiddenLabel'] = true; 965 } 966 967 if ($this->showon) 968 { 969 $options['rel'] = ' data-showon=\'' . 970 json_encode(FormHelper::parseShowOnConditions($this->showon, $this->formControl, $this->group)) . '\''; 971 $options['showonEnabled'] = true; 972 } 973 974 $data = array( 975 'input' => $this->getInput(), 976 'label' => $this->getLabel(), 977 'options' => $options, 978 ); 979 980 return $this->getRenderer($this->renderLayout)->render($data); 981 } 982 983 /** 984 * Method to get the data to be passed to the layout for rendering. 985 * 986 * @return array 987 * 988 * @since 3.5 989 */ 990 protected function getLayoutData() 991 { 992 // Label preprocess 993 $label = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name']; 994 $label = $this->translateLabel ? \JText::_($label) : $label; 995 996 // Description preprocess 997 $description = !empty($this->description) ? $this->description : null; 998 $description = !empty($description) && $this->translateDescription ? \JText::_($description) : $description; 999 1000 $alt = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname); 1001 1002 return array( 1003 'autocomplete' => $this->autocomplete, 1004 'autofocus' => $this->autofocus, 1005 'class' => $this->class, 1006 'description' => $description, 1007 'disabled' => $this->disabled, 1008 'field' => $this, 1009 'group' => $this->group, 1010 'hidden' => $this->hidden, 1011 'hint' => $this->translateHint ? \JText::alt($this->hint, $alt) : $this->hint, 1012 'id' => $this->id, 1013 'label' => $label, 1014 'labelclass' => $this->labelclass, 1015 'multiple' => $this->multiple, 1016 'name' => $this->name, 1017 'onchange' => $this->onchange, 1018 'onclick' => $this->onclick, 1019 'pattern' => $this->pattern, 1020 'validationtext' => $this->validationtext, 1021 'readonly' => $this->readonly, 1022 'repeat' => $this->repeat, 1023 'required' => (bool) $this->required, 1024 'size' => $this->size, 1025 'spellcheck' => $this->spellcheck, 1026 'validate' => $this->validate, 1027 'value' => $this->value, 1028 ); 1029 } 1030 1031 /** 1032 * Allow to override renderer include paths in child fields 1033 * 1034 * @return array 1035 * 1036 * @since 3.5 1037 */ 1038 protected function getLayoutPaths() 1039 { 1040 $renderer = new FileLayout('default'); 1041 1042 return $renderer->getDefaultIncludePaths(); 1043 } 1044 1045 /** 1046 * Get the renderer 1047 * 1048 * @param string $layoutId Id to load 1049 * 1050 * @return FileLayout 1051 * 1052 * @since 3.5 1053 */ 1054 protected function getRenderer($layoutId = 'default') 1055 { 1056 $renderer = new FileLayout($layoutId); 1057 1058 $renderer->setDebug($this->isDebugEnabled()); 1059 1060 $layoutPaths = $this->getLayoutPaths(); 1061 1062 if ($layoutPaths) 1063 { 1064 $renderer->setIncludePaths($layoutPaths); 1065 } 1066 1067 return $renderer; 1068 } 1069 1070 /** 1071 * Is debug enabled for this field 1072 * 1073 * @return boolean 1074 * 1075 * @since 3.5 1076 */ 1077 protected function isDebugEnabled() 1078 { 1079 return $this->getAttribute('debug', 'false') === 'true'; 1080 } 1081} 1082