PageRenderTime 29ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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. }
  1041. else
  1042. {
  1043. eZDebug::writeError( 'Can not find related object by remote-id ID = ' . $relatedObjectRemoteID, __METHOD__ );
  1044. }
  1045. }
  1046. }
  1047. unset( $installParameters['suspended-relations'] );
  1048. }
  1049. /*!
  1050. \private
  1051. Set and install templates
  1052. \param template list
  1053. \param package
  1054. \param subdirectory
  1055. \param install parameters.
  1056. */
  1057. function installTemplates( $templateList, $package, $subdirectory, &$installParameters )
  1058. {
  1059. if ( !$templateList )
  1060. {
  1061. return true;
  1062. }
  1063. $siteAccessDesignPathArray = array();
  1064. $templateRootPath = $package->path() . '/' . $subdirectory;
  1065. foreach( $templateList->getElementsByTagName( 'file' ) as $fileNode )
  1066. {
  1067. $originalSiteAccess = $fileNode->getAttribute( 'site-access' );
  1068. if ( isset( $installParameters['site_access_map'][$originalSiteAccess] ) )
  1069. {
  1070. $newSiteAccess = $installParameters['site_access_map'][$originalSiteAccess];
  1071. }
  1072. else
  1073. {
  1074. $newSiteAccess = $installParameters['site_access_map']['*'];
  1075. }
  1076. if ( !isset( $siteAccessDesignPathArray[$newSiteAccess] ) )
  1077. {
  1078. $ini = eZINI::instance( 'site.ini', 'settings', null, null, true );
  1079. $ini->prependOverrideDir( "siteaccess/$newSiteAccess", false, 'siteaccess' );
  1080. $ini->loadCache();
  1081. if ( isset( $installParameters['design_map'] ) )
  1082. {
  1083. $designMap = $installParameters['design_map'];
  1084. if ( isset( $designMap[$originalSiteAccess] ) )
  1085. $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $designMap[$originalSiteAccess];
  1086. else
  1087. $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $designMap['*'];
  1088. }
  1089. else
  1090. {
  1091. $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $ini->variable( "DesignSettings", "StandardDesign" );
  1092. }
  1093. }
  1094. $path = '';
  1095. foreach( $fileNode->childNodes as $pathNode )
  1096. {
  1097. if ( $pathNode->nodeName == 'path' )
  1098. {
  1099. $path = $pathNode->nodeValue;
  1100. break;
  1101. }
  1102. }
  1103. $sourcePath = $templateRootPath . $path;
  1104. $destinationPath = $siteAccessDesignPathArray[$newSiteAccess] . $path;
  1105. eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true );
  1106. if ( !eZFileHandler::copy( $sourcePath, $destinationPath ) )
  1107. return false;
  1108. // eZDebug::writeNotice( 'Copied: "' . $sourcePath . '" to: "' . $destinationPath . '"', __METHOD__ );
  1109. }
  1110. return true;
  1111. }
  1112. /*!
  1113. \private
  1114. Install overrides
  1115. \param override list
  1116. \param install parameters
  1117. */
  1118. function installOverrides( $overrideListNode, &$parameters )
  1119. {
  1120. if ( !$overrideListNode )
  1121. {
  1122. return true;
  1123. }
  1124. $overrideINIArray = array();
  1125. foreach( $overrideListNode->getElementsByTagName( 'block' ) as $blockNode )
  1126. {
  1127. if ( isset( $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )] ) )
  1128. {
  1129. $newSiteAccess = $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )];
  1130. }
  1131. else
  1132. {
  1133. $newSiteAccess = $parameters['site_access_map']['*'];
  1134. }
  1135. if ( !$newSiteAccess )
  1136. {
  1137. eZDebug::writeError( 'SiteAccess map for : ' . $blockNode->getAttribute( 'site-access' ) . ' not set.', __METHOD__ );
  1138. continue;
  1139. }
  1140. if ( !isset( $overrideINIArray[$newSiteAccess] ) )
  1141. {
  1142. $overrideINIArray[$newSiteAccess] = eZINI::instance( 'override.ini.append.php', "settings/siteaccess/$newSiteAccess", null, null, true );
  1143. }
  1144. $blockArray = array();
  1145. $blockName = $blockNode->getAttribute( 'name' );
  1146. $blockArray[$blockName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $blockNode->getElementsByTagName( $blockName )->item( 0 ) );
  1147. if ( isset( $blockArray[$blockName][$this->OverrideObjectRemoteID] ) )
  1148. {
  1149. $contentObject = eZContentObject::fetchByRemoteID( $blockArray[$blockName][$this->OverrideObjectRemoteID] );
  1150. $blockArray[$blockName]['Match']['object'] = $contentObject->attribute( 'id' );
  1151. unset( $blockArray[$blockName][$this->OverrideObjectRemoteID] );
  1152. // eZDebug::writeNotice( 'Found object id: "' . $blockArray[$blockName]['Match']['object'] . '" for matchblock "[' . $blockName . '][Match][object]"', __METHOD__ );
  1153. }
  1154. if ( isset( $blockArray[$blockName][$this->OverrideNodeRemoteID] ) )
  1155. {
  1156. $contentNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName][$this->OverrideNodeRemoteID] );
  1157. $blockArray[$blockName]['Match']['node'] = $contentNode->attribute( 'node_id' );
  1158. unset( $blockArray[$blockName][$this->OverrideNodeRemoteID] );
  1159. // eZDebug::writeNotice( 'Found node id: "' . $blockArray[$blockName]['Match']['node'] . '" for matchblock "[' . $blockName . '][Match][node]"', __METHOD__ );
  1160. }
  1161. if ( isset( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] ) )
  1162. {
  1163. $parentContentNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] );
  1164. $blockArray[$blockName]['Match']['parent_node'] = $parentContentNode->attribute( 'node_id' );
  1165. unset( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] );
  1166. // eZDebug::writeNotice( 'Found parent node id: "' . $blockArray[$blockName]['Match']['parent_node'] . '" for matchblock "[' . $blockName . '][Match][parent_node]"', __METHOD__ );
  1167. }
  1168. if ( isset( $blockArray[$blockName][$this->OverrideClassRemoteID] ) )
  1169. {
  1170. $contentClass = eZContentClass::fetchByRemoteID( $blockArray[$blockName][$this->OverrideClassRemoteID] );
  1171. if ( !$contentClass )
  1172. {
  1173. eZDebug::writeError( 'No content class found for RemoteID: ' . $blockArray[$blockName][$this->OverrideClassRemoteID], __METHOD__ );
  1174. continue;
  1175. }
  1176. $blockArray[$blockName]['Match']['class'] = $contentClass->attribute( 'id' );
  1177. unset( $blockArray[$blockName][$this->OverrideClassRemoteID] );
  1178. // eZDebug::writeNotice( 'Found class id: "' . $blockArray[$blockName]['Match']['class'] . '" for matchblock "[' . $blockName . '][Match][class]"', __METHOD__ );
  1179. }
  1180. $overrideINIArray[$newSiteAccess]->setVariables( $blockArray );
  1181. }
  1182. foreach( $overrideINIArray as $siteAccess => $iniArray )
  1183. {
  1184. $overrideINIArray[$siteAccess]->save();
  1185. }
  1186. return true;
  1187. }
  1188. /*!
  1189. \private
  1190. Install fetch alias overrides
  1191. \param fetch alias list
  1192. \param install parameters
  1193. */
  1194. function installFetchAliases( $fetchAliasListNode, &$parameters )
  1195. {
  1196. if ( !$fetchAliasListNode )
  1197. {
  1198. return true;
  1199. }
  1200. $fetchAliasINIArray = array();
  1201. foreach( $fetchAliasListNode->getElementsByTagName( 'fetch-alias' ) as $blockNode )
  1202. {
  1203. if ( isset( $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )] ) )
  1204. {
  1205. $newSiteAccess = $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )];
  1206. }
  1207. else
  1208. {
  1209. $newSiteAccess = $parameters['site_access_map']['*'];
  1210. }
  1211. if ( !isset( $fetchAliasINIArray[$newSiteAccess] ) )
  1212. {
  1213. $fetchAliasINIArray[$newSiteAccess] = eZINI::instance( 'fetchalias.ini.append.php', "settings/siteaccess/$newSiteAccess", null, null, true );
  1214. }
  1215. $blockArray = array();
  1216. $blockName = $blockNode->getAttribute( 'name' );
  1217. $blockArray[$blockName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $blockNode->getElementsByTagName( $blockName )->item( 0 ) );
  1218. //$blockArray[$blockName] = $blockArray[$blockName][0];
  1219. if ( isset( $blockArray[$blockName]['Constant'] ) && is_array( $blockArray[$blockName]['Constant'] ) && count( $blockArray[$blockName]['Constant'] ) > 0 )
  1220. {
  1221. foreach( $blockArray[$blockName]['Constant'] as $matchKey => $value )
  1222. {
  1223. if ( strpos( $matchKey, 'class_' ) === 0 &&
  1224. is_int( $value ) )
  1225. {
  1226. $contentClass = eZContentClass::fetchByRemoteID( $blockArray[$blockName]['Constant']['class_remote_id'] );
  1227. $blockArray[$blockName]['Constant'][$matchKey] = $contentClass->attribute( 'id' );
  1228. unset( $blockArray[$blockName]['Constant']['class_remote_id'] );
  1229. }
  1230. if( strpos( $matchKey, 'node_' ) === 0 &&
  1231. is_int( $value ) )
  1232. {
  1233. $contentTreeNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName]['Constant']['node_remote_id'] );
  1234. $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'node_id' );
  1235. unset( $blockArray[$blockName]['Constant']['node_remote_id'] );
  1236. }
  1237. if( strpos( $matchKey, 'parent_node_' ) === 0 &&
  1238. is_int( $value ) )
  1239. {
  1240. $contentTreeNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName]['Constant']['parent_node_remote_id'] );
  1241. $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'node_id' );
  1242. unset( $blockArray[$blockName]['Constant']['parent_node_remote_id'] );
  1243. }
  1244. if( strpos( $matchKey, 'object_' ) === 0 &&
  1245. is_int( $value ) )
  1246. {
  1247. $contentObject = eZContentObject::fetchByRemoteID( $blockArray[$blockName]['Constant']['object_remote_id'] );
  1248. $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'id' );
  1249. unset( $blockArray[$blockName]['Constant']['object_remote_id'] );
  1250. }
  1251. }
  1252. }
  1253. $fetchAliasINIArray[$newSiteAccess]->setVariables( $blockArray );
  1254. }
  1255. foreach( $fetchAliasINIArray as $siteAccess => $iniFetchAlias )
  1256. {
  1257. $fetchAliasINIArray[$siteAccess]->save();
  1258. }
  1259. return true;
  1260. }
  1261. function add( $packageType, $package, $cli, $parameters )
  1262. {
  1263. $options = array();
  1264. foreach ( $parameters['node-list'] as $nodeItem )
  1265. {
  1266. $nodeIDList = $nodeItem['node-id-list'];
  1267. foreach ( $nodeIDList as $nodeIDItem )
  1268. {
  1269. $this->addNode( $nodeIDItem['id'], $nodeIDItem['subtree'] );
  1270. unset( $node );
  1271. $node = false;
  1272. if ( isset( $nodeIDItem['node'] ) )
  1273. {
  1274. $node = $nodeIDItem['node'];
  1275. }
  1276. else
  1277. {
  1278. $node = eZContentObjectTreeNode::fetch( $nodeIDItem['id'] );
  1279. }
  1280. $cli->notice( "Adding node /" . $node->pathWithNames() . " to package" );
  1281. }
  1282. }
  1283. $options['include_classes'] = $parameters['include-classes'];
  1284. $options['include_templates'] = $parameters['include-templates'];
  1285. $options['node_assignment'] = $parameters['node-assignment-type'];
  1286. $options['site_access_array'] = $parameters['siteaccess-list'];
  1287. $options['language_array'] = $parameters['language-list'];
  1288. $options['versions'] = $parameters['version-type'];
  1289. $options['related_objects'] = $parameters['related-type'];
  1290. $options['embed_objects'] = $parameters['embed-type'];
  1291. $options['minimal_template_set'] = $parameters['minimal-template-set'];
  1292. $this->generatePackage( $package, $options );
  1293. }
  1294. function handleAddParameters( $packageType, $package, $cli, $arguments )
  1295. {
  1296. return $this->handleParameters( $packageType, $package, $cli, 'add', $arguments );
  1297. }
  1298. /*!
  1299. \private
  1300. */
  1301. function handleParameters( $packageType, $package, $cli, $type, $arguments )
  1302. {
  1303. $nodeList = array();
  1304. $includeClasses = true;
  1305. $includeTemplates = true;
  1306. $siteAccessList = array();
  1307. $nodeAssignmentType = 'main';
  1308. $relatedObjectType = 'selected';
  1309. $embedObjectType = 'selected';
  1310. $versionType = 'current';
  1311. $languageList = array();
  1312. $minimalTemplateSet = false;
  1313. $nodeItem = array( 'node-id-list' => array() );
  1314. $longOptions = array( 'include-classes' => 'include-classes',
  1315. 'include-templates' => 'include-templates',
  1316. 'exclude-classes' => 'exclude-classes',
  1317. 'exclude-templates' => 'exclude-templates',
  1318. 'language' => 'language',
  1319. 'current-version' => 'current-version',
  1320. 'all-versions' => 'all-versions',
  1321. 'node-main' => 'node-main',
  1322. 'node-selected' => 'node-selected',
  1323. 'siteaccess' => 'siteaccess',
  1324. 'minimal-template-set' => 'minimal-template-set' );
  1325. $shortOptions = array();
  1326. $error = false;
  1327. foreach ( $arguments as $argument )
  1328. {
  1329. if ( $argument[0] == '-' )
  1330. {
  1331. if ( strlen( $argument ) > 1 and
  1332. $argument[1] == '-' )
  1333. {
  1334. $option = substr( $argument, 2 );
  1335. $valuePos = strpos( $option, '=' );
  1336. $optionValue = false;
  1337. if ( $valuePos !== false )
  1338. {
  1339. $optionValue = substr( $option, $valuePos + 1 );
  1340. $option = substr( $option, 0, $valuePos );
  1341. }
  1342. if ( isset( $longOptions[$option] ) )
  1343. $optionName = $longOptions[$option];
  1344. else
  1345. $optionName = false;
  1346. }
  1347. else
  1348. {
  1349. $option = substr( $argument, 1 );
  1350. if ( isset( $shortOptions[$option] ) )
  1351. $optionName = $shortOptions[$option];
  1352. else
  1353. $optionName = false;
  1354. }
  1355. if ( $optionName == 'include-classes' or $optionName == 'exclude-classes' )
  1356. {
  1357. if ( count( $nodeItem['node-id-list'] ) > 0 )
  1358. {
  1359. $nodeList[] = $nodeItem;
  1360. $nodeItem['node-id-list'] = array();
  1361. }
  1362. $includeClasses = ( $optionName == 'include-classes' );
  1363. }
  1364. else if ( $optionName == 'include-templates' or $optionName == 'exclude-templates' )
  1365. {
  1366. if ( count( $nodeItem['node-id-list'] ) > 0 )
  1367. {
  1368. $nodeList[] = $nodeItem;
  1369. $nodeItem['node-id-list'] = array();
  1370. }
  1371. $includeTemplates = ( $optionName == 'include-templates' );
  1372. }
  1373. else if ( $optionName == 'node-main' )
  1374. {
  1375. $nodeAssignmentType = 'main';
  1376. }
  1377. else if ( $optionName == 'node-selected' )
  1378. {
  1379. $nodeAssignmentType = 'selected';
  1380. }
  1381. else if ( $optionName == 'siteaccess' )
  1382. {
  1383. $siteAccessList = explode( ',', $optionValue );
  1384. }
  1385. else if ( $optionName == 'language' )
  1386. {
  1387. $languageList = explode( ',', $optionValue );
  1388. }
  1389. else if ( $optionName == 'current-version' )
  1390. {
  1391. $versionType = 'current';
  1392. }
  1393. else if ( $optionName == 'all-versions' )
  1394. {
  1395. $versionType = 'all';
  1396. }
  1397. else if ( $optionName == 'minimal-template-set' )
  1398. {
  1399. $minimalTemplateSet = true;
  1400. }
  1401. }
  1402. else
  1403. {
  1404. $nodeID = false;
  1405. $subtree = false;
  1406. if ( is_numeric( $argument ) )
  1407. {
  1408. $nodeID = (int)$argument;
  1409. $node = eZContentObjectTreeNode::fetch( $nodeID );
  1410. if ( !is_object( $node ) )
  1411. {
  1412. $error = true;
  1413. $nodeID = false;
  1414. $cli->notice( "Could not find content-node using ID " . $cli->stylize( 'emphasize', $nodeID ) );
  1415. }
  1416. }
  1417. else
  1418. {
  1419. $path = $argument;
  1420. if ( preg_match( "#(.+)/\*$#", $path, $matches ) )
  1421. {
  1422. $path = $matches[1];
  1423. $subtree = true;
  1424. }
  1425. $node = eZContentObjectTreeNode::fetchByURLPath( $path );
  1426. if ( is_object( $node ) )
  1427. {
  1428. $nodeID = $node->attribute( 'node_id' );
  1429. }
  1430. else
  1431. {
  1432. $cli->notice( "Could not find content-node using path " . $cli->stylize( 'emphasize', $path ) );
  1433. $error = true;
  1434. }
  1435. }
  1436. if ( $nodeID )
  1437. {
  1438. $nodeItem['node-id-list'][] = array( 'id' => $nodeID,
  1439. 'subtree' => $subtree,
  1440. 'node' => &$node );
  1441. }
  1442. if ( $error )
  1443. return false;
  1444. }
  1445. }
  1446. if ( count( $nodeItem['node-id-list'] ) > 0 )
  1447. {
  1448. $nodeList[] = $nodeItem;
  1449. }
  1450. if ( count( $nodeList ) == 0 )
  1451. {
  1452. $cli->error( "No objects chosen" );
  1453. return false;
  1454. }
  1455. if ( count( $languageList ) == 0 )
  1456. {
  1457. // The default is to fetch all languages
  1458. $languageList = eZContentLanguage::fetchLocaleList();
  1459. }
  1460. if ( count( $siteAccessList ) == 0 )
  1461. {
  1462. $ini = eZINI::instance();
  1463. $siteAccessList[] = $ini->variable( 'SiteSettings', 'DefaultAccess' );
  1464. }
  1465. return array( 'node-list' => $nodeList,
  1466. 'include-classes' => $includeClasses,
  1467. 'include-templates' => $includeTemplates,
  1468. 'siteaccess-list' => $siteAccessList,
  1469. 'language-list' => $languageList,
  1470. 'node-assignment-type' => $nodeAssignmentType,
  1471. 'related-type' => $relatedObjectType,
  1472. 'embed-type' => $embedObjectType,
  1473. 'version-type' => $versionType,
  1474. 'minimal-template-set' => $minimalTemplateSet,
  1475. );
  1476. }
  1477. function contentObjectDirectory()
  1478. {
  1479. return 'ezcontentobject';
  1480. }
  1481. /*!
  1482. \static
  1483. Creates DOMNodeElement recursivly from recursive array
  1484. */
  1485. static function createElementNodeFromArray( $name, $array )
  1486. {
  1487. $dom = new DOMDocument( '1.0', 'utf-8' );
  1488. $node = $dom->createElement( $name );
  1489. $dom->appendChild( $node );
  1490. foreach ( $array as $arrayKey => $value )
  1491. {
  1492. if ( is_array( $value ) and
  1493. count( $valueKeys = array_keys( $value ) ) > 0 )
  1494. {
  1495. if ( is_int( $valueKeys[0] ) )
  1496. {
  1497. foreach( $value as $child )
  1498. {
  1499. unset( $childNode );
  1500. unset( $importedChildNode );
  1501. $childNode = eZContentObjectPackageHandler::createElementNodeFromArray( $arrayKey, $child );
  1502. $importedChildNode = $dom->importNode( $childNode, true );
  1503. $node->appendChild( $importedChildNode );
  1504. }
  1505. }
  1506. else
  1507. {
  1508. unset( $valueNode );
  1509. unset( $importedValueNode );
  1510. $valueNode = eZContentObjectPackageHandler::createElementNodeFromArray( $arrayKey, $value );
  1511. $importedValueNode = $dom->importNode( $valueNode, true );
  1512. $node->appendChild( $importedValueNode );
  1513. }
  1514. }
  1515. else
  1516. {
  1517. $node->setAttribute( $arrayKey, $value );
  1518. }
  1519. }
  1520. return $node;
  1521. }
  1522. /*!
  1523. \static
  1524. Creates recursive array from DOMNodeElement
  1525. */
  1526. static function createArrayFromDOMNode( $domNode )
  1527. {
  1528. if ( !$domNode )
  1529. {
  1530. return null;
  1531. }
  1532. $retArray = array();
  1533. foreach ( $domNode->childNodes as $childNode )
  1534. {
  1535. if ( $childNode->nodeType != XML_ELEMENT_NODE )
  1536. {
  1537. continue;
  1538. }
  1539. if ( !isset( $retArray[$childNode->localName] ) )
  1540. {
  1541. $retArray[$childNode->localName] = array();
  1542. }
  1543. // If the node has children we create an array for this element
  1544. // and append to it, if not we assign it directly
  1545. if ( $childNode->hasChildNodes() )
  1546. {
  1547. $retArray[$childNode->localName][] = eZContentObjectPackageHandler::createArrayFromDOMNode( $childNode );
  1548. }
  1549. else
  1550. {
  1551. $retArray[$childNode->localName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $childNode );
  1552. }
  1553. }
  1554. foreach( $domNode->attributes as $attributeNode )
  1555. {
  1556. $retArray[$attributeNode->name] = $attributeNode->value;
  1557. }
  1558. return $retArray;
  1559. }
  1560. public $NodeIDArray = array();
  1561. public $RootNodeIDArray = array();
  1562. public $NodeObjectArray = array();
  1563. public $ObjectArray = array();
  1564. public $RootNodeObjectArray = array();
  1565. public $OverrideSettingsArray = array();
  1566. public $TemplateFileArray = array();
  1567. public $Package = null;
  1568. // Static class variables - replacing match values in override.ini
  1569. public $OverrideObjectRemoteID = 'content_object_remote_id';
  1570. public $OverrideNodeRemoteID = 'content_node_remote_id';
  1571. public $OverrideParentNodeRemoteID = 'parent_content_node_remote_id';
  1572. public $OverrideClassRemoteID = 'content_class_remote_id';
  1573. }
  1574. ?>