Server IP : 85.193.89.191 / Your IP : 3.146.34.244 Web Server : Apache System : Linux 956367-cx40159.tmweb.ru 3.10.0-1160.105.1.el7.x86_64 #1 SMP Thu Dec 7 15:39:45 UTC 2023 x86_64 User : bitrix ( 600) PHP Version : 8.1.27 Disable Function : NONE MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/bitrix/www/bitrix/modules/catalog/lib/v2/ |
Upload File : |
<?php namespace Bitrix\Catalog\v2; use Bitrix\Catalog\v2\Fields\FieldStorage; use Bitrix\Catalog\v2\Fields\TypeCasters\MapTypeCaster; use Bitrix\Catalog\v2\Fields\TypeCasters\NullTypeCaster; use Bitrix\Main\Application; use Bitrix\Main\DB\SqlException; use Bitrix\Main\Error; use Bitrix\Main\Result; /** * Class BaseEntity * * @package Bitrix\Catalog\v2 * * !!! This API is in alpha stage and is not stable. This is subject to change at any time without notice. * @internal */ abstract class BaseEntity { /** @var \Bitrix\Catalog\v2\RepositoryContract */ protected $entityRepository; /** @var \Bitrix\Catalog\v2\Fields\FieldStorage */ private $fieldStorage; /** @var \Bitrix\Catalog\v2\BaseCollection */ private $parentCollection; // ToDo do we need $repository for every base entity? public function __construct(RepositoryContract $repository = null) { $this->entityRepository = $repository; } protected function getFieldStorage(): FieldStorage { if ($this->fieldStorage === null) { $this->fieldStorage = $this->createFieldStorage(); } return $this->fieldStorage; } protected function createFieldStorage(): FieldStorage { $fieldMap = $this->getFieldsMap(); if ($fieldMap === null) { $typeCaster = new NullTypeCaster(); } else { $typeCaster = new MapTypeCaster($fieldMap); } return new FieldStorage($typeCaster); } public function initFields(array $fields): self { if (!empty($fields)) { $this->getFieldStorage()->initFields($fields); } return $this; } public function setParentCollection(?BaseCollection $collection): self { $this->parentCollection = $collection; return $this; } public function getParentCollection(): ?BaseCollection { return $this->parentCollection; } public function getParent(): ?self { $collection = $this->getParentCollection(); if ($collection) { return $collection->getParent(); } return null; } public function getHash(): string { return spl_object_hash($this); } public function setField(string $name, $value): self { return $this->setFieldNoDemand($name, $value); } public function setFieldNoDemand(string $name, $value): self { $this->getFieldStorage()->setField($name, $value); return $this; } public function hasField(string $name): bool { return $this->getFieldStorage()->hasField($name); } public function getField(string $name) { return $this->getFieldStorage()->getField($name); } // ToDo make map to execute set{$name} instead of setField($name) to check each field limitations? e.g. price with setFields is string instead of float public function setFields(array $fields): self { foreach ($fields as $name => $value) { $this->setField($name, $value); } return $this; } public function getFields(): array { return $this->getFieldStorage()->toArray(); } public function getChangedFields(): array { return array_intersect_key($this->getFields(), $this->getFieldStorage()->getChangedFields()); } public function hasChangedFields(): bool { return $this->getFieldStorage()->hasChangedFields(); } public function isChanged(): bool { if ($this->hasChangedFields()) { return true; } foreach ($this->getChildCollections() as $childCollection) { if ($childCollection->isChanged()) { return true; } } return false; } public function isNew(): bool { return $this->getId() === null; } public function getId(): ?int { return (int)$this->getField('ID') ?: null; } public function setId(int $id): self { return $this->setField('ID', $id); } public function remove(): self { $collection = $this->getParentCollection(); if ($collection) { $collection->remove($this); } return $this; } public function save(): Result { if ($parent = $this->getParent()) { return $parent->save(); } $connection = Application::getConnection(); try { $connection->startTransaction(); $result = $this->saveInternal(); if ($result->isSuccess()) { $connection->commitTransaction(); } else { $connection->rollbackTransaction(); } } catch (SqlException $exception) { $result = new Result(); $connection->rollbackTransaction(); $result->addError(new Error($exception->getMessage())); } return $result; } protected function getFieldsMap(): ?array { return null; } /** * ToDo is it a BaseEntity method? do all children need it? e.g. Property - doesn't * * @return \Bitrix\Main\Result * @internal */ public function saveInternal(): Result { $result = new Result(); if ($this->hasChangedFields()) { $res = $this->saveInternalEntity(); if (!$res->isSuccess()) { $result->addErrors($res->getErrors()); } } if ($result->isSuccess()) { foreach ($this->getChildCollections() as $childCollection) { $res = $childCollection->saveInternal(); if (!$res->isSuccess()) { $result->addErrors($res->getErrors()); } } } return $result; } protected function saveInternalEntity(): Result { $result = $this->entityRepository->save($this); if ($result->isSuccess()) { $this->clearChangedFields(); } return $result; } /** * @internal */ public function deleteInternal(): Result { $result = $this->entityRepository->delete($this); if ($result->isSuccess()) { foreach ($this->getChildCollections(true) as $childCollection) { $res = $childCollection->deleteInternal(); if (!$res->isSuccess()) { $result->addErrors($res->getErrors()); } } } return $result; } /** * @param bool $initCollections * @return \Generator|\Bitrix\Catalog\v2\BaseCollection[] */ final protected function getChildCollections(bool $initCollections = false): \Generator { $collectionPostfix = 'Collection'; $collectionPostfixLength = mb_strlen($collectionPostfix); $parentCollection = "parent{$collectionPostfix}"; foreach ((new \ReflectionObject($this))->getProperties() as $property) { $propertyName = $property->getName(); if ( $propertyName !== $parentCollection && mb_substr($propertyName, -$collectionPostfixLength) === $collectionPostfix ) { $property->setAccessible(true); $value = $property->getValue($this); if ($value === null && $initCollections) { $propertyGetter = "get{$propertyName}"; if (is_callable([$this, $propertyGetter])) { $value = $this->$propertyGetter(); } } if ($value instanceof BaseCollection) { yield $value; } } } } /** * @return $this * @internal */ public function clearChangedFields(): self { $this->getFieldStorage()->clearChanged(); return $this; } }