1<?php
2/**
3 * @package     Joomla.Platform
4 * @subpackage  Form
5 *
6 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
7 * @license     GNU General Public License version 2 or later; see LICENSE
8 */
9
10defined('JPATH_PLATFORM') or die;
11
12jimport('joomla.filesystem.folder');
13jimport('joomla.filesystem.path');
14
15JFormHelper::loadFieldClass('list');
16
17/**
18 * Supports an HTML select list of folder
19 *
20 * @since  1.7.0
21 */
22class JFormFieldFolderList extends JFormFieldList
23{
24	/**
25	 * The form field type.
26	 *
27	 * @var    string
28	 * @since  1.7.0
29	 */
30	protected $type = 'FolderList';
31
32	/**
33	 * The filter.
34	 *
35	 * @var    string
36	 * @since  3.2
37	 */
38	protected $filter;
39
40	/**
41	 * The exclude.
42	 *
43	 * @var    string
44	 * @since  3.2
45	 */
46	protected $exclude;
47
48	/**
49	 * The recursive.
50	 *
51	 * @var    string
52	 * @since  3.6
53	 */
54	protected $recursive;
55
56	/**
57	 * The hideNone.
58	 *
59	 * @var    boolean
60	 * @since  3.2
61	 */
62	protected $hideNone = false;
63
64	/**
65	 * The hideDefault.
66	 *
67	 * @var    boolean
68	 * @since  3.2
69	 */
70	protected $hideDefault = false;
71
72	/**
73	 * The directory.
74	 *
75	 * @var    string
76	 * @since  3.2
77	 */
78	protected $directory;
79
80	/**
81	 * Method to get certain otherwise inaccessible properties from the form field object.
82	 *
83	 * @param   string  $name  The property name for which to get the value.
84	 *
85	 * @return  mixed  The property value or null.
86	 *
87	 * @since   3.2
88	 */
89	public function __get($name)
90	{
91		switch ($name)
92		{
93			case 'filter':
94			case 'exclude':
95			case 'recursive':
96			case 'hideNone':
97			case 'hideDefault':
98			case 'directory':
99				return $this->$name;
100		}
101
102		return parent::__get($name);
103	}
104
105	/**
106	 * Method to set certain otherwise inaccessible properties of the form field object.
107	 *
108	 * @param   string  $name   The property name for which to set the value.
109	 * @param   mixed   $value  The value of the property.
110	 *
111	 * @return  void
112	 *
113	 * @since   3.2
114	 */
115	public function __set($name, $value)
116	{
117		switch ($name)
118		{
119			case 'filter':
120			case 'directory':
121			case 'exclude':
122			case 'recursive':
123				$this->$name = (string) $value;
124				break;
125
126			case 'hideNone':
127			case 'hideDefault':
128				$value = (string) $value;
129				$this->$name = ($value === 'true' || $value === $name || $value === '1');
130				break;
131
132			default:
133				parent::__set($name, $value);
134		}
135	}
136
137	/**
138	 * Method to attach a JForm object to the field.
139	 *
140	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
141	 * @param   mixed             $value    The form field value to validate.
142	 * @param   string            $group    The field name group control value. This acts as an array container for the field.
143	 *                                      For example if the field has name="foo" and the group value is set to "bar" then the
144	 *                                      full field name would end up being "bar[foo]".
145	 *
146	 * @return  boolean  True on success.
147	 *
148	 * @see     JFormField::setup()
149	 * @since   3.2
150	 */
151	public function setup(SimpleXMLElement $element, $value, $group = null)
152	{
153		$return = parent::setup($element, $value, $group);
154
155		if ($return)
156		{
157			$this->filter  = (string) $this->element['filter'];
158			$this->exclude = (string) $this->element['exclude'];
159
160			$recursive       = (string) $this->element['recursive'];
161			$this->recursive = ($recursive == 'true' || $recursive == 'recursive' || $recursive == '1');
162
163			$hideNone       = (string) $this->element['hide_none'];
164			$this->hideNone = ($hideNone == 'true' || $hideNone == 'hideNone' || $hideNone == '1');
165
166			$hideDefault       = (string) $this->element['hide_default'];
167			$this->hideDefault = ($hideDefault == 'true' || $hideDefault == 'hideDefault' || $hideDefault == '1');
168
169			// Get the path in which to search for file options.
170			$this->directory = (string) $this->element['directory'];
171		}
172
173		return $return;
174	}
175
176	/**
177	 * Method to get the field options.
178	 *
179	 * @return  array  The field option objects.
180	 *
181	 * @since   1.7.0
182	 */
183	protected function getOptions()
184	{
185		$options = array();
186
187		$path = $this->directory;
188
189		if (!is_dir($path))
190		{
191			if (is_dir(JPATH_ROOT . '/' . $path))
192			{
193				$path = JPATH_ROOT . '/' . $path;
194			}
195			else
196			{
197				return;
198			}
199		}
200
201		$path = JPath::clean($path);
202
203		// Prepend some default options based on field attributes.
204		if (!$this->hideNone)
205		{
206			$options[] = JHtml::_('select.option', '-1', JText::alt('JOPTION_DO_NOT_USE', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname)));
207		}
208
209		if (!$this->hideDefault)
210		{
211			$options[] = JHtml::_('select.option', '', JText::alt('JOPTION_USE_DEFAULT', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname)));
212		}
213
214		// Get a list of folders in the search path with the given filter.
215		$folders = JFolder::folders($path, $this->filter, $this->recursive, true);
216
217		// Build the options list from the list of folders.
218		if (is_array($folders))
219		{
220			foreach ($folders as $folder)
221			{
222				// Remove the root part and the leading /
223				$folder = trim(str_replace($path, '', $folder), '/');
224
225				// Check to see if the file is in the exclude mask.
226				if ($this->exclude)
227				{
228					if (preg_match(chr(1) . $this->exclude . chr(1), $folder))
229					{
230						continue;
231					}
232				}
233
234				$options[] = JHtml::_('select.option', $folder, $folder);
235			}
236		}
237
238		// Merge any additional options in the XML definition.
239		$options = array_merge(parent::getOptions(), $options);
240
241		return $options;
242	}
243}
244