Merged revisions 18893-18894,18897-18900,18903-18907,18909-18910,18912,18914-18916...
[tinyz:tinyz.git] / kernel / class / edit.php
1 <?php
2 //
3 // Created on: <16-Apr-2002 11:00:12 amos>
4 //
5 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
6 // SOFTWARE NAME: eZ publish
7 // SOFTWARE RELEASE: 3.10.x
8 // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS
9 // SOFTWARE LICENSE: GNU General Public License v2.0
10 // NOTICE: >
11 //   This program is free software; you can redistribute it and/or
12 //   modify it under the terms of version 2.0  of the GNU General
13 //   Public License as published by the Free Software Foundation.
14 //
15 //   This program is distributed in the hope that it will be useful,
16 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 //   GNU General Public License for more details.
19 //
20 //   You should have received a copy of version 2.0 of the GNU General
21 //   Public License along with this program; if not, write to the Free
22 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 //   MA 02110-1301, USA.
24 //
25 //
26 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
27 //
28
29 include_once( 'kernel/classes/ezcontentclass.php' );
30 include_once( 'kernel/classes/ezcontentclassattribute.php' );
31 include_once( 'kernel/classes/ezcontentclassclassgroup.php' );
32 include_once( 'lib/ezutils/classes/ezhttptool.php' );
33 include_once( 'lib/ezutils/classes/ezhttppersistence.php' );
34
35
36 $Module =& $Params['Module'];
37 $ClassID = $Params['ClassID'];
38 $GroupID = $Params['GroupID'];
39 $GroupName = $Params['GroupName'];
40 $EditLanguage = $Params['Language'];
41 $FromLanguage = false;
42 $ClassVersion = null;
43
44 switch ( $Params['FunctionName'] )
45 {
46     case 'edit':
47     {
48     } break;
49     default:
50     {
51         eZDebug::writeError( 'Undefined function: ' . $params['Function'] );
52         $Module->setExitStatus( EZ_MODULE_STATUS_FAILED );
53         return;
54     };
55 }
56
57 $http = eZHTTPTool::instance();
58 if ( $http->hasPostVariable( 'CancelConflictButton' ) )
59 {
60     $Module->redirectToView( 'grouplist' );
61 }
62
63 if ( $http->hasPostVariable( 'EditLanguage' ) )
64 {
65     $EditLanguage = $http->postVariable( 'EditLanguage' );
66 }
67
68 if ( is_numeric( $ClassID ) )
69 {
70     $class = eZContentClass::fetch( $ClassID, true, EZ_CLASS_VERSION_STATUS_TEMPORARY );
71
72     // If temporary version does not exist fetch the current and add temperory class to corresponding group
73     if ( !is_object( $class ) or $class->attribute( 'id' ) == null )
74     {
75         $class = eZContentClass::fetch( $ClassID, true, EZ_CLASS_VERSION_STATUS_DEFINED );
76         if( is_null( $class ) ) // Class does not exist
77         {
78             return $Module->handleError( EZ_ERROR_KERNEL_NOT_AVAILABLE, 'kernel' );
79         }
80         $classGroups= eZContentClassClassGroup::fetchGroupList( $ClassID, EZ_CLASS_VERSION_STATUS_DEFINED );
81         foreach ( $classGroups as $classGroup )
82         {
83             $groupID = $classGroup->attribute( 'group_id' );
84             $groupName = $classGroup->attribute( 'group_name' );
85             $ingroup = eZContentClassClassGroup::create( $ClassID, EZ_CLASS_VERSION_STATUS_TEMPORARY, $groupID, $groupName );
86             $ingroup->store();
87         }
88     }
89     else
90     {
91         include_once( 'lib/ezlocale/classes/ezdatetime.php' );
92         $user = eZUser::currentUser();
93         $contentIni = eZINI::instance( 'content.ini' );
94         $timeOut = $contentIni->variable( 'ClassSettings', 'DraftTimeout' );
95
96         if ( $class->attribute( 'modifier_id' ) != $user->attribute( 'contentobject_id' ) &&
97              $class->attribute( 'modified' ) + $timeOut > time() )
98         {
99             include_once( 'kernel/common/template.php' );
100             $tpl =& templateInit();
101
102             $res = eZTemplateDesignResource::instance();
103             $res->setKeys( array( array( 'class', $class->attribute( 'id' ) ) ) ); // Class ID
104             $tpl->setVariable( 'class', $class );
105             $tpl->setVariable( 'lock_timeout', $timeOut );
106
107             $Result = array();
108             $Result['content'] = $tpl->fetch( 'design:class/edit_denied.tpl' );
109             $Result['path'] = array( array( 'url' => '/class/grouplist/',
110                                             'text' => ezi18n( 'kernel/class', 'Class list' ) ) );
111             return $Result;
112         }
113     }
114 }
115 else
116 {
117     include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
118
119     if ( !$EditLanguage )
120     {
121         $language = eZContentLanguage::topPriorityLanguage();
122         if ( $language )
123         {
124             $EditLanguage = $language->attribute( 'locale' );
125         }
126         else
127         {
128             eZDebug::writeError( 'Undefined default language', 'class/edit.php' );
129             $Module->setExitStatus( EZ_MODULE_STATUS_FAILED );
130             return;
131         }
132     }
133
134     if ( is_numeric( $GroupID ) and is_string( $GroupName ) and $GroupName != '' )
135     {
136         $user =& eZUser::currentUser();
137         $user_id = $user->attribute( 'contentobject_id' );
138         $class = eZContentClass::create( $user_id, array(), $EditLanguage );
139         $class->setName( ezi18n( 'kernel/class/edit', 'New Class' ), $EditLanguage );
140         $class->store();
141         $editLanguageID = eZContentLanguage::idByLocale( $EditLanguage );
142         $class->setAlwaysAvailableLanguageID( $editLanguageID );
143         $ClassID = $class->attribute( 'id' );
144         $ClassVersion = $class->attribute( 'version' );
145         $ingroup = eZContentClassClassGroup::create( $ClassID, $ClassVersion, $GroupID, $GroupName );
146         $ingroup->store();
147         $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID . '/(language)/' . $EditLanguage );
148         return;
149     }
150     else
151     {
152         $errorResponseGroupName = ( $GroupName == '' ) ? '<Empty name>' : $GroupName;
153         $errorResponseGroupID = ( !is_numeric( $GroupID ) ) ? '<Empty ID>' : $GroupID;
154         eZDebug::writeError( "Unknown class group: {$errorResponseGroupName} (ID: {$errorResponseGroupID})", 'Kernel - Class - Edit' );
155         $Module->setExitStatus( EZ_MODULE_STATUS_FAILED );
156         return $Module->handleError( EZ_ERROR_KERNEL_NOT_AVAILABLE, 'kernel' );
157     }
158 }
159
160
161 $contentClassHasInput = true;
162 if ( $http->hasPostVariable( 'ContentClassHasInput' ) )
163     $contentClassHasInput = $http->postVariable( 'ContentClassHasInput' );
164
165 // Find out the group where class is created or edited from.
166 if ( $http->hasSessionVariable( 'FromGroupID' ) )
167 {
168     $fromGroupID = $http->sessionVariable( 'FromGroupID' );
169 }
170 else
171 {
172     $fromGroupID = false;
173 }
174 $ClassID = $class->attribute( 'id' );
175 $ClassVersion = $class->attribute( 'version' );
176
177 $validation = array( 'processed' => false,
178                      'groups' => array(),
179                      'attributes' => array(),
180                      'class_errors' => array() );
181 $unvalidatedAttributes = array();
182
183 if ( $http->hasPostVariable( 'DiscardButton' ) )
184 {
185     eZSessionDestroy( $http->sessionVariable( 'CanStoreTicket' ) );
186     $http->removeSessionVariable( 'CanStoreTicket' );
187     $class->setVersion( EZ_CLASS_VERSION_STATUS_TEMPORARY );
188     $class->remove( true, EZ_CLASS_VERSION_STATUS_TEMPORARY );
189     eZContentClassClassGroup::removeClassMembers( $ClassID, EZ_CLASS_VERSION_STATUS_TEMPORARY );
190     if ( $fromGroupID === false )
191     {
192         $Module->redirectToView( 'grouplist' );
193     }
194     else
195     {
196         $Module->redirectTo( $Module->functionURI( 'classlist' ) . '/' . $fromGroupID . '/' );
197     }
198     return;
199 }
200 if ( $http->hasPostVariable( 'AddGroupButton' ) && $http->hasPostVariable( 'ContentClass_group' ) )
201 {
202     include_once( "kernel/class/ezclassfunctions.php" );
203     eZClassFunctions::addGroup( $ClassID, $ClassVersion, $http->postVariable( 'ContentClass_group' ) );
204 }
205 if ( $http->hasPostVariable( 'RemoveGroupButton' ) && $http->hasPostVariable( 'group_id_checked' ) )
206 {
207     include_once( "kernel/class/ezclassfunctions.php" );
208     if ( !eZClassFunctions::removeGroup( $ClassID, $ClassVersion, $http->postVariable( 'group_id_checked' ) ) )
209     {
210         $validation['groups'][] = array( 'text' => ezi18n( 'kernel/class', 'You have to have at least one group that the class belongs to!' ) );
211         $validation['processed'] = true;
212     }
213 }
214
215 // Fetch attributes and definitions
216 $attributes = $class->fetchAttributes();
217
218 if ( $http->hasPostVariable( 'SelectLanguageButton' ) && $http->hasPostVariable( 'EditLanguage' ) )
219 {
220     $EditLanguage = $http->postVariable( 'EditLanguage' );
221
222     $FromLanguage = 'None';
223     if ( $http->hasPostVariable( 'FromLanguage' ) )
224         $FromLanguage = $http->postVariable( 'FromLanguage' );
225
226     foreach ( array_keys( $attributes ) as $key )
227     {
228         $name = '';
229         if ( $FromLanguage != 'None' )
230         {
231             $name = $attributes[$key]->name( $FromLanguage );
232         }
233         $attributes[$key]->setName( $name, $EditLanguage );
234     }
235
236     $name = '';
237     if ( $FromLanguage != 'None' )
238     {
239         $name = $class->name( $FromLanguage );
240     }
241
242     $class->setName( $name, $EditLanguage );
243 }
244
245 // No language was specified in the URL, we need to figure out
246 // the language to use.
247 if ( !$EditLanguage )
248 {
249     // Check number of languages
250     include_once( 'kernel/classes/ezcontentlanguage.php' );
251     $languages = eZContentLanguage::fetchList();
252     // If there is only one language we choose it for the user.
253     if ( count( $languages ) == 1 )
254     {
255         $language = array_shift( $languages );
256         $EditLanguage = $language->attribute( 'locale' );
257     }
258     else
259     {
260         $canCreateLanguages = $class->attribute( 'can_create_languages' );
261         if ( count( $canCreateLanguages ) == 0)
262         {
263             $EditLanguage = $class->attribute( 'top_priority_language_locale' );
264         }
265         else
266         {
267             include_once( 'kernel/common/template.php' );
268
269             $tpl =& templateInit();
270
271             $res = eZTemplateDesignResource::instance();
272             $res->setKeys( array( array( 'class', $class->attribute( 'id' ) ) ) ); // Class ID
273
274             $tpl->setVariable( 'module', $Module );
275             $tpl->setVariable( 'class', $class );
276
277             $Result = array();
278             $Result['content'] = $tpl->fetch( 'design:class/select_language.tpl' );
279             $Result['path'] = array( array( 'url' => '/class/edit/',
280                                             'text' => ezi18n( 'kernel/class', 'Class edit' ) ) );
281             return $Result;
282         }
283     }
284 }
285
286 include_once( 'kernel/classes/ezdatatype.php' );
287 eZDataType::loadAndRegisterAllTypes();
288 $datatypes = eZDataType::registeredDataTypes();
289
290 $customAction = false;
291 $customActionAttributeID = null;
292 // Check for custom actions
293 if ( $http->hasPostVariable( 'CustomActionButton' ) )
294 {
295     $customActionArray = $http->postVariable( 'CustomActionButton' );
296     $customActionString = key( $customActionArray );
297
298     $customActionAttributeID = preg_match( "#^([0-9]+)_(.*)$#", $customActionString, $matchArray );
299
300     $customActionAttributeID = $matchArray[1];
301     $customAction = $matchArray[2];
302 }
303
304
305 // Validate input
306 $storeActions = array( 'MoveUp',
307                        'MoveDown',
308                        'StoreButton',
309                        'ApplyButton',
310                        'NewButton',
311                        'CustomActionButton');
312 $validationRequired = false;
313 foreach( $storeActions as $storeAction )
314 {
315     if ( $http->hasPostVariable( $storeAction ) )
316     {
317         $validationRequired = true;
318         break;
319     }
320 }
321
322 include_once( 'lib/ezutils/classes/ezinputvalidator.php' );
323 $canStore = true;
324 $requireFixup = false;
325 if ( $contentClassHasInput )
326 {
327     if ( $validationRequired )
328     {
329         foreach ( array_keys( $attributes ) as $key )
330         {
331             $attribute =& $attributes[$key];
332             $dataType = $attribute->dataType();
333             $status = $dataType->validateClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
334             if ( $status == EZ_INPUT_VALIDATOR_STATE_INTERMEDIATE )
335                 $requireFixup = true;
336             else if ( $status == EZ_INPUT_VALIDATOR_STATE_INVALID )
337             {
338                 $canStore = false;
339                 $attributeName = $dataType->attribute( 'information' );
340                 $attributeName = $attributeName['name'];
341                 $unvalidatedAttributes[] = array( 'id' => $attribute->attribute( 'id' ),
342                                                   'identifier' => $attribute->attribute( 'identifier' ) ? $attribute->attribute( 'identifier' ) : $attribute->attribute( 'name' ),
343                                                   'name' => $attributeName );
344             }
345         }
346         $validation['processed'] = true;
347         $validation['attributes'] = $unvalidatedAttributes;
348         $requireVariable = 'ContentAttribute_is_required_checked';
349         $searchableVariable = 'ContentAttribute_is_searchable_checked';
350         $informationCollectorVariable = 'ContentAttribute_is_information_collector_checked';
351         $canTranslateVariable = 'ContentAttribute_can_translate_checked';
352         $requireCheckedArray = array();
353         $searchableCheckedArray = array();
354         $informationCollectorCheckedArray = array();
355         $canTranslateCheckedArray = array();
356         if ( $http->hasPostVariable( $requireVariable ) )
357             $requireCheckedArray = $http->postVariable( $requireVariable );
358         if ( $http->hasPostVariable( $searchableVariable ) )
359             $searchableCheckedArray = $http->postVariable( $searchableVariable );
360         if ( $http->hasPostVariable( $informationCollectorVariable ) )
361             $informationCollectorCheckedArray = $http->postVariable( $informationCollectorVariable );
362         if ( $http->hasPostVariable( $canTranslateVariable ) )
363             $canTranslateCheckedArray = $http->postVariable( $canTranslateVariable );
364
365         if ( $http->hasPostVariable( 'ContentAttribute_priority' ) )
366             $placementArray = $http->postVariable( 'ContentAttribute_priority' );
367
368         foreach ( array_keys( $attributes ) as $key )
369         {
370             $attribute =& $attributes[$key];
371             $attributeID = $attribute->attribute( 'id' );
372             $attribute->setAttribute( 'is_required', in_array( $attributeID, $requireCheckedArray ) );
373             $attribute->setAttribute( 'is_searchable', in_array( $attributeID, $searchableCheckedArray ) );
374             $attribute->setAttribute( 'is_information_collector', in_array( $attributeID, $informationCollectorCheckedArray ) );
375             // Set can_translate to 0 if user has clicked Disable translation in GUI
376             $attribute->setAttribute( 'can_translate', !in_array( $attributeID, $canTranslateCheckedArray ) );
377
378             $placement = (int) $placementArray[$key];
379             if ( $attribute->attribute( 'placement' ) != $placement )
380                 $attribute->setAttribute( 'placement', $placement );
381         }
382     }
383 }
384
385 // Fixup input
386 if ( $requireFixup )
387 {
388     foreach( array_keys( $attributes ) as $key )
389     {
390         $attribute =& $attributes[$key];
391         $dataType = $attribute->dataType();
392         $status = $dataType->fixupClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
393     }
394 }
395
396 $cur_datatype = 'ezstring';
397 // Apply HTTP POST variables
398 if ( $contentClassHasInput )
399 {
400     eZHTTPPersistence::fetch( 'ContentAttribute', eZContentClassAttribute::definition(), $attributes, $http, true );
401     if ( $http->hasPostVariable( 'ContentAttribute_name' ) )
402     {
403         $attributeNames = $http->postVariable( 'ContentAttribute_name' );
404         foreach( array_keys( $attributes ) as $key )
405         {
406             if ( isset( $attributeNames[$key] ) )
407             {
408                 $attributes[$key]->setName( $attributeNames[$key], $EditLanguage );
409             }
410         }
411     }
412
413     eZHTTPPersistence::fetch( 'ContentClass', eZContentClass::definition(), $class, $http, false );
414     if ( $http->hasPostVariable( 'ContentClass_name' ) )
415     {
416         $class->setName( $http->postVariable( 'ContentClass_name' ), $EditLanguage );
417     }
418
419     if ( $http->hasVariable( 'ContentClass_is_container_exists' ) )
420     {
421         if ( $http->hasVariable( 'ContentClass_is_container_checked' ) )
422         {
423             $class->setAttribute( "is_container", 1 );
424         }
425         else
426         {
427             $class->setAttribute( "is_container", 0 );
428         }
429     }
430
431     if ( $http->hasVariable( 'ContentClass_always_available_exists' ) )
432     {
433         if ( $http->hasVariable( 'ContentClass_always_available' ) )
434         {
435             $class->setAttribute( 'always_available', 1 );
436         }
437         else
438         {
439             $class->setAttribute( 'always_available', 0 );
440         }
441     }
442
443     if ( $http->hasVariable( 'ContentClass_default_sorting_exists' ) )
444     {
445         if ( $http->hasVariable( 'ContentClass_default_sorting_field' ) )
446         {
447             $sortingField = $http->variable( 'ContentClass_default_sorting_field' );
448             $class->setAttribute( 'sort_field', $sortingField );
449         }
450         if ( $http->hasVariable( 'ContentClass_default_sorting_order' ) )
451         {
452             $sortingOrder = $http->variable( 'ContentClass_default_sorting_order' );
453             $class->setAttribute( 'sort_order', $sortingOrder );
454         }
455     }
456
457     if ( $http->hasPostVariable( 'DataTypeString' ) )
458         $cur_datatype = $http->postVariable( 'DataTypeString' );
459 }
460
461 $class->setAttribute( 'version', EZ_CLASS_VERSION_STATUS_TEMPORARY );
462 $class->NameList->setHasDirtyData();
463
464 include_once( 'lib/ezi18n/classes/ezchartransform.php' );
465 $trans = eZCharTransform::instance();
466
467 // Fixed identifiers to only contain a-z0-9_
468 foreach( array_keys( $attributes ) as $key )
469 {
470     $attribute =& $attributes[$key];
471     $attribute->setAttribute( 'version', EZ_CLASS_VERSION_STATUS_TEMPORARY );
472     $identifier = $attribute->attribute( 'identifier' );
473     if ( $identifier == '' )
474         $identifier = $attribute->attribute( 'name' );
475
476     $identifier = $trans->transformByGroup( $identifier, 'identifier' );
477     $attribute->setAttribute( 'identifier', $identifier );
478     if ( $dataType = $attribute->dataType() )
479     {
480         $dataType->initializeClassAttribute( $attribute );
481     }
482 }
483
484 // Fixed class identifier to only contain a-z0-9_
485 $identifier = $class->attribute( 'identifier' );
486 if ( $identifier == '' )
487     $identifier = $class->attribute( 'name' );
488 $identifier = $trans->transformByGroup( $identifier, 'identifier' );
489 $class->setAttribute( 'identifier', $identifier );
490
491 // Run custom actions if any
492 if ( $customAction )
493 {
494     foreach( array_keys( $attributes ) as $key )
495     {
496         $attribute =& $attributes[$key];
497         if ( $customActionAttributeID == $attribute->attribute( 'id' ) )
498         {
499             $attribute->customHTTPAction( $Module, $http, $customAction );
500         }
501     }
502 }
503 // Set new modification date
504 $date_time = time();
505 $class->setAttribute( 'modified', $date_time );
506 include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
507 $user = eZUser::currentUser();
508 $user_id = $user->attribute( 'contentobject_id' );
509 $class->setAttribute( 'modifier_id', $user_id );
510
511 // Remove attributes which are to be deleted
512 if ( $http->hasPostVariable( 'RemoveButton' ) )
513 {
514     $validation['processed'] = true;
515     if ( eZHttpPersistence::splitSelected( 'ContentAttribute', $attributes,
516                                            $http, 'id',
517                                            $keepers, $rejects ) )
518     {
519         $attributes = $keepers;
520         foreach ( $rejects as $reject )
521         {
522             if ( !$reject->remove( true ) )
523             {
524                 $dataType = $reject->dataType();
525                 $removeInfo = $dataType->classAttributeRemovableInformation( $reject );
526                 if ( $removeInfo !== false )
527                 {
528                     $validation['attributes'] = array( array( 'id' => $reject->attribute( 'id' ),
529                                                               'identifier' => $reject->attribute( 'identifier' ),
530                                                               'reason' => $removeInfo ) );
531                 }
532             }
533         }
534     }
535 }
536
537 // Fetch HTTP input
538 $datatypeValidation = array();
539 if ( $contentClassHasInput )
540 {
541     foreach( array_keys( $attributes ) as $key )
542     {
543         $attribute =& $attributes[$key];
544         if ( $dataType = $attribute->dataType() )
545         {
546             $dataType->fetchClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
547         }
548         else
549         {
550             $datatypeValidation['processed'] = 1;
551             $datatypeValidation['attributes'][] =
552                 array( 'reason' => array( 'text' => ezi18n( 'kernel/class', 'Could not load datatype: ' ).
553                                            $attribute->attribute( 'data_type_string' )."\n".
554                                            ezi18n( 'kernel/class', 'Editing this content class may cause data corruption in your system.' ).'<br>'.
555                                            ezi18n( 'kernel/class', 'Press "Cancel" to safely exit this operation.').'<br>'.
556                                            ezi18n( 'kernel/class', 'Please contact your eZ publish administrator to solve this problem.').'<br>' ),
557                        'item' => $attribute->attribute( 'data_type_string' ),
558                        'identifier' => $attribute->attribute( 'data_type_string' ),
559                        'id' => $key );
560         }
561     }
562 }
563
564 if ( $validationRequired )
565 {
566     // check for duplicate attribute identifiers in the input
567     if ( count( $attributes ) > 1 )
568     {
569         for( $attrIndex = 0; $attrIndex < count( $attributes ) - 1; $attrIndex++ )
570         {
571             $classAttribute = $attributes[$attrIndex];
572             $identifier = $classAttribute->attribute( 'identifier' );
573             $placement = $classAttribute->attribute( 'placement' );
574             for ( $attrIndex2 = $attrIndex + 1; $attrIndex2 < count( $attributes ); $attrIndex2++ )
575             {
576                 $classAttribute2 = $attributes[$attrIndex2];
577                 $identifier2 = $classAttribute2->attribute( 'identifier' );
578                 $placement2 = $classAttribute2->attribute( 'placement' );
579                 if (  $placement ==  $placement2 )
580                 {
581                     $validation['attributes'][] = array( 'identifier' => $identifier2,
582                                                          'name' => $classAttribute2->attribute( 'name' ),
583                                                          'id' => $classAttribute2->attribute( 'id' ),
584                                                          'reason' => array ( 'text' => ezi18n( 'kernel/class', 'duplicate attribute placement' ) ) );
585                     $canStore = false;
586                     break;
587                 }
588
589                 if ( $identifier == $identifier2 )
590                 {
591                     $validation['attributes'][] = array( 'identifier' => $identifier,
592                                                          'name' => $classAttribute->attribute( 'name' ),
593                                                          'id' => $classAttribute->attribute( 'id' ),
594                                                          'reason' => array ( 'text' => ezi18n( 'kernel/class', 'duplicate attribute identifier' ) ) );
595                     $canStore = false;
596                     break;
597                 }
598             }
599         }
600     }
601 }
602
603 // Store version 0 and discard version 1
604 if ( $http->hasPostVariable( 'StoreButton' ) && $canStore )
605 {
606
607     $id = $class->attribute( 'id' );
608     $oldClassAttributes = $class->fetchAttributes( $id, true, EZ_CLASS_VERSION_STATUS_DEFINED );
609     $newClassAttributes = $class->fetchAttributes( );
610
611     // validate class name and identifier; check presence of class attributes
612     // FIXME: object pattern name is never validated
613
614     $basicClassPropertiesValid = true;
615     {
616         $className       =& $class->attribute( 'name' );
617         $classIdentifier =& $class->attribute( 'identifier' );
618         $classID         =& $class->attribute( 'id' );
619
620         // validate class name
621         if( trim( $className ) == '' )
622         {
623             $validation['class_errors'][] = array( 'text' => ezi18n( 'kernel/class', 'The class should have nonempty \'Name\' attribute.' ) );
624             $basicClassPropertiesValid = false;
625         }
626
627         // check presence of attributes
628         $newClassAttributes = $class->fetchAttributes( );
629         if ( count( $newClassAttributes ) == 0 )
630         {
631             $validation['class_errors'][] = array( 'text' => ezi18n( 'kernel/class', 'The class should have at least one attribute.' ) );
632             $basicClassPropertiesValid = false;
633         }
634
635         // validate class identifier
636
637         $db = eZDB::instance();
638         $classCount = $db->arrayQuery( "SELECT COUNT(*) AS count FROM ezcontentclass WHERE  identifier='$classIdentifier' AND version=" . EZ_CLASS_VERSION_STATUS_DEFINED . " AND id <> $classID" );
639         if ( $classCount[0]['count'] > 0 )
640         {
641             $validation['class_errors'][] = array( 'text' => ezi18n( 'kernel/class', 'There is a class already having the same identifier.' ) );
642             $basicClassPropertiesValid = false;
643         }
644         unset( $classList );
645         unset( $db );
646     }
647
648     if ( !$basicClassPropertiesValid )
649     {
650         $canStore = false;
651         $validation['processed'] = false;
652     }
653     else
654     {
655         $firstStoreAttempt =& eZSessionRead( $http->sessionVariable( 'CanStoreTicket' ) );
656         if ( !$firstStoreAttempt )
657         {
658             return $Module->redirectToView( 'view', array( $ClassID ), array( 'Language' => $EditLanguage ) );
659         }
660         eZSessionDestroy( $http->sessionVariable( 'CanStoreTicket' ) );
661
662         // Class cleanup, update existing class objects according to new changes
663         include_once( 'kernel/classes/ezcontentobject.php' );
664
665         $db = eZDB::instance();
666         $db->begin();
667
668         $objects = null;
669         $objectCount = eZContentObject::fetchSameClassListCount( $ClassID );
670         if ( $objectCount > 0 )
671         {
672             // Delete object attributes which have been removed.
673             foreach ( $oldClassAttributes as $oldClassAttribute )
674             {
675                 $attributeExist = false;
676                 $oldClassAttributeID = $oldClassAttribute->attribute( 'id' );
677                 foreach ( $newClassAttributes as $newClassAttribute )
678                 {
679                     $newClassAttributeID = $newClassAttribute->attribute( 'id' );
680                     if ( $oldClassAttributeID == $newClassAttributeID )
681                         $attributeExist = true;
682                 }
683                 if ( !$attributeExist )
684                 {
685                     $objectAttributes = eZContentObjectAttribute::fetchSameClassAttributeIDList( $oldClassAttributeID );
686                     foreach ( $objectAttributes as $objectAttribute )
687                     {
688                         $objectAttributeID = $objectAttribute->attribute( 'id' );
689                         $objectAttribute->remove( $objectAttributeID );
690                     }
691                 }
692             }
693             $class->storeDefined( $attributes );
694
695             // Add object attributes which have been added.
696             foreach ( $newClassAttributes as $newClassAttribute )
697             {
698                 $attributeExist = false;
699                 $newClassAttributeID = $newClassAttribute->attribute( 'id' );
700                 foreach ( $oldClassAttributes as $oldClassAttribute )
701                 {
702                     $oldClassAttributeID = $oldClassAttribute->attribute( 'id' );
703                     if ( $oldClassAttributeID == $newClassAttributeID )
704                         $attributeExist = true;
705                 }
706                 if ( !$attributeExist )
707                 {
708                     if ( $objects == null )
709                     {
710                         $objects = eZContentObject::fetchSameClassList( $ClassID );
711                     }
712                     foreach ( $objects as $object )
713                     {
714                         $contentobjectID = $object->attribute( 'id' );
715                         $objectVersions =& $object->versions();
716                         foreach ( $objectVersions as $objectVersion )
717                         {
718                             $translations = $objectVersion->translations( false );
719                             $version = $objectVersion->attribute( 'version' );
720                             foreach ( $translations as $translation )
721                             {
722                                 $objectAttribute = eZContentObjectAttribute::create( $newClassAttributeID, $contentobjectID, $version, $translation );
723                                 $objectAttribute->setAttribute( 'language_code', $translation );
724                                 $objectAttribute->initialize();
725                                 $objectAttribute->store();
726                                 $objectAttribute->postInitialize();
727                             }
728                         }
729                     }
730                 }
731             }
732         }
733         else
734         {
735             $class->storeDefined( $attributes );
736         }
737
738         $db->commit();
739
740         $http->removeSessionVariable( 'CanStoreTicket' );
741         return $Module->redirectToView( 'view', array( $ClassID ), array( 'Language' => $EditLanguage ) );
742     }
743 }
744
745 // Store changes
746 if ( $canStore )
747     $class->store( $attributes );
748
749 if ( $http->hasPostVariable( 'NewButton' ) )
750 {
751     $new_attribute = eZContentClassAttribute::create( $ClassID, $cur_datatype, array(), $EditLanguage );
752     $attrcnt = count( $attributes ) + 1;
753     $new_attribute->setName( ezi18n( 'kernel/class/edit', 'new attribute' ) . $attrcnt, $EditLanguage );
754     $dataType = $new_attribute->dataType();
755     $dataType->initializeClassAttribute( $new_attribute );
756     $new_attribute->store();
757     $attributes[] =& $new_attribute;
758 }
759 else if ( $http->hasPostVariable( 'MoveUp' ) )
760 {
761     $attribute = eZContentClassAttribute::fetch( $http->postVariable( 'MoveUp' ), true, EZ_CLASS_VERSION_STATUS_TEMPORARY,
762                                                   array( 'contentclass_id', 'version', 'placement' ) );
763     $attribute->move( false );
764     $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID . '/(language)/' . $EditLanguage );
765     return;
766 }
767 else if ( $http->hasPostVariable( 'MoveDown' ) )
768 {
769     $attribute = eZContentClassAttribute::fetch( $http->postVariable( 'MoveDown' ), true, EZ_CLASS_VERSION_STATUS_TEMPORARY,
770                                                   array( 'contentclass_id', 'version', 'placement' ) );
771     $attribute->move( true );
772     $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID . '/(language)/' . $EditLanguage );
773     return;
774 }
775
776 $Module->setTitle( 'Edit class ' . $class->attribute( 'name' ) );
777 if ( !$http->hasSessionVariable( 'CanStoreTicket' ) )
778 {
779     $http->setSessionVariable( 'CanStoreTicket', md5( (string)rand() ) );
780     eZSessionWrite( $http->sessionVariable( 'CanStoreTicket' ), 1 );
781 }
782
783 // Fetch updated attributes
784 $attributes = $class->fetchAttributes();
785 $validation = array_merge( $validation, $datatypeValidation );
786
787 // Template handling
788 include_once( 'kernel/common/template.php' );
789 $tpl =& templateInit();
790 $res = eZTemplateDesignResource::instance();
791 $res->setKeys( array( array( 'class', $class->attribute( 'id' ) ) ) ); // Class ID
792 $tpl->setVariable( 'http', $http );
793 $tpl->setVariable( 'validation', $validation );
794 $tpl->setVariable( 'can_store', $canStore );
795 $tpl->setVariable( 'require_fixup', $requireFixup );
796 $tpl->setVariable( 'module', $Module );
797 $tpl->setVariable( 'class', $class );
798 $tpl->setVariable( 'attributes', $attributes );
799 $tpl->setVariable( 'datatypes', $datatypes );
800 $tpl->setVariable( 'datatype', $cur_datatype );
801 $tpl->setVariable( 'language_code', $EditLanguage );
802
803 $Result = array();
804 $Result['content'] = $tpl->fetch( 'design:class/edit.tpl' );
805 $Result['path'] = array( array( 'url' => '/class/edit/',
806                                 'text' => ezi18n( 'kernel/class', 'Class edit' ) ) );
807
808 ?>