19 public const FIELDS_ALL = self::FIELDS_MAIN|self::FIELDS_UF;
21 private static $entity = [];
24 private $tablet =
null;
26 private $tabletFields = [];
28 private $tabletUserFields = [];
34 private $cacheModifyed = [];
37 private $fieldsCount = 0;
38 private $aliases = [];
39 private $fieldMask = [];
40 private $fetchCutMask;
44 $this->initEntityTablet();
45 $this->initEntityCache();
48 $this->fetchCutMask = [];
58 $className = get_called_class();
59 if (empty(self::$entity[$className]))
62 self::$entity[$className] = $entity;
65 return self::$entity[$className];
80 $entity = static::getEntity();
81 $parameters = $entity->prepareTabletQueryParameters($parameters);
82 $entity->result = $entity->getTablet()->getList($parameters);
97 public static function getRow(array $parameters): ?array
99 $parameters[
'limit'] = 1;
100 $result = static::getList($parameters);
101 $row = $result->fetch();
103 return (is_array($row) ? $row :
null);
114 if ($this->result ===
null)
116 $row = $this->result->fetch($converter);
119 $this->result =
null;
120 $this->fetchCutMask = [];
123 if (empty($this->fields))
125 if (!isset($row[
'ID']))
128 $this->setEntityCacheItem((
int)$row[
'ID'], $row,
true);
129 if (!empty($this->fetchCutMask))
130 $row = array_diff_key($row, $this->fetchCutMask);
141 static::getEntity()->clearEntityCache();
154 $entity = static::getEntity();
156 static::normalize($data);
158 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_BEFORE_ADD))
162 ORM\Data\DataManager::EVENT_ON_BEFORE_ADD,
167 $event->mergeData($data);
168 if ($event->getErrors($result))
172 static::prepareForAdd($result,
null, $data);
173 if (!$result->isSuccess())
177 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_ADD))
181 ORM\Data\DataManager::EVENT_ON_ADD,
188 $result = $entity->getTablet()->add($data[
'fields']);
189 $success = $result->isSuccess();
192 $data[
'fields'] = $result->getData();
193 if ($entity->fieldsCount > 0)
194 $entity->setEntityCacheItem((
int)$result->getId(), $result->getData(),
false);
197 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_AFTER_ADD))
201 ORM\Data\DataManager::EVENT_ON_AFTER_ADD,
203 'id' => $result->getId(),
204 'fields' => $data[
'fields'],
205 'external_fields' => $data[
'external_fields'],
206 'actions' => $data[
'actions'],
207 'success' => $success
214 if ($success && !empty($data[
'actions']))
215 static::runAddExternalActions($result->getId(), $data);
217 unset($success, $entity);
233 $entity = static::getEntity();
235 static::normalize($data);
237 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_BEFORE_UPDATE))
241 ORM\Data\DataManager::EVENT_ON_BEFORE_UPDATE,
244 'fields' => $data[
'fields'],
245 'external_fields' => $data[
'external_fields'],
246 'actions' => $data[
'actions']
251 $event->mergeData($data);
252 if ($event->getErrors($result))
256 static::prepareForUpdate($result, $id, $data);
257 if (!$result->isSuccess())
261 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_UPDATE))
265 ORM\Data\DataManager::EVENT_ON_UPDATE,
268 'fields' => $data[
'fields'],
269 'external_fields' => $data[
'external_fields'],
270 'actions' => $data[
'actions']
277 $result = $entity->getTablet()->update($id, $data[
'fields']);
278 $success = $result->isSuccess();
281 $data[
'fields'] = $result->getData();
282 if ($entity->fieldsCount > 0)
283 $entity->modifyEntityCacheItem($id, $data[
'fields']);
286 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_AFTER_UPDATE))
290 ORM\Data\DataManager::EVENT_ON_AFTER_UPDATE,
293 'fields' => $data[
'fields'],
294 'external_fields' => $data[
'external_fields'],
295 'actions' => $data[
'actions'],
296 'success' => $success
303 if ($success && !empty($data[
'actions']))
304 static::runUpdateExternalActions($id, $data);
306 unset($success, $entity);
321 $entity = static::getEntity();
323 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_BEFORE_DELETE))
327 ORM\Data\DataManager::EVENT_ON_BEFORE_DELETE,
332 if ($event->getErrors($result))
336 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_DELETE))
340 ORM\Data\DataManager::EVENT_ON_DELETE,
347 if ($entity->fieldsCount > 0 && !isset($entity->cache[$id]))
348 $entity->loadEntityCacheItem($id);
350 $result = $entity->getTablet()->delete($id);
351 $success = $result->isSuccess();
353 $entity->expireEntityCacheItem((
int)$id);
355 if (Event::existEventHandlers($entity, ORM\Data\DataManager::EVENT_ON_AFTER_DELETE))
359 ORM\Data\DataManager::EVENT_ON_AFTER_DELETE,
360 [
'id' => $id,
'success' => $success]
367 static::runDeleteExternalActions($id);
369 unset($success, $entity);
384 if ($id <= 0 || empty($row))
386 static::getEntity()->setEntityCacheItem($id, $row,
false);
401 return static::getEntity()->getEntityCacheItem($id, $load);
416 static::getEntity()->clearEntityCacheItem($id);
438 $entity = static::getEntity();
439 if ($fields & self::FIELDS_MAIN)
441 $result = array_keys($entity->tabletFields);
443 if ($fields & self::FIELDS_UF)
445 $list = array_keys($entity->tabletUserFields);
448 $result = (empty($result)
450 : array_merge($result, $list)
467 $entity = static::getEntity();
468 return $entity->fields;
479 if (!($this->tablet instanceof ORM\Data\
DataManager))
481 'Tablet not found in entity `%s`',
484 return $this->tablet;
497 $data = static::getEntity()->checkTabletWhiteList($data);
501 'Empty data for add in entity `%s`',
517 $data = static::getEntity()->checkTabletWhiteList($data);
521 'Empty data for update in entity `%s`',
536 $entity = static::getEntity();
538 if ($entity->fieldsCount > 0 && !isset($entity->cache[$id]))
539 $entity->loadEntityCacheItem($id);
541 $result = $entity->getTablet()->delete($id);
542 if ($result->isSuccess())
544 if ($entity->fieldsCount > 0)
545 $entity->expireEntityCacheItem((
int)$id);
546 static::runDeleteExternalActions($id);
564 'external_fields' => [],
568 if (isset($data[
'fields']) && is_array($data[
'fields']))
570 $result[
'fields'] = $data[
'fields'];
571 if (isset($data[
'external_fields']) && is_array($data[
'external_fields']))
572 $result[
'external_fields'] = $data[
'external_fields'];
573 if (isset($data[
'actions']) && is_array($data[
'actions']))
574 $result[
'actions'] = $data[
'actions'];
578 $result[
'fields'] = $data;
627 private function initEntityTablet(): void
629 $tabletClassName = static::getTabletClassName();
630 $this->tablet =
new $tabletClassName;
631 $this->tabletFields = [];
632 $this->tabletUserFields = [];
634 $entity = $this->tablet->getEntity();
635 $checkUseFields = $entity->getUfId() !==
null;
636 $list = $entity->getFields();
637 foreach ($list as $field)
641 $this->tabletFields[$field->getName()] =
true;
645 $this->tabletUserFields[$field->getName()] =
true;
648 unset($field, $list);
649 unset($checkUseFields);
650 unset($entity, $tabletClassName);
659 private function initEntityCache(): void
661 $this->clearEntityCache();
664 $this->fieldMask = [];
665 $fieldList = static::getDefaultCachedFieldList();
666 if (Event::existEventHandlers($this, self::EVENT_ON_BUILD_CACHED_FIELD_LIST))
670 self::EVENT_ON_BUILD_CACHED_FIELD_LIST
674 foreach($event->getResults() as $eventResult)
676 if ($eventResult->getType() == Main\EventResult::SUCCESS)
678 $addFields = $eventResult->getParameters();
679 if (!empty($addFields) && is_array($addFields))
681 foreach ($addFields as $alias => $field)
683 if (!isset($this->tabletFields[$field]))
687 $index = array_search($field, $fieldList);
690 if ($index ===
false || !is_int($index))
692 $fieldList[] = $field;
697 if ($index !== $alias)
699 $fieldList[$alias] = $field;
706 unset($eventResult, $event);
709 $this->fields = $fieldList;
711 if (!empty($this->fields))
713 foreach ($this->fields as $alias => $field)
717 $this->fieldMask[$field] =
true;
721 $this->fieldMask[$alias] =
true;
722 $this->aliases[$alias] = $field;
725 unset($alias, $field);
727 $this->fieldsCount = count($this->fields);
736 private function clearEntityCache(): void
739 $this->cacheModifyed = [];
749 private function prepareTabletQueryParameters(array $parameters): array
751 $this->fetchCutMask = [];
753 if (empty($this->fields))
755 if (!isset($parameters[
'select']))
757 if (in_array(
'*', $parameters[
'select']))
759 if (isset($parameters[
'group']))
762 $select = $parameters[
'select'];
763 foreach ($this->fields as $field)
766 $index = array_search($field, $select);
767 if ($index !==
false && is_int($index))
772 $parameters[
'select'][] = $field;
773 $this->fetchCutMask[$field] =
true;
775 unset($index, $existField, $field);
787 private function replaceFieldToAlias(array &$row): void
789 if (empty($this->aliases))
792 foreach ($this->aliases as $alias => $field)
794 $row[$alias] = $row[$field];
797 unset($alias, $field);
807 private function checkTabletWhiteList(array $fields): array
809 $baseFields = array_intersect_key($fields, $this->tabletFields);
810 if (!empty($this->tabletUserFields))
812 $userFields = array_intersect_key($fields, $this->tabletUserFields);
813 if (!empty($userFields))
815 $baseFields = $baseFields + $userFields;
824 return [Main\Rest\Event::class,
'processItemEvent'];
836 private function loadEntityCacheItem($id): void
838 if (isset($this->cache[$id]))
840 if (empty($this->fields))
843 $iterator = $this->getTablet()->getList([
844 'select' => array_values($this->fields),
845 'filter' => [
'=ID' => $id]
847 $row = $iterator->fetch();
850 $this->setEntityCacheItem($id, $row,
true);
862 private function getEntityCacheItem($id,
bool $load =
false): array
865 if (!isset($this->cache[$id]) && $load && !empty($this->fields))
866 $this->loadEntityCacheItem($id);
867 if (isset($this->cache[$id]))
868 $result = $this->cache[$id];
882 private function setEntityCacheItem($id, array $row,
bool $replaceAliases =
false): void
884 if (empty($this->fieldMask))
886 if (isset($this->cache[$id]))
890 $this->replaceFieldToAlias($row);
891 $data = array_intersect_key($row, $this->fieldMask);
892 if (!empty($data) && count($data) == $this->fieldsCount)
893 $this->cache[$id] = $data;
905 private function modifyEntityCacheItem($id, array $row): void
907 if (empty($this->fieldMask))
910 $data = array_intersect_key($row, $this->fieldMask);
913 if (!isset($this->cache[$id]))
914 $this->loadEntityCacheItem($id);
915 if (isset($this->cache[$id]))
917 $this->expireEntityCacheItem($id,
true);
918 $this->cache[$id] = array_merge($this->cache[$id], $data);
932 private function expireEntityCacheItem($id,
bool $copy =
false): void
934 if (empty($this->fields))
937 if (!isset($this->cache[$id]))
939 if (isset($this->cacheModifyed[$id]))
943 foreach (array_keys($this->fieldMask) as $field)
944 $oldData[self::PREFIX_OLD.$field] = $this->cache[$id][$field];
947 $this->cache[$id] = array_merge($oldData, $this->cache[$id]);
949 $this->cache[$id] = $oldData;
952 $this->cacheModifyed[$id] =
true;
962 private function clearEntityCacheItem($id): void
964 if (isset($this->cache[$id]))
965 unset($this->cache[$id]);
966 if (isset($this->cacheModifyed[$id]))
967 unset($this->cacheModifyed[$id]);
982 if (is_string($value))
984 if ($value !==
'' && is_numeric($value))
986 $value = (float)$value;
987 if (is_finite($value))
997 $value = (float)$value;
1000 is_float($value) && is_finite($value)
1012 if ($value ===
null)
1018 if (is_string($value))
1020 if ($value !==
'' && is_numeric($value))
1022 $result = (int)$value;
1025 elseif (is_int($value))
1035 if (is_string($value))
1037 return trim($value) ?:
null;