PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/rokcommon/RokCommon/Config.php

https://bitbucket.org/pastor399/newcastleunifc
PHP | 781 lines | 385 code | 109 blank | 287 comment | 46 complexity | 5f544ac580be98c80e68723482351219 MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id: Config.php 57540 2012-10-14 18:27:59Z btowles $
  4. * @author RocketTheme http://www.rockettheme.com
  5. * @copyright Copyright (C) 2007 - ${copyright_year} RocketTheme, LLC
  6. * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
  7. */
  8. defined('ROKCOMMON') or die;
  9. /**
  10. *
  11. */
  12. class RokCommon_Config_Exception extends Exception
  13. {
  14. }
  15. /**
  16. *
  17. */
  18. class RokCommon_Config_PathInfo
  19. {
  20. /**
  21. * @var string
  22. */
  23. public $name;
  24. /**
  25. * @var string
  26. */
  27. public $displayName;
  28. }
  29. /**
  30. *
  31. */
  32. class RokCommon_Config
  33. {
  34. /**
  35. * @var
  36. */
  37. protected static $parameters;
  38. /**
  39. * @const string
  40. */
  41. const CONTEXT_PREFIX = 'config';
  42. /**
  43. *
  44. */
  45. const ENTRY_SEPERATOR = '_';
  46. /**
  47. *
  48. */
  49. const MODE_BASEDIR = 'basedir';
  50. /**
  51. *
  52. */
  53. const MODE_CHILDDIR = 'childdir';
  54. /**
  55. *
  56. */
  57. const JOINTYPE_MERGE = 'merge';
  58. /**
  59. *
  60. */
  61. const JOINTYPE_OVERRIDE = 'override';
  62. /**
  63. * @const int
  64. */
  65. const ORDERING_DEFAULT = 100;
  66. /**
  67. * @var RokCommon_Platform_Info
  68. */
  69. protected static $platform_info;
  70. /**
  71. * @var RokCommon_XMLElement
  72. */
  73. protected $xml_node;
  74. /**
  75. * @var string[]
  76. */
  77. protected $paths = array();
  78. /**
  79. * @var RokCommon_Config_PathInfo[]
  80. */
  81. protected $path_configs_info = array();
  82. /**
  83. * @var string
  84. */
  85. protected $name;
  86. /**
  87. * The filename the meta entry looks for
  88. * @var string
  89. */
  90. protected $filename;
  91. /** @var RokCommon_Composite_Context */
  92. protected $context;
  93. /** @var string */
  94. protected $mode = self::MODE_BASEDIR;
  95. /**
  96. * @var
  97. */
  98. protected $jointype = self::JOINTYPE_MERGE;
  99. /**
  100. * @var RokCommon_Config[]
  101. */
  102. protected $subentries = array();
  103. /**
  104. * @var #Fimplode|?
  105. */
  106. protected $identifier;
  107. /** @var RokCommon_Config */
  108. protected $parent;
  109. /** @var string */
  110. protected $root_file;
  111. /**
  112. * @var
  113. */
  114. protected $joined_xml;
  115. /**
  116. * @var string
  117. */
  118. protected $parent_identifier;
  119. /** @var RokCommon_Service_Container */
  120. protected $container;
  121. /**
  122. * @throws \RokCommon_Config_Exception
  123. */
  124. protected function process()
  125. {
  126. /** @var $ret array */
  127. $ret = array();
  128. if ($this->context) {
  129. if ($this->mode == self::MODE_BASEDIR) {
  130. $ret = $this->context->getAll($this->filename);
  131. } elseif ($this->mode == self::MODE_CHILDDIR) {
  132. $ret = $this->context->getAllSubFiles($this->filename);
  133. } else {
  134. throw new RokCommon_Config_Exception(rc__('Unknown mode of %s on config', $this->mode));
  135. }
  136. ksort($ret, SORT_NUMERIC);
  137. $parameters = new RokCommon_Registry();
  138. foreach ($ret as $priority => $files) {
  139. foreach ($files as $file) {
  140. $file_xml = RokCommon_Utils_XMLHelper::getXML($file, true);
  141. if (!isset($file_xml['name'])) {
  142. throw new RokCommon_Config_Exception(rc__('No "name" attribute defined on config %s', $file));
  143. }
  144. // add the infomation to the container
  145. $param_path = explode('_', $this->identifier);
  146. $param_path[] = (string)$file_xml['name'];
  147. self::$parameters->set(implode('.', $param_path) . '.name', (string)$file_xml['name']);
  148. self::$parameters->set(implode('.', $param_path) . '.display_name', (isset($file_xml['displayName'])) ? (string)$file_xml['displayName'] : $file_xml['name']);
  149. self::$parameters->set(implode('.', $param_path) . '.config_file', $file);
  150. $this->container->addParameters(self::$parameters->toArray());
  151. self::mergeNodes($this->joined_xml, $file_xml);
  152. }
  153. }
  154. foreach ($this->subentries as $subentry) {
  155. if ($this->jointype == self::JOINTYPE_MERGE) {
  156. self::mergeNodes($this->joined_xml, $subentry->get());
  157. } else {
  158. throw new RokCommon_Config_Exception(rc__('Unknown Join Type of %s on config', $this->jointype));
  159. }
  160. }
  161. }
  162. //self::reorderNodes($this->joined_xml);
  163. }
  164. /**
  165. * @return \RokCommon_XMLElement
  166. */
  167. public function get()
  168. {
  169. return $this->joined_xml;
  170. }
  171. /**
  172. * @param $identifier
  173. *
  174. * @return \RokCommon_Config_PathInfo[]
  175. */
  176. public function getPathConfigsInfo($identifier)
  177. {
  178. if ($this->identifier == $identifier) {
  179. return $this->path_configs_info;
  180. } else {
  181. $ret = array();
  182. foreach ($this->subentries as $subentry) {
  183. $ret = $subentry->getPathConfigsInfo($identifier);
  184. if (!empty($ret)) {
  185. break;
  186. }
  187. }
  188. return $ret;
  189. }
  190. }
  191. /**
  192. * Get an instance of config
  193. * @static
  194. *
  195. * @param $metaconfig_path
  196. *
  197. * @return \RokCommon_Config
  198. * @throws \RokCommon_Config_Exception
  199. */
  200. public static function &getInstance($metaconfig_path)
  201. {
  202. if (!isset(self::$parameters)) {
  203. self::$parameters = new RokCommon_Registry();
  204. }
  205. if (!file_exists($metaconfig_path) || !is_file($metaconfig_path) || !is_readable($metaconfig_path)) {
  206. throw new RokCommon_Config_Exception(rc__('Unable to read file %s', $metaconfig_path));
  207. }
  208. $config = new self(self::CONTEXT_PREFIX, $metaconfig_path);
  209. return $config;
  210. }
  211. /**
  212. * @param $parent_identifier
  213. * @param $file
  214. *
  215. * @param null $xml
  216. *
  217. * @throws \RokCommon_Config_Exception
  218. */
  219. protected function __construct($parent_identifier, $file = null, $xml = null)
  220. {
  221. $this->parent_identifier = $parent_identifier;
  222. $this->joined_xml = new RokCommon_XMLElement('<config/>');
  223. $this->container = RokCommon_Service::getContainer();
  224. $this->root_file = $file;
  225. if (empty($xml)) {
  226. $xml = RokCommon_Utils_XMLHelper::getXML($file);
  227. }
  228. $this->initialize($xml);
  229. $this->process();
  230. }
  231. /**
  232. * @param \RokCommon_XMLElement $xml_node
  233. *
  234. * @throws \RokCommon_Config_Exception
  235. */
  236. protected function initialize(RokCommon_XMLElement $xml_node)
  237. {
  238. $this->xml_node = $xml_node;
  239. // get the name of the entry
  240. if (!isset($this->xml_node['name'])) {
  241. throw new RokCommon_Config_Exception(rc__('Meta Config entry in %s does not have a name', $this->parent_identifier));
  242. }
  243. $this->name = (string)$this->xml_node['name'];
  244. // set the identifier name
  245. $id_parts = explode(self::ENTRY_SEPERATOR, $this->parent_identifier);
  246. $id_parts[] = $this->name;
  247. $this->identifier = implode(self::ENTRY_SEPERATOR, $id_parts);
  248. // get the filename of the entry
  249. if (!isset($this->xml_node['filename'])) {
  250. throw new RokCommon_Config_Exception(rc__('Meta Config entry %s does not have a filename', $this->identifier));
  251. }
  252. $this->filename = (string)$this->xml_node['filename'];
  253. // get the mode
  254. if (isset($this->xml_node['mode'])) {
  255. $this->mode = (string)$this->xml_node['mode'];
  256. }
  257. // get the jointype
  258. if (isset($this->xml_node['jointype'])) {
  259. $this->jointype = (string)$this->xml_node['jointype'];
  260. }
  261. // see if there is a library and add it to the lib path
  262. $library_paths = $xml_node->xpath('libraries/library');
  263. if ($library_paths) {
  264. foreach ($library_paths as $library_path) {
  265. $resolved_lib_path = RokCommon_Config::replaceTokens((string)$library_path, dirname($this->root_file));
  266. if (is_dir($resolved_lib_path)) {
  267. RokCommon_ClassLoader::addPath($resolved_lib_path);
  268. }
  269. }
  270. }
  271. // get the paths for the config
  272. $paths = $xml_node->xpath('paths/path');
  273. if (!$paths) {
  274. throw new RokCommon_Config_Exception(rc__('Meta Config entry %s must have at least one path.', $this->identifier));
  275. }
  276. foreach ($paths as $path_entry) {
  277. $priority = RokCommon_Composite::DEFAULT_PRIORITY;
  278. if (isset($path_entry['priority'])) {
  279. $priority = (string)$path_entry['priority'];
  280. }
  281. $path = RokCommon_Config::replaceTokens((string)$path_entry, dirname($this->root_file));
  282. if (is_dir($path)) {
  283. // see if there is a testservice entry
  284. if (isset($path_entry['testservice'])) {
  285. // see if the testservice extists
  286. $testservice_name = (string)$path_entry['testservice'];
  287. $container = RokCommon_Service::getContainer();
  288. /** @var $testservice RokCommon_Config_PathTest */
  289. $testservice = $container->$testservice_name;
  290. if (!$container->hasService($testservice_name)) {
  291. throw new RokCommon_Config_Exception(rc__('Path test service %s does not exist', $testservice_name));
  292. }
  293. // see if we can add the
  294. if ($testservice->isPathAvailable()) {
  295. $this->addPath($path, $priority);
  296. }
  297. } else {
  298. // add the path if there is no testclass
  299. $this->addPath($path, $priority);
  300. }
  301. } else {
  302. // TODO log unable to find path
  303. }
  304. }
  305. // add any subconfigs
  306. $subconfigs = $xml_node->xpath('subconfigs/subconfig');
  307. if ($subconfigs) {
  308. foreach ($subconfigs as $subconfig_entry) {
  309. $subconfig = new self($this->identifier, $this->root_file, $subconfig_entry);
  310. $this->subentries[$subconfig->getName()] = $subconfig;
  311. }
  312. }
  313. $this->context = RokCommon_Composite::get($this->identifier);
  314. }
  315. /**
  316. * @param \RokCommon_Composite_Context $context
  317. */
  318. public function setContext($context)
  319. {
  320. $this->context = $context;
  321. }
  322. /**
  323. * @return \RokCommon_Composite_Context
  324. */
  325. public function getContext()
  326. {
  327. return $this->context;
  328. }
  329. /**
  330. * @param string $filename
  331. */
  332. public function setFilename($filename)
  333. {
  334. $this->filename = $filename;
  335. }
  336. /**
  337. * @return string
  338. */
  339. public function getFilename()
  340. {
  341. return $this->filename;
  342. }
  343. /**
  344. * @param $identifier
  345. */
  346. public function setIdentifier($identifier)
  347. {
  348. $this->identifier = $identifier;
  349. }
  350. /**
  351. * @return
  352. */
  353. public function getIdentifier()
  354. {
  355. return $this->identifier;
  356. }
  357. /**
  358. * @param $jointype
  359. */
  360. public function setJointype($jointype)
  361. {
  362. $this->jointype = $jointype;
  363. }
  364. /**
  365. * @return string
  366. */
  367. public function getJointype()
  368. {
  369. return $this->jointype;
  370. }
  371. /**
  372. * @param string $mode
  373. */
  374. public function setMode($mode)
  375. {
  376. $this->mode = $mode;
  377. }
  378. /**
  379. * @return string
  380. */
  381. public function getMode()
  382. {
  383. return $this->mode;
  384. }
  385. /**
  386. * @param string $name
  387. */
  388. public function setName($name)
  389. {
  390. $this->name = $name;
  391. }
  392. /**
  393. * @return string
  394. */
  395. public function getName()
  396. {
  397. return $this->name;
  398. }
  399. /**
  400. * @param \RokCommon_Config $parent
  401. */
  402. public function setParent($parent)
  403. {
  404. $this->parent = $parent;
  405. }
  406. /**
  407. * @return \RokCommon_Config
  408. */
  409. public function getParent()
  410. {
  411. return $this->parent;
  412. }
  413. /**
  414. * @param array $paths
  415. */
  416. public function setPaths($paths)
  417. {
  418. $this->paths = $paths;
  419. }
  420. /**
  421. * @return array
  422. */
  423. public function getPaths()
  424. {
  425. return $this->paths;
  426. }
  427. /**
  428. * @param array $subentries
  429. */
  430. public function setSubentries($subentries)
  431. {
  432. $this->subentries = $subentries;
  433. }
  434. /**
  435. * @return array
  436. */
  437. public function getSubentries()
  438. {
  439. return $this->subentries;
  440. }
  441. /**
  442. * @param \RokCommon_XMLElement $xml_node
  443. */
  444. public function setXmlNode($xml_node)
  445. {
  446. $this->xml_node = $xml_node;
  447. }
  448. /**
  449. * @return \RokCommon_XMLElement
  450. */
  451. public function getXmlNode()
  452. {
  453. return $this->xml_node;
  454. }
  455. /**
  456. * @param string $path
  457. * @param int $priority
  458. */
  459. public function addPath($path, $priority = RokCommon_Composite::DEFAULT_PRIORITY)
  460. {
  461. //self::addConfigPath($this->identifier, $path, $priority);
  462. RokCommon_Composite::addPackagePath($this->identifier, $path, $priority);
  463. }
  464. /**
  465. * @static
  466. *
  467. * @param string $extension
  468. * @param string $path
  469. * @param int $priority
  470. */
  471. public static function addConfigPath($extension, $path, $priority = RokCommon_Composite::DEFAULT_PRIORITY)
  472. {
  473. }
  474. /**
  475. * Adds a new child SimpleXMLElement node to the source.
  476. *
  477. * @param SimpleXMLElement $source The source element on which to append.
  478. * @param SimpleXMLElement $new The new element to append.
  479. *
  480. * @return void
  481. *
  482. * @since 11.1
  483. * @throws Exception if an error occurs.
  484. */
  485. protected static function addNode(SimpleXMLElement $source, SimpleXMLElement $new)
  486. {
  487. // Add the new child node.
  488. $node = $source->addChild($new->getName(), trim($new));
  489. // Add the attributes of the child node.
  490. foreach ($new->attributes() as $name => $value) {
  491. $node->addAttribute($name, $value);
  492. }
  493. // Add any children of the new node.
  494. foreach ($new->children() as $child) {
  495. self::addNode($node, $child);
  496. }
  497. }
  498. /**
  499. * Adds a new child SimpleXMLElement node to the source.
  500. *
  501. * @param SimpleXMLElement $source The source element on which to append.
  502. * @param SimpleXMLElement $new The new element to append.
  503. *
  504. * @return void
  505. *
  506. * @since 11.1
  507. */
  508. protected static function mergeNode(SimpleXMLElement $source, SimpleXMLElement $new)
  509. {
  510. // Update the attributes of the child node.
  511. foreach ($new->attributes() as $name => $value) {
  512. if (isset($source[$name])) {
  513. $source[$name] = (string)$value;
  514. } else {
  515. $source->addAttribute($name, $value);
  516. }
  517. }
  518. // What to do with child elements?
  519. }
  520. /**
  521. * Merges new elements into a source <fields> element.
  522. *
  523. * @param SimpleXMLElement $source The source element.
  524. * @param SimpleXMLElement $new The new element to merge.
  525. *
  526. * @return void
  527. *
  528. * @since 11.1
  529. */
  530. protected static function mergeNodes(SimpleXMLElement &$source, SimpleXMLElement $new)
  531. {
  532. // The assumption is that the inputs are at the same relative level.
  533. // So we just have to scan the children and deal with them.
  534. // Update the attributes of the child node.
  535. foreach ($new->attributes() as $name => $value) {
  536. if (isset($source[$name])) {
  537. $source[$name] = (string)$value;
  538. } else {
  539. $source->addAttribute($name, $value);
  540. }
  541. }
  542. /** @var $child SimpleXMLElement */
  543. foreach ($new->children() as $child) {
  544. $type = $child->getName();
  545. $name = $child['name'];
  546. // Does this node exist?
  547. $fields = $source->xpath($type . '[@name="' . $name . '"]');
  548. if (empty($fields)) {
  549. // This node does not exist, so add it.
  550. self::addNode($source, $child);
  551. } else {
  552. // This node does exist.
  553. switch ($type) {
  554. case 'field':
  555. self::mergeNode($fields[0], $child);
  556. break;
  557. default:
  558. self::mergeNodes($fields[0], $child);
  559. break;
  560. }
  561. }
  562. }
  563. }
  564. /**
  565. * @static
  566. *
  567. * @param \SimpleXMLElement $node
  568. *
  569. * @return array|\SimpleXMLElement
  570. */
  571. protected static function reorderNodes(SimpleXMLElement &$node)
  572. {
  573. $reordered_node = new SimpleXMLElement('<' . $node->getName() . '/>');
  574. foreach ($node->attributes() as $name => $value) {
  575. if (isset($node[$name])) {
  576. $reordered_node[$name] = (string)$value;
  577. } else {
  578. $reordered_node->addAttribute($name, $value);
  579. }
  580. }
  581. /** @var $child SimpleXMLElement */
  582. foreach ($node->children() as $child) {
  583. $type = $child->getName();
  584. switch ($type) {
  585. case 'fieldset':
  586. $reordered_child = self::reorderNode($child);
  587. break;
  588. default:
  589. $reordered_child = self::reorderNodes($child);
  590. break;
  591. }
  592. $reordered_node->addChild($type, $reordered_child);
  593. }
  594. return $reordered_node;
  595. }
  596. /**
  597. * @static
  598. *
  599. * @param SimpleXMLElement $node
  600. *
  601. * @return array|SimpleXMLElement
  602. */
  603. protected static function reorderNode(SimpleXMLElement &$node)
  604. {
  605. $reordered_node = new SimpleXMLElement('<' . $node->getName() . '/>');
  606. foreach ($node->attributes() as $name => $value) {
  607. if (isset($node[$name])) {
  608. $reordered_node[$name] = (string)$value;
  609. } else {
  610. $reordered_node->addAttribute($name, $value);
  611. }
  612. }
  613. /** @var $fieldArray SimpleXMLElement[] */
  614. $fieldArray = array();
  615. foreach ($node->field as $d) {
  616. $fieldArray[] = $d;
  617. }
  618. usort($fieldArray, array('RokCommon_Config', 'sortXmlNodesByConfigOrdering'));
  619. foreach ($fieldArray as $ordered_sub_node) {
  620. $reordered_node->addChild('field', $ordered_sub_node);
  621. }
  622. return $reordered_node;
  623. }
  624. /**
  625. * @static
  626. *
  627. * @param $a
  628. * @param $b
  629. *
  630. * @return int
  631. */
  632. protected static function sortXmlNodesByConfigOrdering($a, $b)
  633. {
  634. $va = (isset($a['configordering'])) ? (int)$a['configordering'] : self::ORDERING_DEFAULT;
  635. $vb = (isset($b['configordering'])) ? (int)$b['configordering'] : self::ORDERING_DEFAULT;
  636. if ($va === $vb) {
  637. return 0;
  638. }
  639. return ($va < $vb) ? -1 : 1;
  640. }
  641. /**
  642. * @param $string
  643. *
  644. * @param $file_directory
  645. *
  646. * @return mixed
  647. */
  648. public static function replaceTokens($string, $file_directory)
  649. {
  650. $contianer = RokCommon_Service::getContainer();
  651. /** @var $platform_info RokCommon_IPlatformInfo */
  652. $platform_info = $contianer->platforminfo;
  653. $string = RokCommon_Template::replace('CURRENT_PATH', $file_directory, $string);
  654. $string = RokCommon_Template::replace('ROOT_PATH', $platform_info->getRootPath(), $string);
  655. $string = RokCommon_Template::replace('TEMPLATE_PATH', $platform_info->getDefaultTemplatePath(), $string);
  656. return $string;
  657. }
  658. /**
  659. * @param string $parent_identifier
  660. */
  661. public function setParentIdentifier($parent_identifier)
  662. {
  663. $this->parent_identifier = $parent_identifier;
  664. }
  665. /**
  666. * @return string
  667. */
  668. public function getParentIdentifier()
  669. {
  670. return $this->parent_identifier;
  671. }
  672. }