- Fixed typo.
[tinyz:tinyz.git] / kernel / class / edit.php
1 <?php
2 //
3 // Created on: <16-Apr-2002 11:00:12 amos>
4 //
5 // Copyright (C) 1999-2004 eZ systems as. All rights reserved.
6 //
7 // This source file is part of the eZ publish (tm) Open Source Content
8 // Management System.
9 //
10 // This file may be distributed and/or modified under the terms of the
11 // "GNU General Public License" version 2 as published by the Free
12 // Software Foundation and appearing in the file LICENSE included in
13 // the packaging of this file.
14 //
15 // Licencees holding a valid "eZ publish professional licence" version 2
16 // may use this file in accordance with the "eZ publish professional licence"
17 // version 2 Agreement provided with the Software.
18 //
19 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
20 // THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 // PURPOSE.
22 //
23 // The "eZ publish professional licence" version 2 is available at
24 // http://ez.no/ez_publish/licences/professional/ and in the file
25 // PROFESSIONAL_LICENCE included in the packaging of this file.
26 // For pricing of this licence please contact us via e-mail to licence@ez.no.
27 // Further contact information is available at http://ez.no/company/contact/.
28 //
29 // The "GNU General Public License" (GPL) is available at
30 // http://www.gnu.org/copyleft/gpl.html.
31 //
32 // Contact licence@ez.no if any conditions of this licencing isn't clear to
33 // you.
34 //
35
36 include_once( 'kernel/classes/ezcontentclass.php' );
37 include_once( 'kernel/classes/ezcontentclassattribute.php' );
38 include_once( 'kernel/classes/ezcontentclassclassgroup.php' );
39 include_once( 'lib/ezutils/classes/ezhttptool.php' );
40 include_once( 'lib/ezutils/classes/ezhttppersistence.php' );
41
42
43 $Module =& $Params['Module'];
44 $ClassID = null;
45 if ( isset( $Params['ClassID'] ) )
46     $ClassID = $Params['ClassID'];
47 $GroupID = null;
48 if ( isset( $Params['GroupID'] ) )
49     $GroupID = $Params['GroupID'];
50 $GroupName = null;
51 if ( isset( $Params['GroupName'] ) )
52     $GroupName = $Params['GroupName'];
53 $ClassVersion = null;
54
55 switch ( $Params['FunctionName'] )
56 {
57     case 'edit':
58     {
59     } break;
60     default:
61     {
62         eZDebug::writeError( 'Undefined function: ' . $params['Function'] );
63         $Module->setExitStatus( EZ_MODULE_STATUS_FAILED );
64         return;
65     };
66 }
67 if ( is_numeric( $ClassID ) )
68 {
69     $class =& eZContentClass::fetch( $ClassID, true, EZ_CLASS_VERSION_STATUS_TEMPORARY );
70
71     // If temporary version does not exist fetch the current and add temperory class to corresponding group
72     if ( $class == null ||$class->attribute( 'id' ) == null )
73     {
74         $class =& eZContentClass::fetch( $ClassID, true, EZ_CLASS_VERSION_STATUS_DEFINED );
75         $classGroups=& eZContentClassClassGroup::fetchGroupList( $ClassID, EZ_CLASS_VERSION_STATUS_DEFINED );
76         foreach ( $classGroups as $classGroup )
77         {
78             $groupID = $classGroup->attribute( 'group_id' );
79             $groupName = $classGroup->attribute( 'group_name' );
80             $ingroup =& eZContentClassClassGroup::create( $ClassID, EZ_CLASS_VERSION_STATUS_TEMPORARY, $groupID, $groupName );
81             $ingroup->store();
82         }
83     }
84     else
85     {
86         include_once( 'lib/ezlocale/classes/ezdatetime.php' );
87         $user =& eZUser::currentUser();
88         $contentIni =& eZIni::instance( 'content.ini' );
89         $timeOut =& $contentIni->variable( 'ClassSettings', 'DraftTimeout' );
90
91         if ( $class->attribute( 'modifier_id' ) != $user->attribute( 'contentobject_id' ) &&
92              $class->attribute( 'modified' ) + $timeOut > time() )
93         {
94             include_once( 'kernel/common/template.php' );
95             $tpl =& templateInit();
96
97             $res =& eZTemplateDesignResource::instance();
98             $res->setKeys( array( array( 'class', $class->attribute( 'id' ) ) ) ); // Class ID
99             $tpl->setVariable( 'class', $class );
100             $tpl->setVariable( 'lock_timeout', $timeOut );
101
102             $Result = array();
103             $Result['content'] =& $tpl->fetch( 'design:class/edit_denied.tpl' );
104             $Result['path'] = array( array( 'url' => '/class/grouplist/',
105                                             'text' => ezi18n( 'kernel/class', 'Class list' ) ) );
106             return $Result;
107         }
108     }
109 }
110 else
111 {
112     include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
113     $user =& eZUser::currentUser();
114     $user_id = $user->attribute( 'contentobject_id' );
115     $class =& eZContentClass::create( $user_id );
116     $class->setAttribute( 'name', ezi18n( 'kernel/class/edit', 'New Class' ) );
117     $class->store();
118     $ClassID = $class->attribute( 'id' );
119     $ClassVersion = $class->attribute( 'version' );
120     $ingroup =& eZContentClassClassGroup::create( $ClassID, $ClassVersion, $GroupID, $GroupName );
121     $ingroup->store();
122     $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID );
123     return;
124 }
125
126 $http =& eZHttpTool::instance();
127 $contentClassHasInput = true;
128 if ( $http->hasPostVariable( 'ContentClassHasInput' ) )
129     $contentClassHasInput = $http->postVariable( 'ContentClassHasInput' );
130
131 // Find out the group where class is created or edited from.
132 if ( $http->hasSessionVariable( 'FromGroupID' ) )
133 {
134     $fromGroupID = $http->sessionVariable( 'FromGroupID' );
135 }
136 else
137 {
138     $fromGroupID = false;
139 }
140 $ClassID = $class->attribute( 'id' );
141 $ClassVersion = $class->attribute( 'version' );
142
143 $validation = array( 'processed' => false,
144                      'groups' => array(),
145                      'attributes' => array() );
146 $unvalidatedAttributes = array();
147
148 if ( $http->hasPostVariable( 'DiscardButton' ) )
149 {
150     eZSessionDestroy( $http->sessionVariable( 'CanStoreTicket' ) );
151     $http->removeSessionVariable( 'CanStoreTicket' );
152     $class->setVersion( EZ_CLASS_VERSION_STATUS_TEMPORARY );
153     $class->remove( true, $ClassVersion );
154     eZContentClassClassGroup::removeClassMembers( $ClassID, $ClassVersion );
155     if ( $fromGroupID === false )
156     {
157         $Module->redirectToView( 'grouplist' );
158     }
159     else
160     {
161         $Module->redirectTo( $Module->functionURI( 'classlist' ) . '/' . $fromGroupID . '/' );
162     }
163     return;
164 }
165 if ( $http->hasPostVariable( 'AddGroupButton' ) && $http->hasPostVariable( 'ContentClass_group' ) )
166 {
167     include_once( "kernel/class/ezclassfunctions.php" );
168     eZClassFunctions::addGroup( $ClassID, $ClassVersion, $http->postVariable( 'ContentClass_group' ) );
169 }
170 if ( $http->hasPostVariable( 'RemoveGroupButton' ) && $http->hasPostVariable( 'group_id_checked' ) )
171 {
172     include_once( "kernel/class/ezclassfunctions.php" );
173     if ( !eZClassFunctions::removeGroup( $ClassID, $ClassVersion, $http->postVariable( 'group_id_checked' ) ) )
174     {
175         $validation['groups'][] = array( 'text' => ezi18n( 'kernel/class', 'You have to have at least one group that the class belongs to!' ) );
176         $validation['processed'] = true;
177     }
178 }
179
180 // Fetch attributes and definitions
181 $attributes =& $class->fetchAttributes();
182
183 include_once( 'kernel/classes/ezdatatype.php' );
184 eZDataType::loadAndRegisterAllTypes();
185 $datatypes =& eZDataType::registeredDataTypes();
186
187 $customAction = false;
188 $customActionAttributeID = null;
189 // Check for custom actions
190 if ( $http->hasPostVariable( 'CustomActionButton' ) )
191 {
192     $customActionArray = $http->postVariable( 'CustomActionButton' );
193     $customActionString = key( $customActionArray );
194
195     $customActionAttributeID = preg_match( "#^([0-9]+)_(.*)$#", $customActionString, $matchArray );
196
197     $customActionAttributeID = $matchArray[1];
198     $customAction = $matchArray[2];
199 }
200
201 // validate name, identifier, object pattern name
202 $bacisClassAttributesInitialized = true;
203
204 // Validate input
205 $storeActions = array( 'MoveUp',
206                        'MoveDown',
207                        'StoreButton',
208                        'ApplyButton',
209                        'NewButton',
210                        'CustomActionButton');
211 $validationRequired = false;
212 foreach( $storeActions as $storeAction )
213 {
214     if ( $http->hasPostVariable( $storeAction ) )
215     {
216         $validationRequired = true;
217         break;
218     }
219 }
220 include_once( 'lib/ezutils/classes/ezinputvalidator.php' );
221 $canStore = true;
222 $requireFixup = false;
223 if ( $contentClassHasInput )
224 {
225     if ( $validationRequired )
226     {
227         foreach ( array_keys( $attributes ) as $key )
228         {
229             $attribute =& $attributes[$key];
230             $dataType =& $attribute->dataType();
231             $status = $dataType->validateClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
232             if ( $status == EZ_INPUT_VALIDATOR_STATE_INTERMEDIATE )
233                 $requireFixup = true;
234             else if ( $status == EZ_INPUT_VALIDATOR_STATE_INVALID )
235             {
236                 $canStore = false;
237                 $attributeName = $dataType->attribute( 'information' );
238                 $attributeName = $attributeName['name'];
239                 $unvalidatedAttributes[] = array( 'id' => $attribute->attribute( 'id' ),
240                                                   'identifier' => $attribute->attribute( 'identifier' ),
241                                                   'name' => $attributeName );
242             }
243         }
244         $validation['processed'] = true;
245         $validation['attributes'] = $unvalidatedAttributes;
246         $requireVariable = 'ContentAttribute_is_required_checked';
247         $searchableVariable = 'ContentAttribute_is_searchable_checked';
248         $informationCollectorVariable = 'ContentAttribute_is_information_collector_checked';
249         $canTranslateVariable = 'ContentAttribute_can_translate_checked';
250         $requireCheckedArray = array();
251         $searchableCheckedArray = array();
252         $informationCollectorCheckedArray = array();
253         $canTranslateCheckedArray = array();
254         if ( $http->hasPostVariable( $requireVariable ) )
255             $requireCheckedArray = $http->postVariable( $requireVariable );
256         if ( $http->hasPostVariable( $searchableVariable ) )
257             $searchableCheckedArray = $http->postVariable( $searchableVariable );
258         if ( $http->hasPostVariable( $informationCollectorVariable ) )
259             $informationCollectorCheckedArray = $http->postVariable( $informationCollectorVariable );
260         if ( $http->hasPostVariable( $canTranslateVariable ) )
261             $canTranslateCheckedArray = $http->postVariable( $canTranslateVariable );
262
263         foreach ( array_keys( $attributes ) as $key )
264         {
265             $attribute =& $attributes[$key];
266             $attributeID = $attribute->attribute( 'id' );
267             $attribute->setAttribute( 'is_required', in_array( $attributeID, $requireCheckedArray ) );
268             $attribute->setAttribute( 'is_searchable', in_array( $attributeID, $searchableCheckedArray ) );
269             $attribute->setAttribute( 'is_information_collector', in_array( $attributeID, $informationCollectorCheckedArray ) );
270             // Set can_translate to 0 if user has clicked Disable translation in GUI
271             $attribute->setAttribute( 'can_translate', !in_array( $attributeID, $canTranslateCheckedArray ) );
272         }
273     }
274 }
275 // Fixup input
276 if ( $requireFixup )
277 {
278     foreach( array_keys( $attributes ) as $key )
279     {
280         $attribute =& $attributes[$key];
281         $dataType =& $attribute->dataType();
282         $status = $dataType->fixupClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
283     }
284 }
285
286 $cur_datatype = 'ezstring';
287 // Apply HTTP POST variables
288 if ( $contentClassHasInput )
289 {
290     eZHTTPPersistence::fetch( 'ContentAttribute', eZContentClassAttribute::definition(),
291                               $attributes, $http, true );
292     eZHttpPersistence::fetch( 'ContentClass', eZContentClass::definition(),
293                               $class, $http, false );
294     if ( $http->hasVariable( 'ContentClass_is_container_exists' ) )
295     {
296         if ( $http->hasVariable( 'ContentClass_is_container_checked' ) )
297         {
298             $class->setAttribute( "is_container", 1 );
299         }
300         else
301         {
302             $class->setAttribute( "is_container", 0 );
303         }
304     }
305     if ( $http->hasPostVariable( 'DataTypeString' ) )
306         $cur_datatype = $http->postVariable( 'DataTypeString' );
307 }
308
309 $class->setAttribute( 'version', EZ_CLASS_VERSION_STATUS_TEMPORARY );
310
311 // Fixed identifiers to only contain a-z0-9_
312 foreach( array_keys( $attributes ) as $key )
313 {
314     $attribute =& $attributes[$key];
315     $attribute->setAttribute( 'version', EZ_CLASS_VERSION_STATUS_TEMPORARY );
316     $identifier = $attribute->attribute( 'identifier' );
317     if ( $identifier == '' )
318         $identifier = $attribute->attribute( 'name' );
319     $identifier = strtolower( $identifier );
320     $identifier = preg_replace( array( "/[^a-z0-9_ ]/" ,
321                                        "/ /",
322                                        "/__+/" ),
323                                 array( "",
324                                        "_",
325                                        "_" ),
326                                 $identifier );
327     $attribute->setAttribute( 'identifier', $identifier );
328     $dataType =& $attribute->dataType();
329     $dataType->initializeClassAttribute( $attribute );
330 }
331
332 // Fixed class identifier to only contain a-z0-9_
333 $identifier = $class->attribute( 'identifier' );
334 if ( $identifier == '' )
335     $identifier = $class->attribute( 'name' );
336 $identifier = strtolower( $identifier );
337 $identifier = preg_replace( array( "/[^a-z0-9_ ]/" ,
338                                    "/ /",
339                                    "/__+/" ),
340                             array( "",
341                                    "_",
342                                    "_" ),
343                             $identifier );
344 $class->setAttribute( 'identifier', $identifier );
345
346 // Run custom actions if any
347 if ( $customAction )
348 {
349     foreach( array_keys( $attributes ) as $key )
350     {
351         $attribute =& $attributes[$key];
352         if ( $customActionAttributeID == $attribute->attribute( 'id' ) )
353         {
354             $attribute->customHTTPAction( $Module, $http, $customAction );
355         }
356     }
357 }
358 // Set new modification date
359 $date_time = time();
360 $class->setAttribute( 'modified', $date_time );
361 include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
362 $user =& eZUser::currentUser();
363 $user_id = $user->attribute( 'contentobject_id' );
364 $class->setAttribute( 'modifier_id', $user_id );
365
366 // Remove attributes which are to be deleted
367 if ( $http->hasPostVariable( 'RemoveButton' ) )
368 {
369     if ( eZHttpPersistence::splitSelected( 'ContentAttribute', $attributes,
370                                            $http, 'id',
371                                            $keepers, $rejects ) )
372     {
373         $attributes = $keepers;
374         foreach ( $rejects as $reject )
375         {
376             $dataType =& $reject->dataType();
377             if ( $dataType->isClassAttributeRemovable( $reject ) )
378             {
379                 $reject->remove();
380             }
381             else
382             {
383                 $removeInfo = $dataType->classAttributeRemovableInformation( $reject );
384                 if ( $removeInfo !== false )
385                 {
386                     $validation['processed'] = true;
387                     $validation['attributes'] = array( array( 'id' => $reject->attribute( 'id' ),
388                                                               'identifier' => $reject->attribute( 'identifier' ),
389                                                               'reason' => $removeInfo ) );
390                 }
391             }
392         }
393     }
394 }
395
396 // Fetch HTTP input
397 if ( $contentClassHasInput )
398 {
399     foreach( array_keys( $attributes ) as $key )
400     {
401         $attribute =& $attributes[$key];
402         $dataType =& $attribute->dataType();
403         $dataType->fetchClassAttributeHTTPInput( $http, 'ContentClass', $attribute );
404     }
405 }
406
407 // Store version 0 and discard version 1
408 if ( $http->hasPostVariable( 'StoreButton' ) && $canStore )
409 {
410     $id = $class->attribute( 'id' );
411     $class_name = $class->attribute( 'name' );
412     $oldClassAttributes = $class->fetchAttributes( $id, true, EZ_CLASS_VERSION_STATUS_DEFINED );
413     $newClassAttributes = $class->fetchAttributes( );
414
415     if( trim( $class_name ) == '' || count( $newClassAttributes ) == 0 )
416     {
417         $canStore = false;
418         $validation['processed'] = false;
419         $bacisClassAttributesInitialized = false;
420     }
421     else
422     {
423
424         $firstStoreAttempt =& eZSessionRead( $http->sessionVariable( 'CanStoreTicket' ) );
425         if ( !$firstStoreAttempt )
426         {
427             return $Module->redirectToView( 'view', array( $ClassID ) );
428         }
429         eZSessionDestroy( $http->sessionVariable( 'CanStoreTicket' ) );
430
431         // Class cleanup, update existing class objects according to new changes
432         include_once( 'kernel/classes/ezcontentobject.php' );
433
434         $objects = null;
435         $objectCount =& eZContentObject::fetchSameClassListCount( $ClassID );
436         if ( $objectCount > 0 )
437         {
438             // Delete object attributes which have been removed.
439             foreach ( $oldClassAttributes as $oldClassAttribute )
440             {
441                 $attributeExist = false;
442                 $oldClassAttributeID = $oldClassAttribute->attribute( 'id' );
443                 foreach ( $newClassAttributes as $newClassAttribute )
444                 {
445                     $newClassAttributeID = $newClassAttribute->attribute( 'id' );
446                     if ( $oldClassAttributeID == $newClassAttributeID )
447                         $attributeExist = true;
448                 }
449                 if ( !$attributeExist )
450                 {
451                     $objectAttributes =& eZContentObjectAttribute::fetchSameClassAttributeIDList( $oldClassAttributeID );
452                     foreach ( $objectAttributes as $objectAttribute )
453                     {
454                         $objectAttributeID = $objectAttribute->attribute( 'id' );
455                         $objectAttribute->remove( $objectAttributeID );
456                     }
457                 }
458             }
459             $class->storeDefined( $attributes );
460
461             // Add object attributes which have been added.
462             foreach ( $newClassAttributes as $newClassAttribute )
463             {
464                 $attributeExist = false;
465                 $newClassAttributeID = $newClassAttribute->attribute( 'id' );
466                 foreach ( $oldClassAttributes as $oldClassAttribute )
467                 {
468                     $oldClassAttributeID = $oldClassAttribute->attribute( 'id' );
469                     if ( $oldClassAttributeID == $newClassAttributeID )
470                         $attributeExist = true;
471                 }
472                 if ( !$attributeExist )
473                 {
474                     if ( $objects == null )
475                     {
476                         $objects =& eZContentObject::fetchSameClassList( $ClassID );
477                     }
478                     foreach ( $objects as $object )
479                     {
480                         $contentobjectID = $object->attribute( 'id' );
481                         $objectVersions =& $object->versions();
482                         foreach ( $objectVersions as $objectVersion )
483                         {
484                             $translations = $objectVersion->translations( false );
485                             $version = $objectVersion->attribute( 'version' );
486                             foreach ( $translations as $translation )
487                             {
488                                 $objectAttribute =& eZContentObjectAttribute::create( $newClassAttributeID, $contentobjectID, $version );
489                                 $objectAttribute->setAttribute( 'language_code', $translation );
490                                 $objectAttribute->initialize();
491                                 $objectAttribute->store();
492                             }
493                         }
494                     }
495                 }
496             }
497         }
498         else
499         {
500             $class->storeDefined( $attributes );
501         }
502
503         $http->removeSessionVariable( 'CanStoreTicket' );
504         return $Module->redirectToView( 'view', array( $ClassID ) );
505     }
506 }
507
508 // Store changes
509 if ( $canStore )
510     $class->store( $attributes );
511
512 if ( $http->hasPostVariable( 'NewButton' ) )
513 {
514     $new_attribute =& eZContentClassAttribute::create( $ClassID, $cur_datatype );
515     $attrcnt = count( $attributes ) + 1;
516     $new_attribute->setAttribute( 'name', ezi18n( 'kernel/class/edit', 'new attribute' ) . $attrcnt );
517     $dataType = $new_attribute->dataType();
518     $dataType->initializeClassAttribute( $new_attribute );
519     $new_attribute->store();
520     $attributes[] =& $new_attribute;
521 }
522 else if ( $http->hasPostVariable( 'MoveUp' ) )
523 {
524     $attribute =& eZContentClassAttribute::fetch( $http->postVariable( 'MoveUp' ), true, EZ_CLASS_VERSION_STATUS_TEMPORARY,
525                                                   array( 'contentclass_id', 'version', 'placement' ) );
526     $attribute->move( false );
527     $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID );
528     return;
529 }
530 else if ( $http->hasPostVariable( 'MoveDown' ) )
531 {
532     $attribute =& eZContentClassAttribute::fetch( $http->postVariable( 'MoveDown' ), true, EZ_CLASS_VERSION_STATUS_TEMPORARY,
533                                                   array( 'contentclass_id', 'version', 'placement' ) );
534     $attribute->move( true );
535     $Module->redirectTo( $Module->functionURI( 'edit' ) . '/' . $ClassID );
536     return;
537 }
538
539 $Module->setTitle( 'Edit class ' . $class->attribute( 'name' ) );
540 if ( !$http->hasSessionVariable( 'CanStoreTicket' ) )
541 {
542     $http->setSessionVariable( 'CanStoreTicket', md5( (string)rand() ) );
543     eZSessionWrite( $http->sessionVariable( 'CanStoreTicket' ), 1 );
544 }
545
546 // Fetch updated attributes
547 $attributes = $class->fetchAttributes();
548
549 // Template handling
550 include_once( 'kernel/common/template.php' );
551 $tpl =& templateInit();
552 $res =& eZTemplateDesignResource::instance();
553 $res->setKeys( array( array( 'class', $class->attribute( 'id' ) ) ) ); // Class ID
554 $tpl->setVariable( 'http', $http );
555 $tpl->setVariable( 'validation', $validation );
556 $tpl->setVariable( 'can_store', $canStore );
557 $tpl->setVariable( 'require_fixup', $requireFixup );
558 $tpl->setVariable( 'module', $Module );
559 $tpl->setVariable( 'class', $class );
560 $tpl->setVariable( 'attributes', $attributes );
561 $tpl->setVariable( 'datatypes', $datatypes );
562 $tpl->setVariable( 'datatype', $cur_datatype );
563 $tpl->setVariable( 'bacis_class_attributes_initialized', $bacisClassAttributesInitialized );
564
565 $Result = array();
566 $Result['content'] =& $tpl->fetch( 'design:class/edit.tpl' );
567 $Result['path'] = array( array( 'url' => '/class/edit/',
568                                 'text' => ezi18n( 'kernel/class', 'Class edit' ) ) );
569
570 ?>