diff --git a/application/Espo/Core/Controllers/Record.php b/application/Espo/Core/Controllers/Record.php index d673db86b2..6ba20c434f 100644 --- a/application/Espo/Core/Controllers/Record.php +++ b/application/Espo/Core/Controllers/Record.php @@ -42,27 +42,16 @@ class Record extends Base public static $defaultAction = 'list'; - protected $defaultRecordServiceName = 'Record'; - protected function getEntityManager() { return $this->getContainer()->get('entityManager'); } - protected function getRecordService($name = null) + protected function getRecordService(?string $name = null) : object { - if (empty($name)) { - $name = $this->name; - } + $name = $name ?? $this->name; - if ($this->getServiceFactory()->checkExists($name)) { - $service = $this->getServiceFactory()->create($name); - } else { - $service = $this->getServiceFactory()->create($this->defaultRecordServiceName); - $service->setEntityType($name); - } - - return $service; + return $this->getContainer()->get('recordServiceContainer')->get($name); } public function actionRead($params, $data, $request) @@ -224,10 +213,9 @@ class Record extends Base $id = $params['id']; - if ($this->getRecordService()->delete($id)) { - return true; - } - throw new Error(); + $this->getRecordService()->delete($id); + + return true; } public function actionExport($params, $data, $request) diff --git a/application/Espo/Core/Controllers/RecordTree.php b/application/Espo/Core/Controllers/RecordTree.php index 84498f83c2..5917f4bcf8 100644 --- a/application/Espo/Core/Controllers/RecordTree.php +++ b/application/Espo/Core/Controllers/RecordTree.php @@ -39,7 +39,7 @@ class RecordTree extends Record { public static $defaultAction = 'list'; - protected $defaultRecordServiceName = 'RecordTree'; + // protected $defaultRecordServiceName = 'RecordTree'; public function actionListTree($params, $data, $request) { diff --git a/application/Espo/Core/Di/FieldManagerUtilAware.php b/application/Espo/Core/Di/FieldManagerUtilAware.php new file mode 100644 index 0000000000..6e7cb3e1c7 --- /dev/null +++ b/application/Espo/Core/Di/FieldManagerUtilAware.php @@ -0,0 +1,37 @@ +fieldManagerUtil = $fieldManagerUtil; + } +} diff --git a/application/Espo/Core/Di/FieldValidatorManagerAware.php b/application/Espo/Core/Di/FieldValidatorManagerAware.php new file mode 100644 index 0000000000..abd84ecc3e --- /dev/null +++ b/application/Espo/Core/Di/FieldValidatorManagerAware.php @@ -0,0 +1,37 @@ +fieldValidatorManager = $fieldValidatorManager; + } +} diff --git a/application/Espo/Core/Di/InjectableFactoryAware.php b/application/Espo/Core/Di/InjectableFactoryAware.php new file mode 100644 index 0000000000..ae99f90e34 --- /dev/null +++ b/application/Espo/Core/Di/InjectableFactoryAware.php @@ -0,0 +1,37 @@ +injectableFactory = $injectableFactory; + } +} diff --git a/application/Espo/Core/Di/RecordServiceContainerAware.php b/application/Espo/Core/Di/RecordServiceContainerAware.php new file mode 100644 index 0000000000..1edfacf0e9 --- /dev/null +++ b/application/Espo/Core/Di/RecordServiceContainerAware.php @@ -0,0 +1,37 @@ +recordServiceContainer = $recordServiceContainer; + } +} diff --git a/application/Espo/Core/RecordServiceContainer.php b/application/Espo/Core/RecordServiceContainer.php new file mode 100644 index 0000000000..0d1592c7ca --- /dev/null +++ b/application/Espo/Core/RecordServiceContainer.php @@ -0,0 +1,86 @@ + 'RecordTree', + ]; + + protected $serviceFactory; + protected $metadata; + + public function __construct(ServiceFactory $serviceFactory, Metadata $metadata) + { + $this->serviceFactory = $serviceFactory; + $this->metadata = $metadata; + } + + public function get(string $entityType) : Record + { + $name = $entityType; + + if (!array_key_exists($name, $this->data)) { + if (!$this->metadata->get(['scopes', $name, 'entity'])) { + throw new Error("Can't create record service {$name}, there's no such entity type."); + } + + if ($this->serviceFactory->checkExists($name)) { + $obj = $this->serviceFactory->create($name); + } else { + $default = 'Record'; + $type = $this->metadata->get(['scopes', $name, 'type']); + if ($type) { + $default = $this->defaultTypeMap[$type] ?? $default; + } + $obj = $this->serviceFactory->create($default); + $service->setEntityType($name); + } + $this->data[$name] = $obj; + } + + return $this->data[$name]; + } +} diff --git a/application/Espo/Core/Services/Base.php b/application/Espo/Core/Services/Base.php index e56fe0b764..9df79deee5 100644 --- a/application/Espo/Core/Services/Base.php +++ b/application/Espo/Core/Services/Base.php @@ -31,6 +31,7 @@ namespace Espo\Core\Services; use Espo\Core\Interfaces\Injectable; +/** Deprecated */ abstract class Base implements Injectable { protected $dependencyList = [ diff --git a/application/Espo/Core/Services/Record.php b/application/Espo/Core/Services/Record.php new file mode 100644 index 0000000000..b1e8deb3bd --- /dev/null +++ b/application/Espo/Core/Services/Record.php @@ -0,0 +1,47 @@ +campaignService; } - protected function findLinkedQueueItems($id, $params) + protected function findLinkedQueueItems(string $id, array $params) : StdClass { $link = 'queueItems'; @@ -540,13 +542,13 @@ class MassEmail extends \Espo\Services\Record $selectParams = array_merge($selectParams, $this->linkSelectParams[$link]); } - $selectParams['whereClause'][] = array( + $selectParams['whereClause'][] = [ 'isTest' => false - ); + ]; $collection = $this->getRepository()->findRelated($entity, $link, $selectParams); - $recordService = $this->getRecordService('EmailQueueItem'); + $recordService = $this->recordServiceContainer->get('EmailQueueItem'); foreach ($collection as $e) { $recordService->loadAdditionalFieldsForList($e); @@ -555,10 +557,10 @@ class MassEmail extends \Espo\Services\Record $total = $this->getRepository()->countRelated($entity, $link, $selectParams); - return array( + return (object) [ 'total' => $total, 'collection' => $collection - ); + ]; } public function getSmtpAccountDataList() diff --git a/application/Espo/Modules/Crm/Services/TargetList.php b/application/Espo/Modules/Crm/Services/TargetList.php index 148b1b575a..6bf4fd8c94 100644 --- a/application/Espo/Modules/Crm/Services/TargetList.php +++ b/application/Espo/Modules/Crm/Services/TargetList.php @@ -29,11 +29,13 @@ namespace Espo\Modules\Crm\Services; -use \Espo\ORM\Entity; +use Espo\ORM\Entity; -use \Espo\Core\Exceptions\NotFound; -use \Espo\Core\Exceptions\BadRequest; -use \Espo\Core\Exceptions\Forbidden; +use Espo\Core\Exceptions\NotFound; +use Espo\Core\Exceptions\BadRequest; +use Espo\Core\Exceptions\Forbidden; + +use StdClass; class TargetList extends \Espo\Services\Record { @@ -43,12 +45,12 @@ class TargetList extends \Espo\Services\Record protected $targetsLinkList = ['accounts', 'contacts', 'leads', 'users']; - protected $entityTypeLinkMap = array( + protected $entityTypeLinkMap = [ 'Lead' => 'leads', 'Account' => 'accounts', 'Contact' => 'contacts', 'User' => 'users', - ); + ]; protected $linkSelectParams = [ 'accounts' => [ @@ -232,7 +234,7 @@ class TargetList extends \Espo\Services\Record } } - protected function findLinkedOptedOut($id, $params) + protected function findLinkedOptedOut(string $id, array $params) : StdClass { $pdo = $this->getEntityManager()->getPDO(); $query = $this->getEntityManager()->getQuery(); @@ -297,13 +299,13 @@ class TargetList extends \Espo\Services\Record $row = $sth->fetch(\PDO::FETCH_ASSOC); $count = $row['count']; - return array( + return (object) [ 'total' => $count, 'list' => $arr - ); + ]; } - public function optOut($id, $targetType, $targetId) + public function optOut(string $id, string $targetType, string $targetId) { $targetList = $this->getEntityManager()->getEntity('TargetList', $id); if (!$targetList) { @@ -342,7 +344,7 @@ class TargetList extends \Espo\Services\Record return false; } - public function cancelOptOut($id, $targetType, $targetId) + public function cancelOptOut(string $id, string $targetType, string $targetId) { $targetList = $this->getEntityManager()->getEntity('TargetList', $id); if (!$targetList) { diff --git a/application/Espo/ORM/Metadata.php b/application/Espo/ORM/Metadata.php index dbe9552c26..31247d4592 100644 --- a/application/Espo/ORM/Metadata.php +++ b/application/Espo/ORM/Metadata.php @@ -29,16 +29,18 @@ namespace Espo\ORM; +use Espo\Core\Utils\Util; + class Metadata { - protected $data = array(); + protected $data = []; public function setData($data) { $this->data = $data; } - public function get($entityType, $key = null, $default = null) + public function get(string $entityType, $key = null, $default = null) { if (!array_key_exists($entityType, $this->data)) { return null; @@ -46,13 +48,13 @@ class Metadata $data = $this->data[$entityType]; if (!$key) return $data; - return \Espo\Core\Utils\Util::getValueByKey($data, $key, $default); + return Util::getValueByKey($data, $key, $default); } - public function has($entityType) + public function has(string $entityType) : bool { if (!array_key_exists($entityType, $this->data)) { - return null; + return false; } return true; } diff --git a/application/Espo/Resources/metadata/app/containerServices.json b/application/Espo/Resources/metadata/app/containerServices.json index 530e898031..56a8abdbe0 100644 --- a/application/Espo/Resources/metadata/app/containerServices.json +++ b/application/Espo/Resources/metadata/app/containerServices.json @@ -41,6 +41,9 @@ "serviceFactory": { "className": "Espo\\Core\\ServiceFactory" }, + "recordServiceContainer": { + "className": "Espo\\Core\\RecordServiceContainer" + }, "templateFileManager": { "className": "Espo\\Core\\Utils\\TemplateFileManager" }, diff --git a/application/Espo/Resources/metadata/scopes/EmailFolder.json b/application/Espo/Resources/metadata/scopes/EmailFolder.json new file mode 100644 index 0000000000..39c96e7ac2 --- /dev/null +++ b/application/Espo/Resources/metadata/scopes/EmailFolder.json @@ -0,0 +1,3 @@ +{ + "entity": true +} diff --git a/application/Espo/Services/Attachment.php b/application/Espo/Services/Attachment.php index ee49dcb9d3..6ba67492b1 100644 --- a/application/Espo/Services/Attachment.php +++ b/application/Espo/Services/Attachment.php @@ -51,7 +51,7 @@ class Attachment extends Record 'image/webp', ]; - public function upload($fileData) + public function upload($fileData) : Entity { if (!$this->getAcl()->checkScope('Attachment', 'create')) { throw new Forbidden(); @@ -72,7 +72,14 @@ class Attachment extends Record return $attachment; } - public function create($data) + protected function afterCreateEntity(Entity $entity, $data) + { + if (!empty($data->file)) { + $entity->clear('contents'); + } + } + + protected function beforeCreateEntity(Entity $entity, $data) { if (!empty($data->file)) { $arr = explode(',', $data->file); @@ -134,17 +141,6 @@ class Attachment extends Record } } - $entity = parent::create($data); - - if (!empty($data->file)) { - $entity->clear('contents'); - } - - return $entity; - } - - protected function beforeCreateEntity(Entity $entity, $data) - { $storage = $entity->get('storage'); if ($storage && !$this->getMetadata()->get(['app', 'fileStorage', 'implementationClassNameMap', $storage])) { $entity->clear('storage'); diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index 14d5a55590..99bb0d312a 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -389,7 +389,7 @@ class Email extends Record return $this->streamService; } - public function create($data) + public function create(\StdClass $data) : Entity { $entity = parent::create($data); @@ -448,11 +448,11 @@ class Email extends Record $this->getEntityManager()->getRepository('Email')->loadReplyToField($entity); } - public function getEntity($id = null) + public function getEntity(?string $id = null) : ?Entity { $entity = parent::getEntity($id); - if (!empty($entity) && !empty($id) && !$entity->get('isRead')) { + if ($entity && $id && !$entity->get('isRead')) { $this->markAsRead($entity->id); } diff --git a/application/Espo/Services/EmailAccount.php b/application/Espo/Services/EmailAccount.php index 77b0963201..ecc20ed44e 100644 --- a/application/Espo/Services/EmailAccount.php +++ b/application/Espo/Services/EmailAccount.php @@ -193,7 +193,7 @@ class EmailAccount extends Record return $storage; } - public function create($data) + public function create(\StdClass $data) : Entity { if (!$this->getUser()->isAdmin()) { $count = $this->getEntityManager()->getRepository('EmailAccount')->where(array( @@ -211,6 +211,7 @@ class EmailAccount extends Record } $this->getEntityManager()->saveEntity($entity); } + return $entity; } diff --git a/application/Espo/Services/EmailFolder.php b/application/Espo/Services/EmailFolder.php index 04c2983208..fbaf3cc875 100644 --- a/application/Espo/Services/EmailFolder.php +++ b/application/Espo/Services/EmailFolder.php @@ -29,11 +29,11 @@ namespace Espo\Services; -use \Espo\ORM\Entity; +use Espo\ORM\Entity; -use \Espo\Core\Exceptions\Forbidden; -use \Espo\Core\Exceptions\NotFound; -use \Espo\Core\Exceptions\Error; +use Espo\Core\Exceptions\Forbidden; +use Espo\Core\Exceptions\NotFound; +use Espo\Core\Exceptions\Error; class EmailFolder extends Record { diff --git a/application/Espo/Services/ExternalAccount.php b/application/Espo/Services/ExternalAccount.php index 68c3dd2752..61d7b2f01b 100644 --- a/application/Espo/Services/ExternalAccount.php +++ b/application/Espo/Services/ExternalAccount.php @@ -113,7 +113,7 @@ class ExternalAccount extends Record } } - public function read($id) + public function read(string $id) : Entity { list($integration, $userId) = explode('__', $id); @@ -135,6 +135,5 @@ class ExternalAccount extends Record } return $entity; - } } diff --git a/application/Espo/Services/Import.php b/application/Espo/Services/Import.php index 44729522b3..7595f38149 100644 --- a/application/Espo/Services/Import.php +++ b/application/Espo/Services/Import.php @@ -37,6 +37,8 @@ use Espo\Core\Exceptions\BadRequest; use Espo\ORM\Entity; use Espo\Entities\User; +use StdClass; + class Import extends \Espo\Services\Record { const REVERT_PERMANENTLY_REMOVE_PERIOD_DAYS = 2; @@ -45,9 +47,7 @@ class Import extends \Espo\Services\Record { parent::init(); - $this->addDependency('serviceFactory'); $this->addDependency('fileManager'); - $this->addDependency('selectManagerFactory'); $this->addDependency('fileStorageManager'); } @@ -71,36 +71,29 @@ class Import extends \Espo\Services\Record 'hh:mmA' => 'h:iA', ]; - protected $services = []; - - protected function getSelectManagerFactory() - { - return $this->injections['selectManagerFactory']; - } - protected function getFileStorageManager() { - return $this->injections['fileStorageManager']; + return $this->getInjection('fileStorageManager'); } protected function getFileManager() { - return $this->injections['fileManager']; + return $this->getInjection('fileManager'); } protected function getAcl() { - return $this->injections['acl']; + return $this->acl; } protected function getMetadata() { - return $this->injections['metadata']; + return $this->metadata; } protected function getServiceFactory() { - return $this->injections['serviceFactory']; + return $this->serviceFactory; } public function loadAdditionalFields(Entity $entity) @@ -113,11 +106,11 @@ class Import extends \Espo\Services\Record $entity->set([ 'importedCount' => $importedCount, 'duplicateCount' => $duplicateCount, - 'updatedCount' => $updatedCount + 'updatedCount' => $updatedCount, ]); } - public function findLinked($id, $link, $params) + public function findLinked(string $id, string $link, array $params) : StdClass { $entity = $this->getRepository()->get($id); $foreignEntityType = $entity->get('entityType'); @@ -137,7 +130,7 @@ class Import extends \Espo\Services\Record $collection = $this->getRepository()->findRelated($entity, $link, $selectParams); - $recordService = $this->getRecordService($foreignEntityType); + $recordService = $this->recordServiceContainer->get($foreignEntityType); foreach ($collection as $e) { $recordService->loadAdditionalFieldsForList($e); @@ -146,9 +139,9 @@ class Import extends \Espo\Services\Record $total = $this->getRepository()->countRelated($entity, $link, $selectParams); - return [ + return (object) [ 'total' => $total, - 'collection' => $collection + 'collection' => $collection, ]; } @@ -318,7 +311,7 @@ class Import extends \Espo\Services\Record return true; } - public function jobRunIdleImport($data) + public function jobRunIdleImport(StdClass $data) : array { if ( empty($data->userId) || @@ -349,7 +342,7 @@ class Import extends \Espo\Services\Record $this->import($entityType, $importAttributeList, $attachmentId, $params, $importId, $user); } - public function importById(string $id, bool $startFromLastIndex = false, $forceResume = false) : array + public function importById(string $id, bool $startFromLastIndex = false, bool $forceResume = false) : array { $import = $this->getEntityManager()->getEntity('Import', $id); @@ -380,7 +373,7 @@ class Import extends \Espo\Services\Record return $this->import($entityType, $attributeList, $import->get('fileId'), $params, $id); } - public function importFileWithParamsId(string $contents, string $importParamsId) + public function importFileWithParamsId(string $contents, string $importParamsId) : array { if (!$contents) { throw new Error("File contents is empty."); @@ -622,8 +615,9 @@ class Import extends \Espo\Services\Record ]; } - public function importRow($scope, array $importAttributeList, array $row, array $params = [], $user) - { + public function importRow( + string $scope, array $importAttributeList, array $row, array $params = [], ?User $user = null + ) : ?array { $id = null; $action = 'create'; if (!empty($params['action'])) { @@ -631,7 +625,7 @@ class Import extends \Espo\Services\Record } if (empty($importAttributeList)) { - return; + return null; } if (in_array($action, ['createAndUpdate', 'update'])) { @@ -647,18 +641,18 @@ class Import extends \Espo\Services\Record } } - $recordService = $this->getRecordService($scope); + $recordService = $this->recordServiceContainer->get($scope); if (in_array($action, ['createAndUpdate', 'update'])) { if (!count($updateByAttributeList)) { - return; + return null; } $entity = $this->getEntityManager()->getRepository($scope)->where($whereClause)->findOne(); if ($entity) { if (!$user->isAdmin()) { if (!$this->getAclManager()->checkEntity($user, $entity, 'edit')) { - return; + return null; } } } @@ -669,7 +663,7 @@ class Import extends \Espo\Services\Record $entity->set('id', $whereClause['id']); } } else { - return; + return null; } } } else { @@ -1091,8 +1085,8 @@ class Import extends \Espo\Services\Record return $value; case Entity::JSON_ARRAY: - if (!is_string($value)) return; - if (!strlen($value)) return; + if (!is_string($value)) return null; + if (!strlen($value)) return null; if ($value[0] === '[') { $value = \Espo\Core\Utils\Json::decode($value); return $value; @@ -1107,21 +1101,7 @@ class Import extends \Espo\Services\Record return $value; } - protected function getRecordService($scope) - { - if (empty($this->services[$scope])) { - if ($this->getServiceFactory()->checkExists($scope)) { - $service = $this->getServiceFactory()->create($scope); - } else { - $service = $this->getServiceFactory()->create('Record'); - $service->setEntityType($scope); - } - $this->services[$scope] = $service; - } - return $this->services[$scope]; - } - - public function unmarkAsDuplicate($id, $entityType, $entityId) + public function unmarkAsDuplicate(string $id, string $entityType, string $entityId) { $pdo = $this->getEntityManager()->getPDO(); diff --git a/application/Espo/Services/Note.php b/application/Espo/Services/Note.php index 4b5323b96c..365c1daf86 100644 --- a/application/Espo/Services/Note.php +++ b/application/Espo/Services/Note.php @@ -39,27 +39,10 @@ class Note extends Record { protected $noteNotificationPeriod = '1 hour'; - public function getEntity($id = null) + public function loadAdditionalFields(Entity $entity) { - $entity = parent::getEntity($id); - if (!empty($id)) { - $entity->loadAttachments(); - } - return $entity; - } - - public function create($data) - { - if (!empty($data->parentType) && !empty($data->parentId)) { - $entity = $this->getEntityManager()->getEntity($data->parentType, $data->parentId); - if ($entity) { - if (!$this->getAcl()->check($entity, 'read')) { - throw new Forbidden(); - } - } - } - - return parent::create($data); + parent::loadAdditionalFields($entity); + $entity->loadAttachments(); } protected function afterCreateEntity(Entity $entity, $data) @@ -81,6 +64,15 @@ class Note extends Record protected function beforeCreateEntity(Entity $entity, $data) { + if (!empty($data->parentType) && !empty($data->parentId)) { + $entity = $this->getEntityManager()->getEntity($data->parentType, $data->parentId); + if ($entity) { + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + } + } + parent::beforeCreateEntity($entity, $data); if ($entity->get('type') === 'Post') { diff --git a/application/Espo/Services/Record.php b/application/Espo/Services/Record.php index ad45f7693c..94febb4084 100644 --- a/application/Espo/Services/Record.php +++ b/application/Espo/Services/Record.php @@ -29,44 +29,76 @@ namespace Espo\Services; +use Espo\Core\Exceptions\{ + Error, + BadRequest, + Conflict, + NotFound, + NotFoundSilent, + ForbiddenSilent, + ConflictSilent, +}; + use Espo\ORM\Entity; - -use Espo\Core\Exceptions\Error; -use Espo\Core\Exceptions\Forbidden; -use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Exceptions\Conflict; -use Espo\Core\Exceptions\NotFound; -use Espo\Core\Exceptions\NotFoundSilent; -use Espo\Core\Exceptions\ForbiddenSilent; -use Espo\Core\Exceptions\ConflictSilent; - -use Espo\Core\Utils\Util; -use Espo\Core\AclManager; -use Espo\Core\Acl; use Espo\Entities\User; -class Record extends \Espo\Core\Services\Base +use Espo\Core\{ + Acl, + ORM\EntityManager, + AclManager, + Utils\Util, + Services\Record as RecordServiceInterface, +}; + +use Espo\Core\Di; + +use StdClass; + +/** + * A layer between Controller and Repository. For CRUD and other operations with records. + * If a service with the name of an entity type exists then it will be used instead this one. + */ +class Record implements RecordServiceInterface, + + Di\ConfigAware, + Di\ServiceFactoryAware, + Di\EntityManagerAware, + Di\UserAware, + Di\MetadataAware, + Di\AclAware, + Di\AclManagerAware, + Di\FileManagerAware, + Di\SelectManagerFactoryAware, + Di\InjectableFactoryAware, + Di\FieldManagerUtilAware, + Di\FieldValidatorManagerAware, + Di\RecordServiceContainerAware, + + /** for backward compatibility, to be removed */ + \Espo\Core\Interfaces\Injectable { - protected $dependencyList = [ - 'entityManager', - 'user', - 'metadata', - 'acl', - 'aclManager', - 'config', - 'serviceFactory', - 'fileManager', - 'selectManagerFactory', - 'fileStorageManager', - 'injectableFactory', - 'fieldManagerUtil', - 'container', - ]; + use Di\ConfigSetter; + use Di\ServiceFactorySetter; + use Di\EntityManagerSetter; + use Di\UserSetter; + use Di\MetadataSetter; + use Di\AclSetter; + use Di\AclManagerSetter; + use Di\FileManagerSetter; + use Di\SelectManagerFactorySetter; + use Di\InjectableFactorySetter; + use Di\FieldManagerUtilSetter; + use Di\FieldValidatorManagerSetter; + use Di\RecordServiceContainerSetter; + + /** for backward compatibility, to be removed */ + use \Espo\Core\Traits\Injectable; + + /** for backward compatibility, to be removed */ + protected $dependencyList = []; protected $getEntityBeforeUpdate = false; - protected $entityName; - protected $entityType; private $streamService; @@ -135,11 +167,11 @@ class Record extends \Espo\Core\Services\Base protected $duplicateIgnoreAttributeList = []; - private $acl = null; + protected $acl = null; - private $user = null; + protected $user = null; - private $aclManager = null; + protected $aclManager = null; const MAX_SELECT_TEXT_ATTRIBUTE_LENGTH = 5000; @@ -149,7 +181,6 @@ class Record extends \Espo\Core\Services\Base public function __construct() { - parent::__construct(); if (empty($this->entityType)) { $name = get_class($this); if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { @@ -159,7 +190,14 @@ class Record extends \Espo\Core\Services\Base $this->entityType = Util::normilizeScopeName($name); } } - $this->entityName = $this->entityType; + + // to be removed + $this->init(); + } + + // for backward compatibility, to be removed + protected function init() + { } public function setAclManager(AclManager $aclManager) @@ -199,77 +237,74 @@ class Record extends \Espo\Core\Services\Base } } - public function setEntityType($entityType) + public function setEntityType(string $entityType) { $this->entityType = $entityType; - $this->entityName = $entityType; } - public function getEntityType() + public function getEntityType() : string { return $this->entityType; } + protected function getConfig() + { + return $this->config; + } + protected function getServiceFactory() { - return $this->injections['serviceFactory']; + return $this->serviceFactory; } protected function getSelectManagerFactory() { - return $this->injections['selectManagerFactory']; + return $this->selectManagerFactory; } protected function getAcl() { - if ($this->acl) return $this->acl; - - return $this->getInjection('acl'); + return $this->acl; } protected function getUser() { - if ($this->user) return $this->user; - - return $this->getInjection('user'); + return $this->user; } public function setAcl(Acl $acl) { $this->acl = $acl; - - // for backward compatibility - $this->inject('acl', $acl); } public function setUser(User $user) { $this->user = $user; - - // for backward compatibility - $this->inject('user', $user); } protected function getAclManager() { - if ($this->aclManager) return $this->aclManager; - - return $this->getInjection('aclManager'); + return $this->aclManager; } protected function getFileManager() { - return $this->getInjection('fileManager'); + return $this->fileManager; } protected function getMetadata() { - return $this->getInjection('metadata'); + return $this->metadata; } protected function getFieldManagerUtil() { - return $this->getInjection('fieldManagerUtil'); + return $this->fieldManagerUtil; + } + + protected function getEntityManager() + { + return $this->entityManager; } protected function getRepository() @@ -277,16 +312,10 @@ class Record extends \Espo\Core\Services\Base return $this->getEntityManager()->getRepository($this->entityType); } + /** Deprecated */ protected function getRecordService($name) { - if ($this->getServiceFactory()->checkExists($name)) { - $service = $this->getServiceFactory()->create($name); - } else { - $service = $this->getServiceFactory()->create('Record'); - $service->setEntityType($name); - } - - return $service; + return $this->recordServiceContainer->get($name); } protected function processActionHistoryRecord($action, Entity $entity) @@ -317,21 +346,22 @@ class Record extends \Espo\Core\Services\Base return $this->read($id); } - public function read($id) + public function read(string $id) : Entity { if (empty($id)) { throw new Error("No ID passed."); } + $entity = $this->getEntity($id); - if (!$entity) throw new NotFoundSilent("Record does not exist."); + if (!$entity) throw new NotFoundSilent("Record {$id} does not exist."); $this->processActionHistoryRecord('read', $entity); return $entity; } - public function getEntity($id = null) + public function getEntity(?string $id = null) : ?Entity { if (!is_null($id)) { $selectParams = []; @@ -571,7 +601,7 @@ class Record extends \Espo\Core\Services\Base $fieldType = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, 'type'); $validationList = $this->getMetadata()->get(['fields', $fieldType, 'validationList'], []); $mandatoryValidationList = $this->getMetadata()->get(['fields', $fieldType, 'mandatoryValidationList'], []); - $fieldValidatorManager = $this->getInjection('container')->get('fieldValidatorManager'); + $fieldValidatorManager = $this->fieldValidatorManager; foreach ($validationList as $type) { $value = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, $type); @@ -843,11 +873,11 @@ class Record extends \Espo\Core\Services\Base } } - protected function filterCreateInput($data) + protected function filterCreateInput(StdClass $data) { } - protected function filterUpdateInput($data) + protected function filterUpdateInput(StdClass $data) { } @@ -919,7 +949,7 @@ class Record extends \Espo\Core\Services\Base return $this->create($data); } - public function create($data) + public function create(StdClass $data) : Entity { if (!$this->getAcl()->check($this->getEntityType(), 'create')) throw new ForbiddenSilent("No create access."); @@ -969,11 +999,11 @@ class Record extends \Espo\Core\Services\Base return $this->update($id, $data); } - public function update($id, $data) + public function update(string $id, StdClass $data) : Entity { - unset($data->deleted); + if (empty($id)) throw new BadRequest("ID is empty."); - if (empty($id)) throw new BadRequest("No ID passed."); + unset($data->deleted); $this->filterInput($data); $this->filterUpdateInput($data); @@ -993,7 +1023,7 @@ class Record extends \Espo\Core\Services\Base $entity = $this->getRepository()->get($id); } - if (!$entity) throw new NotFound("Record not found."); + if (!$entity) throw new NotFound("Record {$id} not found."); if (!$this->getAcl()->check($entity, 'edit')) throw new ForbiddenSilent("No edit access."); @@ -1056,26 +1086,29 @@ class Record extends \Espo\Core\Services\Base return $this->delete($id); } - public function delete($id) + public function delete(string $id) { - if (empty($id)) throw new BadRequest("No ID passed."); + if (empty($id)) throw new BadRequest("ID is empty."); $entity = $this->getRepository()->get($id); - if (!$entity) throw new NotFound("Record not found."); + if (!$entity) throw new NotFound("Record {$id} not found."); if (!$this->getAcl()->check($entity, 'delete')) throw new ForbiddenSilent("No delete access."); $this->beforeDeleteEntity($entity); $result = $this->getRepository()->remove($entity); - if ($result) { - $this->afterDeleteEntity($entity); - $this->processActionHistoryRecord('delete', $entity); - - return $result; + if (!$result) { + throw new Error("Could not delete record {$id}."); } + + $this->afterDeleteEntity($entity); + + $this->processActionHistoryRecord('delete', $entity); + + return $result; } protected function getSelectParams($params) @@ -1096,7 +1129,7 @@ class Record extends \Espo\Core\Services\Base return $this->find($params); } - public function find($params) + public function find(array $params) : StdClass { $disableCount = false; if ( @@ -1150,13 +1183,13 @@ class Record extends \Espo\Core\Services\Base } } - return [ + return (object) [ 'total' => $total, 'collection' => $collection, ]; } - public function getListKanban($params) + public function getListKanban(array $params) : StdClass { $disableCount = false; if ( @@ -1303,7 +1336,7 @@ class Record extends \Espo\Core\Services\Base return $this->findLinked($id, $link, $params); } - public function findLinked($id, $link, $params) + public function findLinked(string $id, string $link, array $params) : StdClass { $entity = $this->getRepository()->get($id); if (!$entity) { @@ -1349,7 +1382,7 @@ class Record extends \Espo\Core\Services\Base } } - $recordService = $this->getRecordService($foreignEntityType); + $recordService = $this->recordServiceContainer->get($foreignEntityType); $disableCount = false; $disableCountPropertyName = 'findLinked' . ucfirst($link) . 'CountQueryDisabled'; @@ -1417,9 +1450,9 @@ class Record extends \Espo\Core\Services\Base } } - return [ + return (object) [ 'total' => $total, - 'collection' => $collection + 'collection' => $collection, ]; } @@ -1428,7 +1461,7 @@ class Record extends \Espo\Core\Services\Base return $this->link($id, $link, $foreignId); } - public function link($id, $link, $foreignId) + public function link(string $id, string $link, string $foreignId) { if (empty($id) || empty($link) || empty($foreignId)) { throw new BadRequest; @@ -1493,7 +1526,7 @@ class Record extends \Espo\Core\Services\Base return $this->unlink($id, $link, $foreignId); } - public function unlink($id, $link, $foreignId) + public function unlink(string $id, string $link, string $foreignId) { if (empty($id) || empty($link) || empty($foreignId)) { throw new BadRequest; @@ -1562,7 +1595,7 @@ class Record extends \Espo\Core\Services\Base return $this->massLink($id, $link, $where, $selectData); } - public function linkFollowers($id, $foreignId) + public function linkFollowers(string $id, string $foreignId) { if (!$this->getMetadata()->get(['scopes', $this->entityType, 'stream'])) throw new NotFound(); @@ -1578,7 +1611,7 @@ class Record extends \Espo\Core\Services\Base return true; } - public function unlinkFollowers($id, $foreignId) + public function unlinkFollowers(string $id, string $foreignId) { if (!$this->getMetadata()->get(['scopes', $this->entityType, 'stream'])) throw new NotFound(); @@ -1594,7 +1627,7 @@ class Record extends \Espo\Core\Services\Base return true; } - public function massLink($id, $link, $where, $selectData = null) + public function massLink(string $id, string $link, array $where, ?array $selectData = null) { if (empty($id) || empty($link)) { throw new BadRequest; @@ -1646,7 +1679,7 @@ class Record extends \Espo\Core\Services\Base } if (!is_array($where)) { - $where = array(); + $where = []; } $params['where'] = $where; @@ -1656,7 +1689,7 @@ class Record extends \Espo\Core\Services\Base } } - $selectParams = $this->getRecordService($foreignEntityType)->getSelectParams($params); + $selectParams = $this->recordServiceContainer->get($foreignEntityType)->getSelectParams($params); if ($this->getAcl()->getLevel($foreignEntityType, $accessActionRequired) === 'all') { return $this->getRepository()->massRelate($entity, $link, $selectParams); @@ -1676,7 +1709,7 @@ class Record extends \Espo\Core\Services\Base } } - public function massUpdate(array $params, $data) + public function massUpdate(array $params, StdClass $data) { if ($this->getAcl()->get('massUpdatePermission') !== 'yes') throw new Forbidden(); @@ -1716,7 +1749,7 @@ class Record extends \Espo\Core\Services\Base $result = ['count' => $count]; if (isset($params['ids'])) $result['ids'] = $resultIdList; - return $result; + return (object) $result; } protected function checkEntityForMassRemove(Entity $entity) @@ -1989,7 +2022,7 @@ class Record extends \Espo\Core\Services\Base if (empty($className)) { throw new Error(); } - $exportObj = $this->getInjection('injectableFactory')->create($className); + $exportObj = $this->injectableFactory->create($className); $collection = null; @@ -2422,7 +2455,7 @@ class Record extends \Espo\Core\Services\Base $fields = $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields'], []); - $fieldManager = new \Espo\Core\Utils\FieldManagerUtil($this->getMetadata()); + $fieldManager = $this->fieldManagerUtil; foreach ($fields as $field => $item) { if (!empty($item['duplicateIgnore']) || in_array($field, $this->duplicateIgnoreFieldList)) { diff --git a/application/Espo/Services/RecordTree.php b/application/Espo/Services/RecordTree.php index c6e7e0f146..424269def8 100644 --- a/application/Espo/Services/RecordTree.php +++ b/application/Espo/Services/RecordTree.php @@ -49,6 +49,7 @@ class RecordTree extends Record public function __construct() { parent::__construct(); + if (!$this->subjectEntityType) { $this->subjectEntityType = substr($this->entityType, 0, strlen($this->entityType) -8 ); } @@ -174,7 +175,7 @@ class RecordTree extends Record } } - public function update($id, $data) + public function update(string $id, \StdClass $data) : Entity { if (!empty($data->parentId) && $data->parentId == $id) { throw new Forbidden(); @@ -183,7 +184,7 @@ class RecordTree extends Record return parent::update($id, $data); } - public function link($id, $link, $foreignId) + public function link(string $id, string $link, string $foreignId) { if ($id == $foreignId ) { throw new Forbidden(); diff --git a/application/Espo/Services/User.php b/application/Espo/Services/User.php index 1391889f9b..f77e57ab85 100644 --- a/application/Espo/Services/User.php +++ b/application/Espo/Services/User.php @@ -36,6 +36,8 @@ use Espo\Core\Utils\Util; use Espo\ORM\Entity; +use StdClass; + class User extends Record { protected function init() @@ -95,7 +97,7 @@ class User extends Record return $this->injections['container']; } - public function getEntity($id = null) + public function getEntity(? string $id = null) : Entity { if (isset($id) && $id == 'system') { throw new Forbidden(); @@ -111,8 +113,9 @@ class User extends Record return $entity; } - public function changePassword($userId, $password, $checkCurrentPassword = false, $currentPassword = null) - { + public function changePassword( + string $userId, string $password, bool $checkCurrentPassword = false, bool $currentPassword = null + ) { $user = $this->getEntityManager()->getEntity('User', $userId); if (!$user) { throw new NotFound(); @@ -268,7 +271,7 @@ class User extends Record } } - public function create($data) + public function create(StdClass $data) : Entity { $newPassword = null; if (property_exists($data, 'password')) { @@ -290,7 +293,7 @@ class User extends Record return $user; } - public function update($id, $data) + public function update(string $id, StdClass $data) : Entity { if ($id == 'system') { throw new Forbidden();