modxmlpackagebuilder.class.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. /*
  3. * This file is part of MODX Revolution.
  4. *
  5. * Copyright (c) MODX, LLC. All Rights Reserved.
  6. *
  7. * For complete copyright and license information, see the COPYRIGHT and LICENSE
  8. * files found in the top-level directory of this distribution.
  9. */
  10. /*
  11. * This file is part of MODX Revolution.
  12. *
  13. * Copyright (c) MODX, LLC. All Rights Reserved.
  14. *
  15. * For complete copyright and license information, see the COPYRIGHT and LICENSE
  16. * files found in the top-level directory of this distribution.
  17. */
  18. require_once MODX_CORE_PATH . 'model/modx/transport/modpackagebuilder.class.php';
  19. /**
  20. * Abstracts the package building process for XML builds
  21. *
  22. * @package modx
  23. * @subpackage transport
  24. */
  25. class modXMLPackageBuilder extends modPackageBuilder {
  26. /**
  27. * Build the package from a specific XML file
  28. * @param string $fileName The XML file to parse
  29. * @return bool True if successful
  30. */
  31. public function build($fileName) {
  32. if (!$this->parseXML($fileName)) {
  33. $this->modx->log(modX::LOG_LEVEL_ERROR,'XML parsing failed for '.$fileName);
  34. return false;
  35. }
  36. /* create a new package */
  37. $this->createPackage($this->build['name'], $this->build['version'], $this->build['release']);
  38. $this->registerNamespace($this->build['namespace'],$this->build['autoincludes']);
  39. /* set up some attributes that define install behavior */
  40. $attributes= array(
  41. xPDOTransport::UNIQUE_KEY => 'name',
  42. xPDOTransport::UPDATE_OBJECT => true,
  43. xPDOTransport::RESOLVE_FILES => true,
  44. xPDOTransport::RESOLVE_PHP => true,
  45. xPDOTransport::PRESERVE_KEYS => false,
  46. );
  47. foreach ($this->build['vehicles'] as $signature => $vehicle) {
  48. $c = $this->modx->getObject($vehicle['class_key'],$vehicle['object']);
  49. if ($c == null) continue;
  50. if (!isset($vehicle['attributes'])) $vehicle['attributes'] = array();
  51. $attr = array_merge($attributes,$vehicle['attributes']);
  52. $v = $this->createVehicle($c,$attr);
  53. if (isset($vehicle['resolvers']) && !empty($vehicle['resolvers'])) {
  54. foreach ($vehicle['resolvers'] as $resolver) {
  55. $v->resolve($resolver['type'],$resolver);
  56. }
  57. }
  58. $this->putVehicle($v);
  59. }
  60. /* zip up the package */
  61. $this->pack();
  62. return true;
  63. }
  64. /**
  65. * Parse the XML file
  66. * @param string $fileName
  67. * @return bool
  68. */
  69. public function parseXML($fileName) {
  70. $this->build = array(
  71. 'autoincludes' => array(),
  72. 'vehicles' => array(),
  73. );
  74. if (!is_file($fileName)) {
  75. $this->modx->log(xPDO::LOG_LEVEL_ERROR, "Could not find specified XML build file {$fileName}");
  76. return false;
  77. } else {
  78. $fileContent= @ file($fileName);
  79. $this->buildXML= implode('', $fileContent);
  80. }
  81. /* Create the parser and set handlers. */
  82. $this->xmlParser= xml_parser_create('UTF-8');
  83. xml_set_object($this->xmlParser, $this);
  84. xml_parser_set_option($this->xmlParser, XML_OPTION_CASE_FOLDING, 0);
  85. xml_parser_set_option($this->xmlParser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
  86. xml_set_element_handler($this->xmlParser, '_handleOpenElement', '_handleCloseElement');
  87. xml_set_character_data_handler($this->xmlParser, "_handleCData");
  88. /* Parse it. */
  89. if (!xml_parse($this->xmlParser, $this->buildXML)) {
  90. $ln= xml_get_current_line_number($this->xmlParser);
  91. $msg= xml_error_string(xml_get_error_code($this->xmlParser));
  92. $this->modx->log(xPDO::LOG_LEVEL_ERROR, "Error parsing XML schema on line $ln: $msg");
  93. return false;
  94. }
  95. /* Free up the parser and clear memory */
  96. xml_parser_free($this->xmlParser);
  97. unset ($this->xmlParser);
  98. return $this->build;
  99. }
  100. /**
  101. * @param xmlParser $parser A reference to the xml parser instance
  102. * @param string|array $element The opening XML element
  103. * @param array $attributes An array of attributes on the element
  104. * @return void
  105. */
  106. protected function _handleOpenElement(& $parser, & $element, & $attributes) {
  107. $element= strtolower($element);
  108. switch ($element) {
  109. case 'component':
  110. foreach ($attributes as $attrName => $attrValue) {
  111. $this->build[$attrName]= $attrValue;
  112. }
  113. break;
  114. case 'autoinclude':
  115. foreach ($attributes as $attrName => $attrValue) {
  116. if ($attrName == 'class') {
  117. $this->build['autoincludes'][$attrValue] = $attrValue;
  118. }
  119. }
  120. break;
  121. case 'vehicle':
  122. $vehicle = array(
  123. 'resolvers' => array(),
  124. 'attributes' => array(),
  125. );
  126. foreach ($attributes as $attrName => $attrValue) {
  127. switch ($attrName) {
  128. case 'class':
  129. $vehicle['class_key'] = $attrValue;
  130. break;
  131. case 'id':
  132. $vehicle['object'] = $attrValue;
  133. break;
  134. default:
  135. $vehicle['attributes'][$attrName] = $attrValue;
  136. break;
  137. }
  138. }
  139. $this->build['vehicles'][$vehicle['class_key'].'-'.$vehicle['object']] = $vehicle;
  140. $this->openVehicle = $vehicle['class_key'].'-'.$vehicle['object'];
  141. break;
  142. case 'resolver':
  143. if ($this->openVehicle == '') break;
  144. $resolver = array();
  145. foreach ($attributes as $attrName => $attrValue) {
  146. $resolver[$attrName] = $attrValue;
  147. }
  148. if (isset($resolver['prependbase']) && $resolver['prependbase'] == true) {
  149. $resolver['source'] = $this->modx->getOption('base_path').$resolver['source'];
  150. }
  151. $this->build['vehicles'][$this->openVehicle]['resolvers'][] = $resolver;
  152. break;
  153. }
  154. }
  155. /**
  156. * Handles a closed XML tag
  157. * @param xmlParser $parser A reference to the xml parser instance
  158. * @param string|array $element The closing element
  159. * @return void
  160. */
  161. protected function _handleCloseElement(& $parser, & $element) {
  162. switch ($element) {
  163. case 'vehicle':
  164. $this->openVehicle = '';
  165. break;
  166. }
  167. }
  168. /**
  169. * @param xmlParser $parser A reference to the xml parser instance
  170. * @param $data The data being wrapped in CDATA tags
  171. * @return void
  172. */
  173. protected function _handleCData(& $parser, & $data) {}
  174. }