diff --git a/application/Espo/Core/ORM/EntityManager.php b/application/Espo/Core/ORM/EntityManager.php index 28706ee2c2..09009d9e18 100644 --- a/application/Espo/Core/ORM/EntityManager.php +++ b/application/Espo/Core/ORM/EntityManager.php @@ -47,8 +47,6 @@ class EntityManager extends BaseEntityManager protected $user = null; - private $entityClassNameHash = []; - public function __construct( array $params, RepositoryFactory $repositoryFactory, diff --git a/application/Espo/Core/ORM/Repositories/RDB.php b/application/Espo/Core/ORM/Repositories/RDB.php index 8dc8455973..49f9c34e87 100644 --- a/application/Espo/Core/ORM/Repositories/RDB.php +++ b/application/Espo/Core/ORM/Repositories/RDB.php @@ -34,35 +34,23 @@ use Espo\ORM\EntityFactory; use Espo\ORM\Entity; -use Espo\ORM\IEntity; -use Espo\Core\Utils\Util; - use Espo\Core\Interfaces\Injectable; -use Espo\ORM\Repositories\RDB as BaseRDB; +use Espo\Core\{ + Utils\Metadata, + Utils\Config, + Utils\FieldManagerUtil, +}; -class RDB extends BaseRDB implements Injectable +/** Deprecated */ +class RDB extends \Espo\Core\Repositories\Database implements Injectable { - protected $dependencyList = [ - 'metadata', - 'config', - 'fieldManagerUtil', - ]; + protected $dependencyList = []; - protected $dependencies = []; // for backward compatibility + protected $dependencies = []; protected $injections = []; - private $restoreData = null; - - protected $hooksDisabled = false; - - protected $processFieldsAfterSaveDisabled = false; - - protected $processFieldsBeforeSaveDisabled = false; - - protected $processFieldsAfterRemoveDisabled = false; - protected function addDependency($name) { $this->dependencyList[] = $name; @@ -105,585 +93,24 @@ class RDB extends BaseRDB implements Injectable return $this->getInjection('fieldManagerUtil'); } - public function __construct(string $entityType, EntityManager $entityManager, EntityFactory $entityFactory) - { - parent::__construct($entityType, $entityManager, $entityFactory); + public function __construct( + string $entityType, + EntityManager $entityManager, + EntityFactory $entityFactory, + Metadata $metadata, + Config $config, + FieldManagerUtil $fieldManagerUtil + ) { + parent::__construct($entityType, $entityManager, $entityFactory, $metadata, $config, $fieldManagerUtil); + + $this->metadata = $metadata; + $this->config = $config; + $this->fieldManagerUtil = $fieldManagerUtil; + $this->init(); } protected function init() { } - - public function handleSelectParams(&$params) - { - } - - protected function handleCurrencyParams(&$params) - { - $entityType = $this->entityType; - - $metadata = $this->getMetadata(); - - if (!$metadata) { - return; - } - - $defs = $metadata->get(['entityDefs', $entityType]); - - foreach ($defs['fields'] as $field => $d) { - if (isset($d['type']) && $d['type'] == 'currency') { - if (!empty($d['notStorable'])) continue; - if (empty($params['leftJoins'])) $params['leftJoins'] = []; - $alias = $field . 'CurrencyRate'; - - $params['leftJoins'][] = ['Currency', $alias, [ - $alias . '.id:' => $field . 'Currency' - ]]; - } - } - - } - - protected function handleEmailAddressParams(&$params) - { - $defs = $this->getEntityManager()->getMetadata()->get($this->entityType); - if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) { - if (empty($params['leftJoins'])) $params['leftJoins'] = []; - $params['leftJoins'][] = ['emailAddresses', null, [ - 'primary' => 1 - ]]; - } - } - - protected function handlePhoneNumberParams(&$params) - { - $defs = $this->getEntityManager()->getMetadata()->get($this->entityType); - if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) { - if (empty($params['leftJoins'])) $params['leftJoins'] = []; - $params['leftJoins'][] = ['phoneNumbers', null, [ - 'primary' => 1 - ]]; - } - } - - protected function beforeRemove(Entity $entity, array $options = []) - { - parent::beforeRemove($entity, $options); - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - $this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeRemove', $entity, $options); - } - - $nowString = date('Y-m-d H:i:s', time()); - if ($entity->hasAttribute('modifiedAt')) { - $entity->set('modifiedAt', $nowString); - } - if ($entity->hasAttribute('modifiedById')) { - if ($this->getEntityManager()->getUser()) { - $entity->set('modifiedById', $this->getEntityManager()->getUser()->id); - } - } - } - - protected function afterRemove(Entity $entity, array $options = []) - { - parent::afterRemove($entity, $options); - - if (!$this->processFieldsAfterRemoveDisabled) { - $this->processArrayFieldsRemove($entity); - } - - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options); - } - } - - protected function afterMassRelate(Entity $entity, $relationName, array $params = [], array $options = []) - { - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - $hookData = [ - 'relationName' => $relationName, - 'relationParams' => $params, - ]; - $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterMassRelate', $entity, $options, $hookData); - } - } - - public function remove(Entity $entity, array $options = []) - { - $result = parent::remove($entity, $options); - return $result; - } - - protected function afterRelate(Entity $entity, $relationName, $foreign, $data = null, array $options = []) - { - parent::afterRelate($entity, $relationName, $foreign, $data, $options); - - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - if (is_string($foreign)) { - $foreignId = $foreign; - $foreignEntityType = $entity->getRelationParam($relationName, 'entity'); - if ($foreignEntityType) { - $foreign = $this->getEntityManager()->getEntity($foreignEntityType); - $foreign->id = $foreignId; - $foreign->setAsFetched(); - } - } - - if ($foreign instanceof Entity) { - $hookData = [ - 'relationName' => $relationName, - 'relationData' => $data, - 'foreignEntity' => $foreign, - 'foreignId' => $foreign->id, - ]; - $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRelate', $entity, $options, $hookData); - } - } - } - - protected function afterUnrelate(Entity $entity, $relationName, $foreign, array $options = []) - { - parent::afterUnrelate($entity, $relationName, $foreign, $options); - - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - if (is_string($foreign)) { - $foreignId = $foreign; - $foreignEntityType = $entity->getRelationParam($relationName, 'entity'); - if ($foreignEntityType) { - $foreign = $this->getEntityManager()->getEntity($foreignEntityType); - $foreign->id = $foreignId; - $foreign->setAsFetched(); - } - } - - if ($foreign instanceof Entity) { - $hookData = [ - 'relationName' => $relationName, - 'foreignEntity' => $foreign, - 'foreignId' => $foreign->id, - ]; - $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterUnrelate', $entity, $options, $hookData); - } - } - } - - protected function beforeSave(Entity $entity, array $options = []) - { - parent::beforeSave($entity, $options); - - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - $this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeSave', $entity, $options); - } - - if (!$this->processFieldsBeforeSaveDisabled) { - $this->processCurrencyFieldsBeforeSave($entity); - } - } - - protected function afterSave(Entity $entity, array $options = []) - { - if (!empty($this->restoreData)) { - $entity->set($this->restoreData); - $this->restoreData = null; - } - parent::afterSave($entity, $options); - - if (!$this->processFieldsAfterSaveDisabled) { - $this->processEmailAddressSave($entity); - $this->processPhoneNumberSave($entity); - $this->processSpecifiedRelationsSave($entity, $options); - $this->processFileFieldsSave($entity); - $this->processArrayFieldsSave($entity); - $this->processWysiwygFieldsSave($entity); - } - - if (!$this->hooksDisabled && empty($options['skipHooks'])) { - $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterSave', $entity, $options); - } - } - - public function save(Entity $entity, array $options = []) - { - $nowString = date('Y-m-d H:i:s', time()); - $restoreData = []; - - if ($entity->isNew()) { - if (!$entity->has('id')) { - $entity->set('id', Util::generateId()); - } - } - - if (empty($options['skipAll'])) { - if ($entity->isNew()) { - if ($entity->hasAttribute('createdAt')) { - if (empty($options['import']) || !$entity->has('createdAt')) { - $entity->set('createdAt', $nowString); - } - } - if ($entity->hasAttribute('modifiedAt')) { - $entity->set('modifiedAt', $nowString); - } - if ($entity->hasAttribute('createdById')) { - if (!empty($options['createdById'])) { - $entity->set('createdById', $options['createdById']); - } else if (empty($options['skipCreatedBy']) && (empty($options['import']) || !$entity->has('createdById'))) { - if ($this->getEntityManager()->getUser()) { - $entity->set('createdById', $this->getEntityManager()->getUser()->id); - } - } - } - } else { - if (empty($options['silent']) && empty($options['skipModifiedBy'])) { - if ($entity->hasAttribute('modifiedAt')) { - $entity->set('modifiedAt', $nowString); - } - if ($entity->hasAttribute('modifiedById')) { - if (!empty($options['modifiedById'])) { - $entity->set('modifiedById', $options['modifiedById']); - } else if ($this->getEntityManager()->getUser()) { - $entity->set('modifiedById', $this->getEntityManager()->getUser()->id); - $entity->set('modifiedByName', $this->getEntityManager()->getUser()->get('name')); - } - } - } - } - } - - $this->restoreData = $restoreData; - - $result = parent::save($entity, $options); - - return $result; - } - - protected function getFieldByTypeList($type) - { - return $this->getFieldManagerUtil()->getFieldByTypeList($this->entityType, $type); - } - - protected function processCurrencyFieldsBeforeSave(Entity $entity) - { - foreach ($this->getFieldByTypeList('currency') as $field) { - $currencyAttribute = $field . 'Currency'; - $defaultCurrency = $this->getConfig()->get('defaultCurrency'); - if ($entity->isNew()) { - if ($entity->get($field) && !$entity->get($currencyAttribute)) { - $entity->set($currencyAttribute, $defaultCurrency); - } - } else { - if ($entity->isAttributeChanged($field) && $entity->has($currencyAttribute) && !$entity->get($currencyAttribute)) { - $entity->set($currencyAttribute, $defaultCurrency); - } - } - } - } - - protected function processFileFieldsSave(Entity $entity) - { - foreach ($entity->getRelations() as $name => $defs) { - if (!isset($defs['type']) || !isset($defs['entity'])) continue; - if (!($defs['type'] === $entity::BELONGS_TO && $defs['entity'] === 'Attachment')) continue; - - $attribute = $name . 'Id'; - if (!$entity->hasAttribute($attribute)) continue; - if (!$entity->get($attribute)) continue; - if (!$entity->isAttributeChanged($attribute)) continue; - - $attachment = $this->getEntityManager()->getEntity('Attachment', $entity->get($attribute)); - if (!$attachment) continue; - $attachment->set(array( - 'relatedId' => $entity->id, - 'relatedType' => $entity->getEntityType() - )); - $this->getEntityManager()->saveEntity($attachment); - } - - if (!$entity->isNew()) { - - foreach ($this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields']) as $name => $defs) { - if (!empty($defs['type']) && in_array($defs['type'], ['file', 'image'])) { - $attribute = $name . 'Id'; - if ($entity->isAttributeChanged($attribute)) { - $previousAttachmentId = $entity->getFetched($attribute); - if ($previousAttachmentId) { - $attachment = $this->getEntityManager()->getEntity('Attachment', $previousAttachmentId); - if ($attachment) { - $this->getEntityManager()->removeEntity($attachment); - } - } - } - } - } - } - } - - protected function processArrayFieldsSave(Entity $entity) - { - foreach ($entity->getAttributes() as $attribute => $defs) { - if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue; - if (!$entity->has($attribute)) continue; - if (!$entity->isAttributeChanged($attribute)) continue; - if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue; - if ($entity->getAttributeParam($attribute, 'notStorable')) continue; - $this->getEntityManager()->getRepository('ArrayValue')->storeEntityAttribute($entity, $attribute); - } - } - - protected function processWysiwygFieldsSave(Entity $entity) - { - if (!$entity->isNew()) return; - - $fieldsDefs = $this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields'], []); - foreach ($fieldsDefs as $field => $defs) { - if (!empty($defs['type']) && $defs['type'] === 'wysiwyg') { - $content = $entity->get($field); - if (!$content) continue; - if (preg_match_all("/\?entryPoint=attachment&id=([^&=\"']+)/", $content, $matches)) { - if (!empty($matches[1]) && is_array($matches[1])) { - foreach ($matches[1] as $id) { - $attachment = $this->getEntityManager()->getEntity('Attachment', $id); - if ($attachment) { - if (!$attachment->get('relatedId') && !$attachment->get('sourceId')) { - $attachment->set([ - 'relatedId' => $entity->id, - 'relatedType' => $entity->getEntityType() - ]); - $this->getEntityManager()->saveEntity($attachment); - } - } - } - } - } - } - } - } - - protected function processArrayFieldsRemove(Entity $entity) - { - foreach ($entity->getAttributes() as $attribute => $defs) { - if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue; - if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue; - if ($entity->getAttributeParam($attribute, 'notStorable')) continue; - $this->getEntityManager()->getRepository('ArrayValue')->deleteEntityAttribute($entity, $attribute); - } - } - - protected function processEmailAddressSave(Entity $entity) - { - if ($entity->hasRelation('emailAddresses') && $entity->hasAttribute('emailAddress')) { - $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity); - } - } - - protected function processPhoneNumberSave(Entity $entity) - { - if ($entity->hasRelation('phoneNumbers') && $entity->hasAttribute('phoneNumber')) { - $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity); - } - } - - public function processLinkMultipleFieldSave(Entity $entity, $link, array $options = []) - { - $name = $link; - - $idListAttribute = $link . 'Ids'; - $columnsAttribute = $link . 'Columns'; - - if ($this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.noSave")) { - return; - } - - $skipCreate = false; - $skipRemove = false; - $skipUpdate = false; - if (!empty($options['skipLinkMultipleCreate'])) $skipCreate = true; - if (!empty($options['skipLinkMultipleRemove'])) $skipRemove = true; - if (!empty($options['skipLinkMultipleUpdate'])) $skipUpdate = true; - - if ($entity->isNew()) { - $skipRemove = true; - $skipUpdate = true; - } - - if ($entity->has($idListAttribute)) { - $specifiedIdList = $entity->get($idListAttribute); - } else if ($entity->has($columnsAttribute)) { - $skipRemove = true; - $specifiedIdList = []; - foreach ($entity->get($columnsAttribute) as $id => $d) { - $specifiedIdList[] = $id; - } - } else { - return; - } - - if (!is_array($specifiedIdList)) return; - - $toRemoveIdList = []; - $existingIdList = []; - $toUpdateIdList = []; - $toCreateIdList = []; - $existingColumnsData = (object)[]; - - $defs = []; - $columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.columns"); - if (!empty($columns)) { - $columnData = $entity->get($columnsAttribute); - $defs['additionalColumns'] = $columns; - } - - if (!$skipRemove && !$skipUpdate) { - $foreignEntityList = $entity->get($name, $defs); - if ($foreignEntityList) { - foreach ($foreignEntityList as $foreignEntity) { - $existingIdList[] = $foreignEntity->id; - if (!empty($columns)) { - $data = (object)[]; - foreach ($columns as $columnName => $columnField) { - $foreignId = $foreignEntity->id; - $data->$columnName = $foreignEntity->get($columnField); - } - $existingColumnsData->$foreignId = $data; - if (!$entity->isNew()) { - $entity->setFetched($columnsAttribute, $existingColumnsData); - } - } - } - } - } - - if (!$entity->isNew()) { - if ($entity->has($idListAttribute) && !$entity->hasFetched($idListAttribute)) { - $entity->setFetched($idListAttribute, $existingIdList); - } - if ($entity->has($columnsAttribute) && !empty($columns)) { - $entity->setFetched($columnsAttribute, $existingColumnsData); - } - } - - foreach ($existingIdList as $id) { - if (!in_array($id, $specifiedIdList)) { - if (!$skipRemove) { - $toRemoveIdList[] = $id; - } - } else { - if (!$skipUpdate && !empty($columns)) { - foreach ($columns as $columnName => $columnField) { - if (isset($columnData->$id) && is_object($columnData->$id)) { - if ( - property_exists($columnData->$id, $columnName) - && - ( - !property_exists($existingColumnsData->$id, $columnName) - || - $columnData->$id->$columnName !== $existingColumnsData->$id->$columnName - ) - ) { - $toUpdateIdList[] = $id; - } - } - } - } - } - } - - if (!$skipCreate) { - foreach ($specifiedIdList as $id) { - if (!in_array($id, $existingIdList)) { - $toCreateIdList[] = $id; - } - } - } - - foreach ($toCreateIdList as $id) { - $data = null; - if (!empty($columns) && isset($columnData->$id)) { - $data = $columnData->$id; - } - $this->relate($entity, $name, $id, $data); - } - - foreach ($toRemoveIdList as $id) { - $this->unrelate($entity, $name, $id); - } - - foreach ($toUpdateIdList as $id) { - $data = $columnData->$id; - $this->updateRelation($entity, $name, $id, $data); - } - } - - protected function processSpecifiedRelationsSave(Entity $entity, array $options = []) - { - $relationTypeList = [$entity::HAS_MANY, $entity::MANY_MANY, $entity::HAS_CHILDREN]; - foreach ($entity->getRelations() as $name => $defs) { - if (in_array($defs['type'], $relationTypeList)) { - $idListAttribute = $name . 'Ids'; - $columnsAttribute = $name . 'Columns'; - if ($entity->has($idListAttribute) || $entity->has($columnsAttribute)) { - $this->processLinkMultipleFieldSave($entity, $name, $options); - } - } else if ($defs['type'] === $entity::HAS_ONE) { - if (empty($defs['entity']) || empty($defs['foreignKey'])) continue; - - if ($this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.noSave")) { - continue; - } - - $foreignEntityType = $defs['entity']; - $foreignKey = $defs['foreignKey']; - $idAttribute = $name . 'Id'; - - if (!$entity->has($idAttribute)) continue; - - $where = []; - $where[$foreignKey] = $entity->id; - - $previousForeignEntity = $this->getEntityManager()->getRepository($foreignEntityType) - ->select(['id'])->where($where)->findOne(); - - if ($previousForeignEntity) { - if (!$entity->isNew()) { - $entity->setFetched($idAttribute, $previousForeignEntity->id); - } - if (!$entity->get($idAttribute)) { - $previousForeignEntity->set($foreignKey, null); - $this->getEntityManager()->saveEntity($previousForeignEntity, ['skipAll' => true]); - } - } else { - if (!$entity->isNew()) { - $entity->setFetched($idAttribute, null); - } - } - - if ($entity->get($idAttribute)) { - $relateResult = $this->relate($entity, $name, $entity->get($idAttribute)); - if (!$relateResult) { - $entity->set($idAttribute, null); - } - } - } else if ($defs['type'] === $entity::BELONGS_TO) { - if (!$entity->get($name . 'Id')) continue; - if (!$entity->isAttributeChanged($name . 'Id')) continue; - - $foreignEntityType = $defs['entity'] ?? null; - $foreignLink = $defs['foreign'] ?? null; - - if ( - $this->getMetadata()->get(['entityDefs', $foreignEntityType, 'links', $foreignLink, 'type']) === $entity::HAS_ONE - ) { - $anotherEntity = $this->select(['id'])->where([ - $name . 'Id' => $entity->get($name . 'Id'), - 'id!=' => $entity->id, - ])->findOne(); - - if ($anotherEntity) { - $anotherEntity->set($name . 'Id', null); - $this->getEntityManager()->saveEntity($anotherEntity, ['skipAll' => true]); - } - } - } - } - } } diff --git a/application/Espo/Core/ORM/Repository.php b/application/Espo/Core/ORM/Repository.php index 62e5072e56..b7692866f5 100644 --- a/application/Espo/Core/ORM/Repository.php +++ b/application/Espo/Core/ORM/Repository.php @@ -29,9 +29,9 @@ namespace Espo\Core\ORM; -use \Espo\Core\Interfaces\Injectable; +use Espo\Core\Interfaces\Injectable; -use \Espo\ORM\EntityFactory; +use Espo\ORM\EntityFactory; /** Deprecated */ abstract class Repository extends \Espo\ORM\Repository implements Injectable diff --git a/application/Espo/Core/ORM/RepositoryFactory.php b/application/Espo/Core/ORM/RepositoryFactory.php index b44a7877cc..f00d6fae9d 100644 --- a/application/Espo/Core/ORM/RepositoryFactory.php +++ b/application/Espo/Core/ORM/RepositoryFactory.php @@ -32,13 +32,14 @@ namespace Espo\Core\ORM; use Espo\Core\{ InjectableFactory, Utils\ClassFinder, + Repositories\Database as DatabaseRepository, }; use Espo\ORM\RepositoryFactory as RepositoryFactoryInterface; class RepositoryFactory implements RepositoryFactoryInterface { - protected $defaultClassName = Repositories\RDB::class; + protected $defaultClassName = DatabaseRepository::class; protected $entityFactory; protected $injectableFactory; diff --git a/application/Espo/Core/Repositories/Database.php b/application/Espo/Core/Repositories/Database.php new file mode 100644 index 0000000000..6918a978f1 --- /dev/null +++ b/application/Espo/Core/Repositories/Database.php @@ -0,0 +1,676 @@ +metadata = $metadata; + $this->config = $config; + $this->fieldManagerUtil = $fieldManagerUtil; + } + + protected function getMetadata() + { + return $this->metadata; + } + + protected function getConfig() + { + return $this->config; + } + + protected function getFieldManagerUtil() + { + return $this->fieldManagerUtil; + } + + public function handleSelectParams(&$params) + { + } + + protected function handleCurrencyParams(&$params) + { + $entityType = $this->entityType; + + $metadata = $this->getMetadata(); + + if (!$metadata) { + return; + } + + $defs = $metadata->get(['entityDefs', $entityType]); + + foreach ($defs['fields'] as $field => $d) { + if (isset($d['type']) && $d['type'] == 'currency') { + if (!empty($d['notStorable'])) continue; + if (empty($params['leftJoins'])) $params['leftJoins'] = []; + $alias = $field . 'CurrencyRate'; + + $params['leftJoins'][] = ['Currency', $alias, [ + $alias . '.id:' => $field . 'Currency' + ]]; + } + } + + } + + protected function handleEmailAddressParams(&$params) + { + $defs = $this->getEntityManager()->getMetadata()->get($this->entityType); + if (!empty($defs['relations']) && array_key_exists('emailAddresses', $defs['relations'])) { + if (empty($params['leftJoins'])) $params['leftJoins'] = []; + $params['leftJoins'][] = ['emailAddresses', null, [ + 'primary' => 1 + ]]; + } + } + + protected function handlePhoneNumberParams(&$params) + { + $defs = $this->getEntityManager()->getMetadata()->get($this->entityType); + if (!empty($defs['relations']) && array_key_exists('phoneNumbers', $defs['relations'])) { + if (empty($params['leftJoins'])) $params['leftJoins'] = []; + $params['leftJoins'][] = ['phoneNumbers', null, [ + 'primary' => 1 + ]]; + } + } + + protected function beforeRemove(Entity $entity, array $options = []) + { + parent::beforeRemove($entity, $options); + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + $this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeRemove', $entity, $options); + } + + $nowString = date('Y-m-d H:i:s', time()); + if ($entity->hasAttribute('modifiedAt')) { + $entity->set('modifiedAt', $nowString); + } + if ($entity->hasAttribute('modifiedById')) { + if ($this->getEntityManager()->getUser()) { + $entity->set('modifiedById', $this->getEntityManager()->getUser()->id); + } + } + } + + protected function afterRemove(Entity $entity, array $options = []) + { + parent::afterRemove($entity, $options); + + if (!$this->processFieldsAfterRemoveDisabled) { + $this->processArrayFieldsRemove($entity); + } + + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterRemove', $entity, $options); + } + } + + protected function afterMassRelate(Entity $entity, $relationName, array $params = [], array $options = []) + { + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + $hookData = [ + 'relationName' => $relationName, + 'relationParams' => $params, + ]; + $this->getEntityManager()->getHookManager()->process( + $this->entityType, 'afterMassRelate', $entity, $options, $hookData + ); + } + } + + public function remove(Entity $entity, array $options = []) + { + $result = parent::remove($entity, $options); + return $result; + } + + protected function afterRelate(Entity $entity, $relationName, $foreign, $data = null, array $options = []) + { + parent::afterRelate($entity, $relationName, $foreign, $data, $options); + + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + if (is_string($foreign)) { + $foreignId = $foreign; + $foreignEntityType = $entity->getRelationParam($relationName, 'entity'); + if ($foreignEntityType) { + $foreign = $this->getEntityManager()->getEntity($foreignEntityType); + $foreign->id = $foreignId; + $foreign->setAsFetched(); + } + } + + if ($foreign instanceof Entity) { + $hookData = [ + 'relationName' => $relationName, + 'relationData' => $data, + 'foreignEntity' => $foreign, + 'foreignId' => $foreign->id, + ]; + $this->getEntityManager()->getHookManager()->process( + $this->entityType, 'afterRelate', $entity, $options, $hookData + ); + } + } + } + + protected function afterUnrelate(Entity $entity, $relationName, $foreign, array $options = []) + { + parent::afterUnrelate($entity, $relationName, $foreign, $options); + + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + if (is_string($foreign)) { + $foreignId = $foreign; + $foreignEntityType = $entity->getRelationParam($relationName, 'entity'); + if ($foreignEntityType) { + $foreign = $this->getEntityManager()->getEntity($foreignEntityType); + $foreign->id = $foreignId; + $foreign->setAsFetched(); + } + } + + if ($foreign instanceof Entity) { + $hookData = [ + 'relationName' => $relationName, + 'foreignEntity' => $foreign, + 'foreignId' => $foreign->id, + ]; + $this->getEntityManager()->getHookManager()->process( + $this->entityType, 'afterUnrelate', $entity, $options, $hookData + ); + } + } + } + + protected function beforeSave(Entity $entity, array $options = []) + { + parent::beforeSave($entity, $options); + + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + $this->getEntityManager()->getHookManager()->process($this->entityType, 'beforeSave', $entity, $options); + } + + if (!$this->processFieldsBeforeSaveDisabled) { + $this->processCurrencyFieldsBeforeSave($entity); + } + } + + protected function afterSave(Entity $entity, array $options = []) + { + if (!empty($this->restoreData)) { + $entity->set($this->restoreData); + $this->restoreData = null; + } + parent::afterSave($entity, $options); + + if (!$this->processFieldsAfterSaveDisabled) { + $this->processEmailAddressSave($entity); + $this->processPhoneNumberSave($entity); + $this->processSpecifiedRelationsSave($entity, $options); + $this->processFileFieldsSave($entity); + $this->processArrayFieldsSave($entity); + $this->processWysiwygFieldsSave($entity); + } + + if (!$this->hooksDisabled && empty($options['skipHooks'])) { + $this->getEntityManager()->getHookManager()->process($this->entityType, 'afterSave', $entity, $options); + } + } + + public function save(Entity $entity, array $options = []) + { + $nowString = date('Y-m-d H:i:s', time()); + $restoreData = []; + + if ($entity->isNew()) { + if (!$entity->has('id')) { + $entity->set('id', Util::generateId()); + } + } + + if (empty($options['skipAll'])) { + if ($entity->isNew()) { + if ($entity->hasAttribute('createdAt')) { + if (empty($options['import']) || !$entity->has('createdAt')) { + $entity->set('createdAt', $nowString); + } + } + if ($entity->hasAttribute('modifiedAt')) { + $entity->set('modifiedAt', $nowString); + } + if ($entity->hasAttribute('createdById')) { + if (!empty($options['createdById'])) { + $entity->set('createdById', $options['createdById']); + } else if (empty($options['skipCreatedBy']) && (empty($options['import']) || !$entity->has('createdById'))) { + if ($this->getEntityManager()->getUser()) { + $entity->set('createdById', $this->getEntityManager()->getUser()->id); + } + } + } + } else { + if (empty($options['silent']) && empty($options['skipModifiedBy'])) { + if ($entity->hasAttribute('modifiedAt')) { + $entity->set('modifiedAt', $nowString); + } + if ($entity->hasAttribute('modifiedById')) { + if (!empty($options['modifiedById'])) { + $entity->set('modifiedById', $options['modifiedById']); + } else if ($this->getEntityManager()->getUser()) { + $entity->set('modifiedById', $this->getEntityManager()->getUser()->id); + $entity->set('modifiedByName', $this->getEntityManager()->getUser()->get('name')); + } + } + } + } + } + + $this->restoreData = $restoreData; + + $result = parent::save($entity, $options); + + return $result; + } + + protected function getFieldByTypeList($type) + { + return $this->getFieldManagerUtil()->getFieldByTypeList($this->entityType, $type); + } + + protected function processCurrencyFieldsBeforeSave(Entity $entity) + { + foreach ($this->getFieldByTypeList('currency') as $field) { + $currencyAttribute = $field . 'Currency'; + $defaultCurrency = $this->getConfig()->get('defaultCurrency'); + if ($entity->isNew()) { + if ($entity->get($field) && !$entity->get($currencyAttribute)) { + $entity->set($currencyAttribute, $defaultCurrency); + } + } else { + if ( + $entity->isAttributeChanged($field) && $entity->has($currencyAttribute) && + !$entity->get($currencyAttribute) + ) { + $entity->set($currencyAttribute, $defaultCurrency); + } + } + } + } + + protected function processFileFieldsSave(Entity $entity) + { + foreach ($entity->getRelations() as $name => $defs) { + if (!isset($defs['type']) || !isset($defs['entity'])) continue; + if (!($defs['type'] === $entity::BELONGS_TO && $defs['entity'] === 'Attachment')) continue; + + $attribute = $name . 'Id'; + if (!$entity->hasAttribute($attribute)) continue; + if (!$entity->get($attribute)) continue; + if (!$entity->isAttributeChanged($attribute)) continue; + + $attachment = $this->getEntityManager()->getEntity('Attachment', $entity->get($attribute)); + if (!$attachment) continue; + $attachment->set([ + 'relatedId' => $entity->id, + 'relatedType' => $entity->getEntityType(), + ]); + $this->getEntityManager()->saveEntity($attachment); + } + + if (!$entity->isNew()) { + + foreach ($this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields']) as $name => $defs) { + if (!empty($defs['type']) && in_array($defs['type'], ['file', 'image'])) { + $attribute = $name . 'Id'; + if ($entity->isAttributeChanged($attribute)) { + $previousAttachmentId = $entity->getFetched($attribute); + if ($previousAttachmentId) { + $attachment = $this->getEntityManager()->getEntity('Attachment', $previousAttachmentId); + if ($attachment) { + $this->getEntityManager()->removeEntity($attachment); + } + } + } + } + } + } + } + + protected function processArrayFieldsSave(Entity $entity) + { + foreach ($entity->getAttributes() as $attribute => $defs) { + if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue; + if (!$entity->has($attribute)) continue; + if (!$entity->isAttributeChanged($attribute)) continue; + if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue; + if ($entity->getAttributeParam($attribute, 'notStorable')) continue; + $this->getEntityManager()->getRepository('ArrayValue')->storeEntityAttribute($entity, $attribute); + } + } + + protected function processWysiwygFieldsSave(Entity $entity) + { + if (!$entity->isNew()) return; + + $fieldsDefs = $this->getMetadata()->get(['entityDefs', $entity->getEntityType(), 'fields'], []); + foreach ($fieldsDefs as $field => $defs) { + if (!empty($defs['type']) && $defs['type'] === 'wysiwyg') { + $content = $entity->get($field); + if (!$content) continue; + if (preg_match_all("/\?entryPoint=attachment&id=([^&=\"']+)/", $content, $matches)) { + if (!empty($matches[1]) && is_array($matches[1])) { + foreach ($matches[1] as $id) { + $attachment = $this->getEntityManager()->getEntity('Attachment', $id); + if ($attachment) { + if (!$attachment->get('relatedId') && !$attachment->get('sourceId')) { + $attachment->set([ + 'relatedId' => $entity->id, + 'relatedType' => $entity->getEntityType() + ]); + $this->getEntityManager()->saveEntity($attachment); + } + } + } + } + } + } + } + } + + protected function processArrayFieldsRemove(Entity $entity) + { + foreach ($entity->getAttributes() as $attribute => $defs) { + if (!isset($defs['type']) || $defs['type'] !== Entity::JSON_ARRAY) continue; + if (!$entity->getAttributeParam($attribute, 'storeArrayValues')) continue; + if ($entity->getAttributeParam($attribute, 'notStorable')) continue; + $this->getEntityManager()->getRepository('ArrayValue')->deleteEntityAttribute($entity, $attribute); + } + } + + protected function processEmailAddressSave(Entity $entity) + { + if ($entity->hasRelation('emailAddresses') && $entity->hasAttribute('emailAddress')) { + $this->getEntityManager()->getRepository('EmailAddress')->storeEntityEmailAddress($entity); + } + } + + protected function processPhoneNumberSave(Entity $entity) + { + if ($entity->hasRelation('phoneNumbers') && $entity->hasAttribute('phoneNumber')) { + $this->getEntityManager()->getRepository('PhoneNumber')->storeEntityPhoneNumber($entity); + } + } + + public function processLinkMultipleFieldSave(Entity $entity, $link, array $options = []) + { + $name = $link; + + $idListAttribute = $link . 'Ids'; + $columnsAttribute = $link . 'Columns'; + + if ($this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.noSave")) { + return; + } + + $skipCreate = false; + $skipRemove = false; + $skipUpdate = false; + if (!empty($options['skipLinkMultipleCreate'])) $skipCreate = true; + if (!empty($options['skipLinkMultipleRemove'])) $skipRemove = true; + if (!empty($options['skipLinkMultipleUpdate'])) $skipUpdate = true; + + if ($entity->isNew()) { + $skipRemove = true; + $skipUpdate = true; + } + + if ($entity->has($idListAttribute)) { + $specifiedIdList = $entity->get($idListAttribute); + } else if ($entity->has($columnsAttribute)) { + $skipRemove = true; + $specifiedIdList = []; + foreach ($entity->get($columnsAttribute) as $id => $d) { + $specifiedIdList[] = $id; + } + } else { + return; + } + + if (!is_array($specifiedIdList)) return; + + $toRemoveIdList = []; + $existingIdList = []; + $toUpdateIdList = []; + $toCreateIdList = []; + $existingColumnsData = (object)[]; + + $defs = []; + $columns = $this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.columns"); + if (!empty($columns)) { + $columnData = $entity->get($columnsAttribute); + $defs['additionalColumns'] = $columns; + } + + if (!$skipRemove && !$skipUpdate) { + $foreignEntityList = $entity->get($name, $defs); + if ($foreignEntityList) { + foreach ($foreignEntityList as $foreignEntity) { + $existingIdList[] = $foreignEntity->id; + if (!empty($columns)) { + $data = (object)[]; + foreach ($columns as $columnName => $columnField) { + $foreignId = $foreignEntity->id; + $data->$columnName = $foreignEntity->get($columnField); + } + $existingColumnsData->$foreignId = $data; + if (!$entity->isNew()) { + $entity->setFetched($columnsAttribute, $existingColumnsData); + } + } + } + } + } + + if (!$entity->isNew()) { + if ($entity->has($idListAttribute) && !$entity->hasFetched($idListAttribute)) { + $entity->setFetched($idListAttribute, $existingIdList); + } + if ($entity->has($columnsAttribute) && !empty($columns)) { + $entity->setFetched($columnsAttribute, $existingColumnsData); + } + } + + foreach ($existingIdList as $id) { + if (!in_array($id, $specifiedIdList)) { + if (!$skipRemove) { + $toRemoveIdList[] = $id; + } + } else { + if (!$skipUpdate && !empty($columns)) { + foreach ($columns as $columnName => $columnField) { + if (isset($columnData->$id) && is_object($columnData->$id)) { + if ( + property_exists($columnData->$id, $columnName) + && + ( + !property_exists($existingColumnsData->$id, $columnName) + || + $columnData->$id->$columnName !== $existingColumnsData->$id->$columnName + ) + ) { + $toUpdateIdList[] = $id; + } + } + } + } + } + } + + if (!$skipCreate) { + foreach ($specifiedIdList as $id) { + if (!in_array($id, $existingIdList)) { + $toCreateIdList[] = $id; + } + } + } + + foreach ($toCreateIdList as $id) { + $data = null; + if (!empty($columns) && isset($columnData->$id)) { + $data = $columnData->$id; + } + $this->relate($entity, $name, $id, $data); + } + + foreach ($toRemoveIdList as $id) { + $this->unrelate($entity, $name, $id); + } + + foreach ($toUpdateIdList as $id) { + $data = $columnData->$id; + $this->updateRelation($entity, $name, $id, $data); + } + } + + protected function processSpecifiedRelationsSave(Entity $entity, array $options = []) + { + $relationTypeList = [$entity::HAS_MANY, $entity::MANY_MANY, $entity::HAS_CHILDREN]; + foreach ($entity->getRelations() as $name => $defs) { + if (in_array($defs['type'], $relationTypeList)) { + $idListAttribute = $name . 'Ids'; + $columnsAttribute = $name . 'Columns'; + if ($entity->has($idListAttribute) || $entity->has($columnsAttribute)) { + $this->processLinkMultipleFieldSave($entity, $name, $options); + } + } else if ($defs['type'] === $entity::HAS_ONE) { + if (empty($defs['entity']) || empty($defs['foreignKey'])) continue; + + if ($this->getMetadata()->get("entityDefs." . $entity->getEntityType() . ".fields.{$name}.noSave")) { + continue; + } + + $foreignEntityType = $defs['entity']; + $foreignKey = $defs['foreignKey']; + $idAttribute = $name . 'Id'; + + if (!$entity->has($idAttribute)) continue; + + $where = []; + $where[$foreignKey] = $entity->id; + + $previousForeignEntity = $this->getEntityManager()->getRepository($foreignEntityType) + ->select(['id'])->where($where)->findOne(); + + if ($previousForeignEntity) { + if (!$entity->isNew()) { + $entity->setFetched($idAttribute, $previousForeignEntity->id); + } + if (!$entity->get($idAttribute)) { + $previousForeignEntity->set($foreignKey, null); + $this->getEntityManager()->saveEntity($previousForeignEntity, ['skipAll' => true]); + } + } else { + if (!$entity->isNew()) { + $entity->setFetched($idAttribute, null); + } + } + + if ($entity->get($idAttribute)) { + $relateResult = $this->relate($entity, $name, $entity->get($idAttribute)); + if (!$relateResult) { + $entity->set($idAttribute, null); + } + } + } else if ($defs['type'] === $entity::BELONGS_TO) { + if (!$entity->get($name . 'Id')) continue; + if (!$entity->isAttributeChanged($name . 'Id')) continue; + + $foreignEntityType = $defs['entity'] ?? null; + $foreignLink = $defs['foreign'] ?? null; + + if ( + $this->getMetadata()->get( + ['entityDefs', $foreignEntityType, 'links', $foreignLink, 'type']) === $entity::HAS_ONE + ) { + $anotherEntity = $this->select(['id'])->where([ + $name . 'Id' => $entity->get($name . 'Id'), + 'id!=' => $entity->id, + ])->findOne(); + + if ($anotherEntity) { + $anotherEntity->set($name . 'Id', null); + $this->getEntityManager()->saveEntity($anotherEntity, ['skipAll' => true]); + } + } + } + } + } +} diff --git a/application/Espo/ORM/Repositories/Findable.php b/application/Espo/ORM/Repositories/Findable.php new file mode 100644 index 0000000000..5f8d9b3b0d --- /dev/null +++ b/application/Espo/ORM/Repositories/Findable.php @@ -0,0 +1,41 @@ +entityManager = $entityManager; } - protected function getMapper() + protected function getMapper() : Mapper { if (empty($this->mapper)) { $this->mapper = $this->getEntityManager()->getMapper('RDB'); @@ -82,16 +85,6 @@ class RDB extends \Espo\ORM\Repository { } - protected function getEntityFactory() - { - return $this->entityFactory; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - public function reset() { $this->whereClause = []; @@ -197,7 +190,7 @@ class RDB extends \Espo\ORM\Repository return $this->getMapper()->deleteFromDb($this->entityType, $id, $onlyDeleted); } - public function find(array $params = []) + public function find(array $params = []) : \Traversable { $params = $this->getSelectParams($params); @@ -221,7 +214,7 @@ class RDB extends \Espo\ORM\Repository return $collection; } - public function findOne(array $params = []) + public function findOne(array $params = []) : ?Entity { $collection = $this->limit(0, 1)->find($params); if (count($collection)) { @@ -246,7 +239,7 @@ class RDB extends \Espo\ORM\Repository return $collection; } - public function findRelated(Entity $entity, $relationName, array $params = []) + public function findRelated(Entity $entity, string $relationName, array $params = []) { if (!$entity->id) { return []; @@ -281,10 +274,10 @@ class RDB extends \Espo\ORM\Repository } } - public function countRelated(Entity $entity, string $relationName, array $params = []) + public function countRelated(Entity $entity, string $relationName, array $params = []) : int { if (!$entity->id) { - return; + return 0; } $entityType = $entity->relations[$relationName]['entity']; if (empty($params['skipAdditionalSelectParams'])) { @@ -294,10 +287,10 @@ class RDB extends \Espo\ORM\Repository return intval($this->getMapper()->countRelated($entity, $relationName, $params)); } - public function isRelated(Entity $entity, string $relationName, $foreign) + public function isRelated(Entity $entity, string $relationName, $foreign) : bool { if (!$entity->id) { - return null; + return false; } if ($foreign instanceof Entity) { @@ -305,14 +298,14 @@ class RDB extends \Espo\ORM\Repository } else if (is_string($foreign)) { $id = $foreign; } else { - return null; + return false; } - if (!$id) return null; + if (!$id) return false; if ($entity->getRelationType($relationName) === Entity::BELONGS_TO) { $foreignEntityType = $entity->getRelationParam($relationName, 'entity'); - if (!$foreignEntityType) return null; + if (!$foreignEntityType) return false; $foreignId = $entity->get($relationName . 'Id'); @@ -334,9 +327,9 @@ class RDB extends \Espo\ORM\Repository return $foreignEntity->id === $id; } - return !!$this->countRelated($entity, $relationName, [ + return (bool) $this->countRelated($entity, $relationName, [ 'whereClause' => [ - 'id' => $id + 'id' => $id, ] ]); } @@ -483,13 +476,14 @@ class RDB extends \Espo\ORM\Repository return $result; } + /** Deprecated */ public function getAll() { $this->reset(); return $this->find(); } - public function count(array $params = []) + public function count(array $params = []) : int { if (empty($params['skipAdditionalSelectParams'])) { $this->handleSelectParams($params); @@ -501,19 +495,19 @@ class RDB extends \Espo\ORM\Repository return intval($count); } - public function max($field) + public function max(string $field) { $params = $this->getSelectParams(); return $this->getMapper()->max($this->seed, $params, $field); } - public function min($field) + public function min(string $field) { $params = $this->getSelectParams(); return $this->getMapper()->min($this->seed, $params, $field); } - public function sum($field) + public function sum(string $field) { $params = $this->getSelectParams(); return $this->getMapper()->sum($this->seed, $params, $field); diff --git a/application/Espo/ORM/Repositories/Relatable.php b/application/Espo/ORM/Repositories/Relatable.php new file mode 100644 index 0000000000..bdf97e2b2c --- /dev/null +++ b/application/Espo/ORM/Repositories/Relatable.php @@ -0,0 +1,45 @@ +entityManager = $entityManager; } - protected function getEntityFactory() + protected function getEntityFactory() : EntityFactory { return $this->entityFactory; } - protected function getEntityManager() + protected function getEntityManager() : EntityManager { return $this->entityManager; } - public function getEntityType() + public function getEntityType() : string { return $this->entityType; } - abstract public function get(?string $id = null); + /** + * Get entity. If $id is NULL, a new entity is returned. + */ + abstract public function get(?string $id = null) : ?Entity; + /** + * Store entity. + */ abstract public function save(Entity $entity); - - abstract public function remove(Entity $entity); - - abstract public function find(array $params); - - abstract public function findOne(array $params); - - abstract public function getAll(); - - abstract public function count(array $params); } diff --git a/application/Espo/Repositories/ActionHistoryRecord.php b/application/Espo/Repositories/ActionHistoryRecord.php index 4688b1fb24..d13211b07f 100644 --- a/application/Espo/Repositories/ActionHistoryRecord.php +++ b/application/Espo/Repositories/ActionHistoryRecord.php @@ -31,7 +31,7 @@ namespace Espo\Repositories; use Espo\ORM\Entity; -class ActionHistoryRecord extends \Espo\Core\ORM\Repositories\RDB +class ActionHistoryRecord extends \Espo\Core\Repositories\Database { protected $hooksDisabled = true; diff --git a/application/Espo/Repositories/ArrayValue.php b/application/Espo/Repositories/ArrayValue.php index 67b93669cf..eb5088a660 100644 --- a/application/Espo/Repositories/ArrayValue.php +++ b/application/Espo/Repositories/ArrayValue.php @@ -31,9 +31,9 @@ namespace Espo\Repositories; use Espo\ORM\Entity; -use \Espo\Core\Exceptions\Error; +use Espo\Core\Exceptions\Error; -class ArrayValue extends \Espo\Core\ORM\Repositories\RDB +class ArrayValue extends \Espo\Core\Repositories\Database { protected $hooksDisabled = true; @@ -43,7 +43,7 @@ class ArrayValue extends \Espo\Core\ORM\Repositories\RDB protected $processFieldsAfterRemoveDisabled = true; - public function storeEntityAttribute(Entity $entity, $attribute, $populateMode = false) + public function storeEntityAttribute(Entity $entity, string $attribute, bool $populateMode = false) { if (!$entity->getAttributeType($attribute) === Entity::JSON_ARRAY) { throw new Error("ArrayValue: Can't store non array attribute."); @@ -89,13 +89,13 @@ class ArrayValue extends \Espo\Core\ORM\Repositories\RDB 'entityType' => $entity->getEntityType(), 'entityId' => $entity->id, 'attribute' => $attribute, - 'value' => $value + 'value' => $value, ]); $this->save($arrayValue); } } - public function deleteEntityAttribute(Entity $entity, $attribute) + public function deleteEntityAttribute(Entity $entity, string $attribute) { if (!$entity->id) { throw new Error("ArrayValue: Can't delete {$attribute} w/o id given."); diff --git a/application/Espo/Repositories/Preferences.php b/application/Espo/Repositories/Preferences.php index 240e15a459..19d51e2f59 100644 --- a/application/Espo/Repositories/Preferences.php +++ b/application/Espo/Repositories/Preferences.php @@ -33,27 +33,20 @@ use Espo\ORM\Entity; use Espo\ORM\Repository; use Espo\Core\Utils\Json; -use Espo\Core\Di\{ - FileManagerAware, - FileManagerSetter, - MetadataAware, - MetadataSetter, - ConfigAware, - ConfigSetter, - EntityManagerAware, - EntityManagerSetter, +use Espo\ORM\Repositories\{ + Removable, }; -class Preferences extends Repository implements - FileManagerAware, - MetadataAware, - ConfigAware, - EntityManagerAware +use Espo\Core\Di; + +class Preferences extends Repository implements Removable, + Di\MetadataAware, + Di\ConfigAware, + Di\EntityManagerAware { - use FileManagerSetter; - use MetadataSetter; - use ConfigSetter; - use EntityManagerSetter; + use Di\MetadataSetter; + use Di\ConfigSetter; + use Di\EntityManagerSetter; protected $defaultAttributeListFromSettings = [ 'decimalMark', @@ -66,33 +59,13 @@ class Preferences extends Repository implements protected $entityType = 'Preferences'; - protected function getFileManager() - { - return $this->fileManager; - } - - protected function getEntityManger() - { - return $this->entityManager; - } - - protected function getMetadata() - { - return $this->metadata; - } - - protected function getConfig() - { - return $this->config; - } - - public function get(?string $id = null) + public function get(?string $id = null) : ?Entity { if ($id) { $entity = $this->entityFactory->create('Preferences'); $entity->id = $id; if (empty($this->data[$id])) { - $pdo = $this->getEntityManger()->getPDO(); + $pdo = $this->entityManager->getPDO(); $sql = "SELECT `id`, `data` FROM `preferences` WHERE id = ".$pdo->quote($id); $ps = $pdo->query($sql); @@ -110,18 +83,18 @@ class Preferences extends Repository implements if ($data) { $this->data[$id] = $data; } else { - $fields = $this->getMetadata()->get('entityDefs.Preferences.fields'); - $defaults = array(); + $fields = $this->metadata->get('entityDefs.Preferences.fields'); + $defaults = []; - $dashboardLayout = $this->getConfig()->get('dashboardLayout'); + $dashboardLayout = $this->config->get('dashboardLayout'); $dashletsOptions = null; if (!$dashboardLayout) { - $dashboardLayout = $this->getMetadata()->get('app.defaultDashboardLayouts.Standard'); - $dashletsOptions = $this->getMetadata()->get('app.defaultDashboardOptions.Standard'); + $dashboardLayout = $this->metadata->get('app.defaultDashboardLayouts.Standard'); + $dashletsOptions = $this->metadata->get('app.defaultDashboardOptions.Standard'); } if ($dashletsOptions === null) { - $dashletsOptions = $this->getConfig()->get('dashletsOptions', (object) []); + $dashletsOptions = $this->config->get('dashletsOptions', (object) []); } $defaults['dashboardLayout'] = $dashboardLayout; @@ -133,7 +106,7 @@ class Preferences extends Repository implements } } foreach ($this->defaultAttributeListFromSettings as $attr) { - $defaults[$attr] = $this->getConfig()->get($attr); + $defaults[$attr] = $this->config->get($attr); } $this->data[$id] = $defaults; @@ -156,7 +129,7 @@ class Preferences extends Repository implements $id = $entity->id; $autoFollowEntityTypeList = []; - $pdo = $this->getEntityManger()->getPDO(); + $pdo = $this->entityManager->getPDO(); $sql = " SELECT `entity_type` AS 'entityType' FROM `autofollow` WHERE `user_id` = ".$pdo->quote($id)." @@ -189,11 +162,11 @@ class Preferences extends Repository implements if ($was == $became) { return; } - $pdo = $this->getEntityManger()->getPDO(); + $pdo = $this->entityManager->getPDO(); $sql = "DELETE FROM autofollow WHERE user_id = ".$pdo->quote($id).""; $pdo->query($sql); - $scopes = $this->getMetadata()->get('scopes'); + $scopes = $this->metadata->get('scopes'); foreach ($became as $entityType) { if (isset($scopes[$entityType]) && !empty($scopes[$entityType]['stream'])) { $sql = " @@ -205,15 +178,15 @@ class Preferences extends Repository implements } } - public function save(Entity $entity, array $options = array()) + public function save(Entity $entity, array $options = []) { if (!$entity->id) return; $this->data[$entity->id] = $entity->toArray(); - $fields = $fields = $this->getMetadata()->get('entityDefs.Preferences.fields'); + $fields = $fields = $this->metadata->get('entityDefs.Preferences.fields'); - $data = array(); + $data = []; foreach ($this->data[$entity->id] as $field => $value) { if (empty($fields[$field]['notStorable'])) { $data[$field] = $value; @@ -222,7 +195,7 @@ class Preferences extends Repository implements $dataString = Json::encode($data, \JSON_PRETTY_PRINT); - $pdo = $this->getEntityManger()->getPDO(); + $pdo = $this->entityManager->getPDO(); $sql = " INSERT INTO `preferences` (`id`, `data`) VALUES (".$pdo->quote($entity->id).", ".$pdo->quote($dataString).") @@ -231,7 +204,7 @@ class Preferences extends Repository implements $pdo->query($sql); - $user = $this->getEntityManger()->getEntity('User', $entity->id); + $user = $this->entityManager->getEntity('User', $entity->id); if ($user && !$user->isPortal()) { $this->storeAutoFollowEntityTypeList($entity); } @@ -239,9 +212,9 @@ class Preferences extends Repository implements return $entity; } - public function deleteFromDb($id) + public function deleteFromDb(string $id) { - $pdo = $this->getEntityManger()->getPDO(); + $pdo = $this->entityManager->getPDO(); $sql = "DELETE FROM `preferences` WHERE `id` = " . $pdo->quote($id); $ps = $pdo->query($sql); } @@ -255,7 +228,7 @@ class Preferences extends Repository implements } } - public function resetToDefaults($userId) + public function resetToDefaults(string $userId) { $this->deleteFromDb($userId); if (isset($this->data[$userId])) { @@ -265,20 +238,4 @@ class Preferences extends Repository implements return $entity->toArray(); } } - - public function find(array $params) - { - } - - public function findOne(array $params) - { - } - - public function getAll() - { - } - - public function count(array $params) - { - } }