-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathSC_Element.php
More file actions
2342 lines (2093 loc) · 86.8 KB
/
SC_Element.php
File metadata and controls
2342 lines (2093 loc) · 86.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/*
Sow Peace License (MIT-Compatible with Attribution Visit)
Copyright (c) 2025 Ruben Schaffer Levine and Luca Lauretta
https://simplonphp.org/Sow-PeaceLicense.txt
*/
/**
* Base class for all SimplOn Elements.
* Elements are fundamental building blocks in SimplOn, representing a set of related data and providing a standardized way to interact with that data.
* They include the information required to allow datastorage and render clases extend traditional object capabilities capabilities allowing
* for common tasks such as displaying, storing, searching, and generating user interfaces like forms.
*
* Elements work in conjunction with SimplON Data objects. Each attribute of an Element that holds data intended for interaction (display, storage, etc.)
* should be an instance of a SimplON Data class (or a class extending SC_Data). These Data objects encapsulate the data itself along with important metadata
* about how the data should be handled (e.g., whether it should be shown in a view, included in a form, searchable, validated, etc.).
*
* By combining the Element's methods and the metadata within its Data attributes, SimplOn's Renderers and DataStorage classes can automatically generate
* interfaces and interact with data storage without needing specific knowledge of each Element's internal structure. This allows for seamless integration
* and automatic updates of the interface and storage mechanisms as the Element's definition changes.
*
* Inherits from {@see SC_BaseObject} for fundamental SimplOn object capabilities.
*
* @version 1b.1.0
* @package SimplOn\Core
* @author Ruben Schaffer
*
**/
class SC_Element extends SC_BaseObject {
/**
* Name of the Data attribute that represents the unique identifier field of the Element.
* This typically corresponds to the primary key column name in an SQL database.
*
* @todo enable handle of multiple id fields, that should be automatically
* detected, as those should be all instances of \SimplOn\Data\Id).
* @var string|null
*/
protected $fieldId;
/**
* The DataStorage instance used by this Element to interact with the underlying data source.
* By default, it is initialized with the global DataStorage instance configured in {@see SC_Main::$DATA_STORAGE}.
*
* @var \SimplOn\DataStorages\SDS_DataStorage
*/
protected $dataStorage;
/**
* The name of the data storage location associated with this Element.
* This could be a table name in a relational database, a collection name in a NoSQL database, or a path in a file system.
* By default, this is set to the class name of the Element (without the namespace).
*
* @var string
*/
protected $storage;
/**
* Criteria to use for searching in the dataStorage.
*
* By default builds it using the Data attributes' default criteria and the search flags of each
*
* @example (.Data1) AND (Data2 == "Hello")
* @var string
*/
protected $filterCriteria;
/**
* Criteria to use for selection on the time of deletion in the dataStorage.
*
* By default builds it using the Data attributes' default criteria and the delete flags of each
*
* @example (.Data1) AND (Data2 == "Hello")
* @var string
*/
protected $deleteCriteria;
/**
* Elements can be nested using a special kind of data called ElementContainer.
* If an element is contained within another element, the containing element can be accessed via this attribute.
*
* NOTE: This property is NOT the same as the `parent::` keyword used to call a parent class's methods or access parent properties.
*
* @var SC_Element|null The parent element, or null if this element is not nested.
*/
protected $parent;
/**
* Flag to avoid the system to validate
* DataStorage more than once.
* @var boolean
*/
public static $storageChecked;
/**
* Array with the exception Messages
*
* Used for example when validating for Storing Data
*/
protected $exceptionMessages = array();
/**
* Flag to allow deletion without confirmation
*
* By default it uses the value of SC_MAIN::$QUICK_DELETE
*
* @var string
*/
public static $quickDelete;
/**
* Stores a list of Element's attributes of type SC_Data.
*
* TODO: Evalute if can be made static
*
* @var array containing objects of type SC_Data
*/
protected $dataAttributes;
/**
* Used to store Data atributes added on the fly for all the instances of the class usually links to actions like edit delete or view.
*
* TODO: Evalute if can be mixed/integrated with $dataAttributes
*
* */
static $onTheFlyAttributes = array();
protected $defaultAction = null;
/**
* Array containing the acces rules for the datas and methods.
*
*
* Example:
admin' => array('*'=>'allow'),
'Asesor' => array(
'View'=>array(
'updateAction'=>'viewableWhen_id_=_CurrentUserId',
'deleteAction'=>'hide',
),
'Search'=>'allow',
'Update'=>array(
'asesor'=>'fixed_CurrentUserId',
),
'Create'=>array(
'asesor'=>'fixed_CurrentUserId',
),
'Delete'=>'deny',
),
'*' => array('showView'=>'allow','*'=>'deny')
*
*/
static $permissions;
protected $Name, $NamePlural;
protected $nameInParent;
/**
* How to order the elements when listing them
*
*
*/
protected $OrderCriteria = 'SimplOn_id desc';
/** @var SR_htmlJQuery */
protected $renderer;
/**
* Determines the kind of permissions that are given to the attributes.
*
* Depending on the $methodsFamilies array each method is assigned a DatasMode
* View, Update, Create, Delete, Search or the method it static. This way the permissions don't have to be asigned for each method but for DatasMode and special methods.
*
*/
protected $datasMode;
/**
* Keeps the relationship between the methods and the datasMode so that is simplier to write the permissions.
*/
static $methodsFamilies = array(
'showView'=>'View',
'showSearch'=>'View',
'showList'=>'View',
'showEmbed'=>'View',
'showEmbededStrip'=>'View',
'processReport'=>'View',
'showAdmin'=>'Admin',
'showUpdate'=>'Update',
'showUpdateSelect'=>'Update',
'processUpdate'=>'Update',
'processUpdateJSon'=>'Update',
'processUpdateSelect'=>'Update',
'showCreate'=>'Create',
'showContinusCreate'=>'Create',
'showCreateAppend'=>'Create',
'showCreateSelect'=>'Create',
'processContinusCreate'=>'Create',
'processCreate'=>'Create',
'processCreateAppend'=>'Create',
'processCreateJSon'=>'Create',
'processCreateSelect'=>'Create',
'processCreprocessUpdateate'=>'Create',
'showDelete'=>'Delete',
'processDeletePage'=>'Delete',
'showSearch'=>'Search',
'showSearchSelect'=>'Search',
'processAdmin'=>'Search',
'processSearch'=>'Search',
'logout'=>'logout',
'showLogin'=>'showLogin',
'processLogin'=>'processLogin',
/**
* View Update Create Delete Search
* TODO:: Still to be asigned a DataMode methods
processSelect
showEmbededAppendInput
showEmbededSearchInput
showEmbededUpdateInput
showMultiPicker
showReport
showSelect
showSelectAppend
processData
*/
);
static $formMethods = ['showSearch','showCreate','showUpdate'];
/**
* Flag to indicate that the whole constructor has finished. Used to avoid cicles with SC_ElementBased PERMISSIONS like SE_User but can be used to prevent other kind of infite loops and problems.
*
*/
protected $fullyset = false;
static
$AdminMsg,
$ReturnBtnMsg,
$CancelBtnMsg,
$SearchBtnMsg,
$SearchMsg,
$ViewBtnMsg,
$ViewMsg,
$CreateBtnMsg,
$CreatedMsg,
$CreateMsg,
$CreateError,
$UpdateBtnMsg,
$UpdatedMsg,
$UpdateMsg,
$UpdateError,
$DeleteBtnMsg,
$DeletedMsg,
$DeleteMsg,
$DeleteError;
/**
* Constructs a new SimplOn Element instance.
*
* The constructor performs several key initializations:
* - Sets the storage location based on the provided `$storage` parameter or defaults to the class name.
* - Assigns the global renderer instance.
* - Determines and assigns the appropriate DataStorage instance (either a special one provided or the global one).
* - Initializes the Element's singular and plural names if they are not already set.
* - Sets various static message properties used for UI elements (e.g., AdminMsg, CreateMsg) using the localization function `SC_MAIN::L()`.
* - Calls the user-defined `construct()` method, allowing subclasses to perform their own specific initializations and declare Data attributes.
* - Adds any Data attributes defined on the fly.
* - Assigns the name of each Data attribute within the Element instance.
* - Sets the current Element instance as the logical parent for its Data attributes.
* - Ensures the element's storage structure exists in the DataStorage.
* - Attempts to fill the Element's Data values from the provided `$id_or_array` (either an array of values or an ID to fetch from storage).
* - Sets the `$fullyset` flag to true, indicating that the initialization is complete.
*
* @param mixed $id_or_array Optional. The unique identifier (ID) of the Element to load from storage, or an array of key-value pairs to pre-fill the Element's Data attributes. Defaults to null.
* @param string|null $storage Optional. The specific name of the data storage location for this Element. If not provided, the class name is used.
* @param \SimplOn\DataStorages\SDS_DataStorage|null $specialDataStorage Optional. A specific DataStorage instance to use for this Element, overriding the global one. Defaults to null, which means the global DataStorage will be used.
*/
public function __construct($id_or_array = null, $storage = null, $specialDataStorage = null) {
//On heirs put here the asignation of SimplOndata and attributes
if ($storage)
$this->storage($storage);
else
$this->storage($this->getClass());
$this->renderer = SC_Main::$RENDERER;
//Assings the storage element for the SimplonElement. (a global one : or a particular one)
if (!$specialDataStorage) {
$this->dataStorage = SC_Main::dataStorage();
} else {
$this->dataStorage = &$specialDataStorage;
}
if(!$this->Name){$this->Name();}
static::$AdminMsg = $this->NamePlural().' '.SC_MAIN::L('Manager');
static::$ReturnBtnMsg = SC_MAIN::L('Return');
static::$CancelBtnMsg = SC_MAIN::L('Cancel');
static::$SearchBtnMsg = SC_MAIN::L('Search');
static::$SearchMsg = SC_MAIN::L('Search').' '.$this->NamePlural();
static::$ViewBtnMsg = SC_MAIN::L('View');
static::$ViewMsg = SC_MAIN::L('View of '.$this->Name);
static::$CreateBtnMsg = SC_MAIN::L('Create');
static::$CreateMsg = SC_MAIN::L('Create a '.$this->Name);
static::$CreatedMsg = SC_MAIN::L('A '.$this->Name.' has been created');
static::$CreateError = SC_MAIN::L('A '.$this->Name.' can\'t be created');
static::$UpdateBtnMsg = SC_MAIN::L('Update');
static::$UpdateMsg = SC_MAIN::L('Update a '.$this->Name);
static::$UpdatedMsg = SC_MAIN::L('The '.$this->Name.' has been updated');
static::$UpdateError = SC_MAIN::L('The '.$this->Name.' can\'t be updated');
static::$DeleteBtnMsg = SC_MAIN::L('Delete');
static::$DeleteMsg = SC_MAIN::L('Delete a '.$this->Name);
static::$DeletedMsg = SC_MAIN::L('A '.$this->Name.' has been deleted');
static::$DeleteError = SC_MAIN::L('The '.$this->Name.' has been deleted');
$this->construct($id_or_array, $storage);
$this->addDatas();
$this->assignDatasName();
$this->assignAsDatasParent();
//checking if there is already a dataStorage and storage for this element
$this->dataStorage->ensureElementStorage($this);
if (is_array($id_or_array)) {
try{$this->fillFromArray($id_or_array);}catch(SC_ElementValidationException $ev){}
} else if ($id_or_array) {
//if there is a storage and an ID it fills the element with the proper info.
$this->fillFromDSById($id_or_array);
} else {
//$this->fillFromRequest();
}
// if( !empty(SC_Main::$PERMISSIONS)
// && !is_string(SC_Main::$PERMISSIONS)
// && (SC_Main::$PERMISSIONS !== $this)
// && ( !in_array($this,SC_Main::$PERMISSIONS::$excentObjects) )
// ){
// SC_Main::$PERMISSIONS->setValuesByPermissions($this, '' );
// }
$this->fullyset = true;
}
/**
* Returns an array of attribute names (properties) of the Element instance
* that are instances of the specified class type.
*
* @param string $type The class type to filter attributes by.
* @return array An array of attribute names that are instances of the specified type.
*/
function attributesOfClass($type){
$ret = array();
foreach ($this as $property => $value) {
if($value instanceof $type){
$ret[] = $property;
}
}
return $ret;
}
/**
* Returns the static permissions array for the Element.
*
* This array defines the access rules for the element's data and methods.
*
* @return array The permissions array.
* @see SC_Element::$permissions
*/
function permissions(){
return static::$permissions;
}
/**
* User defined constructor, called within {@link __constructor()},
* useful to declare specific Data attributes.
* @param mixed $id_or_array ID of the Element or array of Element's Datas values.
* @param \SimplOn\DataStorages\DataStorage $specialDataStorage DataStorage to use in uncommon cases.
*/
public function construct() {
}
/**
* Gets or sets the name of the Data attribute that represents the unique identifier field of the Element.
* If the field ID is not already set and no value is provided, it attempts to automatically detect the first attribute of type `SD_Id`.
*
* @param string|null $val Optional. The name of the attribute to set as the unique identifier field. If null, the current field ID is returned.
* @return string|null The name of the unique identifier field.
*/
public function fieldId($val = null) {
if (!$this->fieldId) {
$this->fieldId = $this->attributesTypes('SD_Id');
$this->fieldId = $this->fieldId[0];
}
if ($val) {
$this->fieldId = $val;
} else {
return $this->fieldId;
}
}
/**
* Gets or sets the parent element of this instance.
*
* This is used when elements are nested within {@see ElementContainer}.
*
* @param SC_Element|null $parent Optional. The parent element to set. If null, the current parent element is returned.
* @return SC_Element|null The parent element, or null if not set.
* @see SC_Element::$parent
*/
function parent(&$parent = null) {
if (!$parent) {
return $this->parent;
} else {
$this->parent = $parent;
}
}
// May be no longer used
// function elementContainerName(){
// if( $this->nameInParent() || $this->nameInParent() === 0 ){ return $this->nameInParent(); }else{ return 'placeHolderName'; }
// }
/**
* Magic method to handle dynamic method calls, providing simplified access to Data attributes and rendering methods.
*
* This method intercepts calls to methods that are not explicitly defined in the class. It provides several functionalities:
* 1. If the method name matches a Data attribute of the Element, it acts as a getter or setter for the Data attribute's value.
* - If arguments are provided, the first argument is used to set the Data attribute's value.
* - If no arguments are provided, it returns the current value of the Data attribute.
* 2. If the method name starts with "show", it delegates the call to the renderer's `render` method to generate a representation of the element.
* 3. If the method name starts with 'O', 'F', or 'L' followed by the name of a Data attribute:
* - 'O' followed by a Data attribute name: Provides direct access to the Data object instance (getter/setter).
* - 'F' followed by a Data attribute name: Calls the `fixValue` method on the Data attribute, wich set the value of the attribute and does not allow to be changed later on.
* - 'L' followed by a Data attribute name: Returns the label of the Data attribute.
* 4. For any other method calls, it falls back to the parent class's `__call` method.
*
* @param string $name The name of the method being called.
* @param array $arguments An array of arguments passed to the method.
* @return mixed The result of the called method or operation.
* @throws SC_Exception If an unrecognized letter !('O', 'F' or 'L') is used before a Data attribute name.
* @see SC_BaseObject::__call()
*/
public function __call($name, $arguments) {
//ensure there is a response to ->id() even if ID it's not defined as ->id ex: ->name in user
if ($name == 'id' && !$this->id){
if ($arguments[0]!==null){
$this->{$this->fieldId()}($arguments[0]);
}else{
return $this->{$this->fieldId()}();
}
}
if (@$this->$name instanceof SC_Data) {
if ($arguments) {
return $this->$name->val($arguments[0]);
}else {
return $this->$name->val();
}
} else if(substr($name, 0, 4) === "show"){
// return $this->renderer->render($this,$name);
array_unshift($arguments,$name);
array_unshift($arguments,$this);
return call_user_func_array(array($this->renderer, 'render'), $arguments);
} else {
$letter = substr($name, 0, 1);
$Xname = substr($name, 1);
if (($letter == strtoupper($letter)) && (@$this->$Xname instanceof SC_Data)) {
switch ($letter) {
case 'O': //Get the object / Change the object
if ($arguments) {
//$this->$Xname->val($arguments[0]);
$this->$Xname = $arguments[0];
} else {
return $this->$Xname;
}
break;
case 'F': //Fix value
if ($arguments) {
$this->$Xname->fixValue($arguments[0]);
} else {
return $this->$Xname;
}
break;
case 'L':
if ($arguments) {
$this->$Xname->val($arguments[0]);
} else {
return $this->$Xname->label();
}
break;
default:
throw new SC_Exception('Letter ' . $letter . ' not recognized!');
}
} else {
return parent::__call($name, $arguments);
}
}
}
// -- SimplON key methods
/**
* Fills the Element's Data attributes with values from a given array.
*
* This method iterates through the provided array, and for each key-value pair,
* it attempts to assign the value to the corresponding Data attribute within
* the Element instance. It also performs validation for each Data attribute
* during the assignment process.
*
* @param array &$array_of_data An associative array where keys are the names of the Data attributes
* and values are the data to be assigned. The array is passed by reference.
* @return int The number of Data attributes successfully filled.
* @throws SC_ElementValidationException If any of the Data attributes fail validation during the filling process.
*/
public function fillFromArray(&$array_of_data) {
$filled = 0;
if (is_array($array_of_data)) {
foreach ($array_of_data as $dataName => $value) {
if (isset($this->$dataName) && ($this->$dataName instanceof SC_Data)) {
try {
$this->$dataName($value);
$filled++;
} catch (SC_DataValidationException $ve) {
$this->excetionsMessages[$dataName] = array($ve->getMessage());
}
}
}
}
if(!empty($this->excetionsMessages)){
throw new SC_ElementValidationException($this->excetionsMessages);
}
return $filled;
}
/**
* Fills the Element's Data attributes with values from the $_REQUEST and $_FILES superglobal arrays.
*
* This method processes data submitted via a request. It first checks if $_REQUEST is populated.
* If so, it iterates through $_FILES and, for any entry corresponding to an SD_File attribute
* on the element, it incorporates the file data into the $_REQUEST array before
* passing the combined data to `fillFromArray` for assignment and validation.
*
* This is necessary because `fillFromArray` is designed to handle a single array of data,
* but file uploads are provided in the separate $_FILES superglobal.
*
* @return bool True if $_REQUEST was processed, false otherwise.
* @throws SC_ElementValidationException If any of the Data attributes fail validation during the filling process via `fillFromArray`.
*/
public function fillFromRequest() {
if ($_REQUEST) {
if(!empty($_FILES)){
foreach ($_FILES as $key => $value) {
if ( isset($this->$key) && $this->$key instanceof SD_File && is_array($value) ) {
$_REQUEST[$key] = $value;
}
}
}
try{$this->fillFromArray($_REQUEST);}catch(SC_ElementValidationException $ev){
//TODO
}
return true; // Return true if $_REQUEST was processed
} else {
return false;
}
}
/**
* Fills the Element's Data attributes with values from the `$_POST` superglobal array.
*
* This method processes data submitted via a POST request. It checks if `$_POST` is populated.
* If so, it passes the `$_POST` array to `fillFromArray` for assignment and validation.
* It suppresses potential errors during the call to `fillFromArray`.
* Validation exceptions thrown by `fillFromArray` are currently caught but not handled within this method's catch block.
*
* @return int|false The number of attributes successfully filled if `$_POST` is not empty, or `false` otherwise.
* Note: Due to error suppression and an empty catch block, the return value might be
* unpredictable if `fillFromArray` throws an exception.
*/
// public function fillFromPost() {
// if ($_POST) {
// try{@$ret = $this->fillFromArray($_POST);}catch(SC_ElementValidationException $ev){
// //TODO
// }
// return @$ret;
// } else {
// return false;
// }
// }
//------------Data Storage
/**
* Retrieves the element's Data attribute values from the configured DataStorage.
*
* It uses the provided `$id` to fetch the record. If no `$id` is provided,
* it attempts to use the element's currently set ID (retrieved via {@see getId()}).
* The fetched data is then used to fill the Element's Data attributes
* by calling {@see fillFromArray()}.
*
* @param mixed $id Optional. The unique identifier of the element to fetch from the data storage.
* If null, the element's current ID is used.
* @throws SC_Exception If neither a valid `$id` is provided nor the element has a pre-existing ID.
* @return void
*/
public function fillFromDSById($id = null) {
if (isset($id)) {
$this->setId($id);
}
if ($this->getId() || $this->getId() === 0) {
$dataArray = $this->dataStorage->readElement($this);
try{$this->fillFromArray($dataArray);}catch(SC_ElementValidationException $ev){}
} else {
throw new SC_Exception('The object of class: ' . $this->getClass() . " has no id so it can't be filled using method fillFromDSById");
}
}
/**
* Saves the element to the configured DataStorage.
*
* This method checks if the element instance has a unique identifier (ID) set.
* If an ID is present, it calls the `update()` method to update the existing record in the data storage.
* If no ID is present, it calls the `create()` method to create a new record in the data storage.
*
* @return mixed The result of the `update()` or `create()` operation, typically the number of affected rows or the new ID.
*/
public function save() {
return $this->getId() ? $this->update() : $this->create();
}
/**
* Updates the element's data in the configured DataStorage.
*
* This method first calls `processData('preUpdate')` to execute any pre-update processing
* defined for the element's Data attributes. It then delegates the actual update operation
* to the DataStorage instance's `updateElement` method. After the update is performed,
* it calls `processData('postUpdate')` to execute any post-update processing.
*
* @return mixed The result of the DataStorage update operation, which typically
* indicates the success or failure of the update (e.g., number of affected rows).
*/
public function update() {
$this->processData('preUpdate');
$return = $this->dataStorage->updateElement($this);
$this->processData('postUpdate');
return $return;
}
/**
* Deletes the element from the configured DataStorage.
*
* This method first calls `processData('preDelete')` to execute any pre-deletion
* processing defined for the element's Data attributes. It then delegates the
* actual deletion operation to the DataStorage instance's `deleteElement` method.
* After the deletion is performed, it calls `processData('postDelete')` to execute
* any post-deletion processing.
*
* @return mixed The result of the DataStorage deletion operation, which typically
* indicates the success or failure of the deletion (e.g., number of affected rows).
*/
public function delete() {
$this->processData('preDelete');
$return = $this->dataStorage->deleteElement($this);
$this->processData('postDelete');
return $return;
}
/**
* Validates the Element's Data attributes before interacting with the DataStorage (e.g., before creating or updating a record).
*
* This method primarily checks for required Data attributes by calling {@see requiredCheck()}.
* If any required attributes are missing or validation fails during the `requiredCheck`,
* it collects the validation messages and throws an {@see SC_ElementValidationException}.
*
* This method is typically called internally by methods like {@see create()} and {@see update()}.
*
* @throws SC_ElementValidationException If required fields are not filled or fail validation checks.
*/
function validateForDB() {
@$exceptionMessages = $this->requiredCheck($this->excetionsMessages);
if (!empty($exceptionMessages)) {
throw new SC_ElementValidationException($exceptionMessages);
}
}
/**
* Checks if all required Data attributes of the Element have values.
*
* This method iterates through all Data attributes marked as 'required'.
* If a required Data attribute is empty and is not an auto-incrementing field,
* it adds a validation message to the provided array.
*
* @param array $array An associative array to which validation messages will be added.
* The keys are the names of the Data attributes that failed validation.
* @return array The updated array containing validation messages for any required fields that are empty.
*/
public function requiredCheck($array = array()) {
$requiredDatas = $this->datasWith('required');
foreach ($requiredDatas as $requiredData) {
if (!$this->$requiredData->val() && ($this->$requiredData->required() && !@$this->$requiredData->autoIncrement())) {
$array[$requiredData][] = $this->$requiredData->validationRequired();
}
}
return $array;
}
/**
* Creates a new record for the element in the configured DataStorage.
*
* This method delegates the creation process to the DataStorage instance's `createElement` method.
* Upon successful creation, it sets the ID of the current Element instance with the newly generated ID
* returned by the DataStorage. Finally, it calls `processData('postCreate')` to execute any post-creation
* processing defined for the element's Data attributes.
*
* @return mixed The result of the DataStorage creation operation, typically the new unique identifier (ID)
* for the created record on success, or `false` on failure.
*/
/**
* Creates a new record for the element in the configured DataStorage.
*
* This method first calls `processData('preCreate')` to execute any pre-creation
* processing defined for the element's Data attributes. It then delegates the
* creation process to the DataStorage instance's `createElement` method.
* Upon successful creation, it sets the ID of the current Element instance with
* the newly generated ID returned by the DataStorage. Finally, it calls
* `processData('postCreate')` to execute any post-creation processing defined
* for the element's Data attributes.
*
* @return mixed The result of the DataStorage creation operation, typically the new unique identifier (ID)
* for the created record on success, or `false` on failure.
*/
public function create() {
$this->processData('preCreate');
$id = $this->dataStorage->createElement($this);
$this->setId($id);
$this->processData('postCreate');
return $id !== false;
}
/**
* Processes the creation of an Element via a JSON request.
*
* This method handles incoming request data, validates it, attempts to create
* a new record for the element in the data storage, and returns a JSON response
* indicating the result or validation errors.
*
* On successful creation, it returns a JSON object containing commands for the
* renderer, typically a command to redirect to the next step.
* If validation fails, it returns a JSON object containing commands for the
* renderer to display validation messages for specific data attributes.
* If a database error occurs during creation, it triggers a user error.
*
* @param string|null $nextStep Optional. The URL or action to redirect to after successful creation. Defaults to null.
* @return string A JSON string containing commands for the renderer or error information.
* @throws SC_ElementValidationException If data validation fails before attempting to create the element. (This is caught internally and returned as JSON)
* @throws PDOException If a database error occurs during the creation process. (This is caught internally and triggers a user error)
*/
function processCreateJSon($nextStep = null) {
try {
$this->fillFromRequest();
$this->validateForDB();
$shouldContinue = true; // Control variable
} catch (SC_Exception $ev) {
$data = array();
if($ev->datasValidationMessages()){
foreach ($ev->datasValidationMessages() as $key => $value) {
$data[] = array(
'func' => 'showValidationMessages',
'args' => array($key, $value[0])
);
}
}else{
//var_dump($ev);
}
$return = array(
'status' => true,
'type' => 'commands',
'data' => $data
);
$return = json_encode($return);
return $return;
}
try {
if ($this->create()) {
$data = array(array(
'func' => 'redirectNextStep',
'args' => array($nextStep)
));
$return = array(
'status' => true,
'type' => 'commands',
'data' => $data
);
$return = json_encode($return);
return $return;
} else {
// @todo: error handling
user_error(static::$CreateError, E_USER_ERROR);
}
} catch (\PDOException $ev) {
//user_error($ev->errorInfo[1]);
//@todo handdle the exising ID (stirngID) in the DS
user_error($ev);
}
}
/**
* Renders a form for creating a new instance of the Element.
*
* This method generates a user interface for creating a new Element record.
* It includes a title, a form containing input fields corresponding to the
* Element's Data attributes that are marked for 'create' and 'show',
* and submit/cancel buttons. The form is configured to submit data to the
* `processCreate` method.
*
* @return \SimplOn\Interface\SI_systemScreen A system screen object containing the creation form.
*/
function showCreate(){
$content = new SI_VContainer();
$content->addItem(new SI_Title(static::$CreateMsg,4));
$form = new SI_Form($this->datasWith('create','show'), SC_Main::$RENDERER->action($this,'processCreate'));
//$form->addItem( new SI_HContainer([ new SI_Submit(SC_Main::L('Create')), new SI_CancelButton() ]) );
$form->addItem( new SI_Submit(SC_Main::L('Create')) );
$form->addItem( new SI_CancelButton() );
$content->addItem($form);
$page = new SI_systemScreen($content,SC_Main::L(static::$CreateBtnMsg) );
return $page;
}
/**
* Processes the creation of a new Element record and returns a JSON response.
*
* This method prepares the necessary data and delegates the actual creation
* and JSON response generation to {@see processCreateJSon()}.
* It sets a success message and determines the next step (typically redirecting to the admin view)
* before calling the JSON processing method.
*
* @return string A JSON string containing commands for the renderer, typically a redirect command.
*/
function processCreate(){
$this->renderer->setMessage(static::$CreatedMsg);
$nextStep = $this->renderer->action($this,'showAdmin','id',static::$CreatedMsg );
return $this->processCreateJSon($nextStep);
}
/**
* Renders a form for continuous creation of new Element instances.
*
* This method is similar to {@see showCreate()} but is intended for scenarios where
* the user needs to create multiple instances consecutively. After a successful
* creation, the form is typically re-displayed with a success message, allowing
* the user to immediately create another element without navigating away.
*
* It sets a success message and defines the form action to point to
* {@see processContinusCreate()} which handles the continuous flow.
* The actual rendering of the form is delegated to the renderer's `render` method,
* using the 'showCreate' method as the basis for the form structure.
*
* @param string|null $template Optional. The template to use for rendering. Defaults to the default template for 'showCreate'.
* @param bool $partOnly Optional. If true, renders only the content part, not the full page. Defaults to false.
* @param string|null $action Optional. The URL or action for the form submission. If not provided, it defaults to the result of {@see processContinusCreate()}.
* @param string|null $nextStep Optional. The URL or action to redirect to after a sequence of continuous creations is finished. Not typically used in the continuous flow itself, but can be passed.
* @return mixed The rendered output, typically an HTML string representing the continuous creation form.
*/
function showContinusCreate($template = null, $partOnly = false,$action=null,$nextStep=null){
$this->renderer->setMessage(static::$CreatedMsg );
$action = $this->renderer->action($this,'processContinusCreate');
return $this->renderer->render($this,'showCreate',$template, $partOnly ,$action ,$nextStep);
// (SC_BaseObject $object, string $method, $template = null, $partOnly = false,$action=null,$nextStep=null)
}
/**
* Processes the continuous creation of a new Element record via a JSON request.
*
* This method is the target of the form submission from {@see showContinusCreate()}.
* It handles incoming request data, validates it, attempts to create a new record,
* and returns a JSON response.
*
* Unlike {@see processCreateJSon()}, upon successful creation, this method generates
* a `$nextStep` that points back to {@see showContinusCreate()} with the newly created
* element's ID (though the ID might not be strictly necessary for displaying an empty form,
* it's included in the action URL). This allows the renderer to stay on the creation form
* and display a success message, facilitating continuous creation.
*
* If validation fails, it returns a JSON object containing commands for the renderer
* to display validation messages, similar to {@see processCreateJSon()}.
* If a database error occurs during creation, it triggers a user error.
*
* @param string|null $nextStep Optional. The URL or action to redirect to after successful creation. If null, it defaults to calling `showContinusCreate` again with the newly created element's ID.
* @return string A JSON string containing commands for the renderer or error information.
* @throws SC_ElementValidationException If data validation fails before attempting to create the element. (Caught internally and returned as JSON)
* @throws PDOException If a database error occurs during the creation process. (Caught internally and triggers a user error)
*/
function processContinusCreate($nextStep = null) {
$nextStep = $this->renderer->action($this,'showContinusCreate','id');
return $this->processCreateJSon($nextStep);
}
/**
* Renders a form for creating a new instance of the Element, intended for scenarios
* where the newly created element should be selected before the creation of another element usually using SD_ElementContainer.
*
* This method delegates the rendering of the creation form to the renderer, typically
* reusing the structure defined for `showCreate`. The form's action is set to
* `processCreateSelect`, which handles the creation and subsequent selection logic.
*
* @param string|null $template Optional. The template to use for rendering. Defaults to the default template for 'showCreate'.
* @param bool $partOnly Optional. If true, renders only the content part, not the full page. Defaults to false.
* @param string|null $action Optional. The URL or action for the form submission. If not provided, it defaults to the result of {@see processCreateSelect()}.
* @param string|null $nextStep Optional. This parameter is typically not directly used in this method but is included for consistency with other show methods.
* @return mixed The rendered output, typically an HTML string representing the creation form for selection.
*/
function showCreateSelect($template = null, $partOnly = false,$action=null,$nextStep=null){
$action = $this->renderer->action($this,'processCreateSelect');
return $this->renderer->render($this,'showCreate', 'AE_basicPage',$template, $action);
//return $this->renderer->render($this,'showCreate',$template, $partOnly ,$action ,$nextStep);
// (SC_BaseObject $object, string $method, $template = null, $partOnly = false,$action=null,$nextStep=null)
}
/**
* Renders a form for creating a new instance of the Element, specifically designed
* for appending the newly created element to a container or list in the parent element's interface, usually using SD_ElementsContainer.
*
* This method delegates the rendering of the creation form to the renderer, typically
* reusing the structure defined for `showCreate`. The form's action is set to
* `processCreateAppend`, which handles the creation and subsequent appending logic.
*
* @param string|null $template Optional. The template to use for rendering. Defaults to the default template for 'showCreate'.
* @param bool $partOnly Optional. If true, renders only the content part, not the full page. Defaults to false.
* @param string|null $action Optional. The URL or action for the form submission. If not provided, it defaults to the result of {@see processCreateAppend()}.
* @param string|null $nextStep Optional. This parameter is typically not directly used in this method but is included for consistency with other show methods.
* @return mixed The rendered output, typically an HTML string representing the creation form for appending.
*/
// function showCreateAppend($template = null, $partOnly = false,$action=null,$nextStep=null){
// //$action = $this->renderer->action($this,'processCreateSelect');
// $action = $this->renderer->action($this,'processCreateAppend');
// return $this->renderer->render($this,'showCreate', 'AE_basicPage',$template, $action);
// //return $this->renderer->render($this,'showCreate',$template, $partOnly ,$action ,$nextStep);
// // (SC_BaseObject $object, string $method, $template = null, $partOnly = false,$action=null,$nextStep=null)
// }
/**
* Displays a message indicating that the user does not have sufficient permissions