PageRenderTime 47ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/kernel/classes/packagehandlers/ezcontentobject/ezcontentobjectpackagehandler.php

https://github.com/aurelienRT1/ezpublish
PHP | 1781 lines | 1449 code | 147 blank | 185 comment | 190 complexity | 0af39445c972eaf4cf17fce3aeba395f MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. //
  3. // Definition of eZContentClassPackageHandler class
  4. //
  5. // Created on: <09-Mar-2004 16:11:42 kk>
  6. //
  7. // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  8. // SOFTWARE NAME: eZ Publish
  9. // SOFTWARE RELEASE: 4.1.x
  10. // COPYRIGHT NOTICE: Copyright (C) 1999-2010 eZ Systems AS
  11. // SOFTWARE LICENSE: GNU General Public License v2.0
  12. // NOTICE: >
  13. // This program is free software; you can redistribute it and/or
  14. // modify it under the terms of version 2.0 of the GNU General
  15. // Public License as published by the Free Software Foundation.
  16. //
  17. // This program is distributed in the hope that it will be useful,
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. // GNU General Public License for more details.
  21. //
  22. // You should have received a copy of version 2.0 of the GNU General
  23. // Public License along with this program; if not, write to the Free
  24. // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  25. // MA 02110-1301, USA.
  26. //
  27. //
  28. // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  29. //
  30. /*! \file
  31. */
  32. /*!
  33. \class eZContentObjectPackageHandler ezcontentobjectpackagehandler.php
  34. \brief Handles content objects in the package system
  35. */
  36. class eZContentObjectPackageHandler extends eZPackageHandler
  37. {
  38. const MAX_LISTED_OBJECTS = 30;
  39. // If number of objects in the package is bigger than this constant,
  40. // they are stored in separate files to prevent memory overflow.
  41. // 'null' means always use separate files
  42. const STORE_OBJECTS_TO_SEPARATE_FILES_THRESHOLD = 100;
  43. const INSTALL_OBJECTS_ERROR_RANGE_FROM = 1;
  44. const INSTALL_OBJECTS_ERROR_RANGE_TO = 100;
  45. const UNINSTALL_OBJECTS_ERROR_RANGE_FROM = 101;
  46. const UNINSTALL_OBJECTS_ERROR_RANGE_TO = 200;
  47. /*!
  48. Constructor
  49. */
  50. function eZContentObjectPackageHandler()
  51. {
  52. $this->eZPackageHandler( 'ezcontentobject',
  53. array( 'extract-install-content' => true ) );
  54. }
  55. /*!
  56. Fetches object stored in separate xml file
  57. */
  58. function fetchObjectFromFile( $objectFileNode )
  59. {
  60. $fileName = $objectFileNode->getAttribute( 'filename' );
  61. $filePath = $this->Package->path() . '/' . $this->contentObjectDirectory() . '/' . $fileName;
  62. $dom = $this->Package->fetchDOMFromFile( $filePath );
  63. if ( $dom )
  64. {
  65. $objectNode = $dom->documentElement;
  66. }
  67. else
  68. {
  69. eZDebug::writeError( "Can't fetch object from package file: $filePath", 'eZContentObjectPackageHandler::getObjectNodeFromFile' );
  70. $objectNode = false;
  71. }
  72. return $objectNode;
  73. }
  74. function getRealObjectNode( $objectNode )
  75. {
  76. if ( $objectNode->localName == 'object' )
  77. {
  78. $realObjectNode = $objectNode;
  79. }
  80. else
  81. {
  82. $realObjectNode = $this->fetchObjectFromFile( $objectNode );
  83. }
  84. return $realObjectNode;
  85. }
  86. /*!
  87. Returns an explanation for the content object install item.
  88. The explanaition is actually a list having the following structure:
  89. array( array( 'description' => 'Content object Foo' ),
  90. array( 'description' => 'Content object Bar' ),
  91. array( 'description' => 'Content object Baz' ) );
  92. When number of items in the above list is too high,
  93. the following array is returned instead:
  94. array( 'description' => 'NNN content objects' );
  95. */
  96. function explainInstallItem( $package, $installItem, $requestedInfo = array() )
  97. {
  98. $this->Package = $package;
  99. if ( $installItem['filename'] )
  100. {
  101. $filename = $installItem['filename'];
  102. $subdirectory = $installItem['sub-directory'];
  103. if ( $subdirectory )
  104. $filepath = $subdirectory . '/' . $filename . '.xml';
  105. else
  106. $filepath = $filename . '.xml';
  107. $filepath = $package->path() . '/' . $filepath;
  108. $dom = $package->fetchDOMFromFile( $filepath );
  109. if ( !$dom )
  110. return null;
  111. $content = $dom->documentElement;
  112. $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 );
  113. if ( $objectListNode )
  114. {
  115. $realObjectNodes = $objectListNode->getElementsByTagName( 'object' );
  116. }
  117. else
  118. {
  119. // If objects are stored in separate files (new format)
  120. $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 );
  121. $objectNodes = $objectListNode->getElementsByTagName( 'object-file' );
  122. if ( count( $objectNodes ) > self::MAX_LISTED_OBJECTS )
  123. {
  124. return array( 'description' => ezpI18n::tr( 'kernel/package', '%number content objects', false,
  125. array( '%number' => count( $objectNodes ) ) ) );
  126. }
  127. $realObjectNodes = array();
  128. foreach( $objectNodes as $objectNode )
  129. {
  130. $realObjectNode = $this->fetchObjectFromFile( $objectNode );
  131. if ( !$realObjectNode )
  132. continue;
  133. $realObjectNodes[] = $realObjectNode;
  134. }
  135. }
  136. // create descriptions array
  137. $objectNames = array();
  138. foreach( $realObjectNodes as $objectNode )
  139. {
  140. $objectName =
  141. $objectNode->getAttribute( 'name' ) .
  142. ' (' . $objectNode->getAttributeNS( 'http://ez.no/ezobject', 'class_identifier' ) .')';
  143. // get info about translations.
  144. $languageInfo = array();
  145. $versionList = $objectNode->getElementsByTagName( 'version-list' )->item( 0 );
  146. $versions = $versionList->getElementsByTagName( 'version' );
  147. foreach( $versions as $version )
  148. {
  149. $versionInfo = $version->getElementsByTagName( 'object-translation' );
  150. foreach( $versionInfo as $info )
  151. {
  152. $languageInfo[] = $info->getAttribute( 'language' );
  153. }
  154. }
  155. $objectNames[] = array( 'description' =>
  156. ezpI18n::tr( 'kernel/package', 'Content object %objectname', false,
  157. array( '%objectname' => $objectName ) ),
  158. 'language_info' => $languageInfo );
  159. }
  160. return $objectNames;
  161. }
  162. }
  163. /*!
  164. Add Node list to ezcontentobject package handler.
  165. \param nodeID node id
  166. \param isSubtree subtree (optional, default true )
  167. */
  168. function addNode( $nodeID, $isSubtree = true )
  169. {
  170. $this->RootNodeIDArray[] = $nodeID;
  171. $this->NodeIDArray[] = $nodeID;
  172. if ( $isSubtree )
  173. {
  174. $nodeArray = eZContentObjectTreeNode::subTreeByNodeID( array( 'AsObject' => false ), $nodeID );
  175. foreach( $nodeArray as $node )
  176. {
  177. $this->NodeIDArray[] = $node['node_id'];
  178. }
  179. }
  180. }
  181. /*!
  182. Generate package based on NodeArray and input options
  183. \param package
  184. \param options
  185. */
  186. function generatePackage( $package, $options )
  187. {
  188. $this->Package = $package;
  189. $remoteIDArray = array();
  190. $this->NodeIDArray = array_unique( $this->NodeIDArray );
  191. foreach( $this->NodeIDArray as $nodeID )
  192. {
  193. $this->NodeObjectArray[(string)$nodeID] = eZContentObjectTreeNode::fetch( $nodeID );
  194. }
  195. foreach( $this->RootNodeIDArray as $nodeID )
  196. {
  197. $this->RootNodeObjectArray[(string)$nodeID] = eZContentObjectTreeNode::fetch( $nodeID );
  198. }
  199. $this->generateObjectArray( $options['node_assignment'] );
  200. $classIDArray = false;
  201. if ( $options['include_classes'] )
  202. {
  203. $remoteIDArray['class'] = array();
  204. $classIDArray = $this->generateClassIDArray();
  205. foreach ( $classIDArray as $classID )
  206. {
  207. eZContentClassPackageHandler::addClass( $package, $classID );
  208. }
  209. }
  210. $dom = new DOMDocument( '1.0', 'utf-8' );
  211. $packageRoot = $dom->createElement( 'content-object' );
  212. $dom->appendChild( $packageRoot );
  213. $objectListDOMNode = $this->createObjectListNode( $options );
  214. $importedObjectListDOMNode = $dom->importNode( $objectListDOMNode, true );
  215. $packageRoot->appendChild( $importedObjectListDOMNode );
  216. $overrideSettingsArray = false;
  217. $templateFilenameArray = false;
  218. if ( $options['include_templates'] )
  219. {
  220. $overrideSettingsListNode = $this->generateOverrideSettingsArray( $options['site_access_array'], $options['minimal_template_set'] );
  221. $importedOverrideSettingsListNode = $dom->importNode( $overrideSettingsListNode, true );
  222. $packageRoot->appendChild( $importedOverrideSettingsListNode );
  223. $designTemplateListNode = $this->generateTemplateFilenameArray();
  224. $importedDesignTemplateListNode = $dom->importNode( $designTemplateListNode, true );
  225. $packageRoot->appendChild( $importedDesignTemplateListNode );
  226. $fetchAliasListNode = $this->generateFetchAliasArray();
  227. $importedFetchAliasListNode = $dom->importNode( $fetchAliasListNode, true );
  228. $packageRoot->appendChild( $importedFetchAliasListNode );
  229. }
  230. $siteAccessListDOMNode = $this->createSiteAccessListNode( $options );
  231. $importedSiteAccessListDOMNode = $dom->importNode( $siteAccessListDOMNode, true );
  232. $packageRoot->appendChild( $importedSiteAccessListDOMNode );
  233. $topNodeListDOMNode = $this->createTopNodeListDOMNode( $options );
  234. $importedTopNodeListDOMNode = $dom->importNode( $topNodeListDOMNode, true );
  235. $packageRoot->appendChild( $importedTopNodeListDOMNode );
  236. //$filename = substr( md5( mt_rand() ), 0, 8 );
  237. $filename = 'contentobjects';
  238. $this->Package->appendInstall( 'ezcontentobject', false, false, true,
  239. $filename, $this->contentObjectDirectory(),
  240. array( 'content' => $packageRoot ) );
  241. $this->Package->appendInstall( 'ezcontentobject', false, false, false,
  242. $filename, $this->contentObjectDirectory(),
  243. array( 'content' => false ) );
  244. }
  245. /*!
  246. \private
  247. Create DOMNode for list of top nodes.
  248. \param options
  249. */
  250. function createTopNodeListDOMNode( $options )
  251. {
  252. $dom = new DOMDocument( '1.0', 'utf-8' );
  253. $topNodeListDOMNode = $dom->createElement( 'top-node-list' );
  254. $dom->appendChild( $topNodeListDOMNode );
  255. foreach( $this->RootNodeObjectArray as $rootNode )
  256. {
  257. unset( $topNode );
  258. $topNode = $dom->createElement( 'top-node' );
  259. $topNode->appendChild( $dom->createTextNode( $rootNode->attribute( 'name' ) ) );
  260. $topNode->setAttribute( 'node-id', $rootNode->attribute( 'node_id' ) );
  261. $topNode->setAttribute( 'remote-id', $rootNode->attribute( 'remote_id' ) );
  262. $topNodeListDOMNode->appendChild( $topNode );
  263. }
  264. return $topNodeListDOMNode;
  265. }
  266. /*!
  267. \private
  268. Create DOMNode for list of added siteaccesses.
  269. \param options
  270. */
  271. function createSiteAccessListNode( $options )
  272. {
  273. $dom = new DOMDocument( '1.0', 'utf-8' );
  274. $siteAccessListDOMNode = $dom->createElement( 'site-access-list' );
  275. $dom->appendChild( $siteAccessListDOMNode );
  276. foreach( $options['site_access_array'] as $siteAccess )
  277. {
  278. unset( $siteAccessNode );
  279. $siteAccessNode = $dom->createElement( 'site-access' );
  280. $siteAccessNode->appendChild( $dom->createTextNode( $siteAccess ) );
  281. $siteAccessListDOMNode->appendChild( $siteAccessNode );
  282. }
  283. return $siteAccessListDOMNode;
  284. }
  285. /*!
  286. \private
  287. Serializes and adds all contentobjects to package
  288. \param options
  289. */
  290. function createObjectListNode( $options )
  291. {
  292. if ( $options['versions'] == 'current' )
  293. {
  294. $version = true;
  295. }
  296. else
  297. {
  298. $version = false;
  299. }
  300. $path = $this->Package->path() . '/' . $this->contentObjectDirectory();
  301. if ( !file_exists( $path ) )
  302. eZDir::mkdir( $path, false, true );
  303. $dom = new DOMDocument( '1.0', 'utf-8' );
  304. // Store objects to separate files or not
  305. $storeToMultiple = count( $this->ObjectArray ) >= self::STORE_OBJECTS_TO_SEPARATE_FILES_THRESHOLD ? true : false;
  306. if ( $storeToMultiple )
  307. $objectListNode = $dom->createElement( 'object-files-list' );
  308. else
  309. $objectListNode = $dom->createElement( 'object-list' );
  310. $dom->appendChild( $objectListNode );
  311. foreach( array_keys( $this->ObjectArray ) as $objectID )
  312. {
  313. $objectNode = $this->ObjectArray[$objectID]->serialize( $this->Package, $version, $options, $this->NodeObjectArray, $this->RootNodeIDArray );
  314. if ( $storeToMultiple )
  315. {
  316. $fileName = 'object-' . $objectNode->getAttribute( 'remote_id' ) . '.xml';
  317. $filePath = $path . '/' . $fileName;
  318. $objectFileNode = $dom->createElement( 'object-file' );
  319. $objectFileNode->setAttribute( 'filename', $fileName );
  320. $objectListNode->appendChild( $objectFileNode );
  321. $partDOM = new DOMDocument( '1.0', 'utf-8' );
  322. $partDOM->formatOutput = true;
  323. $importedObjectNode = $partDOM->importNode( $objectNode, true );
  324. $partDOM->appendChild( $importedObjectNode );
  325. $this->Package->storeDOM( $filePath, $partDOM );
  326. unset( $partDOM );
  327. unset( $objectFileNode );
  328. }
  329. else
  330. {
  331. $importedObjectNode = $dom->importNode( $objectNode, true );
  332. $objectListNode->appendChild( $importedObjectNode );
  333. }
  334. unset( $objectNode );
  335. }
  336. return $objectListNode;
  337. }
  338. /*!
  339. \private
  340. Generate list of content objects to export, and store them to
  341. \param nodeAssignment which node assignments to include, either 'selected' or 'main'
  342. */
  343. function generateObjectArray( $nodeAssignment )
  344. {
  345. foreach( $this->NodeObjectArray as $contentNode )
  346. {
  347. if ( $nodeAssignment == 'main' )
  348. {
  349. if ( $contentNode->attribute( 'main_node_id' ) == $contentNode->attribute( 'node_id' ) )
  350. {
  351. $this->ObjectArray[(string)$contentNode->attribute( 'contentobject_id' )] = $contentNode->object();
  352. }
  353. }
  354. else
  355. {
  356. $this->ObjectArray[(string)$contentNode->attribute( 'contentobject_id' )] = $contentNode->object();
  357. }
  358. }
  359. }
  360. /*!
  361. \private
  362. */
  363. function &generateFetchAliasArray()
  364. {
  365. $dom = new DOMDocument( '1.0', 'utf-8' );
  366. $fetchAliasListDOMNode = $dom->createElement( 'fetch-alias-list' );
  367. $registeredAliases = array();
  368. foreach( array_keys( $this->TemplateFileArray ) as $siteAccess )
  369. {
  370. $aliasINI = eZINI::instance( 'fetchalias.ini', 'settings', null, null, true );
  371. $aliasINI->prependOverrideDir( "siteaccess/$siteAccess", false, 'siteaccess' );
  372. $aliasINI->loadCache();
  373. foreach ( $this->TemplateFileArray[$siteAccess] as $filename )
  374. {
  375. $fp = fopen( $filename, 'r' );
  376. if ( !$fp )
  377. {
  378. eZDebug::writeError( 'Could not open ' . $filename . ' during content object export.',
  379. 'eZContentObjectPackageHandler::generateFethAliasArray()' );
  380. continue;
  381. }
  382. $str = fread( $fp, filesize( $filename ) );
  383. $matchArray = array();
  384. preg_match_all( "#.*fetch_alias\([ ]*([a-zA-Z0-9_]+)[ |,|)]+.*#U", $str, $matchArray, PREG_PATTERN_ORDER );
  385. foreach( $matchArray[1] as $fetchAlias )
  386. {
  387. if ( isset( $registeredAliases[$fetchAlias] ) )
  388. {
  389. continue;
  390. }
  391. $registeredAliases[$fetchAlias] = true;
  392. unset( $fetchAliasDOMNode );
  393. $fetchAliasDOMNode = $dom->createElement( 'fetch-alias' );
  394. $fetchAliasDOMNode->setAttribute( 'name', $fetchAlias );
  395. $fetchAliasDOMNode->setAttribute( 'site-access', $siteAccess );
  396. $fetchBlock = $aliasINI->group( $fetchAlias );
  397. if ( isset( $fetchBlock['Constant'] ) )
  398. {
  399. foreach ( $fetchBlock['Constant'] as $matchKey => $value )
  400. {
  401. if ( strpos( $matchKey, 'class_' ) === 0 &&
  402. is_int( $value ) )
  403. {
  404. $contentClass = eZContentClass::fetch( $value );
  405. $fetchBlock['Constant']['class_remote_id'] = $contentClass->attribute( 'remote_id' );
  406. }
  407. if ( strpos( $matchKey, 'node_' ) === 0 &&
  408. is_int( $value ) )
  409. {
  410. $contentTreeNode = eZContentObjectTreeNode::fetch( $value );
  411. $fetchBlock['Constant']['node_remote_id'] = $contentTreeNode->attribute( 'remote_id' );
  412. }
  413. if ( strpos( $matchKey, 'parent_node_' ) === 0 &&
  414. is_int( $value ) )
  415. {
  416. $contentTreeNode = eZContentObjectTreeNode::fetch( $value );
  417. $fetchBlock['Constant']['parent_node_remote_id'] = $contentTreeNode->attribute( 'remote_id' );
  418. }
  419. if ( strpos( $matchKey, 'object_' ) === 0 &&
  420. is_int( $value ) )
  421. {
  422. $contentObject = eZContentObject::fetch( $value );
  423. $fetchBlock['Constant']['object_remote_id'] = $contentObject->attribute( 'remote_id' );
  424. }
  425. }
  426. }
  427. $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $fetchAlias, $fetchBlock ), true );
  428. $fetchAliasDOMNode->appendChild( $importedNode );
  429. $fetchAliasListDOMNode->appendChild( $fetchAliasDOMNode );
  430. }
  431. }
  432. }
  433. return $fetchAliasListDOMNode;
  434. }
  435. /*!
  436. \private
  437. */
  438. function &generateTemplateFilenameArray()
  439. {
  440. $dom = new DOMDocument( '1.0', 'utf-8' );
  441. $templateListDOMNode = $dom->createElement( 'template-list' );
  442. $dom->appendChild( $templateListDOMNode );
  443. foreach( array_keys( $this->OverrideSettingsArray ) as $siteAccess )
  444. {
  445. $this->TemplateFileArray[$siteAccess] = array();
  446. $overrideArray = eZTemplateDesignResource::overrideArray( $siteAccess );
  447. foreach( $this->OverrideSettingsArray[$siteAccess] as $override )
  448. {
  449. $customMatchArray = $overrideArray['/' . $override['Source']]['custom_match'];
  450. foreach( $customMatchArray as $customMatch )
  451. {
  452. if ( $customMatch['conditions'] == null )
  453. {
  454. //$templateListDOMNode->appendChild( $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' ) );
  455. //$this->TemplateFileArray[$siteAccess][] = $customMatch['match_file'];
  456. }
  457. else if ( count( array_diff( $customMatch['conditions'], $override['Match'] ) ) == 0 &&
  458. count( array_diff( $override['Match'], $customMatch['conditions'] ) ) == 0 )
  459. {
  460. unset( $node );
  461. $node = $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' );
  462. $importedNode = $dom->importNode( $node, true );
  463. $templateListDOMNode->appendChild( $importedNode );
  464. $this->TemplateFileArray[$siteAccess][] = $customMatch['match_file'];
  465. }
  466. }
  467. }
  468. }
  469. return $templateListDOMNode;
  470. //TODO : add templates included in templates here.
  471. }
  472. /*!
  473. \private
  474. Add file to repository and return DONNode description of file
  475. \param filename
  476. \param siteAccess
  477. \param filetype (optional)
  478. */
  479. function createDOMNodeFromFile( $filename, $siteAccess, $filetype = false )
  480. {
  481. $path = substr( $filename, strpos( $filename, '/', 7 ) );
  482. $dom = new DOMDocument( '1.0', 'utf-8' );
  483. $fileDOMNode = $dom->createElement( 'file' );
  484. $fileDOMNode->setAttribute( 'site-access', $siteAccess );
  485. if ( $filetype !== false )
  486. {
  487. $fileDOMNode->setAttribute( 'file-type', $filetype );
  488. }
  489. $dom->appendChild( $fileDOMNode );
  490. $originalPathNode = $dom->createElement( 'original-path' );
  491. $originalPathNode->appendChild( $dom->createTextNode( $filename ) );
  492. $fileDOMNode->appendChild( $originalPathNode );
  493. $pathNode = $dom->createElement( 'path' );
  494. $pathNode->appendChild( $dom->createTextNode( $path ) );
  495. $fileDOMNode->appendChild( $pathNode );
  496. $destinationPath = $this->Package->path() . '/' . eZContentObjectPackageHandler::contentObjectDirectory() . '/' . $path;
  497. eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true );
  498. eZFileHandler::copy( $filename, $destinationPath );
  499. return $fileDOMNode;
  500. }
  501. /*!
  502. \private
  503. Get all template overrides used by exported objects
  504. \param siteAccessArray site access array
  505. */
  506. function &generateOverrideSettingsArray( $siteAccessArray, $minimalTemplateSet )
  507. {
  508. $datatypeHash = array();
  509. $simpleMatchList = array();
  510. $regexpMatchList = array();
  511. foreach ( $siteAccessArray as $siteAccess )
  512. {
  513. $overrideINI = eZINI::instance( 'override.ini', 'settings', null, null, true );
  514. $overrideINI->prependOverrideDir( "siteaccess/$siteAccess", false, 'siteaccess' );
  515. $overrideINI->loadCache();
  516. $matchBlock = false;
  517. $blockMatchArray = array();
  518. foreach( array_keys( $this->NodeObjectArray ) as $nodeID )
  519. {
  520. // Extract some information that will be used
  521. unset( $contentNode, $contentObject, $contentClass );
  522. $contentNode = $this->NodeObjectArray[$nodeID];
  523. $contentObject = $contentNode->attribute( 'object' );
  524. $contentClass = $contentObject->attribute( 'content_class' );
  525. $attributeList = $contentClass->fetchAttributes( false, false, false );
  526. $datatypeList = array();
  527. foreach ( $attributeList as $attribute )
  528. {
  529. $datatypeList[] = $attribute['data_type_string'];
  530. if ( !isset( $datatypeHash[$attribute['data_type_string']] ) )
  531. {
  532. $datatype = eZDataType::create( $attribute['data_type_string'] );
  533. $datatypeHash[$attribute['data_type_string']] = $datatype;
  534. if ( !method_exists( $datatype, 'templateList' ) )
  535. continue;
  536. $templateList = $datatype->templateList();
  537. if ( $templateList === false )
  538. continue;
  539. foreach ( $templateList as $templateMatch )
  540. {
  541. if ( is_string( $templateMatch ) )
  542. {
  543. $simpleMatchList[] = $templateMatch;
  544. }
  545. else if ( is_array( $templateMatch ) )
  546. {
  547. if ( $templateMatch[0] == 'regexp' )
  548. {
  549. $regexpMatchList[] = $templateMatch[1];
  550. }
  551. }
  552. }
  553. }
  554. }
  555. $datatypeText = implode( '|', array_unique( $datatypeList ) );
  556. foreach( array_keys( $overrideINI->groups() ) as $blockName )
  557. {
  558. if ( isset( $blockMatchArray[$blockName] ) )
  559. {
  560. continue;
  561. }
  562. $blockData = $overrideINI->group( $blockName );
  563. $sourceName = $blockData['Source'];
  564. $matchSettings = false;
  565. if ( isset( $blockData['Match'] ) )
  566. $matchSettings = $blockData['Match'];
  567. $matchValue = array();
  568. $validMatch = true;
  569. $hasMatchType = false;
  570. if ( $matchSettings )
  571. {
  572. foreach( array_keys( $matchSettings ) as $matchType )
  573. {
  574. switch( $matchType )
  575. {
  576. case 'object':
  577. {
  578. $hasMatchType = true;
  579. if ( $contentNode->attribute( 'contentobject_id' ) != $matchSettings[$matchType] )
  580. {
  581. $validMatch = false;
  582. }
  583. else
  584. {
  585. $matchValue[$this->OverrideObjectRemoteID] = $contentObject->attribute( 'remote_id' );
  586. }
  587. } break;
  588. case 'node':
  589. {
  590. $hasMatchType = true;
  591. if ( $nodeID != $matchSettings[$matchType] )
  592. {
  593. $validMatch = false;
  594. }
  595. else
  596. {
  597. $matchValue[$this->OverrideNodeRemoteID] = $contentNode->attribute( 'remote_id' );
  598. }
  599. } break;
  600. case 'parent_node':
  601. {
  602. $hasMatchType = true;
  603. if ( $contentNode->attribute( 'parent_node_id' ) != $matchSettings[$matchType] )
  604. {
  605. $validMatch = false;
  606. }
  607. else
  608. {
  609. $parentNode = $contentNode->attribute( 'parent' );
  610. $matchValue[$this->OverrideParentNodeRemoteID] = $parentNode->attribute( 'remote_id' );
  611. }
  612. } break;
  613. case 'class':
  614. {
  615. $hasMatchType = true;
  616. if ( $contentObject->attribute( 'contentclass_id' ) != $matchSettings[$matchType] )
  617. {
  618. $validMatch = false;
  619. }
  620. else
  621. {
  622. $matchValue[$this->OverrideClassRemoteID] = $contentClass->attribute( 'remote_id' );
  623. }
  624. } break;
  625. case 'class_identifier':
  626. {
  627. $hasMatchType = true;
  628. if ( $contentObject->attribute( 'class_identifier' ) != $matchSettings[$matchType] )
  629. {
  630. $validMatch = false;
  631. }
  632. } break;
  633. case 'section':
  634. {
  635. $hasMatchType = true;
  636. if ( $contentObject->attribute( 'section_id' ) != $matchSettings[$matchType] )
  637. {
  638. $validMatch = false;
  639. }
  640. } break;
  641. case 'depth':
  642. {
  643. $hasMatchType = true;
  644. if ( $contentNode->attribute( 'depth' ) != $matchSettings[$matchType] )
  645. {
  646. $validMatch = false;
  647. }
  648. } break;
  649. }
  650. if ( !$validMatch )
  651. {
  652. break;
  653. }
  654. }
  655. }
  656. else
  657. {
  658. $validMatch = false;
  659. }
  660. if ( !$hasMatchType )
  661. {
  662. // Datatype match, we include overrides for datatype templates
  663. if ( preg_match( "#^content/datatype/[a-zA-Z]+/(" . $datatypeText . ")\\.tpl$#", $sourceName ) )
  664. {
  665. $validMatch = true;
  666. $hasMatchType = true;
  667. }
  668. else if ( in_array( $sourceName, $simpleMatchList ) )
  669. {
  670. $validMatch = true;
  671. $hasMatchType = true;
  672. }
  673. else
  674. {
  675. foreach ( $regexpMatchList as $regexpMatch )
  676. {
  677. if ( preg_match( $regexpMatch, $sourceName ) )
  678. {
  679. $validMatch = true;
  680. $hasMatchType = true;
  681. }
  682. }
  683. }
  684. }
  685. if ( $validMatch )
  686. {
  687. if ( !$minimalTemplateSet or
  688. $hasMatchType )
  689. {
  690. $blockMatchArray[$blockName] = array_merge( $blockData,
  691. $matchValue );
  692. }
  693. }
  694. }
  695. }
  696. $this->OverrideSettingsArray[$siteAccess] = $blockMatchArray;
  697. }
  698. $dom = new DOMDocument( '1.0', 'utf-8' );
  699. $overrideSettingsListDOMNode = $dom->createElement( 'override-list' );
  700. $dom->appendChild( $overrideSettingsListDOMNode );
  701. foreach ( $this->OverrideSettingsArray as $siteAccess => $blockMatchArray )
  702. {
  703. foreach( $blockMatchArray as $blockName => $iniGroup )
  704. {
  705. unset( $blockMatchNode );
  706. $blockMatchNode = $dom->createElement( 'block' );
  707. $blockMatchNode->setAttribute( 'name', $blockName );
  708. $blockMatchNode->setAttribute( 'site-access', $siteAccess );
  709. $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $blockName, $iniGroup ), true );
  710. $blockMatchNode->appendChild( $importedNode );
  711. $overrideSettingsListDOMNode->appendChild( $blockMatchNode );
  712. }
  713. }
  714. return $overrideSettingsListDOMNode;
  715. }
  716. /*!
  717. \private
  718. Get list of all class objects used in by the nodes in NodeArray
  719. */
  720. function &generateClassIDArray()
  721. {
  722. $classIDArray = array();
  723. foreach( $this->NodeObjectArray as $nodeObject )
  724. {
  725. $contentObject = $nodeObject->object();
  726. $classIDArray[] = $contentObject->attribute( 'contentclass_id' );
  727. }
  728. $classIDArray = array_unique( $classIDArray );
  729. return $classIDArray;
  730. }
  731. /*!
  732. Uninstalls all previously installed content objects.
  733. */
  734. function uninstall( $package, $installType, $parameters,
  735. $name, $os, $filename, $subdirectory,
  736. $content, &$installParameters,
  737. &$installData )
  738. {
  739. $this->Package = $package;
  740. if ( isset( $installParameters['error']['error_code'] ) )
  741. $errorCode = $installParameters['error']['error_code'];
  742. else
  743. $errorCode = false;
  744. // Error codes reserverd for content object uninstallation
  745. if ( !$errorCode || ( $errorCode >= self::UNINSTALL_OBJECTS_ERROR_RANGE_FROM &&
  746. $errorCode <= self::UNINSTALL_OBJECTS_ERROR_RANGE_TO ) )
  747. {
  748. $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 );
  749. if ( $objectListNode )
  750. {
  751. $objectNodes = $objectListNode->getElementsByTagName( 'object' );
  752. }
  753. else
  754. {
  755. $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 );
  756. $objectNodes = $objectListNode->getElementsByTagName( 'object-file' );
  757. }
  758. // loop intentionally from the last until the first
  759. // objects need to be uninstalled in reverse order of installation
  760. for ( $i = $objectNodes->length - 1; $i >=0; $i-- )
  761. {
  762. $objectNode = $objectNodes->item( $i );
  763. $realObjectNode = $this->getRealObjectNode( $objectNode );
  764. $objectRemoteID = $realObjectNode->getAttribute( 'remote_id' );
  765. $name = $realObjectNode->getAttribute( 'name' );
  766. if ( isset( $installParameters['error']['error_code'] ) &&
  767. !$this->isErrorElement( $objectRemoteID, $installParameters ) )
  768. continue;
  769. if ( isset( $object ) )
  770. {
  771. eZContentObject::clearCache( $object->attribute( 'id' ) );
  772. unset( $object );
  773. }
  774. $object = eZContentObject::fetchByRemoteID( $objectRemoteID );
  775. if ( $object !== null )
  776. {
  777. $modified = $object->attribute( 'modified' );
  778. $published = $object->attribute( 'published' );
  779. if ( $modified > $published )
  780. {
  781. $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_MODIFIED,
  782. $installParameters, false, $this->HandlerType );
  783. if ( $choosenAction == eZContentObject::PACKAGE_KEEP )
  784. {
  785. continue;
  786. }
  787. if ( $choosenAction != eZContentObject::PACKAGE_DELETE )
  788. {
  789. $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_MODIFIED,
  790. 'element_id' => $objectRemoteID,
  791. 'description' => ezpI18n::tr( 'kernel/package',
  792. "Object '%objectname' has been modified since installation. Are you sure you want to remove it?",
  793. false, array( '%objectname' => $name ) ),
  794. 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', 'Remove' ),
  795. eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) );
  796. return false;
  797. }
  798. }
  799. $assignedNodes = $object->attribute( 'assigned_nodes' );
  800. $assignedNodeIDArray = array();
  801. foreach( $assignedNodes as $node )
  802. {
  803. $assignedNodeIDArray[] = $node->attribute( 'node_id' );
  804. }
  805. if ( count( $assignedNodeIDArray ) == 0 )
  806. continue;
  807. $info = eZContentObjectTreeNode::subtreeRemovalInformation( $assignedNodeIDArray );
  808. $childrenCount = $info['total_child_count'];
  809. if ( $childrenCount > 0 )
  810. {
  811. $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_HAS_CHILDREN,
  812. $installParameters, false, $this->HandlerType );
  813. if ( $choosenAction == eZContentObject::PACKAGE_KEEP )
  814. {
  815. continue;
  816. }
  817. if ( $choosenAction != eZContentObject::PACKAGE_DELETE )
  818. {
  819. $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_HAS_CHILDREN,
  820. 'element_id' => $objectRemoteID,
  821. 'description' => ezpI18n::tr( 'kernel/package',
  822. "Object '%objectname' has %childrencount sub-item(s) that will be removed.",
  823. false, array( '%objectname' => $name,
  824. '%childrencount' => $childrenCount ) ),
  825. 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', "Remove object and its sub-item(s)" ),
  826. eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) );
  827. return false;
  828. }
  829. }
  830. eZContentObjectTreeNode::removeSubtrees( $assignedNodeIDArray, false );
  831. //eZContentObjectOperations::remove( $object->attribute( 'id' ) );
  832. }
  833. else
  834. {
  835. eZDebug::writeNotice( "Can't uninstall object '$name': object not found", 'eZContentObjectPackageHandler::uninstall' );
  836. }
  837. unset( $realObjectNode );
  838. }
  839. }
  840. return true;
  841. }
  842. /*!
  843. Creates a new contentobject as defined in the xml structure.
  844. */
  845. function install( $package, $installType, $parameters,
  846. $name, $os, $filename, $subdirectory,
  847. $content, &$installParameters,
  848. &$installData )
  849. {
  850. $this->Package = $package;
  851. if ( isset( $installParameters['error']['error_code'] ) )
  852. $errorCode = $installParameters['error']['error_code'];
  853. else
  854. $errorCode = false;
  855. // Error codes reservered for content object installation
  856. if ( !$errorCode || ( $errorCode >= self::INSTALL_OBJECTS_ERROR_RANGE_FROM &&
  857. $errorCode <= self::INSTALL_OBJECTS_ERROR_RANGE_TO ) )
  858. {
  859. $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 );
  860. if ( $objectListNode )
  861. {
  862. $objectNodes = $objectListNode->getElementsByTagName( 'object' );
  863. }
  864. else
  865. {
  866. $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 );
  867. $objectNodes = $objectListNode->getElementsByTagName( 'object-file' );
  868. }
  869. if ( !$this->installContentObjects( $objectNodes,
  870. $content->getElementsByTagName( 'top-node-list' )->item( 0 ),
  871. $installParameters ) )
  872. return false;
  873. $errorCode = false;
  874. }
  875. if ( !$this->installTemplates( $content->getElementsByTagName( 'template-list' )->item( 0 ),
  876. $package,
  877. $subdirectory,
  878. $installParameters ) )
  879. return false;
  880. if ( !$this->installOverrides( $content->getElementsByTagName( 'override-list' )->item( 0 ),
  881. $installParameters ) )
  882. return false;
  883. if ( !$this->installFetchAliases( $content->getElementsByTagName( 'fetch-alias-list' )->item( 0 ),
  884. $installParameters ) )
  885. return false;
  886. return true;
  887. }
  888. /*!
  889. \private
  890. Serialize and install content objects
  891. \param objectNodes object-list DOMNode
  892. \param topNodeListNode
  893. \param installParameters install parameters
  894. */
  895. function installContentObjects( $objectNodes, $topNodeListNode, &$installParameters )
  896. {
  897. if ( isset( $installParameters['user_id'] ) )
  898. $userID = $installParameters['user_id'];
  899. else
  900. $userID = eZUser::currentUserID();
  901. $handlerType = $this->handlerType();
  902. $firstInstalledID = null;
  903. foreach( $objectNodes as $objectNode )
  904. {
  905. $realObjectNode = $this->getRealObjectNode( $objectNode );
  906. // Cycle until we reach an element where error has occured.
  907. // If action has been choosen, try install this item again, else skip it.
  908. if ( isset( $installParameters['error']['error_code'] ) &&
  909. !$this->isErrorElement( $realObjectNode->getAttribute( 'remote_id' ), $installParameters ) )
  910. {
  911. continue;
  912. }
  913. //we are here, it means we'll try to install some object.
  914. if ( !$firstInstalledID )
  915. {
  916. $firstInstalledID = $realObjectNode->getAttribute( 'remote_id' );
  917. }
  918. $newObject = eZContentObject::unserialize( $this->Package, $realObjectNode, $installParameters, $userID, $handlerType );
  919. if ( !$newObject )
  920. {
  921. return false;
  922. }
  923. if ( is_object( $newObject ) )
  924. {
  925. eZContentObject::clearCache( $newObject->attribute( 'id' ) );
  926. unset( $newObject );
  927. }
  928. unset( $realObjectNode );
  929. if ( isset( $installParameters['error'] ) && count( $installParameters['error'] ) )
  930. {
  931. $installParameters['error'] = array();
  932. }
  933. }
  934. $this->installSuspendedNodeAssignment( $installParameters );
  935. $this->installSuspendedObjectRelations( $installParameters );
  936. // Call postUnserialize on all installed objects
  937. foreach( $objectNodes as $objectNode )
  938. {
  939. if ( $objectNode->localName == 'object' )
  940. {
  941. $remoteID = $objectNode->getAttribute( 'remote_id' );
  942. }
  943. else
  944. {
  945. $remoteID = substr( $objectNode->getAttribute( 'filename' ), 7, 32 );
  946. }
  947. // Begin from the object that we started from in the previous cycle
  948. if ( $firstInstalledID && $remoteID != $firstInstalledID )
  949. {
  950. continue;
  951. }
  952. else
  953. {
  954. $firstInstalledID = null;
  955. }
  956. $object = eZContentObject::fetchByRemoteID( $remoteID );
  957. if ( is_object( $object ) )
  958. {
  959. $object->postUnserialize( $this->Package );
  960. eZContentObject::clearCache( $object->attribute( 'id' ) );
  961. }
  962. unset( $object );
  963. }
  964. return true;
  965. }
  966. /*!
  967. \private
  968. \param install parameters
  969. */
  970. function installSuspendedNodeAssignment( &$installParameters )
  971. {
  972. if ( !isset( $installParameters['suspended-nodes'] ) )
  973. {
  974. return;
  975. }
  976. foreach ( $installParameters['suspended-nodes'] as $parentNodeRemoteID => $suspendedNodeInfo )
  977. {
  978. $parentNode = eZContentObjectTreeNode::fetchByRemoteID( $parentNodeRemoteID );
  979. if ( $parentNode !== null )
  980. {
  981. $nodeInfo = $suspendedNodeInfo['nodeinfo'];
  982. $nodeInfo['parent_node'] = $parentNode->attribute( 'node_id' );
  983. $existNodeAssignment = eZPersistentObject::fetchObject( eZNodeAssignment::definition(),
  984. null,
  985. $nodeInfo );
  986. $nodeInfo['priority'] = $suspendedNodeInfo['priority'];
  987. if( !is_object( $existNodeAssignment ) )
  988. {
  989. $nodeAssignment = eZNodeAssignment::create( $nodeInfo );
  990. $nodeAssignment->store();
  991. }
  992. $contentObject = eZContentObject::fetch( $nodeInfo['contentobject_id'] );
  993. if ( is_object( $contentObject ) && $contentObject->attribute( 'current_version' ) == $nodeInfo['contentobject_version'] )
  994. {
  995. eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $nodeInfo['contentobject_id'],
  996. 'version' => $nodeInfo['contentobject_version'] ) );
  997. }
  998. if ( isset( $nodeInfo['is_main'] ) && $nodeInfo['is_main'] )
  999. {
  1000. $existingMainNode = eZContentObjectTreeNode::fetchByRemoteID( $nodeInfo['parent_remote_id'], false );
  1001. if ( $existingMainNode )
  1002. {
  1003. eZContentObjectTreeNode::updateMainNodeID( $existingMainNode['node_id'],
  1004. $nodeInfo['contentobject_id'],
  1005. $nodeInfo['contentobject_version'],
  1006. $nodeInfo['parent_node'] );
  1007. }
  1008. }
  1009. }
  1010. else
  1011. {
  1012. eZDebug::writeError( 'Can not find parent node by remote-id ID = ' . $parentNodeRemoteID, 'eZContentObjectPackageHandler::installSuspendedNodeAssignment()' );
  1013. }
  1014. unset( $installParameters['suspended-nodes'][$parentNodeRemoteID] );
  1015. }
  1016. }
  1017. /*!
  1018. \private
  1019. Installs suspended content object relations (need for complex content-relations structure)
  1020. \param install parameters
  1021. */
  1022. function installSuspendedObjectRelations( &$installParameters )
  1023. {
  1024. if ( !isset( $installParameters['suspended-relations'] ) )
  1025. {
  1026. return;
  1027. }
  1028. foreach( $installParameters['suspended-relations'] as $suspendedObjectRelation )
  1029. {
  1030. $contentObjectID = $suspendedObjectRelation['contentobject-id'];
  1031. $contentObjectVersionID = $suspendedObjectRelation['contentobject-version'];
  1032. $contentObjectVersion = eZContentObjectVersion::fetchVersion( $contentObjectVersionID, $contentObjectID );
  1033. if ( is_object( $contentObjectVersion ) )
  1034. {
  1035. $relatedObjectRemoteID = $suspendedObjectRelation['related-object-remote-id'];
  1036. $relatedObject = eZContentObject::fetchByRemoteID( $relatedObjectRemoteID );
  1037. $relatedObjectID = ( $relatedObject !== null ) ? $relatedObject->attribute( 'id'

Large files files are truncated, but you can click here to view the full file