PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

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

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