ILIAS  trunk Revision v11.0_alpha-1713-gd8962da2f67
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ActiveRecord.php
Go to the documentation of this file.
1 <?php
2 
26 #[\AllowDynamicProperties]
27 abstract 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 
66  $ar = self::getCalledClass();
67 
68  return $ar::returnDbTableName();
69  }
70 
71  public function setConnectorContainerName(string $connector_container_name): void
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  {
116  arObjectCache::store($this);
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  }
156  arObjectCache::store($this);
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);
359  arObjectCache::store($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 === []) {
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  }
398  arObjectCache::store($this);
399  }
400  }
401 
402  public function update(): void
403  {
404  $this->getArConnector()->update($this);
405  arObjectCache::store($this);
406  }
407 
408  public function delete(): void
409  {
410  $this->getArConnector()->delete($this);
411  arObjectCache::purge($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 }
static getFirstFromLastQuery()
buildFromArray(array $array)
static findOrGetInstance($primary_key, array $add_constructor_args=[])
static get(string $class_name)
fixDateField($field_name, string $value)
const UNKNONWN_EXCEPTION
static get(string $class, string $id)
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 _toCamelCase(string $str, bool $capitalise_first_char=false)
sleep($field_name)
static returnDbTableName()
static innerjoinAR(ActiveRecord $activeRecord, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
__call($name, $arguments)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$c
Definition: deliver.php:25
static where($where, $operator=null)
const COPY_DESTINATION_ID_EXISTS
static limit(int $start, int $end)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
setPrimaryFieldValue($value)
static innerjoin(string $tablename, $on_this, string $on_external, array $fields=[' *'], string $operator='=', bool $both_external=false)
getConnectorContainerName()
Return the Name of your Connector Table
get(string $class_name)
static fromCamelCase(string $str)
static getPrimaryFieldName(ActiveRecord $activeRecord)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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
static getArray(?string $key=null, string|array|null $values=null)
static dateFormat(string $date_format='d.m.Y - H:i:s')
static leftjoin(string $tablename, $on_this, string $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)