eZ Publish  [4.0]
ezobjectrelationlisttype.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZObjectRelationListType class
00004 //
00005 // Created on: <16-Apr-2002 11:08:14 amos>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   \class eZObjectRelationListType ezobjectrelationlisttype.php
00033   \ingroup eZDatatype
00034   \brief A content datatype which handles object relations
00035 
00036 Bugs/missing/deprecated features:
00037 - No identifier support yet
00038 - Validation and fixup for "Add new object" functionality
00039 - Proper embed views for admin classes
00040 - No translation page support yet (maybe?)
00041 - is_modified is deprecated and is used for BC only.
00042 
00043 */
00044 
00045 //include_once( 'kernel/classes/ezdatatype.php' );
00046 //include_once( 'kernel/classes/ezcontentobject.php' );
00047 //include_once( 'lib/ezutils/classes/ezintegervalidator.php' );
00048 //include_once( 'lib/ezutils/classes/ezinputvalidator.php' );
00049 //include_once( 'lib/ezi18n/classes/eztranslatormanager.php' );
00050 
00051 class eZObjectRelationListType extends eZDataType
00052 {
00053     const DATA_TYPE_STRING = "ezobjectrelationlist";
00054 
00055     /*!
00056      Initializes with a string id and a description.
00057     */
00058     function eZObjectRelationListType()
00059     {
00060         $this->eZDataType( self::DATA_TYPE_STRING, ezi18n( 'kernel/classes/datatypes', "Object relations", 'Datatype name' ),
00061                            array( 'serialize_supported' => true ) );
00062     }
00063 
00064     /*!
00065      Validates the input and returns true if the input was
00066      valid for this datatype.
00067     */
00068     function validateObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute )
00069     {
00070         $inputParameters = $contentObjectAttribute->inputParameters();
00071         $contentClassAttribute = $contentObjectAttribute->contentClassAttribute();
00072         $parameters = $contentObjectAttribute->validationParameters();
00073         if ( isset( $parameters['prefix-name'] ) and
00074              $parameters['prefix-name'] )
00075             $parameters['prefix-name'][] = $contentClassAttribute->attribute( 'name' );
00076         else
00077             $parameters['prefix-name'] = array( $contentClassAttribute->attribute( 'name' ) );
00078 
00079         $status = eZInputValidator::STATE_ACCEPTED;
00080         $postVariableName = $base . "_data_object_relation_list_" . $contentObjectAttribute->attribute( "id" );
00081         $contentClassAttribute = $contentObjectAttribute->contentClassAttribute();
00082         $classContent = $contentClassAttribute->content();
00083         // Check if selection type is not browse
00084         if ( $classContent['selection_type'] != 0 )
00085         {
00086             $selectedObjectIDArray = $http->hasPostVariable( $postVariableName ) ? $http->postVariable( $postVariableName ) : false;
00087             if ( $contentObjectAttribute->validateIsRequired() and $selectedObjectIDArray === false )
00088             {
00089                 $contentObjectAttribute->setValidationError( ezi18n( 'kernel/classes/datatypes',
00090                                                                      'Missing objectrelation list input.' ) );
00091                 return eZInputValidator::STATE_INVALID;
00092             }
00093             return $status;
00094         }
00095 
00096         $content = $contentObjectAttribute->content();
00097         if ( $contentObjectAttribute->validateIsRequired() and count( $content['relation_list'] ) == 0 )
00098         {
00099             $contentObjectAttribute->setValidationError( ezi18n( 'kernel/classes/datatypes',
00100                                                                  'Missing objectrelation list input.' ) );
00101             return eZInputValidator::STATE_INVALID;
00102         }
00103 
00104         for ( $i = 0; $i < count( $content['relation_list'] ); ++$i )
00105         {
00106             $relationItem = $content['relation_list'][$i];
00107             if ( $relationItem['is_modified'] )
00108             {
00109                 $subObjectID = $relationItem['contentobject_id'];
00110                 $subObjectVersion = $relationItem['contentobject_version'];
00111                 $attributeBase = $base . '_ezorl_edit_object_' . $subObjectID;
00112                 $object = eZContentObject::fetch( $subObjectID );
00113                 if ( $object )
00114                 {
00115                     $attributes = $object->contentObjectAttributes( true,
00116                                                                     $subObjectVersion,
00117                                                                     $contentObjectAttribute->attribute( 'language_code' ) );
00118                     $validationResult = $object->validateInput( $attributes, $attributeBase,
00119                                                                 $inputParameters, $parameters );
00120                     $inputValidated = $validationResult['input-validated'];
00121                     $content['temp'][$subObjectID]['require-fixup'] = $validationResult['require-fixup'];
00122                     $statusMap = $validationResult['status-map'];
00123                     foreach ( $statusMap as $statusItem )
00124                     {
00125                         $statusValue = $statusItem['value'];
00126                         if ( $statusValue == eZInputValidator::STATE_INTERMEDIATE and
00127                              $status == eZInputValidator::STATE_ACCEPTED )
00128                             $status = eZInputValidator::STATE_INTERMEDIATE;
00129                         else if ( $statusValue == eZInputValidator::STATE_INVALID )
00130                         {
00131                             $contentObjectAttribute->setHasValidationError( false );
00132                             $status = eZInputValidator::STATE_INVALID;
00133                         }
00134                     }
00135 
00136                     $content['temp'][$subObjectID]['attributes'] = $attributes;
00137                     $content['temp'][$subObjectID]['object'] = $object;
00138                 }
00139             }
00140         }
00141 
00142         $contentObjectAttribute->setContent( $content );
00143         return $status;
00144     }
00145 
00146     /*!
00147      Validates the input and returns true if the input was
00148      valid for this datatype.
00149     */
00150     function fixupObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute )
00151     {
00152         $content = $contentObjectAttribute->content();
00153         for ( $i = 0; $i < count( $content['relation_list'] ); ++$i )
00154         {
00155             $relationItem = $content['relation_list'][$i];
00156             if ( $relationItem['is_modified'] )
00157             {
00158                 $subObjectID = $relationItem['contentobject_id'];
00159                 $attributeBase = $base . '_ezorl_edit_object_' . $subObjectID;
00160                 $object = $content['temp'][$subObjectID]['object'];
00161                 $requireFixup = $content['temp'][$subObjectID]['require-fixup'];
00162                 if ( $object and
00163                      $requireFixup )
00164                 {
00165                     $attributes = $content['temp'][$subObjectID]['attributes'];
00166                     $object->fixupInput( $attributes, $attributeBase );
00167                 }
00168             }
00169         }
00170     }
00171 
00172     /*!
00173      Fetches the http post var string input and stores it in the data instance.
00174     */
00175     function fetchObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute )
00176     {
00177         $content = $contentObjectAttribute->content();
00178         // new object creation
00179         $newObjectPostVariableName = "attribute_" . $contentObjectAttribute->attribute( "id" ) . "_new_object_name";
00180         if ( $http->hasPostVariable( $newObjectPostVariableName ) )
00181         {
00182             $name = $http->postVariable( $newObjectPostVariableName );
00183             if ( !empty( $name ) )
00184             {
00185                 $content['new_object'] = $name;
00186             }
00187         }
00188         $singleSelectPostVariableName = "single_select_" . $contentObjectAttribute->attribute( "id" );
00189         if ( $http->hasPostVariable( $singleSelectPostVariableName ) )
00190             $content['singleselect'] = true;
00191 
00192         $postVariableName = $base . "_data_object_relation_list_" . $contentObjectAttribute->attribute( "id" );
00193         $contentClassAttribute = $contentObjectAttribute->contentClassAttribute();
00194         $classContent = $contentClassAttribute->content();
00195         // Check if selection type is not browse
00196         if ( $classContent['selection_type'] != 0 )
00197         {
00198             $selectedObjectIDArray = $http->hasPostVariable( $postVariableName ) ? $http->postVariable( $postVariableName ) : false;
00199             $priority = 0;
00200             // We should clear content
00201             $content['relation_list'] = array();
00202             // If we got an empty object id list
00203             if ( $selectedObjectIDArray === false or ( isset( $selectedObjectIDArray[0] ) and $selectedObjectIDArray[0] == 'no_relation' ) )
00204             {
00205                 $contentObjectAttribute->setContent( $content );
00206                 $contentObjectAttribute->store();
00207                 return true;
00208             }
00209 
00210             foreach ( $selectedObjectIDArray as $objectID )
00211             {
00212                 // Check if the given object ID has a numeric value, if not go to the next object.
00213                 if ( !is_numeric( $objectID ) )
00214                 {
00215                     eZDebug::writeError( "Related object ID (objectID): '$objectID', is not a numeric value.",
00216                                          "eZObjectRelationListType::fetchObjectAttributeHTTPInput" );
00217 
00218                     continue;
00219                 }
00220                 ++$priority;
00221                 $content['relation_list'][] = $this->appendObject( $objectID, $priority, $contentObjectAttribute );
00222             }
00223 
00224             $contentObjectAttribute->setContent( $content );
00225             return true;
00226         }
00227 
00228         $contentObjectAttributeID = $contentObjectAttribute->attribute( 'id' );
00229         $priorityBase = $base . '_priority';
00230         $priorities = array();
00231         if ( $http->hasPostVariable( $priorityBase ) )
00232             $priorities = $http->postVariable( $priorityBase );
00233         $reorderedRelationList = array();
00234         // Contains existing priorities
00235         $existsPriorities = array();
00236 
00237         for ( $i = 0; $i < count( $content['relation_list'] ); ++$i )
00238         {
00239             $priorities[$contentObjectAttributeID][$i] = (int) $priorities[$contentObjectAttributeID][$i];
00240             $existsPriorities[$i] = $priorities[$contentObjectAttributeID][$i];
00241 
00242             // Change objects' priorities providing their uniqueness.
00243             for ( $j = 0; $j < count( $content['relation_list'] ); ++$j )
00244             {
00245                 if ( $i == $j ) continue;
00246                 if ( $priorities[$contentObjectAttributeID][$i] == $priorities[$contentObjectAttributeID][$j] )
00247                 {
00248                     $index = $priorities[$contentObjectAttributeID][$i];
00249                     while ( in_array( $index, $existsPriorities ) )
00250                         ++$index;
00251                     $priorities[$contentObjectAttributeID][$j] = $index;
00252                 }
00253             }
00254             $relationItem = $content['relation_list'][$i];
00255             if ( $relationItem['is_modified'] )
00256             {
00257                 $subObjectID = $relationItem['contentobject_id'];
00258                 $attributeBase = $base . '_ezorl_edit_object_' . $subObjectID;
00259                 $object = $content['temp'][$subObjectID]['object'];
00260                 if ( $object )
00261                 {
00262                     $attributes = $content['temp'][$subObjectID]['attributes'];
00263 
00264                     $customActionAttributeArray = array();
00265                     $fetchResult = $object->fetchInput( $attributes, $attributeBase,
00266                                                         $customActionAttributeArray,
00267                                                         $contentObjectAttribute->inputParameters() );
00268                     $content['temp'][$subObjectID]['attribute-input-map'] = $fetchResult['attribute-input-map'];
00269                     $content['temp'][$subObjectID]['attributes'] = $attributes;
00270                     $content['temp'][$subObjectID]['object'] = $object;
00271                 }
00272             }
00273             if ( isset( $priorities[$contentObjectAttributeID][$i] ) )
00274                 $relationItem['priority'] = $priorities[$contentObjectAttributeID][$i];
00275             $reorderedRelationList[$relationItem['priority']] = $relationItem;
00276         }
00277         ksort( $reorderedRelationList );
00278         unset( $content['relation_list'] );
00279         $content['relation_list'] = array();
00280         reset( $reorderedRelationList );
00281         $i = 0;
00282         while ( list( $key, $relationItem ) = each( $reorderedRelationList ) )
00283         {
00284             $content['relation_list'][] = $relationItem;
00285             $content['relation_list'][$i]['priority'] = $i + 1;
00286             ++$i;
00287         }
00288         $contentObjectAttribute->setContent( $content );
00289         return true;
00290     }
00291 
00292     function createNewObject( $contentObjectAttribute, $name )
00293     {
00294         $classAttribute = $contentObjectAttribute->attribute( 'contentclass_attribute' );
00295         $classContent = $classAttribute->content();
00296         $classID = $classContent['object_class'];
00297         if ( !isset( $classID ) or !is_numeric( $classID ) )
00298             return false;
00299 
00300         $defaultPlacementNode = ( is_array( $classContent['default_placement'] ) and isset( $classContent['default_placement']['node_id'] ) ) ? $classContent['default_placement']['node_id'] : false;
00301         if ( !$defaultPlacementNode )
00302         {
00303             eZDebug::writeError( 'Default placement is missing', 'eZObjectRelationListType::createNewObject' );
00304             return false;
00305         }
00306 
00307         $node = eZContentObjectTreeNode::fetch( $defaultPlacementNode );
00308         // Check if current user can create a new node as child of this node.
00309         if ( !$node or !$node->canCreate() )
00310         {
00311             eZDebug::writeError( 'Default placement is wrong or the current user can\'t create a new node as child of this node.', 'eZObjectRelationListType::createNewObject' );
00312             return false;
00313         }
00314 
00315         $classList = $node->canCreateClassList( false );
00316         $canCreate = false;
00317         // Check if current user can create object of class (with $classID)
00318         foreach ( $classList as $class )
00319         {
00320             if ( $class['id'] == $classID )
00321             {
00322                 $canCreate = true;
00323                 break;
00324             }
00325         }
00326         if ( !$canCreate )
00327         {
00328             eZDebug::writeError( 'The current user is not allowed to create objects of class (ID=' . $classID . ')', 'eZObjectRelationListType::createNewObject' );
00329             return false;
00330         }
00331 
00332         $class = eZContentClass::fetch( $classID );
00333         if ( !$class )
00334             return false;
00335 
00336         $currentObject = $contentObjectAttribute->attribute( 'object' );
00337         $sectionID = $currentObject->attribute( 'section_id' );
00338         //instantiate object, same section, currentuser as owner (i.e. provide false as param)
00339         $newObjectInstance = $class->instantiate( false, $sectionID );
00340         $nodeassignment = $newObjectInstance->createNodeAssignment( $defaultPlacementNode, true );
00341         $nodeassignment->store();
00342         $newObjectInstance->sync();
00343         //include_once( "lib/ezutils/classes/ezoperationhandler.php" );
00344         $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $newObjectInstance->attribute( 'id' ), 'version' => 1 ) );
00345         // so it updates the attributes
00346         $newObjectInstance->rename( $name );
00347 
00348         return $newObjectInstance->attribute( 'id' );
00349     }
00350 
00351     /*!
00352     */
00353     function storeObjectAttribute( $attribute )
00354     {
00355         $content = $attribute->content();
00356         if ( isset( $content['new_object'] ) )
00357         {
00358             $newID = $this->createNewObject( $attribute, $content['new_object'] );
00359             // if this is a single element selection mode (radio or dropdown), then the newly created item is the only one selected
00360             if ( $newID )
00361             {
00362                 if ( isset( $content['singleselect'] ) )
00363                     $content['relation_list'] = array();
00364                 $content['relation_list'][] = $this->appendObject( $newID, 0, $attribute );
00365             }
00366             unset( $content['new_object'] );
00367             $attribute->setContent( $content );
00368         }
00369 
00370         $contentClassAttributeID = $attribute->ContentClassAttributeID;
00371         $contentObjectID = $attribute->ContentObjectID;
00372         $contentObjectVersion = $attribute->Version;
00373 
00374         $obj = $attribute->object();
00375         //get eZContentObjectVersion
00376         $currVerobj = $obj->version( $contentObjectVersion );
00377 
00378         // create translation List
00379         // $translationList will contain for example eng-GB, ita-IT etc.
00380         $translationList = $currVerobj->translations( false );
00381 
00382         // get current language_code
00383         $langCode = $attribute->attribute( 'language_code' );
00384         // get count of LanguageCode in translationList
00385         $countTsl = count( $translationList );
00386         // order by asc
00387         sort( $translationList );
00388 
00389         if ( ( $countTsl == 1 ) or ( $countTsl > 1 and $translationList[0] == $langCode ) )
00390         {
00391              eZContentObject::fetch( $contentObjectID )->removeContentObjectRelation( false, $contentObjectVersion, $contentClassAttributeID, eZContentObject::RELATION_ATTRIBUTE );
00392         }
00393 
00394         foreach( $content['relation_list'] as $relationItem )
00395         {
00396             // Installing content object, postUnserialize is not called yet,
00397             // so object's ID is unknown.
00398             if ( !$relationItem['contentobject_id'] || !isset( $relationItem['contentobject_id'] ) )
00399                 continue;
00400 
00401             $subObjectID = $relationItem['contentobject_id'];
00402             $subObjectVersion = $relationItem['contentobject_version'];
00403 
00404             eZContentObject::fetch( $contentObjectID )->addContentObjectRelation( $subObjectID, $contentObjectVersion, $contentClassAttributeID, eZContentObject::RELATION_ATTRIBUTE );
00405 
00406             if ( $relationItem['is_modified'] && isset( $content['temp'][$subObjectID]['object' ] ) )
00407             {
00408                 // handling sub-objects
00409                 $object = $content['temp'][$subObjectID]['object'];
00410                 if ( $object )
00411                 {
00412                     $attributes = $content['temp'][$subObjectID]['attributes'];
00413                     $attributeInputMap = $content['temp'][$subObjectID]['attribute-input-map'];
00414                     $object->storeInput( $attributes,
00415                                          $attributeInputMap );
00416                     $version = eZContentObjectVersion::fetchVersion( $subObjectVersion, $subObjectID );
00417                     if ( $version )
00418                     {
00419                         $version->setAttribute( 'modified', time() );
00420                         $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
00421                         $version->store();
00422                     }
00423 
00424                     $object->setAttribute( 'status', eZContentObject::STATUS_DRAFT );
00425                     $object->store();
00426                 }
00427             }
00428         }
00429         return eZObjectRelationListType::storeObjectAttributeContent( $attribute, $content );
00430     }
00431 
00432     /*!
00433      \reimp
00434     */
00435     function onPublish( $contentObjectAttribute, $contentObject, $publishedNodes )
00436     {
00437         $content = $contentObjectAttribute->content();
00438         foreach( $content['relation_list'] as $key => $relationItem )
00439         {
00440             if ( $relationItem['is_modified'] )
00441             {
00442                 $subObjectID = $relationItem['contentobject_id'];
00443                 $subObjectVersion = $relationItem['contentobject_version'];
00444                 $object = eZContentObject::fetch( $subObjectID );
00445 
00446                 $time = time();
00447                 $version = eZContentObjectVersion::fetchVersion( $subObjectVersion, $subObjectID );
00448                 $version->setAttribute( 'modified', $time );
00449                 $version->store();
00450 
00451                 if ( $relationItem['parent_node_id'] > 0 )
00452                 {
00453                     // action 1: edit a normal object
00454                     if ( !eZNodeAssignment::fetch( $object->attribute( 'id' ), $object->attribute( 'current_version' ), $relationItem['parent_node_id'], false ) )
00455                     {
00456                         $nodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $object->attribute( 'id' ),
00457                                                                            'contentobject_version' => $object->attribute( 'current_version' ),
00458                                                                            'parent_node' => $relationItem['parent_node_id'],
00459                                                                            'sort_field' => 2,
00460                                                                            'sort_order' => 0,
00461                                                                            'is_main' => 1 ) );
00462                         $nodeAssignment->store();
00463                     }
00464                     $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $object->attribute( 'id' ),
00465                                                                                                  'version' => $subObjectVersion ) );
00466                     $objectNodeID = $object->attribute( 'main_node_id' );
00467                     $content['relation_list'][$key]['node_id'] = $objectNodeID;
00468                 }
00469                 else
00470                 {
00471                     // action 2: edit a nodeless object (or creating a new node
00472                     // Make the previous version archived
00473                     $currentVersion = $object->currentVersion();
00474                     $currentVersion->setAttribute( 'status', eZContentObjectVersion::STATUS_ARCHIVED );
00475                     $currentVersion->setAttribute( 'modified', $time );
00476                     $currentVersion->store();
00477 
00478                     $version->setAttribute( 'status', eZContentObjectVersion::STATUS_PUBLISHED );
00479                     $version->store();
00480 
00481                     $object->setAttribute( 'status', eZContentObject::STATUS_PUBLISHED );
00482                     if ( !$object->attribute( 'published' ) )
00483                         $object->setAttribute( 'published', $time );
00484                     $object->setAttribute( 'modified', $time );
00485                     $object->setAttribute( 'current_version', $subObjectVersion );
00486                     $object->setAttribute( 'is_published', true );
00487                     $class = $object->contentClass();
00488                     $objectName = $class->contentObjectName( $object, $version->attribute( 'version' ) );
00489                     $object->setName( $objectName, $version->attribute( 'version' ) );
00490                     $object->store();
00491 
00492                     if ( !eZNodeAssignment::fetch( $object->attribute( 'id' ), $object->attribute( 'current_version' ), $contentObject->attribute( 'main_node_id' ), false ) )
00493                     {
00494                         $nodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $object->attribute( 'id' ),
00495                                                                            'contentobject_version' => $object->attribute( 'current_version' ),
00496                                                                            'parent_node' => $contentObject->attribute( 'main_node_id' ),
00497                                                                            'sort_field' => 2,
00498                                                                            'sort_order' => 0,
00499                                                                            'is_main' => 1 ) );
00500                         $nodeAssignment->store();
00501                     }
00502                 }
00503                 $content['relation_list'][$key]['is_modified'] = false;
00504             }
00505         }
00506         eZObjectRelationListType::storeObjectAttributeContent( $contentObjectAttribute, $content );
00507         $contentObjectAttribute->setContent( $content );
00508         $contentObjectAttribute->store();
00509     }
00510 
00511     function initializeObjectAttribute( $contentObjectAttribute, $currentVersion, $originalContentObjectAttribute )
00512     {
00513 
00514         static $copiedRelatedAccordance;
00515         if ( !isset( $copiedRelatedAccordance ) )
00516             $copiedRelatedAccordance = array();
00517 
00518         if ( $currentVersion != false )
00519         {
00520             $dataText = $originalContentObjectAttribute->attribute( 'data_text' );
00521             $contentObjectAttribute->setAttribute( 'data_text', $dataText );
00522             $contentObjectID = $contentObjectAttribute->attribute( 'contentobject_id' );
00523             $originalContentObjectID = $originalContentObjectAttribute->attribute( 'contentobject_id' );
00524 
00525             if ( $contentObjectID != $originalContentObjectID )
00526             {
00527                 $classContent = eZObjectRelationListType::defaultClassAttributeContent();
00528                 if ( !$classContent['default_placement'] )
00529                 {
00530                     $content = $originalContentObjectAttribute->content();
00531                     $contentModified = false;
00532 
00533                     foreach ( $content['relation_list'] as $key => $relationItem )
00534                     {
00535                         // create related object copies only if they are subobjects
00536                         $object = eZContentObject::fetch( $relationItem['contentobject_id'] );
00537                         if ( !$object instanceof eZContentObject )
00538                         {
00539                             unset( $content['relation_list'][$key] );
00540                             $contentModified = true;
00541                             continue;
00542                         }
00543 
00544                         $mainNode = $object->attribute( 'main_node' );
00545                         if ( $mainNode instanceof eZContentObjectTreeNode )
00546                         {
00547                             $node = ( is_numeric( $relationItem['node_id'] ) and $relationItem['node_id'] ) ?
00548                                       eZContentObjectTreeNode::fetch( $relationItem['node_id'] ) : null;
00549 
00550                             if ( !$node or $node->attribute( 'contentobject_id' ) != $relationItem['contentobject_id'] )
00551                             {
00552                                 $content['relation_list'][$key]['node_id'] = $mainNode->attribute( 'node_id' );
00553                                 $node = $mainNode;
00554                                 $contentModified = true;
00555                             }
00556 
00557                             if ( $node instanceof eZContentObjectTreeNode )
00558                                 $parentNodeID =  $node->attribute( 'parent_node_id' );
00559                             else
00560                                 $parentNodeID = -1;
00561 
00562                             if ( $relationItem['parent_node_id'] != $parentNodeID )
00563                             {
00564                                 $content['relation_list'][$key]['parent_node_id'] = $parentNodeID;
00565                                 $contentModified = true;
00566                             }
00567                         }
00568                         else
00569                         {
00570                             if ( !isset( $copiedRelatedAccordance[ $relationItem['contentobject_id'] ] ) )
00571                                 $copiedRelatedAccordance[ $relationItem['contentobject_id'] ] = array();
00572 
00573                             if ( isset( $copiedRelatedAccordance[ $relationItem['contentobject_id'] ] ) and
00574                                  isset( $copiedRelatedAccordance[ $relationItem['contentobject_id'] ][ $contentObjectID ] ) )
00575                             {
00576                                 $newObjectID = $copiedRelatedAccordance[ $relationItem['contentobject_id'] ][ $contentObjectID ][ 'to' ];
00577                             }
00578                             else
00579                             {
00580                                 $newObject = $object->copy( true );
00581                                 $newObjectID = $newObject->attribute( 'id' );
00582                                 $copiedRelatedAccordance[ $relationItem['contentobject_id'] ][ $contentObjectID ] = array( 'to' => $newObjectID,
00583                                                                                                                            'from' => $originalContentObjectID );
00584                             }
00585                             $content['relation_list'][$key]['contentobject_id'] = $newObjectID;
00586                             $contentModified = true;
00587                         }
00588                     }
00589 
00590                     if ( $contentModified )
00591                     {
00592                         $contentObjectAttribute->setContent( $content );
00593                         $contentObjectAttribute->store();
00594                     }
00595                 }
00596             }
00597         }
00598     }
00599 
00600     /*!
00601      \reimp
00602     */
00603     function validateClassAttributeHTTPInput( $http, $base, $classAttribute )
00604     {
00605         return eZInputValidator::STATE_ACCEPTED;
00606     }
00607 
00608     /*!
00609      \reimp
00610     */
00611     function fixupClassAttributeHTTPInput( $http, $base, $classAttribute )
00612     {
00613     }
00614 
00615     /*!
00616      \reimp
00617     */
00618     function fetchClassAttributeHTTPInput( $http, $base, $classAttribute )
00619     {
00620         $content = $classAttribute->content();
00621         $postVariable = 'ContentClass_ezobjectrelationlist_class_list_' . $classAttribute->attribute( 'id' );
00622         if ( $http->hasPostVariable( $postVariable ) )
00623         {
00624             $constrainedList = $http->postVariable( $postVariable );
00625             $constrainedClassList = array();
00626             foreach ( $constrainedList as $constraint )
00627             {
00628                 if ( trim( $constraint ) != '' )
00629                     $constrainedClassList[] = $constraint;
00630             }
00631             $content['class_constraint_list'] = $constrainedClassList;
00632         }
00633         $typeVariable = 'ContentClass_ezobjectrelationlist_type_' . $classAttribute->attribute( 'id' );
00634         if ( $http->hasPostVariable( $typeVariable ) )
00635         {
00636             $type = $http->postVariable( $typeVariable );
00637             $content['type'] = $type;
00638         }
00639         $selectionTypeVariable = 'ContentClass_ezobjectrelationlist_selection_type_' . $classAttribute->attribute( 'id' );
00640         if ( $http->hasPostVariable( $selectionTypeVariable ) )
00641         {
00642             $selectionType = $http->postVariable( $selectionTypeVariable );
00643             $content['selection_type'] = $selectionType;
00644         }
00645         $objectClassVariable = 'ContentClass_ezobjectrelation_object_class_' . $classAttribute->attribute( 'id' );
00646         if ( $http->hasPostVariable( $objectClassVariable ) )
00647         {
00648             $content['object_class'] = $http->postVariable( $objectClassVariable );
00649         }
00650 
00651         $classAttribute->setContent( $content );
00652         $classAttribute->store();
00653         return true;
00654     }
00655 
00656     /*!
00657      \reimp
00658     */
00659     function initializeClassAttribute( $classAttribute )
00660     {
00661         $xmlText = $classAttribute->attribute( 'data_text5' );
00662         if ( trim( $xmlText ) == '' )
00663         {
00664             $content = eZObjectRelationListType::defaultClassAttributeContent();
00665             return eZObjectRelationListType::storeClassAttributeContent( $classAttribute, $content );
00666         }
00667     }
00668 
00669     /*!
00670      \reimp
00671     */
00672     function preStoreClassAttribute( $classAttribute, $version )
00673     {
00674         $content = $classAttribute->content();
00675         return eZObjectRelationListType::storeClassAttributeContent( $classAttribute, $content );
00676     }
00677 
00678     function storeClassAttributeContent( $classAttribute, $content )
00679     {
00680         if ( is_array( $content ) )
00681         {
00682             $doc = eZObjectRelationListType::createClassDOMDocument( $content );
00683             eZObjectRelationListType::storeClassDOMDocument( $doc, $classAttribute );
00684             return true;
00685         }
00686         return false;
00687     }
00688 
00689     function storeObjectAttributeContent( $objectAttribute, $content )
00690     {
00691         if ( is_array( $content ) )
00692         {
00693             $doc = eZObjectRelationListType::createObjectDOMDocument( $content );
00694             eZObjectRelationListType::storeObjectDOMDocument( $doc, $objectAttribute );
00695             return true;
00696         }
00697         return false;
00698     }
00699 
00700     static function storeClassDOMDocument( $doc, $classAttribute )
00701     {
00702         $docText = eZObjectRelationListType::domString( $doc );
00703         $classAttribute->setAttribute( 'data_text5', $docText );
00704     }
00705 
00706     static function storeObjectDOMDocument( $doc, $objectAttribute )
00707     {
00708         $docText = eZObjectRelationListType::domString( $doc );
00709         $objectAttribute->setAttribute( 'data_text', $docText );
00710     }
00711 
00712     /*!
00713      \static
00714      \return the XML structure in \a $domDocument as text.
00715              It will take of care of the necessary charset conversions
00716              for content storage.
00717     */
00718     static function domString( $domDocument )
00719     {
00720         $ini = eZINI::instance();
00721         $xmlCharset = $ini->variable( 'RegionalSettings', 'ContentXMLCharset' );
00722         if ( $xmlCharset == 'enabled' )
00723         {
00724             //include_once( 'lib/ezi18n/classes/eztextcodec.php' );
00725             $charset = eZTextCodec::internalCharset();
00726         }
00727         else if ( $xmlCharset == 'disabled' )
00728             $charset = true;
00729         else
00730             $charset = $xmlCharset;
00731         if ( $charset !== true )
00732         {
00733             //include_once( 'lib/ezi18n/classes/ezcharsetinfo.php' );
00734             $charset = eZCharsetInfo::realCharsetCode( $charset );
00735         }
00736         $domString = $domDocument->saveXML();
00737         return $domString;
00738     }
00739 
00740     static function createClassDOMDocument( $content )
00741     {
00742         $doc = new DOMDocument( '1.0', 'utf-8' );
00743         $root = $doc->createElement( 'related-objects' );
00744         $constraints = $doc->createElement( 'constraints' );
00745         foreach ( $content['class_constraint_list'] as $constraintClassIdentifier )
00746         {
00747             unset( $constraintElement );
00748             $constraintElement = $doc->createElement( 'allowed-class' );
00749             $constraintElement->setAttribute( 'contentclass-identifier', $constraintClassIdentifier );
00750             $constraints->appendChild( $constraintElement );
00751         }
00752         $root->appendChild( $constraints );
00753         $constraintType = $doc->createElement( 'type' );
00754         $constraintType->setAttribute( 'value', $content['type'] );
00755         $root->appendChild( $constraintType );
00756         $selectionType = $doc->createElement( 'selection_type' );
00757         $selectionType->setAttribute( 'value', $content['selection_type'] );
00758         $root->appendChild( $selectionType );
00759         $objectClass = $doc->createElement( 'object_class' );
00760         $objectClass->setAttribute( 'value', $content['object_class'] );
00761         $root->appendChild( $objectClass );
00762 
00763         $placementNode = $doc->createElement( 'contentobject-placement' );
00764         if ( $content['default_placement'] )
00765         {
00766             $placementNode->setAttribute( 'node-id',  $content['default_placement']['node_id'] );
00767         }
00768         $root->appendChild( $placementNode );
00769         $doc->appendChild( $root );
00770         return $doc;
00771     }
00772 
00773     static function createObjectDOMDocument( $content )
00774     {
00775         $doc = new DOMDocument( '1.0', 'utf-8' );
00776         $root = $doc->createElement( 'related-objects' );
00777         $relationList = $doc->createElement( 'relation-list' );
00778         $attributeDefinitions = eZObjectRelationListType::contentObjectArrayXMLMap();
00779 
00780         foreach ( $content['relation_list'] as $relationItem )
00781         {
00782             unset( $relationElement );
00783             $relationElement = $doc->createElement( 'relation-item' );
00784 
00785             foreach ( $attributeDefinitions as $attributeXMLName => $attributeKey )
00786             {
00787                 if ( isset( $relationItem[$attributeKey] ) && $relationItem[$attributeKey] !== false )
00788                 {
00789                     $value = $relationItem[$attributeKey];
00790                     $relationElement->setAttribute( $attributeXMLName, $value );
00791                 }
00792             }
00793 
00794             $relationList->appendChild( $relationElement );
00795         }
00796         $root->appendChild( $relationList );
00797         $doc->appendChild( $root );
00798         return $doc;
00799     }
00800 
00801     static function contentObjectArrayXMLMap()
00802     {
00803         return array( 'identifier' => 'identifier',
00804                       'priority' => 'priority',
00805                       'in-trash' => 'in_trash',
00806                       'contentobject-id' => 'contentobject_id',
00807                       'contentobject-version' => 'contentobject_version',
00808                       'node-id' => 'node_id',
00809                       'parent-node-id' => 'parent_node_id',
00810                       'contentclass-id' => 'contentclass_id',
00811                       'contentclass-identifier' => 'contentclass_identifier',
00812                       'is-modified' => 'is_modified',
00813                       'contentobject-remote-id' => 'contentobject_remote_id' );
00814     }
00815 
00816     /*!
00817      \reimp
00818     */
00819     function deleteStoredObjectAttribute( $objectAttribute, $version = null )
00820     {
00821         $content = $objectAttribute->content();
00822         if ( is_array( $content ) and
00823              is_array( $content['relation_list'] ) )
00824         {
00825             $db = eZDB::instance();
00826             $db->begin();
00827             foreach ( $content['relation_list'] as $deletionItem )
00828             {
00829                 eZObjectRelationListType::removeRelationObject( $objectAttribute, $deletionItem );
00830             }
00831             $db->commit();
00832         }
00833     }
00834 
00835     /*!
00836      \reimp
00837     */
00838     function customObjectAttributeHTTPAction( $http, $action, $contentObjectAttribute, $parameters )
00839     {
00840         $contentobjectID = false;
00841         if ( eZDataType::fetchActionValue( $action, 'new_class', $classID ) or
00842              $action == 'new_class' )
00843         {
00844             if ( $action == 'new_class' )
00845             {
00846                 $base = $parameters['base_name'];
00847                 $classVariableName = $base . '_new_class';
00848                 if ( $http->hasPostVariable( $classVariableName ) )
00849                 {
00850                     $classVariable = $http->postVariable( $classVariableName );
00851                     $classID = $classVariable[$contentObjectAttribute->attribute( 'id' )];
00852                     $class = eZContentClass::fetch( $classID );
00853                 }
00854                 else
00855                     return false;
00856             }
00857             else
00858                 $class = eZContentClass::fetch( $classID );
00859             if ( $class )
00860             {
00861                 $classAttribute = $contentObjectAttribute->attribute( 'contentclass_attribute' );
00862                 $class_content = $classAttribute->content();
00863                 $content = $contentObjectAttribute->content();
00864                 $priority = 0;
00865                 for ( $i = 0; $i < count( $content['relation_list'] ); ++$i )
00866                 {
00867                     if ( $content['relation_list'][$i]['priority'] > $priority )
00868                         $priority = $content['relation_list'][$i]['priority'];
00869                 }
00870 
00871                 $base = $parameters['base_name'];
00872                 $nodePlacement = false;
00873                 $nodePlacementName = $base . '_object_initial_node_placement';
00874                 if ( $http->hasPostVariable( $nodePlacementName ) )
00875                 {
00876                     $nodePlacementMap = $http->postVariable( $nodePlacementName );
00877                     if ( isset( $nodePlacementMap[$contentObjectAttribute->attribute( 'id' )] ) )
00878                         $nodePlacement = $nodePlacementMap[$contentObjectAttribute->attribute( 'id' )];
00879                 }
00880                 $relationItem = eZObjectRelationListType::createInstance( $class,
00881                                                                           $priority + 1,
00882                                                                           $contentObjectAttribute,
00883                                                                           $nodePlacement );
00884                 if ( $class_content['default_placement'] )
00885                 {
00886                     $relationItem['parent_node_id'] = $class_content['default_placement']['node_id'];
00887                 }
00888 
00889                 $content['relation_list'][] = $relationItem;
00890 
00891                 $hasAttributeInput = false;
00892                 $attributeInputVariable = $base . '_has_attribute_input';
00893                 if ( $http->hasPostVariable( $attributeInputVariable ) )
00894                 {
00895                     $attributeInputMap = $http->postVariable( $attributeInputVariable );
00896                     if ( isset( $attributeInputMap[$contentObjectAttribute->attribute( 'id' )] ) )
00897                         $hasAttributeInput = $attributeInputMap[$contentObjectAttribute->attribute( 'id' )];
00898                 }
00899 
00900                 if ( $hasAttributeInput )
00901                 {
00902                     $object = $relationItem['object'];
00903                     $attributes = $object->contentObjectAttributes();
00904                     foreach ( $attributes as $attribute )
00905                     {
00906                         $attributeBase = $base . '_ezorl_init_class_' . $object->attribute( 'contentclass_id' ) . '_attr_' . $attribute->attribute( 'contentclassattribute_id' );
00907                         $oldAttributeID = $attribute->attribute( 'id' );
00908                         $attribute->setAttribute( 'id', false );
00909                         if ( $attribute->fetchInput( $http, $attributeBase ) )
00910                         {
00911                             $attribute->setAttribute( 'id', $oldAttributeID );
00912                             $attribute->store();
00913                         }
00914                     }
00915                 }
00916 
00917                 $contentObjectAttribute->setContent( $content );
00918                 $contentObjectAttribute->store();
00919             }
00920             else
00921 
00922                 eZDebug::writeError( "Unknown class ID $classID, cannot instantiate object",
00923                                      'eZObjectRelationListType::customObjectAttributeHTTPAction' );
00924         }
00925         else if ( eZDataType::fetchActionValue( $action, 'edit_objects', $contentobjectID ) or
00926                   $action == 'edit_objects' or
00927                   $action == 'remove_objects' )
00928         {
00929             $base = $parameters['base_name'];
00930             $selectionBase = $base . '_selection';
00931             $selections = array();
00932             $http = eZHTTPTool::instance();
00933             if ( $http->hasPostVariable( $selectionBase ) )
00934             {
00935                 $selectionMap = $http->postVariable( $selectionBase );
00936                 $selections = $selectionMap[$contentObjectAttribute->attribute( 'id' )];
00937             }
00938             if ( $contentobjectID !== false )
00939                 $selections[] = $contentobjectID;
00940             if ( $action == 'edit_objects' or
00941                  eZDataType::fetchActionValue( $action, 'edit_objects', $contentobjectID ) )
00942             {
00943                 $content = $contentObjectAttribute->content();
00944                 foreach ( $content['relation_list'] as $key => $relationItem )
00945                 {
00946                     if ( !$relationItem['is_modified'] and
00947                          in_array( $relationItem['contentobject_id'], $selections ) )
00948                     {
00949                         $object = eZContentObject::fetch( $relationItem['contentobject_id'] );
00950                         if ( $object->attribute( 'can_edit' ) )
00951                         {
00952                             $content['relation_list'][$key]['is_modified'] = true;
00953                             $translationSourceBase = $base . '_translation_source_' .
00954                             $contentObjectAttribute->attribute( 'id' ) . '_' .
00955                             $relationItem['contentobject_id'];
00956                             $languageFrom = false;
00957                             if( $http->hasPostVariable( $translationSourceBase ) &&
00958                                     $http->postVariable( $translationSourceBase ) !== '' )
00959                             {
00960                                 $languageFrom = $http->postVariable( $translationSourceBase );
00961                             }
00962 
00963                             $version = $object->createNewVersionIn( $contentObjectAttribute->attribute( 'language_code' ), $languageFrom );
00964                             $content['relation_list'][$key]['contentobject_version'] = $version->attribute( 'version' );
00965                         }
00966                     }
00967                 }
00968                 $contentObjectAttribute->setContent( $content );
00969                 $contentObjectAttribute->store();
00970             }
00971             else if ( $action == 'remove_objects' )
00972             {
00973                 $content = $contentObjectAttribute->content();
00974                 $relationList = $content['relation_list'];
00975                 $newRelationList = array();
00976                 foreach( $relationList as $relationItem )
00977                 {
00978                     if ( in_array( $relationItem['contentobject_id'], $selections ) )
00979                     {
00980                         eZObjectRelationListType::removeRelationObject( $contentObjectAttribute, $relationItem );
00981                     }
00982                     else
00983                     {
00984                         $newRelationList[] = $relationItem;
00985                     }
00986                 }
00987                 $content['relation_list'] = $newRelationList;
00988                 $contentObjectAttribute->setContent( $content );
00989                 $contentObjectAttribute->store();
00990             }
00991         }
00992         else if ( $action == 'browse_objects' )
00993         {
00994             $module = $parameters['module'];
00995             $redirectionURI = $parameters['current-redirection-uri'];
00996 
00997             $ini = eZINI::instance( 'content.ini' );
00998             $browseType = 'AddRelatedObjectListToDataType';
00999             $browseTypeINIVariable = $ini->variable( 'ObjectRelationDataTypeSettings', 'ClassAttributeStartNode' );
01000             foreach ( $browseTypeINIVariable as $value )
01001             {
01002                 list( $classAttributeID, $type ) = explode( ';',$value );
01003                 if ( is_numeric( $classAttributeID ) and
01004                      $classAttributeID == $contentObjectAttribute->attribute( 'contentclassattribute_id' ) and
01005                      strlen( $type ) > 0 )
01006                 {
01007                     $browseType = $type;
01008                     break;
01009                 }
01010             }
01011 
01012             // Fetch the list of "allowed" classes .
01013             // A user can select objects of only those allowed classes when browsing.
01014             $classAttribute = $contentObjectAttribute->attribute( 'contentclass_attribute' );
01015             $classContent   = $classAttribute->content();
01016             if ( isset( $classContent['class_constraint_list'] ) )
01017             {
01018                 $classConstraintList = $classContent['class_constraint_list'];
01019             }
01020             else
01021             {
01022                 $classConstraintList = array();
01023             }
01024 
01025             //include_once( 'kernel/classes/ezcontentbrowse.php' );
01026             $browseParameters = array( 'action_name' => 'AddRelatedObject_' . $contentObjectAttribute->attribute( 'id' ),
01027                                        'type' =>  $browseType,
01028                                        'browse_custom_action' => array( 'name' => 'CustomActionButton[' . $contentObjectAttribute->attribute( 'id' ) . '_set_object_relation_list]',
01029                                                                         'value' => $contentObjectAttribute->attribute( 'id' ) ),
01030                                        'persistent_data' => array( 'HasObjectInput' => 0 ),
01031                                        'from_page' => $redirectionURI );
01032             $base = $parameters['base_name'];
01033             $nodePlacementName = $base . '_browse_for_object_start_node';
01034             if ( $http->hasPostVariable( $nodePlacementName ) )
01035             {
01036                 $nodePlacement = $http->postVariable( $nodePlacementName );
01037                 if ( isset( $nodePlacement[$contentObjectAttribute->attribute( 'id' )] ) )
01038                     $browseParameters['start_node'] = eZContentBrowse::nodeAliasID( $nodePlacement[$contentObjectAttribute->attribute( 'id' )] );
01039             }
01040             if ( count($classConstraintList) > 0 )
01041                 $browseParameters['class_array'] = $classConstraintList;
01042 
01043             eZContentBrowse::browse( $browseParameters,
01044                                      $module );
01045         }
01046         else if ( $action == 'set_object_relation_list' )
01047         {
01048             if ( !$http->hasPostVariable( 'BrowseCancelButton' ) )
01049             {
01050                 $selectedObjectIDArray = $http->postVariable( "SelectedObjectIDArray" );
01051                 $content = $contentObjectAttribute->content();
01052                 $priority = 0;
01053                 for ( $i = 0; $i < count( $content['relation_list'] ); ++$i )
01054                 {
01055                     if ( $content['relation_list'][$i]['priority'] > $priority )
01056                         $priority = $content['relation_list'][$i]['priority'];
01057                 }
01058 
01059                 foreach ( $selectedObjectIDArray as $objectID )
01060                 {
01061                     // Check if the given object ID has a numeric value, if not go to the next object.
01062                     if ( !is_numeric( $objectID ) )
01063                     {
01064                         eZDebug::writeError( "Related object ID (objectID): '$objectID', is not a numeric value.",
01065                                              "eZObjectRelationListType::customObjectAttributeHTTPAction" );
01066 
01067                         continue;
01068                     }
01069 
01070                     /* Here we check if current object is already in the related objects list.
01071                      * If so, we don't add it again.
01072                      * FIXME: Stupid linear search. Maybe there's some better way?
01073                      */
01074                     $found = false;
01075                     foreach ( $content['relation_list'] as $i )
01076                     {
01077                         if ( $i['contentobject_id'] == $objectID )
01078                         {
01079                             $found = true;
01080                             break;
01081                         }
01082                     }
01083                     if ( $found )
01084                         continue;
01085 
01086                     ++$priority;
01087                     $content['relation_list'][] = $this->appendObject( $objectID, $priority, $contentObjectAttribute );
01088                     $contentObjectAttribute->setContent( $content );
01089                     $contentObjectAttribute->store();
01090                 }
01091             }
01092         }
01093         else
01094         {
01095             eZDebug::writeError( "Unknown custom HTTP action: " . $action,
01096                                  'eZObjectRelationListType' );
01097         }
01098     }
01099 
01100     /*!
01101      \reimp
01102     */
01103     function handleCustomObjectHTTPActions( $http, $attributeDataBaseName,
01104                                             $customActionAttributeArray, $customActionParameters )
01105     {
01106         $contentObjectAttribute = $customActionParameters['contentobject_attribute'];
01107         $content = $contentObjectAttribute->content();
01108         foreach( $content['relation_list'] as $relationItem )
01109         {
01110             if ( $relationItem['is_modified'] )
01111             {
01112                 $subObjectID = $relationItem['contentobject_id'];
01113                 $subObjectVersion = $relationItem['contentobject_version'];
01114 
01115                 $attributeBase = $attributeDataBaseName . '_ezorl_edit_object_' . $subObjectID;
01116                 if ( eZContentObject::recursionProtect( $subObjectID ) )
01117                 {
01118                     if ( isset ( $content['temp'] ) )
01119                         $object = $content['temp'][$subObjectID]['object'];
01120                     else
01121                         $object = eZContentObject::fetch( $subObjectID );
01122                     if ( $object )
01123                         $object->handleAllCustomHTTPActions( $attributeBase,
01124                                                              $customActionAttributeArray,
01125                                                              $customActionParameters,
01126                                                              $subObjectVersion );
01127                 }
01128             }
01129         }
01130     }
01131 
01132     /*!
01133      \static
01134      \return \c true if the relation item \a $relationItem exist in the content tree.
01135     */
01136     static function isItemPublished( $relationItem )
01137     {
01138         return is_numeric( $relationItem['node_id'] ) and $relationItem['node_id'] > 0;
01139     }
01140 
01141     /*!
01142      \private
01143      Removes the relation object \a $deletionItem if the item is owned solely by this
01144      version and is not published in the content tree.
01145     */
01146     function removeRelationObject( $contentObjectAttribute, $deletionItem )
01147     {
01148         if ( eZObjectRelationListType::isItemPublished( $deletionItem ) )
01149         {
01150             return;
01151         }
01152 
01153         $hostObject = $contentObjectAttribute->attribute( 'object' );
01154         $hostObjectVersions = $hostObject->versions();
01155         $isDeletionAllowed = true;
01156 
01157         // check if the relation item to be deleted is unique in the domain of all host-object versions
01158         foreach ( $hostObjectVersions as $version )
01159         {
01160             if ( $isDeletionAllowed and
01161                  $version->attribute( 'version' ) != $contentObjectAttribute->attribute( 'version' ) )
01162             {
01163                 $relationAttribute = eZPersistentObject::fetchObjectList( eZContentObjectAttribute::definition(),
01164                                                                            null,
01165                                                                            array( 'version' => $version->attribute( 'version' ),
01166                                                                                   'contentobject_id' => $hostObject->attribute( 'id' ),
01167                                                                                   'contentclassattribute_id' => $contentObjectAttribute->attribute( 'contentclassattribute_id' ) ) );
01168 
01169                 if ( count( $relationAttribute ) > 0 )
01170                 {
01171                     $relationContent = $relationAttribute[0]->content();
01172                     if ( is_array( $relationContent ) and
01173                          is_array( $relationContent['relation_list'] ) )
01174                     {
01175                         foreach( $relationContent['relation_list'] as $relationItem )
01176                         {
01177                             if ( $deletionItem['contentobject_id'] == $relationItem['contentobject_id'] &&
01178                                  $deletionItem['contentobject_version'] == $relationItem['contentobject_version'] )
01179                             {
01180                                 $isDeletionAllowed = false;
01181                                 break 2;
01182                             }
01183                         }
01184                     }
01185                 }
01186             }
01187         }
01188 
01189         if ( $isDeletionAllowed )
01190         {
01191             $subObjectVersion = eZContentObjectVersion::fetchVersion( $deletionItem['contentobject_version'],
01192                                                                       $deletionItem['contentobject_id'] );
01193             if ( $subObjectVersion instanceof eZContentObjectVersion )
01194             {
01195                 $subObjectVersion->removeThis();
01196             }
01197             else
01198             {
01199                 eZDebug::writeError( 'Cleanup of subobject-version failed. Could not fetch object from relation list.\n' .
01200                                      'Requested subobject id: ' . $deletionItem['contentobject_id'] . '\n' .
01201                                      'Requested Subobject version: ' . $deletionItem['contentobject_version'],
01202                                      'eZObjectRelationListType::removeRelationObject' );
01203             }
01204         }
01205     }
01206 
01207 
01208     function createInstance( $class, $priority, $contentObjectAttribute, $nodePlacement = false )
01209     {
01210         $currentObject = $contentObjectAttribute->attribute( 'object' );
01211         $sectionID = $currentObject->attribute( 'section_id' );
01212         $object = $class->instantiate( false, $sectionID, false, $contentObjectAttribute->attribute( 'language_code' ) );
01213         if ( !is_numeric( $nodePlacement ) or $nodePlacement <= 0 )
01214             $nodePlacement = false;
01215         $object->sync();
01216         $relationItem = array( 'identifier' => false,
01217                                'priority' => $priority,
01218                                'in_trash' => false,
01219                                'contentobject_id' => $object->attribute( 'id' ),
01220                                'contentobject_version' => $object->attribute( 'current_version' ),
01221                                'contentobject_remote_id' => $object->attribute( 'remote_id' ),
01222                                'node_id' => false,
01223                                'parent_node_id' => $nodePlacement,
01224                                'contentclass_id' => $class->attribute( 'id' ),
01225                                'contentclass_identifier' => $class->attribute( 'identifier' ),
01226                                'is_modified' => true );
01227         $relationItem['object'] = $object;
01228         return $relationItem;
01229     }
01230 
01231     function appendObject( $objectID, $priority, $contentObjectAttribute )
01232     {
01233         $object = eZContentObject::fetch( $objectID );
01234         $class = $object->attribute( 'content_class' );
01235         $sectionID = $object->attribute( 'section_id' );
01236         $relationItem = array( 'identifier' => false,
01237                                'priority' => $priority,
01238                                'in_trash' => false,
01239                                'contentobject_id' => $object->attribute( 'id' ),
01240                                'contentobject_version' => $object->attribute( 'current_version' ),
01241                                'contentobject_remote_id' => $object->attribute( 'remote_id' ),
01242                                'node_id' => $object->attribute( 'main_node_id' ),
01243                                'parent_node_id' => $object->attribute( 'main_parent_node_id' ),
01244                                'contentclass_id' => $class->attribute( 'id' ),
01245                                'contentclass_identifier' => $class->attribute( 'identifier' ),
01246                                'is_modified' => false );
01247         $relationItem['object'] = $object;
01248         return $relationItem;
01249     }
01250 
01251 
01252     function fixRelatedObjectItem ( $contentObjectAttribute, $objectID, $mode )
01253     {
01254         switch ( $mode )
01255         {
01256             case 'move':
01257             {
01258                 eZObjectRelationListType::fixRelationsMove( $objectID, $contentObjectAttribute );
01259             } break;
01260 
01261             case 'trash':
01262             {
01263                 eZObjectRelationListType::fixRelationsTrash( $objectID, $contentObjectAttribute );
01264             } break;
01265 
01266             case 'restore':
01267             {
01268                 eZObjectRelationListType::fixRelationsRestore( $objectID, $contentObjectAttribute );
01269             } break;
01270 
01271             case 'remove':
01272             {
01273                 eZObjectRelationListType::fixRelationsRemove( $objectID, $contentObjectAttribute );
01274             } break;
01275 
01276             case 'swap':
01277             {
01278                 eZObjectRelationListType::fixRelationsSwap( $objectID, $contentObjectAttribute );
01279             } break;
01280 
01281             default:
01282             {
01283                 eZDebug::writeWarning( $mode, 'Unknown mode eZObjectRelationListType::fixRelatedObjectItem()' );
01284             } break;
01285         }
01286     }
01287 
01288     function fixRelationsMove ( $objectID, $contentObjectAttribute )
01289     {
01290         $this->fixRelationsSwap( $objectID, $contentObjectAttribute );
01291     }
01292 
01293     function fixRelationsTrash ( $objectID, $contentObjectAttribute )
01294     {
01295         $content = $contentObjectAttribute->attribute( 'content' );
01296         foreach ( array_keys( $content['relation_list'] ) as $key )
01297         {
01298             if ( $content['relation_list'][$key]['contentobject_id'] == $objectID )
01299             {
01300                 $content['relation_list'][$key]['in_trash'] = true;
01301                 $content['relation_list'][$key]['node_id'] = null;
01302                 $content['relation_list'][$key]['parent_node_id']= null;
01303             }
01304         }
01305         eZObjectRelationListType::storeObjectAttributeContent( $contentObjectAttribute, $content );
01306         $contentObjectAttribute->setContent( $content );
01307         $contentObjectAttribute->storeData();
01308     }
01309 
01310     function fixRelationsRestore ( $objectID, $contentObjectAttribute )
01311     {
01312         $content = $contentObjectAttribute->content();
01313 
01314         foreach ( array_keys( $content['relation_list'] ) as $key )
01315         {
01316             if ( $content['relation_list'][$key]['contentobject_id'] == $objectID )
01317             {
01318                 $priority = $content['relation_list'][$key]['priority'];
01319                 $content['relation_list'][$key] = $this->appendObject( $objectID, $priority, $contentObjectAttribute);
01320             }
01321         }
01322         eZObjectRelationListType::storeObjectAttributeContent( $contentObjectAttribute, $content );
01323         $contentObjectAttribute->setContent( $content );
01324         $contentObjectAttribute->storeData();
01325     }
01326 
01327     function fixRelationsRemove ( $objectID, $contentObjectAttribute )
01328     {
01329         $this->removeRelatedObjectItem( $contentObjectAttribute, $objectID );
01330         $contentObjectAttribute->storeData();
01331     }
01332 
01333     function fixRelationsSwap ( $objectID, $contentObjectAttribute )
01334     {
01335         $content =& $contentObjectAttribute->content();
01336 
01337         foreach ( array_keys( $content['relation_list'] ) as $key )
01338         {
01339             $relatedObject =& $content['relation_list'][$key];
01340             if ( $relatedObject['contentobject_id'] == $objectID )
01341             {
01342                 $priority = $content['relation_list'][$key]['priority'];
01343                 $content['relation_list'][$key] = $this->appendObject($objectID, $priority, $contentObjectAttribute );
01344             }
01345         }
01346 
01347         eZObjectRelationListType::storeObjectAttributeContent( $contentObjectAttribute, $content );
01348         $contentObjectAttribute->setContent( $content );
01349         $contentObjectAttribute->storeData();
01350     }
01351 
01352 
01353     /*!
01354      Returns the content.
01355     */
01356     function objectAttributeContent( $contentObjectAttribute )
01357     {
01358         $xmlText = $contentObjectAttribute->attribute( 'data_text' );
01359         if ( trim( $xmlText ) == '' )
01360         {
01361             $objectAttributeContent = eZObjectRelationListType::defaultObjectAttributeContent();
01362             return $objectAttributeContent;
01363         }
01364         $doc = eZObjectRelationListType::parseXML( $xmlText );
01365         $content = eZObjectRelationListType::createObjectContentStructure( $doc );
01366 
01367         return $content;
01368     }
01369 
01370     /*!
01371      \reimp
01372     */
01373     function classAttributeContent( $classAttribute )
01374     {
01375         $xmlText = $classAttribute->attribute( 'data_text5' );
01376         if ( trim( $xmlText ) == '' )
01377         {
01378             return eZObjectRelationListType::defaultClassAttributeContent();
01379         }
01380         $doc = eZObjectRelationListType::parseXML( $xmlText );
01381         return eZObjectRelationListType::createClassContentStructure( $doc );
01382     }
01383 
01384     static function parseXML( $xmlText )
01385     {
01386         $dom = new DOMDocument( '1.0', 'utf-8' );
01387         $dom->loadXML( $xmlText );
01388         return $dom;
01389     }
01390 
01391     function defaultClassAttributeContent()
01392     {
01393         return array( 'object_class' => '',
01394                       'selection_type' => 0,
01395                       'type' => 0,
01396                       'class_constraint_list' => array(),
01397                       'default_placement' => false );
01398     }
01399 
01400     function defaultObjectAttributeContent()
01401     {
01402         return array( 'relation_list' => array() );
01403     }
01404 
01405     function createClassContentStructure( $doc )
01406     {
01407         $content = eZObjectRelationListType::defaultClassAttributeContent();
01408         $root = $doc->documentElement;
01409         $objectPlacement = $root->getElementsByTagName( 'contentobject-placement' )->item( 0 );
01410 
01411         if ( $objectPlacement and $objectPlacement->hasAttributes() )
01412         {
01413             $nodeID = $objectPlacement->getAttribute( 'node-id' );
01414             $content['default_placement'] = array( 'node_id' => $nodeID );
01415         }
01416         $constraints = $root->getElementsByTagName( 'constraints' )->item( 0 );
01417         if ( $constraints )
01418         {
01419             $allowedClassList = $constraints->getElementsByTagName( 'allowed-class' );
01420             foreach( $allowedClassList as $allowedClass )
01421             {
01422                 $content['class_constraint_list'][] = $allowedClass->getAttribute( 'contentclass-identifier' );
01423             }
01424         }
01425         $type = $root->getElementsByTagName( 'type' )->item( 0 );
01426         if ( $type )
01427         {
01428             $content['type'] = $type->getAttribute( 'value' );
01429         }
01430         $selectionType = $root->getElementsByTagName( 'selection_type' )->item( 0 );
01431         if ( $selectionType )
01432         {
01433             $content['selection_type'] = $selectionType->getAttribute( 'value' );
01434         }
01435         $objectClass = $root->getElementsByTagName( 'object_class' )->item( 0 );
01436         if ( $objectClass )
01437         {
01438             $content['object_class'] = $objectClass->getAttribute( 'value' );
01439         }
01440 
01441         return $content;
01442     }
01443 
01444     function createObjectContentStructure( $doc )
01445     {
01446         $content = eZObjectRelationListType::defaultObjectAttributeContent();
01447         $root = $doc->documentElement;
01448         $relationList = $root->getElementsByTagName( 'relation-list' )->item( 0 );
01449         if ( $relationList )
01450         {
01451             $contentObjectArrayXMLMap = eZObjectRelationListType::contentObjectArrayXMLMap();
01452             $relationItems = $relationList->getElementsByTagName( 'relation-item' );
01453             foreach ( $relationItems as $relationItem )
01454             {
01455                 $hash = array();
01456 
01457                 foreach ( $contentObjectArrayXMLMap as $attributeXMLName => $attributeKey )
01458                 {
01459                     $attributeValue = $relationItem->hasAttribute( $attributeXMLName ) ? $relationItem->getAttribute( $attributeXMLName ) : false;
01460                     $hash[$attributeKey] = $attributeValue;
01461                 }
01462                 $content['relation_list'][] = $hash;
01463             }
01464         }
01465         return $content;
01466     }
01467 
01468     /*!
01469      \reimp
01470     */
01471     function customClassAttributeHTTPAction( $http, $action, $classAttribute )
01472     {
01473         switch ( $action )
01474         {
01475             case 'browse_for_placement':
01476             {
01477                 $module = $classAttribute->currentModule();
01478                 //include_once( 'kernel/classes/ezcontentbrowse.php' );
01479                 $customActionName = 'CustomActionButton[' . $classAttribute->attribute( 'id' ) . '_browsed_for_placement]';
01480                 eZContentBrowse::browse( array( 'action_name' => 'SelectObjectRelationListNode',
01481                                                 'content' => array( 'contentclass_id' => $classAttribute->attribute( 'contentclass_id' ),
01482                                                                     'contentclass_attribute_id' => $classAttribute->attribute( 'id' ),
01483                                                                     'contentclass_version' => $classAttribute->attribute( 'version' ),
01484                                                                     'contentclass_attribute_identifier' => $classAttribute->attribute( 'identifier' ) ),
01485                                                 'persistent_data' => array( $customActionName => '',
01486                                                                             'ContentClassHasInput' => false ),
01487                                                 'description_template' => 'design:class/datatype/browse_objectrelationlist_placement.tpl',
01488                                                 'from_page' => $module->currentRedirectionURI() ),
01489                                          $module );
01490             } break;
01491             case 'browsed_for_placement':
01492             {
01493                 //include_once( 'kernel/classes/ezcontentbrowse.php' );
01494                 $nodeSelection = eZContentBrowse::result( 'SelectObjectRelationListNode' );
01495                 if ( $nodeSelection and count( $nodeSelection ) > 0 )
01496                 {
01497                     $nodeID = $nodeSelection[0];
01498                     $content = $classAttribute->content();
01499                     $content['default_placement'] = array( 'node_id' => $nodeID );
01500                     $classAttribute->setContent( $content );
01501                 }
01502             } break;
01503             case 'disable_placement':
01504             {
01505                 $content = $classAttribute->content();
01506                 $content['default_placement'] = false;
01507                 $classAttribute->setContent( $content );
01508             } break;
01509             default:
01510             {
01511                 eZDebug::writeError( "Unknown objectrelationlist action '$action'", 'eZContentObjectRelationListType::customClassAttributeHTTPAction' );
01512             } break;
01513         }
01514     }
01515 
01516     /*!
01517      Returns the meta data used for storing search indexes.
01518     */
01519     function metaData( $contentObjectAttribute )
01520     {
01521         $metaDataArray = array();
01522         $content = $contentObjectAttribute->content();
01523         foreach( $content['relation_list'] as $relationItem )
01524         {
01525             $subObjectID = $relationItem['contentobject_id'];
01526             if ( !$subObjectID )
01527                 continue;
01528 
01529             if ( isset( $content['temp'] ) )
01530                 $attributes = $content['temp'][$subObjectID]['attributes'];
01531             else
01532             {
01533                 $subObjectVersion = $relationItem['contentobject_version'];
01534                 $object = eZContentObject::fetch( $subObjectID );
01535                 if ( eZContentObject::recursionProtect( $subObjectID ) )
01536                 {
01537                     if ( !$object )
01538                     {
01539                         continue;
01540                     }
01541                     $attributes = $object->contentObjectAttributes( true, $subObjectVersion );
01542                 }
01543             }
01544 
01545             $attributeMetaDataArray = eZContentObjectAttribute::metaDataArray( $attributes );
01546             $metaDataArray = array_merge( $metaDataArray, $attributeMetaDataArray );
01547         }
01548 
01549         return $metaDataArray;
01550     }
01551 
01552     /*!
01553      \return string representation of an contentobjectattribute data for simplified export
01554 
01555     */
01556     function toString( $contentObjectAttribute )
01557     {
01558         $objectAttributeContent = $contentObjectAttribute->attribute( 'content' );
01559         $objectIDList = array();
01560         foreach( $objectAttributeContent['relation_list'] as $objectInfo )
01561         {
01562             $objectIDList[] = $objectInfo['contentobject_id'];
01563         }
01564         return implode( '-', $objectIDList );
01565     }
01566 
01567     function fromString( $contentObjectAttribute, $string )
01568     {
01569         $objectIDList = explode( '-', $string );
01570 
01571         $content = eZObjectRelationListType::defaultObjectAttributeContent();
01572         $priority = 0;
01573         foreach( $objectIDList as $objectID )
01574         {
01575             $object = eZContentObject::fetch( $objectID );
01576             if ( $object )
01577             {
01578                 ++$priority;
01579                 $content['relation_list'][] = $this->appendObject( $objectID, $priority, $contentObjectAttribute );
01580             }
01581             else
01582             {
01583                 eZDebug::writeWarning( $objectID, "Can not create relation because object is missing" );
01584             }
01585         }
01586         $contentObjectAttribute->setContent( $content );
01587         return true;
01588     }
01589 
01590     function hasObjectAttributeContent( $contentObjectAttribute )
01591     {
01592         $content = $contentObjectAttribute->content();
01593         return count( $content['relation_list'] ) > 0;
01594     }
01595 
01596     /*!
01597      \reimp
01598     */
01599     function isIndexable()
01600     {
01601         return true;
01602     }
01603 
01604     /*!
01605      Returns the content of the string for use as a title,
01606      for simplicity this is the name of the first object referenced or false.
01607     */
01608     function title( $contentObjectAttribute, $name = null )
01609     {
01610         $objectAttributeContent = $this->objectAttributeContent( $contentObjectAttribute );
01611 
01612         if ( count( $objectAttributeContent['relation_list'] ) > 0 )
01613         {
01614             $target = $objectAttributeContent['relation_list'][0];
01615             $targetObject = eZContentObject::fetch( $target['contentobject_id'], false );
01616             return $targetObject['name'];
01617         }
01618         else
01619         {
01620             return false;
01621         }
01622     }
01623 
01624     /*!
01625      \reimp
01626     */
01627     function serializeContentClassAttribute( $classAttribute, $attributeNode, $attributeParametersNode )
01628     {
01629         $dom = $attributeParametersNode->ownerDocument;
01630         $content = $classAttribute->content();
01631         if ( $content['default_placement'] )
01632         {
01633             $defaultPlacementNode = $dom->createElement( 'default-placement' );
01634             $defaultPlacementNode->setAttribute( 'node-id', $content['default_placement']['node_id'] );
01635             $attributeParametersNode->appendChild( $defaultPlacementNode );
01636         }
01637 
01638         $type = is_numeric( $content['type'] ) ? $content['type'] : '0';
01639         $typeNode = $dom->createElement( 'type' );
01640         $typeNode->appendChild( $dom->createTextNode( $type ) );
01641         $attributeParametersNode->appendChild( $typeNode );
01642 
01643         $classConstraintsNode = $dom->createElement( 'class-constraints' );
01644         $attributeParametersNode->appendChild( $classConstraintsNode );
01645         foreach ( $content['class_constraint_list'] as $classConstraint )
01646         {
01647             $classConstraintIdentifier = $classConstraint;
01648             $classConstraintNode = $dom->createElement( 'class-constraint' );
01649             $classConstraintNode->setAttribute( 'class-identifier', $classConstraintIdentifier );
01650             $classConstraintsNode->appendChild( $classConstraintNode );
01651         }
01652 
01653         if ( isset( $content['selection_type'] ) && is_numeric( $content['selection_type'] ) )
01654         {
01655             $selectionTypeNode = $dom->createElement( 'selection-type' );
01656             $selectionTypeNode->appendChild( $dom->createTextNode( $content['selection_type'] ) );
01657             $attributeParametersNode->appendChild( $selectionTypeNode );
01658         }
01659 
01660         if ( isset( $content['object_class'] ) && is_numeric( $content['object_class'] ) )
01661         {
01662             $objectClassNode = $dom->createElement( 'object-class' );
01663             $objectClassNode->appendChild( $dom->createTextNode( $content['object_class'] ) );
01664             $attributeParametersNode->appendChild( $objectClassNode );
01665         }
01666     }
01667 
01668     /*!
01669      \reimp
01670     */
01671     function unserializeContentClassAttribute( $classAttribute, $attributeNode, $attributeParametersNode )
01672     {
01673         $content = $classAttribute->content();
01674         $defaultPlacementNode = $attributeParametersNode->getElementsByTagName( 'default-placement' )->item( 0 );
01675         $content['default_placement'] = false;
01676 
01677         if ( $defaultPlacementNode )
01678         {
01679             $content['default_placement'] = array( 'node_id' => $defaultPlacementNode->getAttribute( 'node-id' ) );
01680         }
01681         $content['type'] = $attributeParametersNode->getElementsByTagName( 'type' )->item( 0 )->textContent;
01682         $classConstraintsNode = $attributeParametersNode->getElementsByTagName( 'class-constraints' )->item( 0 );
01683         $classConstraintList = $classConstraintsNode->getElementsByTagName( 'class-constraint' );
01684         $content['class_constraint_list'] = array();
01685         foreach ( $classConstraintList as $classConstraintNode )
01686         {
01687             $classIdentifier = $classConstraintNode->getAttribute( 'class-identifier' );
01688             $content['class_constraint_list'][] = $classIdentifier;
01689         }
01690 
01691         $objectClassNode = $attributeParametersNode->getElementsByTagName( 'object-class' )->item( 0 );
01692         if ( $objectClassNode )
01693         {
01694             $content['object_class'] = $objectClassNode->textContent;
01695         }
01696 
01697         $selectionTypeNode = $attributeParametersNode->getElementsByTagName( 'selection-type' )->item( 0 );
01698         if ( $selectionTypeNode )
01699         {
01700             $content['selection_type'] = $selectionTypeNode->textContent;
01701         }
01702 
01703         $classAttribute->setContent( $content );
01704         $this->storeClassAttributeContent( $classAttribute, $content );
01705     }
01706 
01707     /*!
01708      For each relation export its priority and content object remote_id, like this:
01709       <related-objects>
01710         <relation-list>
01711           <relation-item priority="1"
01712                          contentobject-remote-id="faaeb9be3bd98ed09f606fc16d144eca" />
01713           <relation-item priority="2"
01714                          contentobject-remote-id="1bb4fe25487f05527efa8bfd394cecc7" />
01715         </relation-list>
01716      To do this we fetch content XML and strip all the relation attributes except of "priority" from there,
01717      and add "contentobject-remote-id" attribute.
01718      \reimp
01719     */
01720     function serializeContentObjectAttribute( $package, $objectAttribute )
01721     {
01722         $node = $this->createContentObjectAttributeDOMNode( $objectAttribute );
01723 
01724         eZDebug::writeDebug( $objectAttribute->attribute( 'data_text' ), 'xml string from data_text field' );
01725         if ( $objectAttribute->attribute( 'data_text' ) === null )
01726         {
01727             $content = array( 'relation_list' => array() );
01728             $dom = eZObjectRelationListType::createObjectDOMDocument( $content );
01729         }
01730         else
01731         {
01732             $dom = new DOMDocument( '1.0', 'utf-8' );
01733             $success = $dom->loadXML( $objectAttribute->attribute( 'data_text' ) );
01734         }
01735         $rootNode = $dom->documentElement;
01736         $relationList = $rootNode->getElementsByTagName( 'relation-list' )->item( 0 );
01737         if ( $relationList )
01738         {
01739             require_once( 'kernel/classes/ezcontentobject.php' );
01740             $relationItems = $relationList->getElementsByTagName( 'relation-item' );
01741             for ( $i = 0; $i < $relationItems->length; $i++ )
01742             {
01743                 $relationItem = $relationItems->item( $i );
01744                 // Add related object remote id as attribute to the relation item.
01745                 $relatedObjectID = $relationItem->getAttribute( 'contentobject-id' );
01746                 $relatedObject = eZContentObject::fetch( $relatedObjectID );
01747                 $relatedObjectRemoteID = $relatedObject->attribute( 'remote_id' );
01748                 $relationItem->setAttribute( 'contentobject-remote-id', $relatedObjectRemoteID );
01749 
01750                 $attributes = $relationItem->attributes;
01751                 // Remove all other relation item attributes except of "priority".
01752                 // This loop intentionally starts with the last attribute, otherwise you will get unexpected results
01753                 for ( $j = $attributes->length - 1; $j >= 0; $j-- )
01754                 {
01755                     $attribute = $attributes->item( $j );
01756                     $attrName = $attribute->localName;
01757 
01758                     eZDebug::writeDebug( $attrName );
01759                     if ( $attrName != 'priority' && $attrName != 'contentobject-remote-id' )
01760                     {
01761                         $success = $relationItem->removeAttribute( $attribute->localName );
01762                         if ( !$success )
01763                         {
01764                             eZDebug::writeError( 'failed removing attribute ' . $attrName . ' from relation-item element' );
01765                         }
01766                     }
01767                 }
01768             }
01769         }
01770 
01771         eZDebug::writeDebug( $dom->saveXML(), 'old xml doc' );
01772 
01773         $importedRootNode = $node->ownerDocument->importNode( $rootNode, true );
01774         $node->appendChild( $importedRootNode );
01775 
01776         return $node;
01777     }
01778 
01779     /*!
01780      \reimp
01781     */
01782     function unserializeContentObjectAttribute( $package, $objectAttribute, $attributeNode )
01783     {
01784         $rootNode = $attributeNode->getElementsByTagName( 'related-objects' )->item( 0 );
01785         $xmlString = $rootNode ? $rootNode->ownerDocument->saveXML( $rootNode ) : '';
01786         $objectAttribute->setAttribute( 'data_text', $xmlString );
01787     }
01788 
01789     function postUnserializeContentObjectAttribute( $package, $objectAttribute )
01790     {
01791         $xmlString = $objectAttribute->attribute( 'data_text' );
01792         $doc = $this->parseXML( $xmlString );
01793         $rootNode = $doc->documentElement;
01794 
01795         $relationList = $rootNode->getElementsByTagName( 'relation-list' )->item( 0 );
01796         if ( !$relationList )
01797             return false;
01798 
01799         require_once( 'kernel/classes/ezcontentobject.php' );
01800         $relationItems = $relationList->getElementsByTagName( 'relation-item' );
01801         for ( $i = $relationItems->length - 1; $i >= 0; $i-- )
01802         {
01803             $relationItem = $relationItems->item( $i );
01804             $relatedObjectRemoteID = $relationItem->getAttribute( 'contentobject-remote-id' );
01805             $object = eZContentObject::fetchByRemoteID( $relatedObjectRemoteID );
01806 
01807             if ( $object === null )
01808             {
01809                 eZDebug::writeWarning( "Object with remote id '$relatedObjectRemoteID' not found: removing the link.",
01810                                        'eZObjectRelationListType::unserializeContentObjectAttribute()' );
01811                 $relationItem->parentNode->removeChild( $relationItem );
01812                 continue;
01813             }
01814 
01815             $relationItem->setAttribute( 'contentobject-id',        $object->attribute( 'id' ) );
01816             $relationItem->setAttribute( 'contentobject-version',   $object->attribute( 'current_version' ) );
01817             $relationItem->setAttribute( 'node-id',                 $object->attribute( 'main_node_id' ) );
01818             $relationItem->setAttribute( 'parent-node-id',          $object->attribute( 'main_parent_node_id' ) );
01819             $relationItem->setAttribute( 'contentclass-id',         $object->attribute( 'contentclass_id' ) );
01820             $relationItem->setAttribute( 'contentclass-identifier', $object->attribute( 'class_identifier' ) );
01821         }
01822 
01823         $newXmlString = $doc->saveXML( $rootNode );
01824 
01825         $objectAttribute->setAttribute( 'data_text', $newXmlString );
01826         return true;
01827     }
01828 
01829     /*!
01830      Removes objects with given ID from the relations list
01831     */
01832     function removeRelatedObjectItem( $contentObjectAttribute, $objectID )
01833     {
01834         $xmlText = $contentObjectAttribute->attribute( 'data_text' );
01835         if ( trim( $xmlText ) == '' ) return;
01836 
01837         $doc = eZObjectRelationListType::parseXML( $xmlText );
01838 
01839         $return = false;
01840         $root = $doc->documentElement;
01841         $relationList = $root->getElementsByTagName( 'relation-list' )->item( 0 );
01842         if ( $relationList )
01843         {
01844             $relationItems = $relationList->getElementsByTagName( 'relation-item' );
01845             if ( !empty( $relationItems ) )
01846             {
01847                 foreach( $relationItems as $relationItem )
01848                 {
01849                     if ( $relationItem->getAttribute( 'contentobject-id' ) == $objectID )
01850                     {
01851                         $relationList->removeChild( $relationItem );
01852                         $return = true;
01853                     }
01854                 }
01855             }
01856         }
01857         eZObjectRelationListType::storeObjectDOMDocument( $doc, $contentObjectAttribute );
01858         return $return;
01859     }
01860 
01861     /// \privatesection
01862 }
01863 
01864 eZDataType::register( eZObjectRelationListType::DATA_TYPE_STRING, "eZObjectRelationListType" );
01865 
01866 ?>