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

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

https://github.com/granitegreg/ezpublish
PHP | 1773 lines | 1446 code | 147 blank | 180 comment | 190 complexity | bf7c185563cadff3926dc3ce613765f8 MD5 | raw file
Possible License(s): 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-2011 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", __METHOD__ );
  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.', __METHOD__ );
  379. continue;
  380. }
  381. $str = fread( $fp, filesize( $filename ) );
  382. $matchArray = array();
  383. preg_match_all( "#.*fetch_alias\([ ]*([a-zA-Z0-9_]+)[ |,|)]+.*#U", $str, $matchArray, PREG_PATTERN_ORDER );
  384. foreach( $matchArray[1] as $fetchAlias )
  385. {
  386. if ( isset( $registeredAliases[$fetchAlias] ) )
  387. {
  388. continue;
  389. }
  390. $registeredAliases[$fetchAlias] = true;
  391. unset( $fetchAliasDOMNode );
  392. $fetchAliasDOMNode = $dom->createElement( 'fetch-alias' );
  393. $fetchAliasDOMNode->setAttribute( 'name', $fetchAlias );
  394. $fetchAliasDOMNode->setAttribute( 'site-access', $siteAccess );
  395. $fetchBlock = $aliasINI->group( $fetchAlias );
  396. if ( isset( $fetchBlock['Constant'] ) )
  397. {
  398. foreach ( $fetchBlock['Constant'] as $matchKey => $value )
  399. {
  400. if ( strpos( $matchKey, 'class_' ) === 0 &&
  401. is_int( $value ) )
  402. {
  403. $contentClass = eZContentClass::fetch( $value );
  404. $fetchBlock['Constant']['class_remote_id'] = $contentClass->attribute( 'remote_id' );
  405. }
  406. if ( strpos( $matchKey, 'node_' ) === 0 &&
  407. is_int( $value ) )
  408. {
  409. $contentTreeNode = eZContentObjectTreeNode::fetch( $value );
  410. $fetchBlock['Constant']['node_remote_id'] = $contentTreeNode->attribute( 'remote_id' );
  411. }
  412. if ( strpos( $matchKey, 'parent_node_' ) === 0 &&
  413. is_int( $value ) )
  414. {
  415. $contentTreeNode = eZContentObjectTreeNode::fetch( $value );
  416. $fetchBlock['Constant']['parent_node_remote_id'] = $contentTreeNode->attribute( 'remote_id' );
  417. }
  418. if ( strpos( $matchKey, 'object_' ) === 0 &&
  419. is_int( $value ) )
  420. {
  421. $contentObject = eZContentObject::fetch( $value );
  422. $fetchBlock['Constant']['object_remote_id'] = $contentObject->attribute( 'remote_id' );
  423. }
  424. }
  425. }
  426. $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $fetchAlias, $fetchBlock ), true );
  427. $fetchAliasDOMNode->appendChild( $importedNode );
  428. $fetchAliasListDOMNode->appendChild( $fetchAliasDOMNode );
  429. }
  430. }
  431. }
  432. return $fetchAliasListDOMNode;
  433. }
  434. /*!
  435. \private
  436. */
  437. function &generateTemplateFilenameArray()
  438. {
  439. $dom = new DOMDocument( '1.0', 'utf-8' );
  440. $templateListDOMNode = $dom->createElement( 'template-list' );
  441. $dom->appendChild( $templateListDOMNode );
  442. foreach( array_keys( $this->OverrideSettingsArray ) as $siteAccess )
  443. {
  444. $this->TemplateFileArray[$siteAccess] = array();
  445. $overrideArray = eZTemplateDesignResource::overrideArray( $siteAccess );
  446. foreach( $this->OverrideSettingsArray[$siteAccess] as $override )
  447. {
  448. $customMatchArray = $overrideArray['/' . $override['Source']]['custom_match'];
  449. foreach( $customMatchArray as $customMatch )
  450. {
  451. if ( $customMatch['conditions'] == null )
  452. {
  453. //$templateListDOMNode->appendChild( $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' ) );
  454. //$this->TemplateFileArray[$siteAccess][] = $customMatch['match_file'];
  455. }
  456. else if ( count( array_diff( $customMatch['conditions'], $override['Match'] ) ) == 0 &&
  457. count( array_diff( $override['Match'], $customMatch['conditions'] ) ) == 0 )
  458. {
  459. unset( $node );
  460. $node = $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' );
  461. $importedNode = $dom->importNode( $node, true );
  462. $templateListDOMNode->appendChild( $importedNode );
  463. $this->TemplateFileArray[$siteAccess][] = $customMatch['match_file'];
  464. }
  465. }
  466. }
  467. }
  468. return $templateListDOMNode;
  469. //TODO : add templates included in templates here.
  470. }
  471. /*!
  472. \private
  473. Add file to repository and return DONNode description of file
  474. \param filename
  475. \param siteAccess
  476. \param filetype (optional)
  477. */
  478. function createDOMNodeFromFile( $filename, $siteAccess, $filetype = false )
  479. {
  480. $path = substr( $filename, strpos( $filename, '/', 7 ) );
  481. $dom = new DOMDocument( '1.0', 'utf-8' );
  482. $fileDOMNode = $dom->createElement( 'file' );
  483. $fileDOMNode->setAttribute( 'site-access', $siteAccess );
  484. if ( $filetype !== false )
  485. {
  486. $fileDOMNode->setAttribute( 'file-type', $filetype );
  487. }
  488. $dom->appendChild( $fileDOMNode );
  489. $originalPathNode = $dom->createElement( 'original-path' );
  490. $originalPathNode->appendChild( $dom->createTextNode( $filename ) );
  491. $fileDOMNode->appendChild( $originalPathNode );
  492. $pathNode = $dom->createElement( 'path' );
  493. $pathNode->appendChild( $dom->createTextNode( $path ) );
  494. $fileDOMNode->appendChild( $pathNode );
  495. $destinationPath = $this->Package->path() . '/' . eZContentObjectPackageHandler::contentObjectDirectory() . '/' . $path;
  496. eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true );
  497. eZFileHandler::copy( $filename, $destinationPath );
  498. return $fileDOMNode;
  499. }
  500. /*!
  501. \private
  502. Get all template overrides used by exported objects
  503. \param siteAccessArray site access array
  504. */
  505. function &generateOverrideSettingsArray( $siteAccessArray, $minimalTemplateSet )
  506. {
  507. $datatypeHash = array();
  508. $simpleMatchList = array();
  509. $regexpMatchList = array();
  510. foreach ( $siteAccessArray as $siteAccess )
  511. {
  512. $overrideINI = eZINI::instance( 'override.ini', 'settings', null, null, true );
  513. $overrideINI->prependOverrideDir( "siteaccess/$siteAccess", false, 'siteaccess' );
  514. $overrideINI->loadCache();
  515. $matchBlock = false;
  516. $blockMatchArray = array();
  517. foreach( array_keys( $this->NodeObjectArray ) as $nodeID )
  518. {
  519. // Extract some information that will be used
  520. unset( $contentNode, $contentObject, $contentClass );
  521. $contentNode = $this->NodeObjectArray[$nodeID];
  522. $contentObject = $contentNode->attribute( 'object' );
  523. $contentClass = $contentObject->attribute( 'content_class' );
  524. $attributeList = $contentClass->fetchAttributes( false, false, false );
  525. $datatypeList = array();
  526. foreach ( $attributeList as $attribute )
  527. {
  528. $datatypeList[] = $attribute['data_type_string'];
  529. if ( !isset( $datatypeHash[$attribute['data_type_string']] ) )
  530. {
  531. $datatype = eZDataType::create( $attribute['data_type_string'] );
  532. $datatypeHash[$attribute['data_type_string']] = $datatype;
  533. if ( !method_exists( $datatype, 'templateList' ) )
  534. continue;
  535. $templateList = $datatype->templateList();
  536. if ( $templateList === false )
  537. continue;
  538. foreach ( $templateList as $templateMatch )
  539. {
  540. if ( is_string( $templateMatch ) )
  541. {
  542. $simpleMatchList[] = $templateMatch;
  543. }
  544. else if ( is_array( $templateMatch ) )
  545. {
  546. if ( $templateMatch[0] == 'regexp' )
  547. {
  548. $regexpMatchList[] = $templateMatch[1];
  549. }
  550. }
  551. }
  552. }
  553. }
  554. $datatypeText = implode( '|', array_unique( $datatypeList ) );
  555. foreach( array_keys( $overrideINI->groups() ) as $blockName )
  556. {
  557. if ( isset( $blockMatchArray[$blockName] ) )
  558. {
  559. continue;
  560. }
  561. $blockData = $overrideINI->group( $blockName );
  562. $sourceName = $blockData['Source'];
  563. $matchSettings = false;
  564. if ( isset( $blockData['Match'] ) )
  565. $matchSettings = $blockData['Match'];
  566. $matchValue = array();
  567. $validMatch = true;
  568. $hasMatchType = false;
  569. if ( $matchSettings )
  570. {
  571. foreach( array_keys( $matchSettings ) as $matchType )
  572. {
  573. switch( $matchType )
  574. {
  575. case 'object':
  576. {
  577. $hasMatchType = true;
  578. if ( $contentNode->attribute( 'contentobject_id' ) != $matchSettings[$matchType] )
  579. {
  580. $validMatch = false;
  581. }
  582. else
  583. {
  584. $matchValue[$this->OverrideObjectRemoteID] = $contentObject->attribute( 'remote_id' );
  585. }
  586. } break;
  587. case 'node':
  588. {
  589. $hasMatchType = true;
  590. if ( $nodeID != $matchSettings[$matchType] )
  591. {
  592. $validMatch = false;
  593. }
  594. else
  595. {
  596. $matchValue[$this->OverrideNodeRemoteID] = $contentNode->attribute( 'remote_id' );
  597. }
  598. } break;
  599. case 'parent_node':
  600. {
  601. $hasMatchType = true;
  602. if ( $contentNode->attribute( 'parent_node_id' ) != $matchSettings[$matchType] )
  603. {
  604. $validMatch = false;
  605. }
  606. else
  607. {
  608. $parentNode = $contentNode->attribute( 'parent' );
  609. $matchValue[$this->OverrideParentNodeRemoteID] = $parentNode->attribute( 'remote_id' );
  610. }
  611. } break;
  612. case 'class':
  613. {
  614. $hasMatchType = true;
  615. if ( $contentObject->attribute( 'contentclass_id' ) != $matchSettings[$matchType] )
  616. {
  617. $validMatch = false;
  618. }
  619. else
  620. {
  621. $matchValue[$this->OverrideClassRemoteID] = $contentClass->attribute( 'remote_id' );
  622. }
  623. } break;
  624. case 'class_identifier':
  625. {
  626. $hasMatchType = true;
  627. if ( $contentObject->attribute( 'class_identifier' ) != $matchSettings[$matchType] )
  628. {
  629. $validMatch = false;
  630. }
  631. } break;
  632. case 'section':
  633. {
  634. $hasMatchType = true;
  635. if ( $contentObject->attribute( 'section_id' ) != $matchSettings[$matchType] )
  636. {
  637. $validMatch = false;
  638. }
  639. } break;
  640. case 'depth':
  641. {
  642. $hasMatchType = true;
  643. if ( $contentNode->attribute( 'depth' ) != $matchSettings[$matchType] )
  644. {
  645. $validMatch = false;
  646. }
  647. } break;
  648. }
  649. if ( !$validMatch )
  650. {
  651. break;
  652. }
  653. }
  654. }
  655. else
  656. {
  657. $validMatch = false;
  658. }
  659. if ( !$hasMatchType )
  660. {
  661. // Datatype match, we include overrides for datatype templates
  662. if ( preg_match( "#^content/datatype/[a-zA-Z]+/(" . $datatypeText . ")\\.tpl$#", $sourceName ) )
  663. {
  664. $validMatch = true;
  665. $hasMatchType = true;
  666. }
  667. else if ( in_array( $sourceName, $simpleMatchList ) )
  668. {
  669. $validMatch = true;
  670. $hasMatchType = true;
  671. }
  672. else
  673. {
  674. foreach ( $regexpMatchList as $regexpMatch )
  675. {
  676. if ( preg_match( $regexpMatch, $sourceName ) )
  677. {
  678. $validMatch = true;
  679. $hasMatchType = true;
  680. }
  681. }
  682. }
  683. }
  684. if ( $validMatch )
  685. {
  686. if ( !$minimalTemplateSet or
  687. $hasMatchType )
  688. {
  689. $blockMatchArray[$blockName] = array_merge( $blockData,
  690. $matchValue );
  691. }
  692. }
  693. }
  694. }
  695. $this->OverrideSettingsArray[$siteAccess] = $blockMatchArray;
  696. }
  697. $dom = new DOMDocument( '1.0', 'utf-8' );
  698. $overrideSettingsListDOMNode = $dom->createElement( 'override-list' );
  699. $dom->appendChild( $overrideSettingsListDOMNode );
  700. foreach ( $this->OverrideSettingsArray as $siteAccess => $blockMatchArray )
  701. {
  702. foreach( $blockMatchArray as $blockName => $iniGroup )
  703. {
  704. unset( $blockMatchNode );
  705. $blockMatchNode = $dom->createElement( 'block' );
  706. $blockMatchNode->setAttribute( 'name', $blockName );
  707. $blockMatchNode->setAttribute( 'site-access', $siteAccess );
  708. $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $blockName, $iniGroup ), true );
  709. $blockMatchNode->appendChild( $importedNode );
  710. $overrideSettingsListDOMNode->appendChild( $blockMatchNode );
  711. }
  712. }
  713. return $overrideSettingsListDOMNode;
  714. }
  715. /*!
  716. \private
  717. Get list of all class objects used in by the nodes in NodeArray
  718. */
  719. function &generateClassIDArray()
  720. {
  721. $classIDArray = array();
  722. foreach( $this->NodeObjectArray as $nodeObject )
  723. {
  724. $contentObject = $nodeObject->object();
  725. $classIDArray[] = $contentObject->attribute( 'contentclass_id' );
  726. }
  727. $classIDArray = array_unique( $classIDArray );
  728. return $classIDArray;
  729. }
  730. /*!
  731. Uninstalls all previously installed content objects.
  732. */
  733. function uninstall( $package, $installType, $parameters,
  734. $name, $os, $filename, $subdirectory,
  735. $content, &$installParameters,
  736. &$installData )
  737. {
  738. $this->Package = $package;
  739. if ( isset( $installParameters['error']['error_code'] ) )
  740. $errorCode = $installParameters['error']['error_code'];
  741. else
  742. $errorCode = false;
  743. // Error codes reserverd for content object uninstallation
  744. if ( !$errorCode || ( $errorCode >= self::UNINSTALL_OBJECTS_ERROR_RANGE_FROM &&
  745. $errorCode <= self::UNINSTALL_OBJECTS_ERROR_RANGE_TO ) )
  746. {
  747. $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 );
  748. if ( $objectListNode )
  749. {
  750. $objectNodes = $objectListNode->getElementsByTagName( 'object' );
  751. }
  752. else
  753. {
  754. $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 );
  755. $objectNodes = $objectListNode->getElementsByTagName( 'object-file' );
  756. }
  757. // loop intentionally from the last until the first
  758. // objects need to be uninstalled in reverse order of installation
  759. for ( $i = $objectNodes->length - 1; $i >=0; $i-- )
  760. {
  761. $objectNode = $objectNodes->item( $i );
  762. $realObjectNode = $this->getRealObjectNode( $objectNode );
  763. $objectRemoteID = $realObjectNode->getAttribute( 'remote_id' );
  764. $name = $realObjectNode->getAttribute( 'name' );
  765. if ( isset( $installParameters['error']['error_code'] ) &&
  766. !$this->isErrorElement( $objectRemoteID, $installParameters ) )
  767. continue;
  768. if ( isset( $object ) )
  769. {
  770. eZContentObject::clearCache( $object->attribute( 'id' ) );
  771. unset( $object );
  772. }
  773. $object = eZContentObject::fetchByRemoteID( $objectRemoteID );
  774. if ( $object !== null )
  775. {
  776. $modified = $object->attribute( 'modified' );
  777. $published = $object->attribute( 'published' );
  778. if ( $modified > $published )
  779. {
  780. $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_MODIFIED,
  781. $installParameters, false, $this->HandlerType );
  782. if ( $choosenAction == eZContentObject::PACKAGE_KEEP )
  783. {
  784. continue;
  785. }
  786. if ( $choosenAction != eZContentObject::PACKAGE_DELETE )
  787. {
  788. $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_MODIFIED,
  789. 'element_id' => $objectRemoteID,
  790. 'description' => ezpI18n::tr( 'kernel/package',
  791. "Object '%objectname' has been modified since installation. Are you sure you want to remove it?",
  792. false, array( '%objectname' => $name ) ),
  793. 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', 'Remove' ),
  794. eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) );
  795. return false;
  796. }
  797. }
  798. $assignedNodes = $object->attribute( 'assigned_nodes' );
  799. $assignedNodeIDArray = array();
  800. foreach( $assignedNodes as $node )
  801. {
  802. $assignedNodeIDArray[] = $node->attribute( 'node_id' );
  803. }
  804. if ( count( $assignedNodeIDArray ) == 0 )
  805. continue;
  806. $info = eZContentObjectTreeNode::subtreeRemovalInformation( $assignedNodeIDArray );
  807. $childrenCount = $info['total_child_count'];
  808. if ( $childrenCount > 0 )
  809. {
  810. $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_HAS_CHILDREN,
  811. $installParameters, false, $this->HandlerType );
  812. if ( $choosenAction == eZContentObject::PACKAGE_KEEP )
  813. {
  814. continue;
  815. }
  816. if ( $choosenAction != eZContentObject::PACKAGE_DELETE )
  817. {
  818. $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_HAS_CHILDREN,
  819. 'element_id' => $objectRemoteID,
  820. 'description' => ezpI18n::tr( 'kernel/package',
  821. "Object '%objectname' has %childrencount sub-item(s) that will be removed.",
  822. false, array( '%objectname' => $name,
  823. '%childrencount' => $childrenCount ) ),
  824. 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', "Remove object and its sub-item(s)" ),
  825. eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) );
  826. return false;
  827. }
  828. }
  829. eZContentObjectTreeNode::removeSubtrees( $assignedNodeIDArray, false );
  830. //eZContentObjectOperations::remove( $object->attribute( 'id' ) );
  831. }
  832. else
  833. {
  834. eZDebug::writeNotice( "Can't uninstall object '$name': object not found", __METHOD__ );
  835. }
  836. unset( $realObjectNode );
  837. }
  838. }
  839. return true;
  840. }
  841. /*!
  842. Creates a new contentobject as defined in the xml structure.
  843. */
  844. function install( $package, $installType, $parameters,
  845. $name, $os, $filename, $subdirectory,
  846. $content, &$installParameters,
  847. &$installData )
  848. {
  849. $this->Package = $package;
  850. if ( isset( $installParameters['error']['error_code'] ) )
  851. $errorCode = $installParameters['error']['error_code'];
  852. else
  853. $errorCode = false;
  854. // Error codes reservered for content object installation
  855. if ( !$errorCode || ( $errorCode >= self::INSTALL_OBJECTS_ERROR_RANGE_FROM &&
  856. $errorCode <= self::INSTALL_OBJECTS_ERROR_RANGE_TO ) )
  857. {
  858. $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 );
  859. if ( $objectListNode )
  860. {
  861. $objectNodes = $objectListNode->getElementsByTagName( 'object' );
  862. }
  863. else
  864. {
  865. $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 );
  866. $objectNodes = $objectListNode->getElementsByTagName( 'object-file' );
  867. }
  868. if ( !$this->installContentObjects( $objectNodes,
  869. $content->getElementsByTagName( 'top-node-list' )->item( 0 ),
  870. $installParameters ) )
  871. return false;
  872. $errorCode = false;
  873. }
  874. if ( !$this->installTemplates( $content->getElementsByTagName( 'template-list' )->item( 0 ),
  875. $package,
  876. $subdirectory,
  877. $installParameters ) )
  878. return false;
  879. if ( !$this->installOverrides( $content->getElementsByTagName( 'override-list' )->item( 0 ),
  880. $installParameters ) )
  881. return false;
  882. if ( !$this->installFetchAliases( $content->getElementsByTagName( 'fetch-alias-list' )->item( 0 ),
  883. $installParameters ) )
  884. return false;
  885. return true;
  886. }
  887. /*!
  888. \private
  889. Serialize and install content objects
  890. \param objectNodes object-list DOMNode
  891. \param topNodeListNode
  892. \param installParameters install parameters
  893. */
  894. function installContentObjects( $objectNodes, $topNodeListNode, &$installParameters )
  895. {
  896. if ( isset( $installParameters['user_id'] ) )
  897. $userID = $installParameters['user_id'];
  898. else
  899. $userID = eZUser::currentUserID();
  900. $handlerType = $this->handlerType();
  901. $firstInstalledID = null;
  902. foreach( $objectNodes as $objectNode )
  903. {
  904. $realObjectNode = $this->getRealObjectNode( $objectNode );
  905. // Cycle until we reach an element where error has occured.
  906. // If action has been choosen, try install this item again, else skip it.
  907. if ( isset( $installParameters['error']['error_code'] ) &&
  908. !$this->isErrorElement( $realObjectNode->getAttribute( 'remote_id' ), $installParameters ) )
  909. {
  910. continue;
  911. }
  912. //we are here, it means we'll try to install some object.
  913. if ( !$firstInstalledID )
  914. {
  915. $firstInstalledID = $realObjectNode->getAttribute( 'remote_id' );
  916. }
  917. $newObject = eZContentObject::unserialize( $this->Package, $realObjectNode, $installParameters, $userID, $handlerType );
  918. if ( !$newObject )
  919. {
  920. return false;
  921. }
  922. if ( is_object( $newObject ) )
  923. {
  924. eZContentObject::clearCache( $newObject->attribute( 'id' ) );
  925. unset( $newObject );
  926. }
  927. unset( $realObjectNode );
  928. if ( isset( $installParameters['error'] ) && count( $installParameters['error'] ) )
  929. {
  930. $installParameters['error'] = array();
  931. }
  932. }
  933. $this->installSuspendedNodeAssignment( $installParameters );
  934. $this->installSuspendedObjectRelations( $installParameters );
  935. // Call postUnserialize on all installed objects
  936. foreach( $objectNodes as $objectNode )
  937. {
  938. if ( $objectNode->localName == 'object' )
  939. {
  940. $remoteID = $objectNode->getAttribute( 'remote_id' );
  941. }
  942. else
  943. {
  944. $remoteID = substr( $objectNode->getAttribute( 'filename' ), 7, 32 );
  945. }
  946. // Begin from the object that we started from in the previous cycle
  947. if ( $firstInstalledID && $remoteID != $firstInstalledID )
  948. {
  949. continue;
  950. }
  951. else
  952. {
  953. $firstInstalledID = null;
  954. }
  955. $object = eZContentObject::fetchByRemoteID( $remoteID );
  956. if ( is_object( $object ) )
  957. {
  958. $object->postUnserialize( $this->Package );
  959. eZContentObject::clearCache( $object->attribute( 'id' ) );
  960. }
  961. unset( $object );
  962. }
  963. return true;
  964. }
  965. /*!
  966. \private
  967. \param install parameters
  968. */
  969. function installSuspendedNodeAssignment( &$installParameters )
  970. {
  971. if ( !isset( $installParameters['suspended-nodes'] ) )
  972. {
  973. return;
  974. }
  975. foreach ( $installParameters['suspended-nodes'] as $parentNodeRemoteID => $suspendedNodeInfo )
  976. {
  977. $parentNode = eZContentObjectTreeNode::fetchByRemoteID( $parentNodeRemoteID );
  978. if ( $parentNode !== null )
  979. {
  980. $nodeInfo = $suspendedNodeInfo['nodeinfo'];
  981. $nodeInfo['parent_node'] = $parentNode->attribute( 'node_id' );
  982. $existNodeAssignment = eZPersistentObject::fetchObject( eZNodeAssignment::definition(),
  983. null,
  984. $nodeInfo );
  985. $nodeInfo['priority'] = $suspendedNodeInfo['priority'];
  986. if( !is_object( $existNodeAssignment ) )
  987. {
  988. $nodeAssignment = eZNodeAssignment::create( $nodeInfo );
  989. $nodeAssignment->store();
  990. }
  991. $contentObject = eZContentObject::fetch( $nodeInfo['contentobject_id'] );
  992. if ( is_object( $contentObject ) && $contentObject->attribute( 'current_version' ) == $nodeInfo['contentobject_version'] )
  993. {
  994. eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $nodeInfo['contentobject_id'],
  995. 'version' => $nodeInfo['contentobject_version'] ) );
  996. }
  997. if ( isset( $nodeInfo['is_main'] ) && $nodeInfo['is_main'] )
  998. {
  999. $existingMainNode = eZContentObjectTreeNode::fetchByRemoteID( $nodeInfo['parent_remote_id'], false );
  1000. if ( $existingMainNode )
  1001. {
  1002. eZContentObjectTreeNode::updateMainNodeID( $existingMainNode['node_id'],
  1003. $nodeInfo['contentobject_id'],
  1004. $nodeInfo['contentobject_version'],
  1005. $nodeInfo['parent_node'] );
  1006. }
  1007. }
  1008. }
  1009. else
  1010. {
  1011. eZDebug::writeError( 'Can not find parent node by remote-id ID = ' . $parentNodeRemoteID, __METHOD__ );
  1012. }
  1013. unset( $installParameters['suspended-nodes'][$parentNodeRemoteID] );
  1014. }
  1015. }
  1016. /*!
  1017. \private
  1018. Installs suspended content object relations (need for complex content-relations structure)
  1019. \param install parameters
  1020. */
  1021. function installSuspendedObjectRelations( &$installParameters )
  1022. {
  1023. if ( !isset( $installParameters['suspended-relations'] ) )
  1024. {
  1025. return;
  1026. }
  1027. foreach( $installParameters['suspended-relations'] as $suspendedObjectRelation )
  1028. {
  1029. $contentObjectID = $suspendedObjectRelation['contentobject-id'];
  1030. $contentObjectVersionID = $suspendedObjectRelation['contentobject-version'];
  1031. $contentObjectVersion = eZContentObjectVersion::fetchVersion( $contentObjectVersionID, $contentObjectID );
  1032. if ( is_object( $contentObjectVersion ) )
  1033. {
  1034. $relatedObjectRemoteID = $suspendedObjectRelation['related-object-remote-id'];
  1035. $relatedObject = eZContentObject::fetchByRemoteID( $relatedObjectRemoteID );
  1036. $relatedObjectID = ( $relatedObject !== null ) ? $relatedObject->attribute( 'id' ) : null;
  1037. if ( $relatedObjectID )
  1038. {
  1039. $relatedObject->addContentObjectRelation( $relatedObjectID, $contentObjectVersionID, $contentObjectID );
  1040. }

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