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