PageRenderTime 53ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/update/common/scripts/5.4/fixremovedezurlobjectlinks.php

https://github.com/zerustech/ezpublish
PHP | 293 lines | 196 code | 41 blank | 56 comment | 16 complexity | 562bb65e07afaeba86dfb4ea02e74c3a MD5 | raw file
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * File containing the upgrade script to fix older occurrences of link items
  5. * remaining in the ezurl_object_table despite being removed from versions/translations.
  6. * Based on ../4.1/fixezurlobjectlinks.php which fixes the opposite case.
  7. *
  8. * @copyright Copyright (C) eZ Systems AS. All rights reserved.
  9. * @license For full copyright and license information view LICENSE file distributed with this source code.
  10. *
  11. */
  12. require 'autoload.php';
  13. set_time_limit( 0 );
  14. $cli = eZCLI::instance();
  15. $script = eZScript::instance( array( 'description' => ( "Fix occurrences of link items that have been removed from XML-blocks, but\n" .
  16. "not from the URL object link table. This script will remove these orphaned\n" .
  17. "entries.\n" .
  18. "\n" .
  19. "fixremovedezurlobjectlinks.php" ),
  20. 'use-session' => false,
  21. 'use-modules' => true,
  22. 'use-extensions' => true,
  23. ) );
  24. $config = "[fix][fetch-limit:]";
  25. $argConfig = "";
  26. $optionHelp = array(
  27. "fix" => "Fix orphaned ezurl-object-link references.",
  28. "fetch-limit" => "The number of attributes to fetch in one chunk. Default value is 200,\nthe limit must be higher than 1."
  29. );
  30. $arguments = false;
  31. $useStandardOptions = true;
  32. $script->startup();
  33. $options = $script->getOptions( $config, $argConfig, $optionHelp, $arguments, $useStandardOptions );
  34. $script->initialize();
  35. $script->setIterationData( '.', '+' );
  36. $linkRemove = new ezpUrlObjectLinkRemove( $cli, $script, $options );
  37. $cli->output( $cli->stylize( 'red', "Found ") . $cli->stylize( 'green', $linkRemove->xmlTextContentObjectAttributeCount() ) . $cli->stylize( 'red', " occurrences of 'ezxmltext'." ) );
  38. $cli->output();
  39. $cli->output( "Starting to process content object attributes." );
  40. $cli->output( "Fetch limit: " . $cli->stylize( 'green', $linkRemove->fetchLimit ) );
  41. $cli->output();
  42. $linkRemove->processData();
  43. $cli->output();
  44. $cli->output();
  45. $cli->output( $cli->stylize( 'red', "Detailed script summary:" ) );
  46. $cli->output();
  47. $linkRemove->showSummary();
  48. $cli->output();
  49. $script->shutdown();
  50. /**
  51. * Utility class to help remove occurrences of external http-links that are
  52. * removed from versions/translations of an object
  53. */
  54. class ezpUrlObjectLinkRemove
  55. {
  56. public $verboseLevel;
  57. public $xmlClassAttributeIdArray = null;
  58. public $xmlAttrCount = null;
  59. public $offset;
  60. public $fetchLimit;
  61. public $processedCount;
  62. public $outputEntryNumber;
  63. public $finalOutputMessageArray = array();
  64. public $cli;
  65. public $script;
  66. public $doFix;
  67. /**
  68. * Create a new instance of the ezpUrlObjectLink object.
  69. *
  70. * @param eZCLI $cli
  71. * @param eZScript $script
  72. * @param array $options
  73. */
  74. public function __construct( $cli, $script, $options )
  75. {
  76. $this->cli = $cli;
  77. $this->script = $script;
  78. $this->offset = 0;
  79. $this->fetchLimit = 200;
  80. $this->processedCount = 0;
  81. $this->verboseLevel = $this->script->verboseOutputLevel();
  82. $this->script->resetIteration( $this->xmlTextContentObjectAttributeCount() );
  83. $this->doFix = false;
  84. if ( $options['fix'] !== null and $options['fix'] )
  85. {
  86. $this->doFix = true;
  87. }
  88. if ($options['fetch-limit'] !== null and $options['fetch-limit'] > 1 )
  89. {
  90. $this->fetchLimit = $options['fetch-limit'];
  91. }
  92. }
  93. /**
  94. * Get an array of all defined class attributes with ezxmltext datatype.
  95. *
  96. * @return array
  97. */
  98. public function xmlClassAttributeIds()
  99. {
  100. if ( $this->xmlClassAttributeIdArray === null )
  101. {
  102. // First we want to find all class attributes which are defined. We won't be touching
  103. // attributes which are in a transient state.
  104. $xmlTextAttributes = eZContentClassAttribute::fetchList( true, array( 'data_type' => 'ezxmltext',
  105. 'version' => 0 ) );
  106. $this->xmlClassAttributeIdArray = array();
  107. foreach ( $xmlTextAttributes as $classAttr )
  108. {
  109. $this->xmlClassAttributeIdArray[] = $classAttr->attribute( 'id' );
  110. }
  111. unset( $xmlTextAttributes );
  112. }
  113. return $this->xmlClassAttributeIdArray;
  114. }
  115. /**
  116. * Retrieve the number of valid ezxmltext occurences
  117. *
  118. * @return int
  119. */
  120. public function xmlTextContentObjectAttributeCount()
  121. {
  122. if ( $this->xmlAttrCount === null )
  123. {
  124. $this->xmlAttrCount = eZContentObjectAttribute::fetchListByClassID( $this->xmlClassAttributeIds(), false, null, false, true );
  125. }
  126. return $this->xmlAttrCount;
  127. }
  128. /**
  129. * Add a message to the message buffer, to be displayed after processData has completed.
  130. *
  131. * @param string $message
  132. * @param string $label
  133. * @param bool $groupedEntry
  134. * @return void
  135. */
  136. public function outputString( $message, $label = null, $groupedEntry = false )
  137. {
  138. if ( $groupedEntry )
  139. {
  140. $this->finalOutputMessageArray[$this->outputEntryNumber]["messages"][] = $message;
  141. }
  142. else
  143. {
  144. $this->outputEntryNumber++;
  145. $this->finalOutputMessageArray[$this->outputEntryNumber] = array( "messages" => array( $message ),
  146. "label" => $label );
  147. }
  148. }
  149. /**
  150. * Search through valid ezxmltext occurrences, and fix missing url object links if
  151. * specified.
  152. *
  153. * @return void
  154. */
  155. public function processData()
  156. {
  157. while ( $this->processedCount < $this->xmlTextContentObjectAttributeCount() )
  158. {
  159. $limit = array( 'offset' => $this->offset,
  160. 'length' => $this->fetchLimit );
  161. $xmlAttributeChunk = eZContentObjectAttribute::fetchListByClassID( $this->xmlClassAttributeIds(), false, $limit, true, false );
  162. foreach ( $xmlAttributeChunk as $xmlAttr )
  163. {
  164. $result = true;
  165. // If the current entry has been logged, we don't increment the running number
  166. // so that the entries can be displayed together on output.
  167. $currentEntryLogged = false;
  168. $currentId = $xmlAttr->attribute( 'id' );
  169. $objectId = $xmlAttr->attribute( 'contentobject_id' );
  170. $version = $xmlAttr->attribute( 'version' );
  171. $languageCode = $xmlAttr->attribute( 'language_code' );
  172. $label = "Attribute [id:{$currentId}] - [Object-id:{$objectId}] - [Version:{$version}] - [Language:{$languageCode}]";
  173. $xmlText = eZXMLTextType::rawXMLText( $xmlAttr );
  174. if ( empty( $xmlText ) )
  175. {
  176. if ( $this->verboseLevel > 0 )
  177. {
  178. $this->outputString( "Empty XML-data", $label, $currentEntryLogged );
  179. $currentEntryLogged = true;
  180. }
  181. $result = false;
  182. continue;
  183. }
  184. $dom = new DOMDocument( '1.0', 'utf-8' );
  185. $success = $dom->loadXML( $xmlText );
  186. if ( !$success )
  187. {
  188. if ( $this->verboseLevel > 0 )
  189. {
  190. $this->outputString( "XML not loaded correctly for attribute", $label, $currentEntryLogged );
  191. $currentEntryLogged = true;
  192. }
  193. $result = false;
  194. continue;
  195. }
  196. $linkNodes = $dom->getElementsByTagName( 'link' );
  197. $urlIdArray = array();
  198. foreach ( $linkNodes as $link )
  199. {
  200. // We are looking for external 'http://'-style links, not the internal
  201. // object or node links.
  202. if ( $link->hasAttribute( 'url_id' ) )
  203. {
  204. $urlIdArray[] = $link->getAttribute( 'url_id' );
  205. }
  206. }
  207. $urlIdArray = array_unique( $urlIdArray );
  208. if ( count( $urlIdArray ) > 0 )
  209. {
  210. if ( $this->verboseLevel > 0 )
  211. {
  212. $this->outputString( "Found http-link elements in xml-block", $label, $currentEntryLogged );
  213. $currentEntryLogged = true;
  214. }
  215. if ( $this->doFix)
  216. {
  217. $db = eZDB::instance();
  218. $db->begin();
  219. eZSimplifiedXMLInput::updateUrlObjectLinks( $xmlAttr, $urlIdArray );
  220. $db->commit();
  221. }
  222. }
  223. $this->script->iterate( $this->cli, $result );
  224. $label = null;
  225. }
  226. $this->processedCount += count( $xmlAttributeChunk );
  227. $this->offset += $this->fetchLimit;
  228. unset( $xmlAttributeChunk );
  229. }
  230. }
  231. /**
  232. * Print a summary of all the messages created during processData.
  233. *
  234. * @return void
  235. */
  236. public function showSummary()
  237. {
  238. foreach ( $this->finalOutputMessageArray as $messageEntry )
  239. {
  240. if ( $messageEntry['label'] !== null )
  241. {
  242. $this->cli->output( $this->cli->stylize( 'bold', $messageEntry['label'] ) );
  243. }
  244. foreach ( $messageEntry['messages'] as $msg )
  245. {
  246. $this->cli->output( $msg);
  247. }
  248. $this->cli->output();
  249. }
  250. }
  251. }
  252. ?>