PageRenderTime 34ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/administrator/components/com_jce/classes/parameter.php

https://bitbucket.org/organicdevelopment/joomla-2.5
PHP | 608 lines | 314 code | 104 blank | 190 comment | 71 complexity | 9bf9fbda7682dc5d59cd0696657a1dec MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * @package JCE
  4. * @copyright Copyright (c) 2009-2012 Ryan Demmer. All rights reserved.
  5. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  6. * @license GNU/GPL 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  7. * JCE is free software. This version may have been modified pursuant
  8. * to the GNU General Public License, and as distributed it includes or
  9. * is derivative of works licensed under the GNU General Public License or
  10. * other free or open source software licenses.
  11. */
  12. defined('_JEXEC') or die('RESTRICTED');
  13. // Register the element class with the loader.
  14. JLoader::register('WFElement', dirname(__FILE__) . '/element.php');
  15. class WFParameter {
  16. /**
  17. * @var object The params data object
  18. */
  19. protected $data = null;
  20. /**
  21. * @var array The params keys array
  22. */
  23. protected $key = null;
  24. /**
  25. * @var object The XML params element
  26. * @since 2.2.5
  27. */
  28. protected $xml = null;
  29. /**
  30. * @var array Loaded elements
  31. * @since 2.2.5
  32. */
  33. protected $elements = array();
  34. /**
  35. * @var string Parameter control
  36. * @since 2.2.5
  37. */
  38. protected $control = 'params';
  39. /**
  40. * @var array Directories, where element types can be stored
  41. * @since 2.2.5
  42. */
  43. protected $elementPath = array();
  44. function __construct($data = null, $path = '', $keys = null, $config = array()) {
  45. //parent::__construct('_default');
  46. if (array_key_exists('control', $config)) {
  47. $this->control = $config['control'];
  48. }
  49. // Set base path.
  50. $this->addElementPath(dirname(dirname(__FILE__)) . '/elements');
  51. /* if ($data = trim($data)) {
  52. $this->loadString($data);
  53. } */
  54. if ($path) {
  55. $this->loadSetupFile($path);
  56. }
  57. //$this->_raw = $data;
  58. $this->data = new StdClass();
  59. if ($data) {
  60. if (!is_object($data)) {
  61. $data = json_decode($data);
  62. }
  63. if ($keys) {
  64. if (!is_array($keys)) {
  65. $keys = explode('.', $keys);
  66. }
  67. $this->key = $keys;
  68. foreach ($keys as $key) {
  69. $data = isset($data->$key) ? $data->$key : $data;
  70. }
  71. }
  72. $this->bindData($this->data, $data);
  73. }
  74. }
  75. /**
  76. * Loads an XML setup file and parses it.
  77. *
  78. * @param string $path A path to the XML setup file.
  79. *
  80. * @return object
  81. * @since 2.2.5
  82. */
  83. public function loadSetupFile($path) {
  84. $result = false;
  85. if ($path) {
  86. /* $xml = JFactory::getXMLParser('Simple');
  87. if ($xml->loadFile($path)) {
  88. if ($params = $xml->document->params) {
  89. foreach ($params as $param) {
  90. $this->setXML($param);
  91. $result = true;
  92. }
  93. }
  94. } */
  95. $controls = explode(':', $this->control);
  96. if ($xml = WFXMLElement::getXML($path)) {
  97. $params = $xml;
  98. foreach ($controls as $control) {
  99. $params = $params->$control;
  100. }
  101. //if ($params = $xml->$control) {
  102. foreach ($params as $param) {
  103. $this->setXML($param);
  104. $result = true;
  105. }
  106. //}
  107. }
  108. } else {
  109. $result = true;
  110. }
  111. return $result;
  112. }
  113. /**
  114. * Sets the XML object from custom XML files.
  115. *
  116. * @param JSimpleXMLElement &$xml An XML object.
  117. *
  118. * @return void
  119. * @since 2.2.5
  120. */
  121. public function setXML(&$xml) {
  122. if (is_object($xml)) {
  123. if ($group = (string) $xml->attributes()->group) {
  124. $this->xml[$group] = $xml;
  125. } else {
  126. $this->xml['_default'] = $xml;
  127. }
  128. if ($dir = (string) $xml->attributes()->addpath) {
  129. $this->addElementPath(JPATH_ROOT . $dir);
  130. }
  131. }
  132. }
  133. /**
  134. * Add a directory where JParameter should search for element types.
  135. *
  136. * You may either pass a string or an array of directories.
  137. *
  138. * JParameter will be searching for a element type in the same
  139. * order you added them. If the parameter type cannot be found in
  140. * the custom folders, it will look in
  141. * JParameter/types.
  142. *
  143. * @param mixed $path Directory (string) or directories (array) to search.
  144. *
  145. * @return void
  146. * @since 2.2.5
  147. */
  148. public function addElementPath($path) {
  149. // Just force path to array.
  150. settype($path, 'array');
  151. // Loop through the path directories.
  152. foreach ($path as $dir) {
  153. // No surrounding spaces allowed!
  154. $dir = trim($dir);
  155. // Add trailing separators as needed.
  156. if (substr($dir, -1) != DIRECTORY_SEPARATOR) {
  157. // Directory
  158. $dir .= DIRECTORY_SEPARATOR;
  159. }
  160. // Add to the top of the search dirs.
  161. array_unshift($this->elementPath, $dir);
  162. }
  163. }
  164. /**
  165. * Loads an element type.
  166. *
  167. * @param string $type The element type.
  168. * @param boolean $new False (default) to reuse parameter elements; true to load the parameter element type again.
  169. *
  170. * @return object
  171. * @since 2.2.5
  172. */
  173. public function loadElement($type, $new = false) {
  174. $signature = md5($type);
  175. if ((isset($this->elements[$signature]) && !($this->elements[$signature] instanceof __PHP_Incomplete_Class)) && $new === false) {
  176. return $this->elements[$signature];
  177. }
  178. $elementClass = 'WFElement' . $type;
  179. if (!class_exists($elementClass)) {
  180. if (isset($this->elementPath)) {
  181. $dirs = $this->elementPath;
  182. } else {
  183. $dirs = array();
  184. }
  185. $file = JFilterInput::getInstance()->clean(str_replace('_', DS, $type) . '.php', 'path');
  186. jimport('joomla.filesystem.path');
  187. if ($elementFile = JPath::find($dirs, $file)) {
  188. include_once $elementFile;
  189. } else {
  190. $false = false;
  191. return $false;
  192. }
  193. }
  194. if (!class_exists($elementClass)) {
  195. $false = false;
  196. return $false;
  197. }
  198. $this->elements[$signature] = new $elementClass($this);
  199. return $this->elements[$signature];
  200. }
  201. /**
  202. * Bind data to the parameter.
  203. *
  204. * @param mixed $data An array or object.
  205. * @param string $group An optional group that the data should bind to. The default group is used if not supplied.
  206. *
  207. * @return boolean True if the data was successfully bound, false otherwise.
  208. */
  209. public function bind($data) {
  210. if (is_array($data)) {
  211. return $this->bindData($this->data, $data);
  212. } else if (is_object($data)) {
  213. return $this->bindData($this->data, $data);
  214. } else {
  215. return $this->bindData($this->data, json_decode($data));
  216. }
  217. }
  218. /**
  219. * Method to recursively bind data to a parent object.
  220. *
  221. * @param object $parent The parent object on which to attach the data values.
  222. * @param mixed $data An array or object of data to bind to the parent object.
  223. *
  224. * @return void
  225. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  226. */
  227. protected function bindData(&$parent, $data) {
  228. // Ensure the input data is an array.
  229. if (is_object($data)) {
  230. $data = get_object_vars($data);
  231. } else {
  232. $data = (array) $data;
  233. }
  234. foreach ($data as $k => $v) {
  235. if (self::is_assoc($v) || is_object($v)) {
  236. $parent->$k = new stdClass();
  237. $this->bindData($parent->$k, $v);
  238. } else {
  239. $parent->$k = $v;
  240. }
  241. }
  242. }
  243. /**
  244. * Return the number of parameters in a group.
  245. *
  246. * @param string $group An optional group. The default group is used if not supplied.
  247. *
  248. * @return mixed False if no params exist or integer number of parameters that exist.
  249. * @since 2.2.5
  250. */
  251. public function getNumParams($group = '_default') {
  252. if (!isset($this->xml[$group]) || !count($this->xml[$group]->children())) {
  253. return false;
  254. } else {
  255. return count($this->xml[$group]->children());
  256. }
  257. }
  258. /**
  259. * Get the number of params in each group.
  260. *
  261. * @return array Array of all group names as key and parameters count as value.
  262. * @since 2.2.5
  263. */
  264. public function getGroups() {
  265. if (!is_array($this->xml)) {
  266. return false;
  267. }
  268. $results = array();
  269. foreach ($this->xml as $name => $group) {
  270. $results[$name] = $this->getNumParams($name);
  271. }
  272. return $results;
  273. }
  274. public function getAll($name = '') {
  275. $results = array();
  276. if ($name) {
  277. $groups = array($name => $this->getNumParams($name));
  278. } else {
  279. $groups = $this->getGroups();
  280. }
  281. foreach ($groups as $group => $num) {
  282. if (!isset($this->xml[$group])) {
  283. return null;
  284. }
  285. $data = new StdClass();
  286. foreach ($this->xml[$group]->children() as $param) {
  287. $key = (string) $param->attributes()->name;
  288. $value = $this->get($key, (string) $param->attributes()->default);
  289. $data->$key = $value;
  290. }
  291. $results[$group] = $data;
  292. }
  293. if ($name) {
  294. return $results[$name];
  295. }
  296. return $results;
  297. }
  298. private function isEmpty($value) {
  299. return (is_string($value) && $value == "") || (is_array($value) && empty($value));
  300. }
  301. /**
  302. * Get a parameter value.
  303. *
  304. * @param string Registry path (e.g. editor.width)
  305. * @param string Optional default value, returned if the internal value is null.
  306. * @return mixed Value of entry or null
  307. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  308. */
  309. public function get($path, $default = '', $allowempty = true) {
  310. // set default value as result
  311. $result = $default;
  312. // Explode the registry path into an array
  313. $nodes = is_array($path) ? $path : explode('.', $path);
  314. // Initialize the current node to be the registry root.
  315. $node = $this->data;
  316. $found = false;
  317. // Traverse the registry to find the correct node for the result.
  318. foreach ($nodes as $n) {
  319. if (isset($node->$n)) {
  320. $node = $node->$n;
  321. $found = true;
  322. } else {
  323. $found = false;
  324. break;
  325. }
  326. }
  327. if ($found) {
  328. $result = $node;
  329. if ($allowempty === false) {
  330. if (self::isEmpty($result)) {
  331. $result = $default;
  332. }
  333. }
  334. }
  335. // convert to float if numeric
  336. if (is_numeric($result)) {
  337. $result = (float) $result;
  338. }
  339. return $result;
  340. }
  341. /**
  342. * Render all parameters
  343. *
  344. * @access public
  345. * @param string The name of the control, or the default text area if a setup file is not found
  346. * @return array Array of all parameters, each as array Any array of the label, the form element and the tooltip
  347. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  348. */
  349. public function getParams($name = 'params', $group = '_default') {
  350. if (!isset($this->xml[$group])) {
  351. return false;
  352. }
  353. $results = array();
  354. $parent = (string) $this->xml[$group]->attributes()->parent;
  355. foreach ($this->xml[$group]->children() as $param) {
  356. $results[] = $this->getParam($param, $name, $group, $parent);
  357. $parameters = (string) $param->attributes()->parameters;
  358. // get sub-parameters
  359. if ($parameters) {
  360. jimport('joomla.filesystem.folder');
  361. // load manifest files for extensions
  362. $files = JFolder::files(JPATH_SITE . DS . $parameters, '\.xml$', false, true);
  363. // get the base key for the parameter
  364. $keys = explode('.', (string) $param->attributes()->name);
  365. foreach ($files as $file) {
  366. $key = $keys[0] . '.' . basename($file, '.xml');
  367. $results[] = new WFParameter($this->data, $file, $key);
  368. }
  369. }
  370. }
  371. return $results;
  372. }
  373. /**
  374. * Render a parameter type
  375. *
  376. * @param object A param tag node
  377. * @param string The control name
  378. * @return array Any array of the label, the form element and the tooltip
  379. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  380. */
  381. public function getParam(&$node, $control_name = 'params', $group = '_default', $parent = '') {
  382. //get the type of the parameter
  383. $type = (string) $node->attributes()->type;
  384. $element = $this->loadElement($type);
  385. // error happened
  386. if ($element === false) {
  387. $result = array();
  388. $result[0] = (string) $node->attributes()->name;
  389. $result[1] = WFText::_('Element not defined for type') . ' = ' . $type;
  390. $result[5] = $result[0];
  391. return $result;
  392. }
  393. $key = (string) $node->attributes()->name;
  394. if ((string) $node->attributes()->group) {
  395. $key = (string) $node->attributes()->group . '.' . $key;
  396. }
  397. // get value
  398. $value = $this->get($key, (string) $node->attributes()->default);
  399. // get value if value is object or has parent
  400. if (is_object($value) || $parent) {
  401. $group = $parent ? $parent . '.' . $group : $group;
  402. $value = $this->get($group . '.' . (string) $node->attributes()->name, (string) $node->attributes()->default);
  403. }
  404. return $element->render($node, $value, $control_name);
  405. }
  406. private function _cleanAttribute($matches) {
  407. return $matches[1] . '="' . preg_replace('#([^a-z0-9_-]+)#i', '', $matches[2]) . '"';
  408. }
  409. public function render($name = 'params', $group = '_default') {
  410. $params = $this->getParams($name, $group);
  411. $html = '<ul class="adminformlist">';
  412. foreach ($params as $item) {
  413. //if (is_a($item, 'WFParameter')) {
  414. if ($item instanceof WFParameter) {
  415. foreach ($item->getGroups() as $group => $num) {
  416. $label = $group;
  417. $class = '';
  418. $parent = '';
  419. $xml = $item->xml[$group];
  420. if ((string) $xml->attributes()->parent) {
  421. $parent = '[' . (string) $xml->attributes()->parent . '][' . $group . ']';
  422. $class = ' class="' . (string) $xml->attributes()->parent . '"';
  423. $label = (string) $xml->attributes()->parent . '_' . $group;
  424. }
  425. $html .= '<div data-type="' . $group . '"' . $class . '>';
  426. $html .= '<h4>' . WFText::_('WF_' . strtoupper($label) . '_TITLE') . '</h4>';
  427. //$html .= $item->render($name . '[' . $parent . '][' . $group . ']', $group);
  428. $html .= $item->render($name . $parent, $group);
  429. $html .= '</div>';
  430. }
  431. } else {
  432. $label = preg_replace_callback('#(for|id)="([^"]+)"#', array($this, '_cleanAttribute'), $item[0]);
  433. $element = preg_replace_callback('#(id)="([^"]+)"#', array($this, '_cleanAttribute'), $item[1]);
  434. $html .= '<li>' . $label . $element;
  435. }
  436. }
  437. $html .= '</li></ul>';
  438. return $html;
  439. }
  440. /**
  441. * Check if a parent attribute is set. If it is, this parameter groups is included by the parent
  442. */
  443. public function hasParent() {
  444. foreach ($this->xml as $name => $group) {
  445. if ((string) $group->attributes()->parent) {
  446. return true;
  447. }
  448. }
  449. return false;
  450. }
  451. public static function mergeParams($params1, $params2, $toObject = true) {
  452. $merged = $params1;
  453. foreach ($params2 as $key => $value) {
  454. if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
  455. $merged[$key] = self::mergeParams($merged[$key], $value);
  456. } else {
  457. if ($value !== '') {
  458. $merged[$key] = $value;
  459. }
  460. }
  461. }
  462. if ($toObject) {
  463. return self::array_to_object($merged);
  464. }
  465. return $merged;
  466. }
  467. /**
  468. * Method to determine if an array is an associative array.
  469. *
  470. * @param array An array to test.
  471. * @return boolean True if the array is an associative array.
  472. * @link http://www.php.net/manual/en/function.is-array.php#98305
  473. */
  474. private static function is_assoc($array) {
  475. return (is_array($array) && (count($array) == 0 || 0 !== count(array_diff_key($array, array_keys(array_keys($array))))));
  476. }
  477. /**
  478. * Convert an associate array to an object
  479. * @param array Associative array
  480. */
  481. private static function array_to_object($array) {
  482. $object = new StdClass();
  483. foreach ($array as $key => $value) {
  484. $object->$key = is_array($value) ? self::array_to_object($value) : $value;
  485. }
  486. return $object;
  487. }
  488. /**
  489. * Get Parameter data
  490. * @param boolean $toString Return as JSON string
  491. * @return object or string
  492. */
  493. public function getData($toString = false) {
  494. if ($toString) {
  495. return json_encode($this->data);
  496. }
  497. return $this->data;
  498. }
  499. }