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