|
eZ Publish
[4.0]
|
00001 #!/usr/bin/env php 00002 <?php 00003 /** 00004 * File containing the upgrade script to fix older occurrences of link items 00005 * not being present in the ezurl_object_table for all versions/translations. 00006 * 00007 * @copyright Copyright (C) 1999-2008 eZ Systems AS. All rights reserved. 00008 * @license http://ez.no/licenses/gnu_gpl GNU GPLv2 00009 * 00010 */ 00011 00012 require 'autoload.php'; 00013 00014 set_time_limit( 0 ); 00015 00016 $cli = eZCLI::instance(); 00017 $script = eZScript::instance( array( 'description' => ( "Fix older occurrences of link items in XML-blocks, where they might not be\n" . 00018 "linked correctly for all versions/translations. This script will update\n" . 00019 "these references for existing entries. Note that URLs which have been lost\n" . 00020 "already will not be restored in this process, these need to be re-entered.\n" . 00021 "\n" . 00022 "fixezurlobjectlink.php" ), 00023 'use-session' => false, 00024 'use-modules' => true, 00025 'use-extensions' => true, 00026 ) ); 00027 00028 00029 $config = "[fix][fetch-limit:]"; 00030 $argConfig = ""; 00031 $optionHelp = array( 00032 "fix" => "Fix missing ezurl-object-link references. This will make sure that URLs\n" . 00033 "created with older versions, will not be lost, when older\nversions/translations are removed.", 00034 "fetch-limit" => "The number of attributes to fetch in one chunk. Default value is 200,\nthe limit must be higher than 1." 00035 ); 00036 $arguments = false; 00037 $useStandardOptions = true; 00038 00039 $script->startup(); 00040 $options = $script->getOptions( $config, $argConfig, $optionHelp, $arguments, $useStandardOptions ); 00041 $script->initialize(); 00042 $script->setIterationData( '.', '+' ); 00043 00044 $linkUpdate = new ezpUrlObjectLinkUpdate( $cli, $script, $options ); 00045 00046 $cli->output( $cli->stylize( 'red', "Found ") . $cli->stylize( 'green', $linkUpdate->xmlTextContentObjectAttributeCount() ) . $cli->stylize( 'red', " occurrences of 'ezxmltext'." ) ); 00047 00048 $cli->output(); 00049 $cli->output( "Starting to process content object attributes." ); 00050 $cli->output( "Fetch limit: " . $cli->stylize( 'green', $linkUpdate->fetchLimit ) ); 00051 $cli->output(); 00052 $linkUpdate->processData(); 00053 00054 $cli->output(); 00055 $cli->output(); 00056 $cli->output( $cli->stylize( 'red', "Detailed script summary:" ) ); 00057 $cli->output(); 00058 $linkUpdate->showSummary(); 00059 00060 $cli->output(); 00061 $script->shutdown(); 00062 00063 /** 00064 * Utility class to help fix occurrences of external http-links not correctly 00065 * associated with all versions/translations of an object 00066 * 00067 */ 00068 class ezpUrlObjectLinkUpdate 00069 { 00070 public $verboseLevel; 00071 public $xmlClassAttributeIdArray = null; 00072 public $xmlAttrCount = null; 00073 00074 public $offset; 00075 public $fetchLimit; 00076 public $processedCount; 00077 00078 public $outputEntryNumber; 00079 public $finalOutputMessageArray; 00080 00081 public $cli; 00082 public $script; 00083 00084 public $doFix; 00085 00086 /** 00087 * Create a new instance of the ezpUrlObjectLink object. 00088 * 00089 * @param eZCLI $cli 00090 * @param eZScript $script 00091 * @param array $options 00092 */ 00093 public function __construct( $cli, $script, $options ) 00094 { 00095 $this->cli = $cli; 00096 $this->script = $script; 00097 00098 $this->offset = 0; 00099 $this->fetchLimit = 200; 00100 $this->processedCount = 0; 00101 00102 $this->verboseLevel = $this->script->verboseOutputLevel(); 00103 00104 $this->script->resetIteration( $this->xmlTextContentObjectAttributeCount() ); 00105 00106 $this->doFix = false; 00107 if ( $options['fix'] !== null and $options['fix'] ) 00108 { 00109 $this->doFix = true; 00110 } 00111 00112 if ($options['fetch-limit'] !== null and $options['fetch-limit'] > 1 ) 00113 { 00114 $this->fetchLimit = $options['fetch-limit']; 00115 } 00116 } 00117 00118 /** 00119 * Get an array of all defined class attributes with ezxmltext datatype. 00120 * 00121 * @return array 00122 */ 00123 public function xmlClassAttributeIds() 00124 { 00125 if ( $this->xmlClassAttributeIdArray === null ) 00126 { 00127 // First we want to find all class attributes which are defined. We won't be touching 00128 // attributes which are in a transient state. 00129 $xmlTextAttributes = eZContentClassAttribute::fetchList( true, array( 'data_type' => 'ezxmltext', 00130 'version' => 0 ) ); 00131 $this->xmlClassAttributeIdArray = array(); 00132 00133 foreach ( $xmlTextAttributes as $classAttr ) 00134 { 00135 $this->xmlClassAttributeIdArray[] = $classAttr->attribute( 'id' ); 00136 } 00137 unset( $xmlTextAttributes ); 00138 } 00139 return $this->xmlClassAttributeIdArray; 00140 } 00141 00142 /** 00143 * Retrieve the number of valid ezxmltext occurences 00144 * 00145 * @return void 00146 */ 00147 public function xmlTextContentObjectAttributeCount() 00148 { 00149 if ( $this->xmlAttrCount === null ) 00150 { 00151 $this->xmlAttrCount = eZContentObjectAttribute::fetchListByClassID( $this->xmlClassAttributeIds(), false, null, false, true ); 00152 } 00153 return $this->xmlAttrCount; 00154 } 00155 00156 /** 00157 * Add a message to the message buffer, to be displayed after processData has completed. 00158 * 00159 * @param string $message 00160 * @param string $label 00161 * @param bool $groupedEntry 00162 * @return void 00163 */ 00164 public function outputString( $message, $label = null, $groupedEntry = false ) 00165 { 00166 if ( $groupedEntry ) 00167 { 00168 $this->finalOutputMessageArray[$this->outputEntryNumber]["messages"][] = $message; 00169 } 00170 else 00171 { 00172 $this->outputEntryNumber++; 00173 $this->finalOutputMessageArray[$this->outputEntryNumber] = array( "messages" => array( $message ), 00174 "label" => $label ); 00175 } 00176 } 00177 00178 /** 00179 * Search through valid ezxmltext occurrences, and fix missing url object links if 00180 * specified. 00181 * 00182 * @return void 00183 */ 00184 public function processData() 00185 { 00186 while ( $this->processedCount < $this->xmlTextContentObjectAttributeCount() ) 00187 { 00188 $limit = array( 'offset' => $this->offset, 00189 'length' => $this->fetchLimit ); 00190 00191 $xmlAttributeChunk = eZContentObjectAttribute::fetchListByClassID( $this->xmlClassAttributeIds(), false, $limit, true, false ); 00192 00193 foreach ( $xmlAttributeChunk as $xmlAttr ) 00194 { 00195 $result = true; 00196 // If the current entry has been logged, we don't increment the running number 00197 // so that the entries can be displayed together on output. 00198 $currentEntryLogged = false; 00199 00200 $currentId = $xmlAttr->attribute( 'id' ); 00201 $objectId = $xmlAttr->attribute( 'contentobject_id' ); 00202 $version = $xmlAttr->attribute( 'version' ); 00203 $languageCode = $xmlAttr->attribute( 'language_code' ); 00204 00205 $label = "Attribute [id:{$currentId}] - [Object-id:{$objectId}] - [Version:{$version}] - [Language:{$languageCode}]"; 00206 00207 $xmlText = eZXMLTextType::rawXMLText( $xmlAttr ); 00208 if ( empty( $xmlText ) ) 00209 { 00210 if ( $this->verboseLevel > 0 ) 00211 { 00212 $this->outputString( "Empty XML-data", $label, $currentEntryLogged ); 00213 $currentEntryLogged = true; 00214 } 00215 $result = false; 00216 continue; 00217 } 00218 00219 $dom = new DOMDocument( '1.0', 'utf-8' ); 00220 $success = $dom->loadXML( $xmlText ); 00221 if ( !$success ) 00222 { 00223 if ( $this->verboseLevel > 0 ) 00224 { 00225 $this->outputString( "XML not loaded correctly for attribute", $label, $currentEntryLogged ); 00226 $currentEntryLogged = true; 00227 } 00228 $result = false; 00229 continue; 00230 } 00231 00232 $linkNodes = $dom->getElementsByTagName( 'link' ); 00233 $urlIdArray = array(); 00234 00235 foreach ( $linkNodes as $link ) 00236 { 00237 // We are looking for external 'http://'-style links, not the internal 00238 // object or node links. 00239 if ( $link->hasAttribute( 'url_id' ) ) 00240 { 00241 $urlIdArray[] = $link->getAttribute( 'url_id' ); 00242 } 00243 } 00244 00245 if ( count( $urlIdArray ) > 0 ) 00246 { 00247 if ( $this->verboseLevel > 0 ) 00248 { 00249 $this->outputString( "Found http-link elements in xml-block", $label, $currentEntryLogged ); 00250 $currentEntryLogged = true; 00251 } 00252 00253 $urlIdArray = array_unique( $urlIdArray ); 00254 00255 foreach ( $urlIdArray as $url ) 00256 { 00257 $linkObjectLink = eZURLObjectLink::fetch( $url, $currentId, $version ); 00258 if ( $linkObjectLink === null ) 00259 { 00260 $result = false; 00261 $this->outputString( "Missing url object link: [id:{$currentId}] - [version:{$version}] - [url:{$url}]", $label, $currentEntryLogged ); 00262 $currentEntryLogged = true; 00263 } 00264 00265 $storedUrl = eZURL::url( $url ); 00266 if ( $storedUrl === false ) 00267 { 00268 $result = false; 00269 $this->outputString( "Missing URL, the referenced url does not exist, [url_id:{$url}]", $label, $currentEntryLogged ); 00270 $currentEntryLogged = true; 00271 } 00272 } 00273 00274 if ( $this->doFix and $linkObjectLink === null and $storedUrl !== false ) 00275 { 00276 $this->outputString( "Reconstructing ezurl-object-link", $label, $currentEntryLogged ); 00277 $currentEntryLogged = true; 00278 eZSimplifiedXMLInput::updateUrlObjectLinks( $xmlAttr, $urlIdArray ); 00279 } 00280 } 00281 00282 $this->script->iterate( $this->cli, $result ); 00283 $label = null; 00284 } 00285 00286 $this->processedCount += count( $xmlAttributeChunk ); 00287 $this->offset += $this->fetchLimit; 00288 unset( $xmlAttributeChunk ); 00289 } 00290 } 00291 00292 /** 00293 * Print a summary of all the messages created during processData. 00294 * 00295 * @return void 00296 */ 00297 public function showSummary() 00298 { 00299 foreach ( $this->finalOutputMessageArray as $messageEntry ) 00300 { 00301 if ( $messageEntry['label'] !== null ) 00302 { 00303 $this->cli->output( $this->cli->stylize( 'bold', $messageEntry['label'] ) ); 00304 } 00305 00306 foreach ( $messageEntry['messages'] as $msg ) 00307 { 00308 $this->cli->output( $msg); 00309 } 00310 $this->cli->output(); 00311 } 00312 } 00313 } 00314 ?>