ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ActiveRecord.php
Go to the documentation of this file.
1<?php
2
26#[\AllowDynamicProperties]
27abstract class ActiveRecord
28{
29 protected bool $ar_safe_read = true;
30 protected string $connector_container_name = '';
31 protected bool $is_new = true;
32
33 public function getArConnector(): \arConnector
34 {
35 return arConnectorMap::get($this);
36 }
37
38 public function getArFieldList(): \arFieldList
39 {
40 return arFieldCache::get($this);
41 }
42
48 public static function returnDbTableName(): string
49 {
50 throw new arException(
52 'Implement getConnectorContainerName in your child-class'
53 );
54 }
55
59 public function getConnectorContainerName(): string
60 {
61 // WILL BE ABSTRACT TO REPLACE returnDbTableName() IN NEXT VERSION
62 if ($this->connector_container_name !== '' && $this->connector_container_name !== '0') {
64 }
65
67
68 return $ar::returnDbTableName();
69 }
70
72 {
73 $this->connector_container_name = $connector_container_name;
74 }
75
79 public function getPrimaryFieldValue()
80 {
81 $primary_fieldname = arFieldCache::getPrimaryFieldName($this);
82
83 return $this->{$primary_fieldname};
84 }
85
89 public function setPrimaryFieldValue($value): void
90 {
91 $primary_fieldname = arFieldCache::getPrimaryFieldName($this);
92
93 $this->{$primary_fieldname} = $value;
94 }
95
96 public function __construct(mixed $primary_key = 0)
97 {
98 $arFieldList = arFieldCache::get($this);
99
100 $primaryFieldName = $arFieldList->getPrimaryFieldName();
101 $this->{$primaryFieldName} = $primary_key;
102 if ($primary_key === 0) {
103 return;
104 }
105 if ($primary_key === null) {
106 return;
107 }
108 if ($primary_key === false) {
109 return;
110 }
111 $this->read();
112 }
113
114 public function storeObjectToCache(): void
115 {
117 }
118
119 public function asStdClass(): \stdClass
120 {
121 $return = new stdClass();
122 foreach ($this->getArFieldList()->getFields() as $arField) {
123 $fieldname = $arField->getName();
124 $return->{$fieldname} = $this->{$fieldname};
125 }
126
127 return $return;
128 }
129
133 public function asArray(): array
134 {
135 $return = [];
136 foreach ($this->getArFieldList()->getFields() as $arField) {
137 $fieldname = $arField->getName();
138 $return[$fieldname] = $this->{$fieldname};
139 }
140
141 return $return;
142 }
143
144 public function buildFromArray(array $array): static
145 {
146 $class = static::class;
147 $primary = $this->getArFieldList()->getPrimaryFieldName();
148 $primary_value = $array[$primary];
149 if ($primary_value && arObjectCache::isCached($class, $primary_value)) {
150 return arObjectCache::get($class, $primary_value);
151 }
152 foreach ($array as $field_name => $value) {
153 $waked = $this->wakeUp($field_name, $value);
154 $this->{$field_name} = $waked ?? $value;
155 }
157
158 return $this;
159 }
160
167 public function fixDateField($field_name, string $value)
168 {
169 if ($this->getArFieldList()->getFieldByName($field_name)->isDateField()) {
170 return $this->getArConnector()->fixDate($value);
171 }
172
173 return $value;
174 }
175
180 public function sleep($field_name)
181 {
182 return null;
183 }
184
190 public function wakeUp($field_name, $field_value)
191 {
192 return null;
193 }
194
198 final public function getArrayForConnector(): array
199 {
200 $data = [];
201 foreach ($this->getArFieldList()->getFields() as $arField) {
202 $field_name = $arField->getName();
203 $sleeped = $this->sleep($field_name);
204 $var = $sleeped ?? ($this->{$field_name});
205 $data[$field_name] = [$arField->getFieldType(), $var];
206 }
207
208 return $data;
209 }
210
211
212
213
214 //
215 // Collector Modifications
216 //
221 protected static function getCalledClass(): \ActiveRecord
222 {
223 $class = static::class;
224
225 return arCalledClassCache::get($class);
226 }
227
233 final public static function installDB(): bool
234 {
235 return self::getCalledClass()->installDatabase();
236 }
237
241 public function installConnector(): bool
242 {
243 return $this->installDatabase();
244 }
245
250 final public static function renameDBField(string $old_name, string $new_name): bool
251 {
252 return self::getCalledClass()->getArConnector()->renameField(self::getCalledClass(), $old_name, $new_name);
253 }
254
255 final public static function tableExists(): bool
256 {
257 return self::getCalledClass()->getArConnector()->checkTableExists(self::getCalledClass());
258 }
259
263 final public static function fieldExists(string $field_name): bool
264 {
265 return self::getCalledClass()->getArConnector()->checkFieldExists(self::getCalledClass(), $field_name);
266 }
267
271 final public static function removeDBField(string $field_name): bool
272 {
273 return self::getCalledClass()->getArConnector()->removeField(self::getCalledClass(), $field_name);
274 }
275
279 final protected function installDatabase(): bool
280 {
281 if (!self::tableExists()) {
282 $fields = [];
283 foreach ($this->getArFieldList()->getFields() as $arField) {
284 $fields[$arField->getName()] = $arField->getAttributesForConnector();
285 }
286
287 return $this->getArConnector()->installDatabase($this, $fields);
288 }
289
290 return $this->getArConnector()->updateDatabase($this);
291 }
292
296 final public static function updateDB(): bool
297 {
298 if (!self::tableExists()) {
299 self::getCalledClass()->installDatabase();
300
301 return true;
302 }
303
304 return self::getCalledClass()->getArConnector()->updateDatabase(self::getCalledClass());
305 }
306
310 final public static function resetDB(): bool
311 {
312 return self::getCalledClass()->getArConnector()->resetDatabase(self::getCalledClass());
313 }
314
318 final public static function truncateDB(): void
319 {
320 self::getCalledClass()->getArConnector()->truncateDatabase(self::getCalledClass());
321 }
322
326 final public static function flushDB(): void
327 {
328 self::truncateDB();
329 }
330
331 //
332 // CRUD
333 //
334 public function store(): void
335 {
336 $primary_fieldname = arFieldCache::getPrimaryFieldName($this);
337 $primary_value = $this->getPrimaryFieldValue();
338
339 if (!self::where([$primary_fieldname => $primary_value])->hasSets()) {
340 $this->create();
341 } else {
342 $this->update();
343 }
344 }
345
346 public function save(): void
347 {
348 $this->store();
349 }
350
351 public function create(): void
352 {
353 if ($this->getArFieldList()->getPrimaryField()->getSequence()) {
354 $primary_fieldname = arFieldCache::getPrimaryFieldName($this);
355 $this->{$primary_fieldname} = $this->getArConnector()->nextID($this);
356 }
357
358 $this->getArConnector()->create($this);
360 }
361
365 public function copy(int $new_id = 0): self
366 {
367 if (self::where([$this->getArFieldList()->getPrimaryFieldName() => $new_id])->hasSets()) {
369 }
370 $new_obj = clone($this);
371 $new_obj->setPrimaryFieldValue($new_id);
372
373 return $new_obj;
374 }
375
376 public function afterObjectLoad(): void
377 {
378 }
379
383 public function read(): void
384 {
385 $records = $this->getArConnector()->read($this);
386 if ($this->ar_safe_read && is_array($records) && $records === []) {
387 throw new arException(arException::RECORD_NOT_FOUND, $this->getPrimaryFieldValue());
388 }
389 if (!$this->ar_safe_read && is_array($records) && $records === []) {
390 $this->is_new = true;
391 }
392 $records = is_array($records) ? $records : [];
393 foreach ($records as $record) {
394 foreach (array_keys($this->getArrayForConnector()) as $k) {
395 $waked = $this->wakeUp($k, $record->{$k} ?? null);
396 $this->{$k} = $waked ?? $record->{$k} ?? null;
397 }
399 }
400 }
401
402 public function update(): void
403 {
404 $this->getArConnector()->update($this);
406 }
407
408 public function delete(): void
409 {
410 $this->getArConnector()->delete($this);
412 }
413
414
415
416 //
417 // Collection
418 //
422 public static function preloadObjects(): array
423 {
424 return self::get();
425 }
426
430 public static function additionalParams(array $additional_params): \ActiveRecordList
431 {
432 $activeRecordList = new ActiveRecordList(self::getCalledClass());
433 $activeRecordList->additionalParams($additional_params);
434
435 return $activeRecordList;
436 }
437
441 public static function find($primary_key, array $add_constructor_args = []): ?\ActiveRecord
442 {
446 try {
447 $class_name = static::class;
448 if (!arObjectCache::isCached($class_name, $primary_key)) {
449 $obj = arFactory::getInstance($class_name, $primary_key, $add_constructor_args);
450 $obj->storeObjectToCache();
451
452 return $obj;
453 }
454 } catch (arException) {
455 return null;
456 }
457
458 try {
459 $obj = arObjectCache::get($class_name, $primary_key);
460 } catch (arException) {
461 return null;
462 }
463
464 return $obj;
465 }
466
472 public static function findOrFail($primary_key, array $add_constructor_args = []): \ActiveRecord
473 {
474 $obj = self::find($primary_key, $add_constructor_args);
475 if (is_null($obj)) {
477 }
478
479 return $obj;
480 }
481
487 public static function findOrGetInstance($primary_key, array $add_constructor_args = []): \ActiveRecord
488 {
489 $obj = self::find($primary_key, $add_constructor_args);
490 if ($obj !== null) {
491 return $obj;
492 }
493
494 $class_name = static::class;
495 $obj = arFactory::getInstance($class_name, 0, $add_constructor_args);
496 $obj->setPrimaryFieldValue($primary_key);
497 $obj->is_new = true;
498 $obj->storeObjectToCache();
499
500 return $obj;
501 }
502
507 public static function where($where, $operator = null): \ActiveRecordList
508 {
509 $activeRecordList = new ActiveRecordList(self::getCalledClass());
510 $activeRecordList->where($where, $operator);
511
512 return $activeRecordList;
513 }
514
520 public static function innerjoinAR(
521 ActiveRecord $activeRecord,
522 $on_this,
523 string $on_external,
524 array $fields = ['*'],
525 string $operator = '=',
526 bool $both_external = false
527 ): \ActiveRecordList {
528 return self::innerjoin(
529 $activeRecord->getConnectorContainerName(),
530 $on_this,
531 $on_external,
532 $fields,
533 $operator,
534 $both_external
535 );
536 }
537
544 public static function innerjoin(
545 string $tablename,
546 $on_this,
547 string $on_external,
548 array $fields = ['*'],
549 string $operator = '=',
550 bool $both_external = false
551 ): \ActiveRecordList {
552 $activeRecordList = new ActiveRecordList(self::getCalledClass());
553
554 return $activeRecordList->innerjoin($tablename, $on_this, $on_external, $fields, $operator, $both_external);
555 }
556
563 public static function leftjoin(
564 string $tablename,
565 $on_this,
566 string $on_external,
567 array $fields = ['*'],
568 string $operator = '=',
569 bool $both_external = false
570 ): \ActiveRecordList {
571 $activeRecordList = new ActiveRecordList(self::getCalledClass());
572
573 return $activeRecordList->leftjoin($tablename, $on_this, $on_external, $fields, $operator, $both_external);
574 }
575
579 public static function orderBy(string $orderBy, string $orderDirection = 'ASC'): \ActiveRecordList
580 {
581 $activeRecordList = new ActiveRecordList(self::getCalledClass());
582 $activeRecordList->orderBy($orderBy, $orderDirection);
583
584 return $activeRecordList;
585 }
586
587 public static function dateFormat(string $date_format = 'd.m.Y - H:i:s'): \ActiveRecordList
588 {
589 $activeRecordList = new ActiveRecordList(self::getCalledClass());
590 $activeRecordList->dateFormat($date_format);
591
592 return $activeRecordList;
593 }
594
599 public static function limit(int $start, int $end): \ActiveRecordList
600 {
601 $activeRecordList = new ActiveRecordList(self::getCalledClass());
602 $activeRecordList->limit($start, $end);
603
604 return $activeRecordList;
605 }
606
607 public static function affectedRows(): int
608 {
609 $activeRecordList = new ActiveRecordList(self::getCalledClass());
610
611 return $activeRecordList->affectedRows();
612 }
613
614 public static function count(): int
615 {
616 return self::affectedRows();
617 }
618
622 public static function get(): array
623 {
624 $activeRecordList = new ActiveRecordList(self::getCalledClass());
625
626 return $activeRecordList->get();
627 }
628
629 public static function debug(): \ActiveRecordList
630 {
631 $activeRecordList = new ActiveRecordList(self::getCalledClass());
632
633 return $activeRecordList->debug();
634 }
635
636 public static function first(): ?\ActiveRecord
637 {
638 $activeRecordList = new ActiveRecordList(self::getCalledClass());
639
640 return $activeRecordList->first();
641 }
642
643 public static function getCollection(): \ActiveRecordList
644 {
645 return new ActiveRecordList(self::getCalledClass());
646 ;
647 }
648
649 public static function last(): ?\ActiveRecord
650 {
651 $activeRecordList = new ActiveRecordList(self::getCalledClass());
652
653 return $activeRecordList->last();
654 }
655
659 public static function getFirstFromLastQuery(): ?\ActiveRecord
660 {
661 $activeRecordList = new ActiveRecordList(self::getCalledClass());
662
663 return $activeRecordList->getFirstFromLastQuery();
664 }
665
666 public static function connector(arConnector $arConnector): \ActiveRecordList
667 {
668 $activeRecordList = new ActiveRecordList(self::getCalledClass());
669
670 return $activeRecordList->connector($arConnector);
671 }
672
673 public static function raw(bool $set_raw = true): \ActiveRecordList
674 {
675 $activeRecordList = new ActiveRecordList(self::getCalledClass());
676
677 return $activeRecordList->raw($set_raw);
678 }
679
684 public static function getArray(?string $key = null, string|array|null $values = null): array
685 {
686 $activeRecordList = new ActiveRecordList(self::getCalledClass());
687
688 return $activeRecordList->getArray($key, $values);
689 }
690
691 //
692 // Magic Methods & Helpers
693 //
700 public function __call($name, $arguments)
701 {
702 // Getter
703 if (preg_match("/get([a-zA-Z]*)/u", (string) $name, $matches) && (is_countable($arguments) ? count(
704 $arguments
705 ) : 0) === 0) {
706 return $this->{self::fromCamelCase($matches[1])};
707 }
708 // Setter
709 if (!preg_match("/set([a-zA-Z]*)/u", (string) $name, $matches)) {
710 return null;
711 }
712 if (count($arguments) !== 1) {
713 return null;
714 }
715 $this->{self::fromCamelCase($matches[1])} = $arguments[0];
716 return null;
717 }
718
719 public static function _toCamelCase(string $str, bool $capitalise_first_char = false): ?string
720 {
721 if ($capitalise_first_char) {
722 $str[0] = strtoupper($str[0]);
723 }
724
725 return preg_replace_callback('/_([a-z])/', fn($c): string => strtoupper($c[1]), $str);
726 }
727
728 protected static function fromCamelCase(string $str): ?string
729 {
730 $str[0] = strtolower($str[0]);
731
732 return preg_replace_callback('/([A-Z])/', fn($c): string => "_" . strtolower($c[1]), $str);
733 }
734}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
innerjoin(string $tablename, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
leftjoin(string $tablename, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static flushDB()
@depracated never use in ILIAS Core, Plugins only
getConnectorContainerName()
@description Return the Name of your Connector Table
static removeDBField(string $field_name)
static connector(arConnector $arConnector)
setPrimaryFieldValue($value)
string $connector_container_name
fixDateField($field_name, string $value)
static where($where, $operator=null)
static returnDbTableName()
static _toCamelCase(string $str, bool $capitalise_first_char=false)
sleep($field_name)
static dateFormat(string $date_format='d.m.Y - H:i:s')
__call($name, $arguments)
static getArray(?string $key=null, string|array|null $values=null)
static renameDBField(string $old_name, string $new_name)
buildFromArray(array $array)
static innerjoinAR(ActiveRecord $activeRecord, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
static raw(bool $set_raw=true)
static fromCamelCase(string $str)
wakeUp($field_name, $field_value)
setConnectorContainerName(string $connector_container_name)
static orderBy(string $orderBy, string $orderDirection='ASC')
static getCalledClass()
@description Returns an instance of the instatiated calling active record (needs to be done in static...
static getFirstFromLastQuery()
static innerjoin(string $tablename, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
static leftjoin(string $tablename, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
static limit(int $start, int $end)
static additionalParams(array $additional_params)
__construct(mixed $primary_key=0)
copy(int $new_id=0)
static findOrFail($primary_key, array $add_constructor_args=[])
Tries to find the object and throws an Exception if object is not found, instead of returning null.
static fieldExists(string $field_name)
static findOrGetInstance($primary_key, array $add_constructor_args=[])
static get(string $class_name)
static get(ActiveRecord $activeRecord)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const COPY_DESTINATION_ID_EXISTS
const UNKNONWN_EXCEPTION
static get(ActiveRecord $activeRecord)
static getPrimaryFieldName(ActiveRecord $activeRecord)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static purge(ActiveRecord $activeRecord)
static isCached($class, $id)
static get(string $class, string $id)
static store(ActiveRecord $activeRecord)
$c
Definition: deliver.php:25
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
get(string $class_name)