ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilDclBaseFieldModel.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 {
23  protected string $id = "";
24  protected int $table_id = 0;
25  protected string $title = "";
26  protected string $description = "";
27  protected int $datatype_id = 0;
28  protected ?int $order = null;
29  protected bool $unique = false;
31  protected array $property = [];
32  protected bool $exportable = false;
33  protected ?ilDclDatatype $datatype = null;
37  protected ?int $storage_location_override = null;
41  public const PROP_LENGTH = "lenght";
42  public const PROP_REGEX = "regex";
43  public const PROP_REFERENCE = "table_id";
44  public const PROP_URL = "url";
45  public const PROP_REFERENCE_LINK = "reference_link";
46  public const PROP_WIDTH = "width";
47  public const PROP_HEIGHT = "height";
48  public const PROP_LEARNING_PROGRESS = "learning_progress";
49  public const PROP_ILIAS_REFERENCE_LINK = "ILIAS_reference_link";
50  public const PROP_N_REFERENCE = "multiple_selection";
51  public const PROP_FORMULA_EXPRESSION = "expression";
52  public const PROP_DISPLAY_COPY_LINK_ACTION_MENU = "display_action_menu";
53  public const PROP_LINK_DETAIL_PAGE_TEXT = "link_detail_page_text";
54  public const PROP_LINK_DETAIL_PAGE_MOB = "link_detail_page_mob";
55  public const PROP_SUPPORTED_FILE_TYPES = "supported_file_types";
56  public const PROP_PLUGIN_HOOK_NAME = "plugin_hook_name";
57  // type of table il_dcl_view
58  public const EDIT_VIEW = 2;
59  public const EXPORTABLE_VIEW = 4;
60 
61  protected ilDBInterface $db;
62  protected ilLanguage $lng;
63 
64  public function __construct(int $a_id = 0)
65  {
66  global $DIC;
67  $this->db = $DIC->database();
68  $this->lng = $DIC->language();
69 
70  if ($a_id != 0) {
71  $this->id = (string) $a_id;
72  $this->doRead();
73  }
74  }
75 
79  public static function _getTitleInvalidChars(bool $a_as_regex = true): string
80  {
81  if ($a_as_regex) {
82  return '/^[^<>\\\\":]*$/i';
83  } else {
84  return '\ < > " :';
85  }
86  }
87 
88  public static function _getFieldIdByTitle(string $title, int $table_id): int
89  {
90  global $DIC;
91  $ilDB = $DIC->database();
92 
93  $result = $ilDB->query(
94  'SELECT id FROM il_dcl_field WHERE title = ' . $ilDB->quote($title, 'text') . ' AND table_id = '
95  . $ilDB->quote($table_id, 'integer')
96  );
97  $id = 0;
98  while ($rec = $ilDB->fetchAssoc($result)) {
99  $id = $rec['id'];
100  }
101 
102  return $id;
103  }
104 
109  public function setId($a_id): void
110  {
111  $this->id = (string) $a_id;
112  }
113 
117  public function getId(): string
118  {
119  return $this->id;
120  }
121 
125  public function setTableId(int $a_id): void
126  {
127  $this->table_id = $a_id;
128  }
129 
133  public function getTableId(): int
134  {
135  return $this->table_id;
136  }
137 
141  public function setTitle(string $a_title): void
142  {
143  //title cannot begin with _ as this is saved for other purposes. make __ instead.
144  if (substr($a_title, 0, 1) == "_" && substr($a_title, 0, 2) != "__") {
145  $a_title = "_" . $a_title;
146  }
147  $this->title = $a_title;
148  }
149 
153  public function getTitle(): string
154  {
155  return $this->title;
156  }
157 
161  public function setDescription(string $a_desc): void
162  {
163  $this->description = $a_desc;
164  }
165 
169  public function getDescription(): string
170  {
171  return $this->description;
172  }
173 
177  public function setDatatypeId(int $a_id): void
178  {
179  //unset the cached datatype.
180  $this->datatype = null;
181  $this->datatype_id = $a_id;
182  }
183 
187  public function getDatatypeId(): ?int
188  {
189  if ($this->isStandardField()) {
191  }
192 
193  return $this->datatype_id;
194  }
195 
196  public function isUnique(): bool
197  {
198  return $this->unique;
199  }
200 
201  public function setUnique(?bool $unique): void
202  {
203  $this->unique = (bool) $unique;
204  }
205 
206  public function getDatatype(): ilDclDatatype
207  {
208  $this->loadDatatype();
209 
210  return $this->datatype;
211  }
212 
213  public function getDatatypeTitle(): string
214  {
215  $this->loadDatatype();
216  return $this->datatype->getTitle();
217  }
218 
219  public function getPresentationTitle(): string
220  {
221  return $this->lng->txt('dcl_' . $this->getDatatypeTitle());
222  }
223 
224  public function getPresentationDescription(): string
225  {
226  return $this->lng->txt('dcl_' . $this->getDatatypeTitle() . '_desc');
227  }
228 
232  public function getStorageLocation(): ?int
233  {
234  if ($this->getStorageLocationOverride() !== null) {
235  return $this->getStorageLocationOverride();
236  }
237 
238  $this->loadDatatype();
239 
240  return $this->datatype->getStorageLocation();
241  }
242 
246  protected function loadDatatype(): void
247  {
248  if ($this->datatype == null) {
249  $this->datatype = ilDclCache::getDatatype($this->datatype_id);
250  }
251  }
252 
256  protected function loadTableFieldSetting(): void
257  {
258  $tablefield_setting = ilDclTableFieldSetting::getInstance($this->getTableId(), $this->getId());
259  $this->exportable = $tablefield_setting->isExportable();
260  $this->order = $tablefield_setting->getFieldOrder();
261  }
262 
266  public function getExportable(): bool
267  {
268  if (!isset($this->exportable)) {
269  $this->loadExportability();
270  }
271 
272  return $this->exportable;
273  }
274 
278  private function loadExportability(): void
279  {
280  if ($this->exportable == null) {
281  $this->loadTableFieldSetting();
282  }
283  }
284 
285  public function toArray(): array
286  {
287  return (array) $this;
288  }
289 
290  public function isStandardField(): bool
291  {
292  return false;
293  }
294 
295  public function doRead(): void
296  {
297  //THEN 1 ELSE 0 END AS has_options FROM il_dcl_field f WHERE id = ".$ilDB->quote($this->getId(),"integer");
298  $query = "SELECT * FROM il_dcl_field WHERE id = " . $this->db->quote($this->getId(), "integer");
299  $set = $this->db->query($query);
300  $rec = $this->db->fetchAssoc($set);
301 
302  if ($rec) {
303  $this->setTableId($rec["table_id"]);
304  if (null !== $rec["title"]) {
305  $this->setTitle($rec["title"]);
306  }
307  if (null !== $rec["description"]) {
308  $this->setDescription($rec["description"]);
309  }
310  $this->setDatatypeId($rec["datatype_id"]);
311  $this->setUnique((bool) $rec["is_unique"]);
312  }
313 
314  $this->loadProperties();
315  $this->loadTableFieldSetting();
316  }
317 
321  public function buildFromDBRecord(array $rec): void
322  {
323  $this->setId($rec["id"]);
324  $this->setTableId($rec["table_id"]);
325  $this->setTitle($rec["title"]);
326  $this->setDescription($rec["description"]);
327  $this->setDatatypeId($rec["datatype_id"]);
328  $this->setUnique($rec["is_unique"] ?? null);
329  }
330 
331  public function doCreate(): void
332  {
333  if (!ilDclTable::_tableExists($this->getTableId())) {
334  throw new ilException("The field does not have a related table!");
335  }
336 
337  $id = $this->db->nextId("il_dcl_field");
338  $this->setId($id);
339  $query = "INSERT INTO il_dcl_field (" . "id" . ", table_id" . ", datatype_id" . ", title" . ", description" . ", is_unique"
340  . " ) VALUES (" . $this->db->quote($this->getId(), "integer") . "," . $this->db->quote(
341  $this->getTableId(),
342  "integer"
343  ) . ","
344  . $this->db->quote($this->getDatatypeId(), "integer") . "," . $this->db->quote($this->getTitle(), "text") . ","
345  . $this->db->quote($this->getDescription(), "text") . "," . $this->db->quote($this->isUnique(), "integer") . ")";
346  $this->db->manipulate($query);
347 
348  $this->updateTableFieldSetting();
349 
350  $this->addToTableViews();
351  }
352 
356  protected function addToTableViews(): void
357  {
358  foreach (ilDclTableView::getAllForTableId($this->table_id) as $tableview) {
359  $tableview->createFieldSetting($this->id);
360  }
361  }
362 
363  public function doUpdate(): void
364  {
365  $this->db->update(
366  "il_dcl_field",
367  [
368  "table_id" => [
369  "integer",
370  $this->getTableId(),
371  ],
372  "datatype_id" => [
373  "text",
374  $this->getDatatypeId(),
375  ],
376  "title" => [
377  "text",
378  $this->getTitle(),
379  ],
380  "description" => [
381  "text",
382  $this->getDescription(),
383  ],
384  "is_unique" => [
385  "integer",
386  $this->isUnique(),
387  ],
388  ],
389  [
390  "id" => [
391  "integer",
392  $this->getId(),
393  ],
394  ]
395  );
396  $this->updateTableFieldSetting();
397  $this->updateProperties();
398  }
399 
403  public function updateProperties(): void
404  {
405  foreach ($this->property as $prop) {
406  $prop->store();
407  }
408  }
409 
413  protected function updateTableFieldSetting(): void
414  {
415  $tablefield_setting = ilDclTableFieldSetting::getInstance($this->getTableId(), $this->getId());
416  $tablefield_setting->setExportable($this->exportable);
417  $tablefield_setting->setFieldOrder($this->getOrder());
418  $tablefield_setting->store();
419  }
420 
424  public function doDelete(): void
425  {
426  // delete tablefield setting.
427  ilDclTableFieldSetting::getInstance($this->getTableId(), $this->getId())->delete();
428 
429  $query = "DELETE FROM il_dcl_field_prop WHERE field_id = " . $this->db->quote($this->getId(), "text");
430  $this->db->manipulate($query);
431 
432  $query = "DELETE FROM il_dcl_field WHERE id = " . $this->db->quote($this->getId(), "text");
433  $this->db->manipulate($query);
434 
435  foreach ($this->getViewSettings() as $field_setting) {
436  $field_setting->delete();
437  }
438  }
439 
443  public function getViewSettings(): array
444  {
445  return ilDclTableViewFieldSetting::where(['field' => $this->getId()])->get();
446  }
447 
448  public function getViewSetting(int $tableview_id): ilDclTableViewFieldSetting
449  {
450  return ilDclTableViewFieldSetting::getTableViewFieldSetting($this->getId(), $tableview_id);
451  }
452 
453  public function getOrder(): int
454  {
455  if ($this->order == null) {
456  $this->loadTableFieldSetting();
457  }
458 
459  return !$this->order ? 0 : $this->order;
460  }
461 
462  public function setOrder(int $order): void
463  {
464  $this->order = $order;
465  }
466 
470  protected function loadProperties(): void
471  {
472  $this->property = ilDclCache::getFieldProperties($this->getId());
473  }
474 
478  public function hasProperty(string $key): bool
479  {
480  $this->loadProperties();
481 
482  return (isset($this->property[$key]) && $this->property[$key]->getValue() != null);
483  }
484 
485  public function getProperty(string $key): mixed
486  {
487  $instance = $this->getPropertyInstance($key);
488 
489  return ($instance !== null) ? $instance->getValue() : null;
490  }
491 
492  public function getPropertyInstance(string $key): ?ilDclFieldProperty
493  {
494  $this->loadProperties();
495  if ($this->hasProperty($key)) {
496  return $this->property[$key];
497  }
498 
499  return null;
500  }
501 
502  public function setProperty(string $key, $value): ?ilDclFieldProperty
503  {
504  $this->loadProperties();
505  if (isset($this->property[$key])) {
506  $this->property[$key]->setValue($value);
507  } else {
508  $property = new ilDclFieldProperty();
509  $property->setName($key);
510  $property->setFieldId((int) $this->getId());
511  $property->setValue($value);
512 
513  $this->property[$key] = $property;
514  }
515 
516  return $this->property[$key];
517  }
518 
522  public function getValidFieldProperties(): array
523  {
524  return [];
525  }
526 
527  public function checkValidityFromForm(ilPropertyFormGUI &$form, ?int $record_id = null): void
528  {
529  $value = $form->getInput('field_' . $this->getId());
530  $this->checkValidity($value, $record_id);
531  }
532 
538  public function checkValidity($value, ?int $record_id = null): bool
539  {
540  //Don't check empty values
541  if (!isset($value)) {
542  return true;
543  }
544 
545  if ($this->isUnique()) {
546  $table = ilDclCache::getTableCache($this->getTableId());
547  foreach ($table->getRecords() as $record) {
548  if ($record->getId() !== $record_id || $record_id === 0) {
549  if ($this->areEqual($record->getRecordFieldValue($this->getId()), $value)) {
551  }
552  }
553  }
554  }
555 
556  return true;
557  }
558 
559  protected function areEqual($value_1, $value_2): bool
560  {
561  return $this->normalizeValue($value_1) === $this->normalizeValue($value_2);
562  }
563 
564  protected function normalizeValue(mixed $value)
565  {
566  if (is_string($value)) {
567  $value = trim(preg_replace("/\\s+/uism", " ", $value));
568  }
569 
570  return $value;
571  }
572 
576  public function cloneStructure(int $original_id): void
577  {
578  $original = ilDclCache::getFieldCache($original_id);
579  $this->setTitle($original->getTitle());
580  $this->setDatatypeId($original->getDatatypeId());
581  $this->setDescription($original->getDescription());
582  $this->setOrder($original->getOrder());
583  $this->setUnique($original->isUnique());
584  $this->setExportable($original->getExportable());
585  $this->doCreate();
586  $this->cloneProperties($original);
587 
588  // mandatory for all cloning functions
589  ilDclCache::setCloneOf($original_id, (int) $this->getId(), ilDclCache::TYPE_FIELD);
590  }
591 
592  public function afterClone(array $records)
593  {
594  foreach ($records as $rec) {
595  ilDclCache::getRecordFieldCache($rec, $this)->afterClone();
596  }
597  }
598 
599  public function cloneProperties(ilDclBaseFieldModel $originalField): void
600  {
601  $orgProps = $originalField->getValidFieldProperties();
602  if (count($orgProps) == 0) {
603  return;
604  }
605  foreach ($orgProps as $prop_name) {
606  $fieldprop_obj = new ilDclFieldProperty();
607  $fieldprop_obj->setFieldId((int) $this->getId());
608  $fieldprop_obj->setName($prop_name);
609 
610  $value = $originalField->getProperty($prop_name);
611 
612  if (
613  $prop_name == ilDclBaseFieldModel::PROP_REFERENCE &&
614  (
617  )
618  ) {
619  $value = null;
620  }
621 
622  if ($value) {
623  $fieldprop_obj->setValue($value);
624  $fieldprop_obj->create();
625  }
626  }
627  }
628 
629  public function setExportable(bool $exportable): void
630  {
631  $this->exportable = $exportable;
632  }
633 
634  public function allowFilterInListView(): bool
635  {
636  return true;
637  }
638 
643  public function getRecordQuerySortObject(
644  string $direction = "asc",
645  bool $sort_by_status = false
647  $sql_obj = new ilDclRecordQueryObject();
648 
649  $select_str = "sort_stloc_{$this->getId()}.value AS field_{$this->getId()}";
650  $join_str
651  = "LEFT JOIN il_dcl_record_field AS sort_record_field_{$this->getId()} ON (sort_record_field_{$this->getId()}.record_id = record.id AND sort_record_field_{$this->getId()}.field_id = "
652  . $this->db->quote($this->getId(), 'integer') . ") ";
653  $join_str .= "LEFT JOIN il_dcl_stloc{$this->getStorageLocation()}_value AS sort_stloc_{$this->getId()} ON (sort_stloc_{$this->getId()}.record_field_id = sort_record_field_{$this->getId()}.id)";
654 
655  $sql_obj->setSelectStatement($select_str);
656  $sql_obj->setJoinStatement($join_str);
657  $sql_obj->setOrderStatement("field_{$this->getId()} $direction, ID ASC");
658 
659  return $sql_obj;
660  }
661 
666  public function getRecordQueryFilterObject(
667  $filter_value = "",
668  ?ilDclBaseFieldModel $sort_field = null
670  return null;
671  }
672 
676  public function getSortField(): string
677  {
678  return $this->getTitle();
679  }
680 
684  public function hasNumericSorting(): bool
685  {
687  return true;
688  }
689 
690  return false;
691  }
692 
698  public function checkFieldCreationInput(ilPropertyFormGUI $form): bool
699  {
700  return true;
701  }
702 
706  public function getStorageLocationOverride(): ?int
707  {
709  }
710 
714  public function setStorageLocationOverride(?int $storage_location_override): void
715  {
716  $this->storage_location_override = $storage_location_override;
717  }
718 
719  public function fillHeaderExcel(ilExcel $worksheet, int &$row, int &$col): void
720  {
721  $worksheet->setCell($row, $col, $this->getTitle());
722  $col++;
723  }
724 
725  public function checkTitlesForImport(array &$titles, array &$import_fields): void
726  {
727  foreach ($titles as $k => $title) {
728  if (!mb_detect_encoding($title, "UTF-8", true) == "UTF-8") {
729  $title = mb_convert_encoding($title, 'UTF-8', 'ISO-8859-1');
730  }
731  if ($title == $this->getTitle()) {
732  $import_fields[$k] = $this;
733  }
734  }
735  }
736 
740  public function storePropertiesFromForm(ilPropertyFormGUI $form): void
741  {
742  $field_props = $this->getValidFieldProperties();
743  $representation = ilDclFieldFactory::getFieldRepresentationInstance($this);
744 
745  foreach ($field_props as $property) {
746  $value = $form->getInput($representation->getPropertyInputFieldId($property));
747 
748  // save non empty values and set them to null, when they already exist. Do not override plugin-hook when already set.
749  if (!empty($value) || ($this->getPropertyInstance($property) != null && $property != self::PROP_PLUGIN_HOOK_NAME)) {
750  $this->setProperty($property, $value)?->store();
751  }
752  }
753  }
754 
758  public function fillPropertiesForm(ilPropertyFormGUI &$form): bool
759  {
760  $values = [
761  'table_id' => $this->getTableId(),
762  'field_id' => $this->getId(),
763  'title' => $this->getTitle(),
764  'datatype' => $this->getDatatypeId(),
765  'description' => $this->getDescription(),
766  'unique' => $this->isUnique(),
767  ];
768 
769  $properties = $this->getValidFieldProperties();
770  foreach ($properties as $prop) {
771  $values['prop_' . $prop] = $this->getProperty($prop);
772  }
773 
774  $form->setValuesByArray($values);
775 
776  return true;
777  }
778 
783  public function isConfirmationRequired(ilPropertyFormGUI $form): bool
784  {
785  return false;
786  }
787 
792  {
793  $ilConfirmationGUI = new ilConfirmationGUI();
794  $ilConfirmationGUI->setFormAction($form->getFormAction());
795  $ilConfirmationGUI->addHiddenItem('confirmed', "1");
796  $ilConfirmationGUI->addHiddenItem('field_id', $form->getInput('field_id'));
797  $ilConfirmationGUI->addHiddenItem('title', $form->getInput('title'));
798  $ilConfirmationGUI->addHiddenItem('description', $form->getInput('description'));
799  $ilConfirmationGUI->addHiddenItem('datatype', $form->getInput('datatype'));
800  $ilConfirmationGUI->addHiddenItem('unique', $form->getInput('unique'));
801  $ilConfirmationGUI->setConfirm($this->lng->txt('dcl_update_field'), 'update');
802  $ilConfirmationGUI->setCancel($this->lng->txt('cancel'), 'edit');
803 
804  return $ilConfirmationGUI;
805  }
806 }
hasProperty(string $key)
Checks if a certain property for a field is set.
checkTitlesForImport(array &$titles, array &$import_fields)
getConfirmationGUI(ilPropertyFormGUI $form)
called by ilDclFieldEditGUI if isConfirmationRequired returns true
checkFieldCreationInput(ilPropertyFormGUI $form)
Checks input of specific fields befor saving.
getRecordQueryFilterObject( $filter_value="", ?ilDclBaseFieldModel $sort_field=null)
Returns a query-object for building the record-loader-sql-query.
checkValidityFromForm(ilPropertyFormGUI &$form, ?int $record_id=null)
getValue()
Get the value that is displayed in the input client side.
Definition: Group.php:47
static getFieldRepresentationInstance(ilDclBaseFieldModel $field)
isConfirmationRequired(ilPropertyFormGUI $form)
called by ilDclFieldEditGUI when updating field properties if you overwrite this method, remember to also overwrite getConfirmationGUI
doDelete()
Remove field and properties.
storePropertiesFromForm(ilPropertyFormGUI $form)
called when saving the &#39;edit field&#39; form
buildFromDBRecord(array $rec)
Builds model from db record.
loadTableFieldSetting()
loadTableFieldSetting
static getFieldCache(int $field_id=0)
updateProperties()
Update properties of this field in Database.
getSortField()
Returns the sort-field id.
static _getDatatypeForId(string $id)
gives you the datatype id of a specified standard field.
fillPropertiesForm(ilPropertyFormGUI &$form)
called to fill the &#39;edit field&#39; form
static _getFieldIdByTitle(string $title, int $table_id)
getStorageLocation()
Get storage location for the model.
static where($where, $operator=null)
checkValidity($value, ?int $record_id=null)
Check if input is valid.
getInput(string $a_post_var, bool $ensureValidation=true)
Returns the input of an item, if item provides getInput method and as fallback the value of the HTTP-...
addToTableViews()
create ilDclTableViewFieldSettings for this field in each tableview
loadExportability()
Load exportability.
static getDatatype(int $datatyp_id)
Get cached datatypes.
setCell(int $a_row, int $col, $value, ?string $datatype=null, bool $disable_strip_tags_for_strings=false)
Set cell value.
loadProperties()
Get all properties of a field.
setDatatypeId(int $a_id)
Set datatype id.
static getTableCache(int $table_id=null)
static getTableViewFieldSetting(string $id, int $tableview_id)
cloneProperties(ilDclBaseFieldModel $originalField)
const PROP_LENGTH
General properties.
global $DIC
Definition: shib_login.php:25
getViewSetting(int $tableview_id)
setValuesByArray(array $a_values, bool $a_restrict_to_value_keys=false)
static setCloneOf(int $old, int $new, string $type)
static getInstance(int $table_id, string $field)
getDescription()
Get description.
loadDatatype()
Load datatype for model.
updateTableFieldSetting()
update exportable and fieldorder
int $storage_location_override
With this property the datatype-storage-location can be overwritten.
hasNumericSorting()
Set to true, when the sorting should be handled numerical.
fillHeaderExcel(ilExcel $worksheet, int &$row, int &$col)
getRecordQuerySortObject(string $direction="asc", bool $sort_by_status=false)
Returns a query-object for building the record-loader-sql-query.
setStorageLocationOverride(?int $storage_location_override)
setTitle(string $a_title)
Set title.
setDescription(string $a_desc)
Set description.
getValidFieldProperties()
Returns all valid properties for a field-type.
static getRecordFieldCache(object $record, object $field)
static getAllForTableId(int $table_id)
setTableId(int $a_id)
Set table id.
static _tableExists(int $table_id)
setProperty(string $key, $value)
static getFieldProperties(string $field_id)
Cache Field properties.
getDatatypeId()
Get datatype_id.
static _getTitleInvalidChars(bool $a_as_regex=true)
All valid chars for filed titles.