- Fixed #16160: Call to undefined function ezi18n()
[tinyz:tinyz.git] / kernel / classes / packagehandlers / ezcontentclass / ezcontentclasspackagehandler.php
1 <?php
2 //
3 // Definition of eZContentClassPackageHandler class
4 //
5 // Created on: <23-Jul-2003 16:11:42 amos>
6 //
7 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
8 // SOFTWARE NAME: eZ Publish
9 // SOFTWARE RELEASE: 4.1.x
10 // COPYRIGHT NOTICE: Copyright (C) 1999-2010 eZ Systems AS
11 // SOFTWARE LICENSE: GNU General Public License v2.0
12 // NOTICE: >
13 //   This program is free software; you can redistribute it and/or
14 //   modify it under the terms of version 2.0  of the GNU General
15 //   Public License as published by the Free Software Foundation.
16 //
17 //   This program is distributed in the hope that it will be useful,
18 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 //   GNU General Public License for more details.
21 //
22 //   You should have received a copy of version 2.0 of the GNU General
23 //   Public License along with this program; if not, write to the Free
24 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 //   MA 02110-1301, USA.
26 //
27 //
28 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
29 //
30
31 /*! \file
32 */
33
34 /*!
35   \class eZContentClassPackageHandler ezcontentclasspackagehandler.php
36   \brief Handles content classes in the package system
37
38 */
39
40 class eZContentClassPackageHandler extends eZPackageHandler
41 {
42     const ERROR_EXISTS = 1;
43     const ERROR_HAS_OBJECTS = 101;
44
45     const ACTION_REPLACE = 1;
46     const ACTION_SKIP = 2;
47     const ACTION_NEW = 3;
48     const ACTION_DELETE = 4;
49
50     /*!
51      Constructor
52     */
53     function eZContentClassPackageHandler()
54     {
55         $this->eZPackageHandler( 'ezcontentclass',
56                                  array( 'extract-install-content' => true ) );
57     }
58
59     /*!
60      Returns an explanation for the content class install item.
61      Use $requestedInfo to request portion of info.
62     */
63     function explainInstallItem( $package, $installItem, $requestedInfo = array( 'name', 'identifier', 'description', 'language_info' ) )
64     {
65         if ( $installItem['filename'] )
66         {
67             $explainClassName = in_array( 'name', $requestedInfo );
68             $explainClassIdentitier = in_array( 'identifier', $requestedInfo );
69             $explainDescription = in_array( 'description', $requestedInfo );
70             $explainLanguageInfo = in_array( 'language_info', $requestedInfo );
71
72             $filename = $installItem['filename'];
73             $subdirectory = $installItem['sub-directory'];
74             if ( $subdirectory )
75                 $filepath = $subdirectory . '/' . $filename . '.xml';
76             else
77                 $filepath = $filename . '.xml';
78
79             $filepath = $package->path() . '/' . $filepath;
80
81             $dom = $package->fetchDOMFromFile( $filepath );
82             if ( $dom )
83             {
84                 $languageInfo = array();
85
86                 $content = $dom->documentElement;
87                 $classIdentifier = $explainClassIdentitier ? $content->getElementsByTagName( 'identifier' )->item( 0 )->textContent : '';
88
89                 $className = '';
90                 if ( $explainClassName )
91                 {
92                     // BC ( <= 3.8 )
93                     $classNameNode = $content->getElementsByTagName( 'name' )->item( 0 );
94
95                     if( $classNameNode )
96                     {
97                         $className = $classNameNode->textContent;
98                     }
99                     else
100                     {
101                         // get info about translations.
102                         $serializedNameListNode = $content->getElementsByTagName( 'serialized-name-list' )->item( 0 );
103                         if( $serializedNameListNode )
104                         {
105                             $serializedNameList = $serializedNameListNode->textContent;
106                             $nameList = new eZContentClassNameList( $serializedNameList );
107                             $languageInfo = $explainLanguageInfo ? $nameList->languageLocaleList() : array();
108                             $className = $nameList->name();
109                         }
110                     }
111                 }
112
113                 $description = $explainDescription ? ezpI18n::translate( 'kernel/package', "Content class '%classname' (%classidentifier)", false,
114                                                              array( '%classname' => $className,
115                                                                     '%classidentifier' => $classIdentifier ) ) : '';
116                 $explainInfo = array( 'description' => $description,
117                                       'language_info' => $languageInfo );
118                 return $explainInfo;
119             }
120         }
121     }
122
123     /*!
124      Uninstalls all previously installed content classes.
125     */
126     function uninstall( $package, $installType, $parameters,
127                       $name, $os, $filename, $subdirectory,
128                       $content, &$installParameters,
129                       &$installData )
130     {
131         $classRemoteID = $content->getElementsByTagName( 'remote-id' )->item( 0 )->textContent;
132
133         $class = eZContentClass::fetchByRemoteID( $classRemoteID );
134
135         if ( $class == null )
136         {
137             eZDebug::writeNotice( "Class having remote id '$classRemoteID' not found.", 'eZContentClassPackageHandler::uninstall()' );
138             return true;
139         }
140
141         if ( $class->isRemovable() )
142         {
143             $choosenAction = $this->errorChoosenAction( self::ERROR_HAS_OBJECTS,
144                                                         $installParameters, false, $this->HandlerType );
145             if ( $choosenAction == self::ACTION_SKIP )
146             {
147                 return true;
148             }
149             if ( $choosenAction != self::ACTION_DELETE )
150             {
151                 $objectsCount = eZContentObject::fetchSameClassListCount( $class->attribute( 'id' ) );
152                 $name = $class->attribute( 'name' );
153                 if ( $objectsCount )
154                 {
155                     $installParameters['error'] = array( 'error_code' => self::ERROR_HAS_OBJECTS,
156                                                          'element_id' => $classRemoteID,
157                                                          'description' => ezpI18n::translate( 'kernel/package',
158                                                                                   "Removing class '%classname' will result in the removal of %objectscount object(s) of this class and all their sub-items. Are you sure you want to uninstall it?",
159                                                                                   false,
160                                                                                   array( '%classname' => $name,
161                                                                                          '%objectscount' => $objectsCount ) ),
162                                                          'actions' => array( self::ACTION_DELETE => "Uninstall class and object(s)",
163                                                                              self::ACTION_SKIP => 'Skip' ) );
164                     return false;
165                 }
166             }
167
168             eZDebug::writeNotice( sprintf( "Removing class '%s' (%d)", $class->attribute( 'name' ), $class->attribute( 'id' ) ) );
169
170             eZContentClassOperations::remove( $class->attribute( 'id' ) );
171         }
172
173         return true;
174     }
175
176     /*!
177      Creates a new contentclass as defined in the xml structure.
178     */
179     function install( $package, $installType, $parameters,
180                       $name, $os, $filename, $subdirectory,
181                       $content, &$installParameters,
182                       &$installData )
183     {
184         $serializedNameListNode = $content->getElementsByTagName( 'serialized-name-list' )->item( 0 );
185         $serializedNameList = $serializedNameListNode ? $serializedNameListNode->textContent : false;
186         $classNameList = new eZContentClassNameList( $serializedNameList );
187         if ( $classNameList->isEmpty() )
188         {
189             $classNameList->initFromString( $content->getElementsByTagName( 'name' )->item( 0 )->textContent ); // for backward compatibility( <= 3.8 )
190         }
191         $classNameList->validate( );
192
193         $classIdentifier = $content->getElementsByTagName( 'identifier' )->item( 0 )->textContent;
194         $classRemoteID = $content->getElementsByTagName( 'remote-id' )->item( 0 )->textContent;
195         $classObjectNamePattern = $content->getElementsByTagName( 'object-name-pattern' )->item( 0 )->textContent;
196         $classURLAliasPattern = is_object( $content->getElementsByTagName( 'url-alias-pattern' )->item( 0 ) ) ?
197             $content->getElementsByTagName( 'url-alias-pattern' )->item( 0 )->textContent :
198             null;
199         $classIsContainer = $content->getAttribute( 'is-container' );
200         if ( $classIsContainer !== false )
201             $classIsContainer = $classIsContainer == 'true' ? 1 : 0;
202
203         $classRemoteNode = $content->getElementsByTagName( 'remote' )->item( 0 );
204         $classID = $classRemoteNode->getElementsByTagName( 'id' )->item( 0 )->textContent;
205         $classGroupsNode = $classRemoteNode->getElementsByTagName( 'groups' )->item( 0 );
206         $classCreated = $classRemoteNode->getElementsByTagName( 'created' )->item( 0 )->textContent;
207         $classModified = $classRemoteNode->getElementsByTagName( 'modified' )->item( 0 )->textContent;
208         $classCreatorNode = $classRemoteNode->getElementsByTagName( 'creator' )->item( 0 );
209         $classModifierNode = $classRemoteNode->getElementsByTagName( 'modifier' )->item( 0 );
210
211         $classAttributesNode = $content->getElementsByTagName( 'attributes' )->item( 0 );
212
213         $dateTime = time();
214         $classCreated = $dateTime;
215         $classModified = $dateTime;
216
217         $userID = false;
218         if ( isset( $installParameters['user_id'] ) )
219             $userID = $installParameters['user_id'];
220
221         $class = eZContentClass::fetchByRemoteID( $classRemoteID );
222
223         if ( $class )
224         {
225             $className = $class->name();
226             $description = ezpI18n::translate( 'kernel/package', "Class '%classname' already exists.", false,
227                                    array( '%classname' => $className ) );
228
229             $choosenAction = $this->errorChoosenAction( self::ERROR_EXISTS,
230                                                         $installParameters, $description, $this->HandlerType );
231             switch( $choosenAction )
232             {
233             case eZPackage::NON_INTERACTIVE:
234             case self::ACTION_REPLACE:
235                 if ( eZContentClassOperations::remove( $class->attribute( 'id' ) ) == false )
236                 {
237                     eZDebug::writeWarning( "Unable to remove class '$className'." );
238                     return true;
239                 }
240                 eZDebug::writeNotice( "Class '$className' will be replaced.", 'eZContentClassPackageHandler' );
241                 break;
242
243             case self::ACTION_SKIP:
244                 return true;
245
246             case self::ACTION_NEW:
247                 $class->setAttribute( 'remote_id', md5( (string)mt_rand() . (string)time() ) );
248                 $class->store();
249                 $classNameList->appendGroupName( " (imported)" );
250                 break;
251
252             default:
253                 $installParameters['error'] = array( 'error_code' => self::ERROR_EXISTS,
254                                                      'element_id' => $classRemoteID,
255                                                      'description' => $description,
256                                                      'actions' => array() );
257                 if ( $class->isRemovable() )
258                 {
259                     $errorMsg = ezpI18n::translate( 'kernel/package', "Replace existing class" );
260                     $objectsCount = eZContentObject::fetchSameClassListCount( $class->attribute( 'id' ) );
261                     if ( $objectsCount )
262                         $errorMsg .= ' ' . ezpI18n::translate( 'kernel/package', "(Warning! $objectsCount content object(s) and their sub-items will be removed)" );
263                     $installParameters['error']['actions'][self::ACTION_REPLACE] = $errorMsg;
264                 }
265                 $installParameters['error']['actions'][self::ACTION_SKIP] = ezpI18n::translate( 'kernel/package', 'Skip installing this class' );
266                 $installParameters['error']['actions'][self::ACTION_NEW] = ezpI18n::translate( 'kernel/package', 'Keep existing and create a new one' );
267                 return false;
268             }
269         }
270
271         unset( $class );
272
273         // Try to create a unique class identifier
274         $currentClassIdentifier = $classIdentifier;
275         $unique = false;
276
277         while( !$unique )
278         {
279             $classList = eZContentClass::fetchByIdentifier( $currentClassIdentifier );
280             if ( $classList )
281             {
282                 // "increment" class identifier
283                 if ( preg_match( '/^(.*)_(\d+)$/', $currentClassIdentifier, $matches ) )
284                     $currentClassIdentifier = $matches[1] . '_' . ( $matches[2] + 1 );
285                 else
286                     $currentClassIdentifier = $currentClassIdentifier . '_1';
287             }
288             else
289                 $unique = true;
290
291             unset( $classList );
292         }
293
294         $classIdentifier = $currentClassIdentifier;
295
296         $values = array( 'version' => 0,
297                          'serialized_name_list' => $classNameList->serializeNames(),
298                          'create_lang_if_not_exist' => true,
299                          'identifier' => $classIdentifier,
300                          'remote_id' => $classRemoteID,
301                          'contentobject_name' => $classObjectNamePattern,
302                          'url_alias_name' => $classURLAliasPattern,
303                          'is_container' => $classIsContainer,
304                          'created' => $classCreated,
305                          'modified' => $classModified );
306
307         if ( $content->hasAttribute( 'sort-field' ) )
308         {
309             $values['sort_field'] = eZContentObjectTreeNode::sortFieldID( $content->getAttribute( 'sort-field' ) );
310         }
311         else
312         {
313             eZDebug::writeNotice( 'The sort field was not specified in the content class package. ' .
314                                   'This property is exported and imported since eZ Publish 4.0.2', __METHOD__ );
315         }
316
317         if ( $content->hasAttribute( 'sort-order' ) )
318         {
319             $values['sort_order'] = $content->getAttribute( 'sort-order' );
320         }
321         else
322         {
323             eZDebug::writeNotice( 'The sort order was not specified in the content class package. ' .
324                                   'This property is exported and imported since eZ Publish 4.0.2', __METHOD__ );
325         }
326
327         if ( $content->hasAttribute( 'always-available' ) )
328         {
329             $values['always_available'] = ( $content->getAttribute( 'always-available' ) === 'true' ? 1 : 0 );
330         }
331         else
332         {
333             eZDebug::writeNotice( 'The default object availability was not specified in the content class package. ' .
334                                   'This property is exported and imported since eZ Publish 4.0.2', __METHOD__ );
335         }
336
337         // create class
338         $class = eZContentClass::create( $userID,
339                                          $values );
340         $class->store();
341
342         $classID = $class->attribute( 'id' );
343
344         if ( !isset( $installData['classid_list'] ) )
345             $installData['classid_list'] = array();
346         if ( !isset( $installData['classid_map'] ) )
347             $installData['classid_map'] = array();
348         $installData['classid_list'][] = $class->attribute( 'id' );
349         $installData['classid_map'][$classID] = $class->attribute( 'id' );
350
351         // create class attributes
352         $classAttributeList = $classAttributesNode->getElementsByTagName( 'attribute' );
353         foreach ( $classAttributeList as $classAttributeNode )
354         {
355             $isNotSupported = strtolower( $classAttributeNode->getAttribute( 'unsupported' ) ) == 'true';
356             if ( $isNotSupported )
357                 continue;
358
359             $attributeDatatype = $classAttributeNode->getAttribute( 'datatype' );
360             $attributeIsRequired = strtolower( $classAttributeNode->getAttribute( 'required' ) ) == 'true';
361             $attributeIsSearchable = strtolower( $classAttributeNode->getAttribute( 'searchable' ) ) == 'true';
362             $attributeIsInformationCollector = strtolower( $classAttributeNode->getAttribute( 'information-collector' ) ) == 'true';
363             $attributeIsTranslatable = strtolower( $classAttributeNode->getAttribute( 'translatable' ) ) == 'true';
364             $attributeSerializedNameListNode = $classAttributeNode->getElementsByTagName( 'serialized-name-list' )->item( 0 );
365             $attributeSerializedNameListContent = $attributeSerializedNameListNode ? $attributeSerializedNameListNode->textContent : false;
366             $attributeSerializedNameList = new eZSerializedObjectNameList( $attributeSerializedNameListContent );
367             if ( $attributeSerializedNameList->isEmpty() )
368                 $attributeSerializedNameList->initFromString( $classAttributeNode->getElementsByTagName( 'name' )->item( 0 )->textContent ); // for backward compatibility( <= 3.8 )
369             $attributeSerializedNameList->validate( );
370             $attributeIdentifier = $classAttributeNode->getElementsByTagName( 'identifier' )->item( 0 )->textContent;
371             $attributePlacement = $classAttributeNode->getElementsByTagName( 'placement' )->item( 0 )->textContent;
372             $attributeDatatypeParameterNode = $classAttributeNode->getElementsByTagName( 'datatype-parameters' )->item( 0 );
373
374             $classAttribute = $class->fetchAttributeByIdentifier( $attributeIdentifier );
375             if ( !$classAttribute )
376             {
377                 $classAttribute = eZContentClassAttribute::create( $class->attribute( 'id' ),
378                                                                    $attributeDatatype,
379                                                                    array( 'version' => 0,
380                                                                           'identifier' => $attributeIdentifier,
381                                                                           'serialized_name_list' => $attributeSerializedNameList->serializeNames(),
382                                                                           'is_required' => $attributeIsRequired,
383                                                                           'is_searchable' => $attributeIsSearchable,
384                                                                           'is_information_collector' => $attributeIsInformationCollector,
385                                                                           'can_translate' => $attributeIsTranslatable,
386                                                                           'placement' => $attributePlacement ) );
387
388                 $dataType = $classAttribute->dataType();
389                 $classAttribute->store();
390                 $dataType->unserializeContentClassAttribute( $classAttribute, $classAttributeNode, $attributeDatatypeParameterNode );
391                 $classAttribute->sync();
392             }
393         }
394
395         // add class to a class group
396         $classGroupsList = $classGroupsNode->getElementsByTagName( 'group' );
397         foreach ( $classGroupsList as $classGroupNode )
398         {
399             $classGroupName = $classGroupNode->getAttribute( 'name' );
400             $classGroup = eZContentClassGroup::fetchByName( $classGroupName );
401             if ( !$classGroup )
402             {
403                 $classGroup = eZContentClassGroup::create();
404                 $classGroup->setAttribute( 'name', $classGroupName );
405                 $classGroup->store();
406             }
407             $classGroup->appendClass( $class );
408         }
409         return true;
410     }
411
412     function add( $packageType, $package, $cli, $parameters )
413     {
414         foreach ( $parameters['class-list'] as $classItem )
415         {
416             $classID = $classItem['id'];
417             $classIdentifier = $classItem['identifier'];
418             $classValue = $classItem['value'];
419             $cli->notice( "Adding class $classValue to package" );
420             $this->addClass( $package, $classID, $classIdentifier );
421         }
422     }
423
424     /*!
425      \static
426      Adds the content class with ID \a $classID to the package.
427      If \a $classIdentifier is \c false then it will be fetched from the class.
428     */
429     static function addClass( $package, $classID, $classIdentifier = false )
430     {
431         $class = false;
432         if ( is_numeric( $classID ) )
433             $class = eZContentClass::fetch( $classID );
434         if ( !$class )
435             return;
436         $classNode = eZContentClassPackageHandler::classDOMTree( $class );
437         if ( !$classNode )
438             return;
439         if ( !$classIdentifier )
440             $classIdentifier = $class->attribute( 'identifier' );
441         $package->appendInstall( 'ezcontentclass', false, false, true,
442                                  'class-' . $classIdentifier, 'ezcontentclass',
443                                  array( 'content' => $classNode ) );
444         $package->appendProvides( 'ezcontentclass', 'contentclass', $class->attribute( 'identifier' ) );
445         $package->appendInstall( 'ezcontentclass', false, false, false,
446                                  'class-' . $classIdentifier, 'ezcontentclass',
447                                  array( 'content' => false ) );
448     }
449
450     function handleAddParameters( $packageType, $package, $cli, $arguments )
451     {
452         return $this->handleParameters( $packageType, $package, $cli, 'add', $arguments );
453     }
454
455     /*!
456      \private
457     */
458     function handleParameters( $packageType, $package, $cli, $type, $arguments )
459     {
460         $classList = false;
461         foreach ( $arguments as $argument )
462         {
463             if ( $argument[0] == '-' )
464             {
465                 if ( strlen( $argument ) > 1 and
466                      $argument[1] == '-' )
467                 {
468                 }
469                 else
470                 {
471                 }
472             }
473             else
474             {
475                 if ( $classList === false )
476                 {
477                     $classList = array();
478                     $classArray = explode( ',', $argument );
479                     $error = false;
480                     foreach ( $classArray as $classID )
481                     {
482                         if ( in_array( $classID, $classList ) )
483                         {
484                             $cli->notice( "Content class $classID already in list" );
485                             continue;
486                         }
487                         if ( is_numeric( $classID ) )
488                         {
489                             if ( !eZContentClass::exists( $classID, 0, false, false ) )
490                             {
491                                 $cli->error( "Content class with ID $classID does not exist" );
492                                 $error = true;
493                             }
494                             else
495                             {
496                                 unset( $class );
497                                 $class = eZContentClass::fetch( $classID );
498                                 $classList[] = array( 'id' => $classID,
499                                                       'identifier' => $class->attribute( 'identifier' ),
500                                                       'value' => $classID );
501                             }
502                         }
503                         else
504                         {
505                             $realClassID = eZContentClass::exists( $classID, 0, false, true );
506                             if ( !$realClassID )
507                             {
508                                 $cli->error( "Content class with identifier $classID does not exist" );
509                                 $error = true;
510                             }
511                             else
512                             {
513                                 unset( $class );
514                                 $class = eZContentClass::fetch( $realClassID );
515                                 $classList[] = array( 'id' => $realClassID,
516                                                       'identifier' => $class->attribute( 'identifier' ),
517                                                       'value' => $classID );
518                             }
519                         }
520                     }
521                     if ( $error )
522                         return false;
523                 }
524             }
525         }
526         if ( $classList === false )
527         {
528             $cli->error( "No class ids chosen" );
529             return false;
530         }
531         return array( 'class-list' => $classList );
532     }
533
534     /*!
535      \static
536      Creates the DOM tree for the content class \a $class and returns the root node.
537     */
538     static function classDOMTree( $class )
539     {
540         if ( !$class )
541         {
542             $retValue = false;
543             return $retValue;
544         }
545
546         $dom = new DOMDocument( '1.0', 'utf-8' );
547         $classNode = $dom->createElement( 'content-class' );
548         $dom->appendChild( $classNode );
549         $serializedNameListNode = $dom->createElement( 'serialized-name-list' );
550         $serializedNameListNode->appendChild( $dom->createTextNode( $class->attribute( 'serialized_name_list' ) ) );
551         $classNode->appendChild( $serializedNameListNode );
552         $identifierNode = $dom->createElement( 'identifier' );
553         $identifierNode->appendChild( $dom->createTextNode( $class->attribute( 'identifier' ) ) );
554         $classNode->appendChild( $identifierNode );
555         $remoteIDNode = $dom->createElement( 'remote-id' );
556         $remoteIDNode->appendChild( $dom->createTextNode( $class->attribute( 'remote_id' ) ) );
557         $classNode->appendChild( $remoteIDNode );
558         $objectNamePatternNode = $dom->createElement( 'object-name-pattern' );
559         $objectNamePatternNode->appendChild( $dom->createTextNode( $class->attribute( 'contentobject_name' ) ) );
560         $classNode->appendChild( $objectNamePatternNode );
561         $urlAliasPatternNode = $dom->createElement( 'url-alias-pattern' );
562         $urlAliasPatternNode->appendChild( $dom->createTextNode( $class->attribute( 'url_alias_name' ) ) );
563         $classNode->appendChild( $urlAliasPatternNode );
564         $isContainer = $class->attribute( 'is_container' ) ? 'true' : 'false';
565         $classNode->setAttribute( 'is-container', $isContainer );
566         $classNode->setAttribute( 'always-available', $class->attribute( 'always_available' ) ? 'true' : 'false' );
567         $classNode->setAttribute( 'sort-field', eZContentObjectTreeNode::sortFieldName( $class->attribute( 'sort_field' ) ) );
568         $classNode->setAttribute( 'sort-order', $class->attribute( 'sort_order' ) );
569
570         // Remote data start
571         $remoteNode = $dom->createElement( 'remote' );
572         $classNode->appendChild( $remoteNode );
573
574         $ini = eZINI::instance();
575         $siteName = $ini->variable( 'SiteSettings', 'SiteURL' );
576
577         $classURL = 'http://' . $siteName . '/class/view/' . $class->attribute( 'id' );
578         $siteURL = 'http://' . $siteName . '/';
579
580         $siteUrlNode = $dom->createElement( 'site-url' );
581         $siteUrlNode->appendChild( $dom->createTextNode( $siteURL ) );
582         $remoteNode->appendChild( $siteUrlNode );
583
584         $urlNode = $dom->createElement( 'url' );
585         $urlNode->appendChild( $dom->createTextNode( $classURL ) );
586         $remoteNode->appendChild( $urlNode );
587
588         $classGroupsNode = $dom->createElement( 'groups' );
589
590         $classGroupList = eZContentClassClassGroup::fetchGroupList( $class->attribute( 'id' ),
591                                                                     $class->attribute( 'version' ) );
592         foreach ( $classGroupList as $classGroupLink )
593         {
594             $classGroup = eZContentClassGroup::fetch( $classGroupLink->attribute( 'group_id' ) );
595             if ( $classGroup )
596             {
597                 unset( $groupNode );
598                 $groupNode = $dom->createElement( 'group' );
599                 $groupNode->setAttribute( 'id', $classGroup->attribute( 'id' ) );
600                 $groupNode->setAttribute( 'name', $classGroup->attribute( 'name' ) );
601                 $classGroupsNode->appendChild( $groupNode );
602             }
603         }
604         $remoteNode->appendChild( $classGroupsNode );
605
606         $idNode = $dom->createElement( 'id' );
607         $idNode->appendChild( $dom->createTextNode( $class->attribute( 'id' ) ) );
608         $remoteNode->appendChild( $idNode );
609         $createdNode = $dom->createElement( 'created' );
610         $createdNode->appendChild( $dom->createTextNode( $class->attribute( 'created' ) ) );
611         $remoteNode->appendChild( $createdNode );
612         $modifiedNode = $dom->createElement( 'modified' );
613         $modifiedNode->appendChild( $dom->createTextNode( $class->attribute( 'modified' ) ) );
614         $remoteNode->appendChild( $modifiedNode );
615
616         $creatorNode = $dom->createElement( 'creator' );
617         $remoteNode->appendChild( $creatorNode );
618         $creatorIDNode = $dom->createElement( 'user-id' );
619         $creatorIDNode->appendChild( $dom->createTextNode( $class->attribute( 'creator_id' ) ) );
620         $creatorNode->appendChild( $creatorIDNode );
621         $creator = $class->attribute( 'creator' );
622         if ( $creator )
623         {
624             $creatorLoginNode = $dom->createElement( 'user-login' );
625             $creatorLoginNode->appendChild( $dom->createTextNode( $creator->attribute( 'login' ) ) );
626             $creatorNode->appendChild( $creatorLoginNode );
627         }
628
629         $modifierNode = $dom->createElement( 'modifier' );
630         $remoteNode->appendChild( $modifierNode );
631         $modifierIDNode = $dom->createElement( 'user-id' );
632         $modifierIDNode->appendChild( $dom->createTextNode( $class->attribute( 'modifier_id' ) ) );
633         $modifierNode->appendChild( $modifierIDNode );
634         $modifier = $class->attribute( 'modifier' );
635         if ( $modifier )
636         {
637             $modifierLoginNode = $dom->createElement( 'user-login' );
638             $modifierLoginNode->appendChild( $dom->createTextNode( $modifier->attribute( 'login' ) ) );
639             $modifierNode->appendChild( $modifierLoginNode );
640         }
641         // Remote data end
642
643         $attributesNode = $dom->createElementNS( 'http://ezpublish/contentclassattribute', 'ezcontentclass-attribute:attributes' );
644         $classNode->appendChild( $attributesNode );
645
646         $attributes = $class->fetchAttributes();
647         foreach( $attributes as $attribute )
648         {
649             $attributeNode = $dom->createElement( 'attribute' );
650             $attributeNode->setAttribute( 'datatype', $attribute->attribute( 'data_type_string' ) );
651             $required = $attribute->attribute( 'is_required' ) ? 'true' : 'false';
652             $attributeNode->setAttribute( 'required' , $required );
653             $searchable = $attribute->attribute( 'is_searchable' ) ? 'true' : 'false';
654             $attributeNode->setAttribute( 'searchable' , $searchable );
655             $informationCollector = $attribute->attribute( 'is_information_collector' ) ? 'true' : 'false';
656             $attributeNode->setAttribute( 'information-collector' , $informationCollector );
657             $translatable = $attribute->attribute( 'can_translate' ) ? 'true' : 'false';
658             $attributeNode->setAttribute( 'translatable' , $translatable );
659
660             $attributeRemoteNode = $dom->createElement( 'remote' );
661             $attributeNode->appendChild( $attributeRemoteNode );
662
663             $attributeIDNode = $dom->createElement( 'id' );
664             $attributeIDNode->appendChild( $dom->createTextNode( $attribute->attribute( 'id' ) ) );
665             $attributeRemoteNode->appendChild( $attributeIDNode );
666
667             $attributeSerializedNameListNode = $dom->createElement( 'serialized-name-list' );
668             $attributeSerializedNameListNode->appendChild( $dom->createTextNode( $attribute->attribute( 'serialized_name_list' ) ) );
669             $attributeNode->appendChild( $attributeSerializedNameListNode );
670
671             $attributeIdentifierNode = $dom->createElement( 'identifier' );
672             $attributeIdentifierNode->appendChild( $dom->createTextNode( $attribute->attribute( 'identifier' ) ) );
673             $attributeNode->appendChild( $attributeIdentifierNode );
674
675             $attributePlacementNode = $dom->createElement( 'placement' );
676             $attributePlacementNode->appendChild( $dom->createTextNode( $attribute->attribute( 'placement' ) ) );
677             $attributeNode->appendChild( $attributePlacementNode );
678
679             $attributeParametersNode = $dom->createElement( 'datatype-parameters' );
680             $attributeNode->appendChild( $attributeParametersNode );
681
682             $dataType = $attribute->dataType();
683             if ( is_object( $dataType ) )
684             {
685                 $dataType->serializeContentClassAttribute( $attribute, $attributeNode, $attributeParametersNode );
686             }
687
688             $attributesNode->appendChild( $attributeNode );
689         }
690         eZDebug::writeDebug( $dom->saveXML(), 'content class package XML' );
691         return $classNode;
692     }
693
694     function contentclassDirectory()
695     {
696         return 'ezcontentclass';
697     }
698 }
699
700 ?>