diff --git a/application/Espo/Core/Di/SelectManagerFactoryAware.php b/application/Espo/Core/Di/SelectManagerFactoryAware.php deleted file mode 100644 index bb53b100a1..0000000000 --- a/application/Espo/Core/Di/SelectManagerFactoryAware.php +++ /dev/null @@ -1,37 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\Di; - -use Espo\Core\Select\SelectManagerFactory; - -interface SelectManagerFactoryAware -{ - public function setSelectManagerFactory(SelectManagerFactory $selectManagerFactory): void; -} diff --git a/application/Espo/Core/Di/SelectManagerFactorySetter.php b/application/Espo/Core/Di/SelectManagerFactorySetter.php deleted file mode 100644 index bef9f329e5..0000000000 --- a/application/Espo/Core/Di/SelectManagerFactorySetter.php +++ /dev/null @@ -1,48 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\Di; - -use Espo\Core\Select\SelectManagerFactory; - -/** - * @phpstan-ignore-next-line - */ -trait SelectManagerFactorySetter -{ - /** - * @var SelectManagerFactory - */ - protected $selectManagerFactory; - - public function setSelectManagerFactory(SelectManagerFactory $selectManagerFactory): void - { - $this->selectManagerFactory = $selectManagerFactory; - } -} diff --git a/application/Espo/Core/Select/AccessControl/Applier.php b/application/Espo/Core/Select/AccessControl/Applier.php index 68b78ac3ce..6288e948a7 100644 --- a/application/Espo/Core/Select/AccessControl/Applier.php +++ b/application/Espo/Core/Select/AccessControl/Applier.php @@ -29,14 +29,10 @@ namespace Espo\Core\Select\AccessControl; -use Espo\Core\Select\OrmSelectBuilder; use Espo\Core\Select\AccessControl\FilterFactory as AccessControlFilterFactory; use Espo\Core\Select\AccessControl\FilterResolverFactory as AccessControlFilterResolverFactory; -use Espo\Core\Select\SelectManager; - use Espo\Entities\User; use Espo\ORM\Query\SelectBuilder as QueryBuilder; - use RuntimeException; class Applier @@ -46,21 +42,10 @@ class Applier private User $user, private AccessControlFilterFactory $accessControlFilterFactory, private AccessControlFilterResolverFactory $accessControlFilterResolverFactory, - private SelectManager $selectManager ) {} public function apply(QueryBuilder $queryBuilder): void { - // For backward compatibility. - if ( - $this->selectManager->hasInheritedAccessMethod() && - $queryBuilder instanceof OrmSelectBuilder - ) { - $this->selectManager->applyAccessToQueryBuilder($queryBuilder); - - return; - } - $this->applyMandatoryFilter($queryBuilder); $accessControlFilterResolver = $this->accessControlFilterResolverFactory @@ -72,16 +57,6 @@ class Applier return; } - // For backward compatibility. - if ( - $this->selectManager->hasInheritedAccessFilterMethod($filterName) && - $queryBuilder instanceof OrmSelectBuilder - ) { - $this->selectManager->applyAccessFilterToQueryBuilder($queryBuilder, $filterName); - - return; - } - if ($this->accessControlFilterFactory->has($this->entityType, $filterName)) { $filter = $this->accessControlFilterFactory ->create($this->entityType, $this->user, $filterName); diff --git a/application/Espo/Core/Select/Applier/Factory.php b/application/Espo/Core/Select/Applier/Factory.php index 6e65485ead..4a1cc15f32 100644 --- a/application/Espo/Core/Select/Applier/Factory.php +++ b/application/Espo/Core/Select/Applier/Factory.php @@ -44,8 +44,6 @@ use Espo\Core\Binding\Binder; use Espo\Core\Binding\BindingContainer; use Espo\Core\Binding\BindingData; use Espo\Core\InjectableFactory; -use Espo\Core\Select\SelectManager; -use Espo\Core\Select\SelectManagerFactory; use Espo\Core\Utils\Acl\UserAclManagerProvider; use Espo\Entities\User; @@ -81,16 +79,12 @@ class Factory public function __construct( private InjectableFactory $injectableFactory, private UserAclManagerProvider $userAclManagerProvider, - private SelectManagerFactory $selectManagerFactory, ) {} private function create(string $entityType, User $user, string $type): object { $className = $this->getDefaultClassName($type); - // SelectManager is used for backward compatibility. - $selectManager = $this->selectManagerFactory->create($entityType, $user); - $aclManager = $this->userAclManagerProvider->get($user); $acl = $aclManager->createUserAcl($user); @@ -101,13 +95,11 @@ class Factory $binder ->bindInstance(User::class, $user) ->bindInstance(AclManager::class, $aclManager) - ->bindInstance(Acl::class, $acl) - ->bindInstance(SelectManager::class, $selectManager); + ->bindInstance(Acl::class, $acl); $binder ->for($className) - ->bindValue('$entityType', $entityType) - ->bindValue('$selectManager', $selectManager); + ->bindValue('$entityType', $entityType); $bindingContainer = new BindingContainer($bindingData); diff --git a/application/Espo/Core/Select/Bool/Applier.php b/application/Espo/Core/Select/Bool/Applier.php index 002c2a5be6..3f78acab0b 100644 --- a/application/Espo/Core/Select/Bool/Applier.php +++ b/application/Espo/Core/Select/Bool/Applier.php @@ -30,13 +30,10 @@ namespace Espo\Core\Select\Bool; use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Select\OrmSelectBuilder; -use Espo\Core\Select\SelectManager; use Espo\Core\Select\Bool\FilterFactory as BoolFilterFactory; use Espo\ORM\Query\Select; use Espo\ORM\Query\SelectBuilder; use Espo\ORM\Query\Part\Where\OrGroupBuilder; -use Espo\ORM\Query\Part\WhereClause; use Espo\Entities\User; @@ -46,7 +43,6 @@ class Applier private string $entityType, private User $user, private BoolFilterFactory $boolFilterFactory, - private SelectManager $selectManager ) {} /** @@ -93,20 +89,6 @@ class Applier return; } - // For backward compatibility. - if ( - $this->selectManager->hasBoolFilter($filterName) && - $queryBuilder instanceof OrmSelectBuilder - ) { - $rawWhereClause = $this->selectManager->applyBoolFilterToQueryBuilder($queryBuilder, $filterName); - - $whereItem = WhereClause::fromRaw($rawWhereClause); - - $orGroupBuilder->add($whereItem); - - return; - } - throw new BadRequest("No bool filter '$filterName' for '$this->entityType'."); } diff --git a/application/Espo/Core/Select/Primary/Applier.php b/application/Espo/Core/Select/Primary/Applier.php index 04e36bc4a3..31080ba11b 100644 --- a/application/Espo/Core/Select/Primary/Applier.php +++ b/application/Espo/Core/Select/Primary/Applier.php @@ -30,8 +30,6 @@ namespace Espo\Core\Select\Primary; use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Select\SelectManager; -use Espo\Core\Select\OrmSelectBuilder; use Espo\ORM\Query\SelectBuilder; use Espo\Entities\User; @@ -41,7 +39,6 @@ class Applier private string $entityType, private User $user, private FilterFactory $primaryFilterFactory, - private SelectManager $selectManager ) {} /** @@ -57,16 +54,6 @@ class Applier return; } - // For backward compatibility. - if ( - $this->selectManager->hasPrimaryFilter($filterName) && - $queryBuilder instanceof OrmSelectBuilder - ) { - $this->selectManager->applyPrimaryFilterToQueryBuilder($queryBuilder, $filterName); - - return; - } - throw new BadRequest("No primary filter '$filterName' for '$this->entityType'."); } } diff --git a/application/Espo/Core/Select/SelectManager.php b/application/Espo/Core/Select/SelectManager.php deleted file mode 100644 index 2d3ea68735..0000000000 --- a/application/Espo/Core/Select/SelectManager.php +++ /dev/null @@ -1,2998 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\Select; - -use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Exceptions\Forbidden; - -use Espo\Core\Acl; -use Espo\Core\AclManager; -use Espo\Core\InjectableFactory; -use Espo\Core\ORM\EntityManager; -use Espo\Core\ORM\Type\FieldType; -use Espo\Core\Utils\Config; -use Espo\Core\Utils\FieldUtil; -use Espo\Core\Utils\Metadata; - -use Espo\Entities\StreamSubscription; -use Espo\ORM\Defs\Params\RelationParam; -use Espo\ORM\Entity; -use Espo\ORM\Name\Attribute; -use Espo\ORM\Query\Select as SelectQuery; -use Espo\ORM\QueryComposer\BaseQueryComposer as QueryComposer; - -use Espo\Entities\User; - -use DateTime; -use DateTimeZone; -use DateInterval; - -use Espo\ORM\Type\AttributeType; -use ReflectionMethod; - -/** - * @deprecated As of v7.0. Use Select framework and SelectBuilder instead. - * @todo Remove in v10.0. - */ -class SelectManager -{ - protected $entityType; - - private $seed = null; - - private $userTimeZone = null; - - protected $additionalFilterTypeList = ['inCategory', 'isUserFromTeams']; - - protected $aclAttributeList = ['assignedUserId', 'createdById']; - - protected $aclPortalAttributeList = ['assignedUserId', 'createdById', 'contactId', 'accountId']; - - protected $textFilterUseContainsAttributeList = []; - - protected $selectAttributesDependancyMap = []; - - protected $fullTextOrderType = self::FT_ORDER_COMBINTED; - - protected $fullTextRelevanceThreshold = null; - - const FT_ORDER_COMBINTED = 0; - - const FT_ORDER_RELEVANCE = 1; - - const FT_ORDER_ORIGINAL = 3; - - const MIN_LENGTH_FOR_CONTENT_SEARCH = 4; - - const MIN_LENGTH_FOR_FULL_TEXT_SEARCH = 4; - - protected $fullTextOrderRelevanceDivider = 5; - - protected $fullTextSearchDataCacheHash = []; - - protected $entityManager; - - protected $user; - - protected $acl; - - protected $aclManager; - - protected $metadata; - - protected $config; - - protected $fieldUtil; - - protected $injectableFactory; - - private $selectBuilderFactory; - - public function __construct( - EntityManager $entityManager, - User $user, - Acl $acl, - AclManager $aclManager, - Metadata $metadata, - Config $config, - FieldUtil $fieldUtil, - InjectableFactory $injectableFactory, - SelectBuilderFactory $selectBuilderFactory - ) { - $this->entityManager = $entityManager; - $this->user = $user; - $this->acl = $acl; - $this->aclManager = $aclManager; - $this->metadata = $metadata; - $this->config = $config; - $this->fieldUtil = $fieldUtil; - $this->injectableFactory = $injectableFactory; - $this->selectBuilderFactory = $selectBuilderFactory; - } - - protected function getEntityManager() : EntityManager - { - return $this->entityManager; - } - - protected function getMetadata() : Metadata - { - return $this->metadata; - } - - protected function getUser() : User - { - return $this->user; - } - - protected function getAcl() : Acl - { - return $this->acl; - } - - protected function getConfig() : Config - { - return $this->config; - } - - protected function getAclManager() : AclManager - { - return $this->aclManager; - } - - protected function getInjectableFactory() : InjectableFactory - { - return $this->injectableFactory; - } - - protected function getFieldUtil() : FieldUtil - { - return $this->fieldUtil; - } - - public function setEntityType(string $entityType) - { - $this->entityType = $entityType; - } - - protected function getEntityType() : string - { - return $this->entityType; - } - - protected function limit(?int $offset, ?int $maxSize, array &$result) - { - if (!is_null($offset)) { - $result['offset'] = $offset; - } - if (!is_null($maxSize)) { - $result['limit'] = $maxSize; - } - } - - protected function order(string $sortBy, $desc, array &$result) - { - if (is_string($desc)) { - $desc = $desc === strtolower('desc'); - } - - if ($sortBy) { - $result['orderBy'] = $sortBy; - $type = $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields', $sortBy, 'type']); - - if (in_array($type, [FieldType::LINK, FieldType::FILE, FieldType::IMAGE, FieldType::LINK_ONE])) { - $result['orderBy'] .= 'Name'; - } else if ($type === FieldType::LINK_PARENT) { - $result['orderBy'] .= 'Type'; - } else if ($type === FieldType::ADDRESS) { - $result['orderBy'] = [ - [$sortBy . 'Country', $desc], - [$sortBy . 'City', $desc], - [$sortBy . 'Street', $desc], - ]; - } else if ($type === FieldType::ENUM) { - $list = $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields', $sortBy, 'options']); - - if ($list && is_array($list) && count($list)) { - if ($this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields', $sortBy, 'isSorted'])) { - asort($list); - } - - if ($desc) { - $list = array_reverse($list); - } - - foreach ($list as $i => $listItem) { - $list[$i] = str_replace(',', '_COMMA_', $listItem); - } - - $result['orderBy'] = [['LIST:' . $sortBy . ':' . implode(',', $list)]]; - } - } else { - if (strpos($sortBy, '.') === false && strpos($sortBy, ':') === false) { - if (!$this->getSeed()->hasAttribute($sortBy)) { - throw new BadRequest("Order by non-existing field '{$sortBy}'."); - } - } - } - - $orderByAttribute = null; - - if (!is_array($result['orderBy'])) { - $orderByAttribute = $result['orderBy']; - $result['orderBy'] = [[$result['orderBy'], $desc]]; - } - - if ( - $sortBy != Attribute::ID && - (!$orderByAttribute || !$this->getSeed()->getAttributeParam($orderByAttribute, 'unique')) && - $this->getSeed()->hasAttribute(Attribute::ID) - ) { - $result['orderBy'][] = [Attribute::ID, $desc]; - } - - return; - } - - if (!$desc) { - $result['order'] = 'ASC'; - } else { - $result['order'] = 'DESC'; - } - } - - protected function getTextFilterFieldList() : array - { - return $this->getMetadata() - ->get(['entityDefs', $this->entityType, 'collection', 'textFilterFields'], ['name']); - } - - protected function getSeed(): Entity - { - if (empty($this->seed)) { - $this->seed = $this->entityManager->getNewEntity($this->entityType); - } - return $this->seed; - } - - public function applyWhere(array $where, array &$result) - { - $this->prepareResult($result); - $this->where($where, $result); - } - - protected function where(array $where, array &$result) - { - $this->prepareResult($result); - - $boolFilterList = []; - - foreach ($where as $item) { - if (!isset($item['type'])) continue; - - if ($item['type'] == 'bool' && !empty($item['value']) && is_array($item['value'])) { - $boolOr = []; - foreach ($item['value'] as $filter) { - $boolFilterList[] = $filter; - } - } else if ($item['type'] == 'textFilter') { - if (isset($item['value']) || $item['value'] !== '') { - $this->textFilter($item['value'], $result); - } - } else if ($item['type'] == 'primary' && !empty($item['value'])) { - $this->applyPrimaryFilter($item['value'], $result); - } - } - - if (count($boolFilterList)) { - $this->applyBoolFilterList($boolFilterList, $result); - } - - $whereClause = $this->convertWhere($where, false, $result); - - $result['whereClause'] = array_merge($result['whereClause'], $whereClause); - - $this->applyLeftJoinsFromWhere($where, $result); - } - - /** - * Convert 'where' parameters from the frontend format to the format needed by ORM. - * - * @return array Where clause for ORM. - */ - public function convertWhere(array $where, bool $ignoreAdditionaFilterTypes = false, array &$result = []) : array - { - $whereClause = []; - - $ignoreTypeList = array_merge(['bool', 'primary'], $this->additionalFilterTypeList); - - foreach ($where as $item) { - if (!isset($item['type'])) continue; - - $type = $item['type']; - if (!in_array($type, $ignoreTypeList)) { - $part = $this->getWherePart($item, $result); - if (!empty($part)) { - $whereClause[] = $part; - } - } else { - if (!$ignoreAdditionaFilterTypes && in_array($type, $this->additionalFilterTypeList)) { - if (!empty($item['value'])) { - $methodName = 'apply' . ucfirst($type); - - if (method_exists($this, $methodName)) { - $attribute = null; - if (isset($item['field'])) { - $attribute = $item['field']; - } - if (isset($item['attribute'])) { - $attribute = $item['attribute']; - } - if ($attribute) { - $this->$methodName($attribute, $item['value'], $result); - } - } - } - } - } - } - - return $whereClause; - } - - protected function applyLinkedWith(string $link, $idsValue, array &$result) - { - $part = []; - - if (is_array($idsValue) && count($idsValue) == 1) { - $idsValue = $idsValue[0]; - } - - $seed = $this->getSeed(); - - if (!$seed->hasRelation($link)) { - return; - } - - $relDefs = $this->entityManager->getMetadata()->get($this->entityType, ['relations']); - - $relationType = $seed->getRelationType($link); - - if ($relationType == 'manyMany') { - $this->addLeftJoin([$link, $link . 'Filter'], $result); - $midKeys = $seed->getRelationParam($link, 'midKeys'); - - if (!empty($midKeys)) { - $key = $midKeys[1]; - $part[$link . 'Filter' . 'Middle.' . $key] = $idsValue; - } - - } else if ($relationType == 'hasMany') { - $alias = $link . 'Filter'; - $this->addLeftJoin([$link, $alias], $result); - - $part[$alias . '.id'] = $idsValue; - - } else if ($relationType == 'belongsTo') { - $key = $seed->getRelationParam($link, 'key'); - if (!empty($key)) { - $part[$key] = $idsValue; - } - - } else if ($relationType == 'hasOne') { - $this->addJoin([$link, $link . 'Filter'], $result); - $part[$link . 'Filter' . '.id'] = $idsValue; - - } else { - return; - } - - if (!empty($part)) { - $result['whereClause'][] = $part; - } - - $this->setDistinct(true, $result); - } - - protected function applyIsUserFromTeams(string $link, $idsValue, array &$result) - { - if (is_array($idsValue) && count($idsValue) == 1) { - $idsValue = $idsValue[0]; - } - - $seed = $this->getSeed(); - - if (!$seed->hasRelation($link)) { - return; - } - - $relationType = $seed->getRelationType($link); - - if ($relationType == 'belongsTo') { - $key = $seed->getRelationParam($link, 'key'); - - $aliasName = 'usersTeams' . ucfirst($link) . strval(rand(10000, 99999)); - - $this->addLeftJoin([ - 'TeamUser', - $aliasName . 'Middle', - [ - $aliasName . 'Middle.userId:' => $key, - $aliasName . 'Middle.deleted' => false, - ] - ], $result); - - $result['whereClause'][] = [ - $aliasName . 'Middle.teamId' => $idsValue - ]; - } else { - throw new BadRequest("Can't apply isUserFromTeams for link {$link}."); - } - - $this->setDistinct(true, $result); - } - - public function applyInCategory(string $link, $value, array &$result) - { - $relDefs = $this->entityManager->getMetadata()->get($this->entityType, ['relations']); - - if (empty($relDefs[$link])) { - throw new BadRequest("Can't apply inCategory for link {$link}."); - } - - $defs = $relDefs[$link]; - - $foreignEntity = $defs['entity'] ?? null; - - if (empty($foreignEntity)) { - throw new BadRequest("Can't apply inCategory for link {$link}."); - } - - $pathName = lcfirst($foreignEntity) . 'Path'; - - if ($defs['type'] == 'manyMany') { - if (empty($defs['midKeys'])) { - throw new BadRequest("Can't apply inCategory for link {$link}."); - } - - $this->setDistinct(true, $result); - $this->addJoin($link, $result); - - $key = $defs['midKeys'][1]; - $middleName = $link . 'Middle'; - - $this->addJoin([ - ucfirst($pathName), - $pathName, - [ - "{$pathName}.descendorId:" => "{$middleName}.{$key}", - ] - ], $result); - - $result['whereClause'][$pathName . '.ascendorId'] = $value; - - return; - } - - if ($defs['type'] == 'belongsTo') { - if (empty($defs['key'])) { - throw new BadRequest("Can't apply inCategory for link {$link}."); - } - - $key = $defs['key']; - - $this->addJoin([ - ucfirst($pathName), - $pathName, - [ - "{$pathName}.descendorId:" => "{$key}", - ] - ], $result); - - $result['whereClause'][$pathName . '.ascendorId'] = $value; - - return; - } - - throw new BadRequest("Can't apply inCategory for link {$link}."); - } - - protected function q(array $params, array &$result) - { - if (isset($params['q']) && $params['q'] !== '') { - $textFilter = $params['q']; - $this->textFilter($textFilter, $result, true); - } - } - - public function manageAccess(array &$result) - { - $this->prepareResult($result); - $this->applyAccess($result); - } - - public function manageTextFilter(string $textFilter, array &$result) - { - $this->prepareResult($result); - $this->q(['q' => $textFilter], $result); - } - - /** - * Get empty select parameters. - */ - public function getEmptySelectParams() : array - { - $result = []; - $this->prepareResult($result); - - return $result; - } - - protected function prepareResult(array &$result) - { - if (empty($result)) { - $result = []; - } - if (empty($result['from'])) { - $result['from'] = $this->entityType; - } - if (empty($result['joins'])) { - $result['joins'] = []; - } - if (empty($result['leftJoins'])) { - $result['leftJoins'] = []; - } - if (empty($result['whereClause'])) { - $result['whereClause'] = []; - } - if (empty($result['customJoin'])) { - $result['customJoin'] = ''; - } - if (empty($result['additionalSelectColumns'])) { - $result['additionalSelectColumns'] = []; - } - if (empty($result['joinConditions'])) { - $result['joinConditions'] = []; - } - } - - protected function checkIsPortal() : bool - { - return !!$this->getUser()->get('portalId'); - } - - protected function access(&$result) - { - if (!$this->checkIsPortal()) { - if ($this->getAcl()->checkReadOnlyOwn($this->getEntityType())) { - $this->accessOnlyOwn($result); - } else { - if (!$this->getUser()->isAdmin()) { - if ($this->getAcl()->checkReadOnlyTeam($this->getEntityType())) { - $this->accessOnlyTeam($result); - } else if ($this->getAcl()->checkReadNo($this->getEntityType())) { - $this->accessNo($result); - } - } - } - } else { - if ($this->getAcl()->checkReadOnlyOwn($this->getEntityType())) { - $this->accessPortalOnlyOwn($result); - } else { - if ($this->getAcl()->checkReadOnlyAccount($this->getEntityType())) { - $this->accessPortalOnlyAccount($result); - } else { - if ($this->getAcl()->checkReadOnlyContact($this->getEntityType())) { - $this->accessPortalOnlyContact($result); - } else if ($this->getAcl()->checkReadNo($this->getEntityType())) { - $this->accessNo($result); - } - } - } - } - } - - protected function accessNo(array &$result) - { - $result['whereClause'][] = [ - 'id' => null - ]; - } - - protected function accessOnlyOwn(&$result) - { - if ($this->hasAssignedUsersField()) { - $this->setDistinct(true, $result); - $this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result); - $result['whereClause'][] = [ - 'assignedUsersAccess.id' => $this->getUser()->getId() - ]; - return; - } - - if ($this->hasAssignedUserField()) { - $result['whereClause'][] = [ - 'assignedUserId' => $this->getUser()->getId() - ]; - return; - } - - if ($this->hasCreatedByField()) { - $result['whereClause'][] = [ - 'createdById' => $this->getUser()->getId() - ]; - } - } - - protected function accessOnlyTeam(&$result) - { - if (!$this->hasTeamsField()) { - return; - } - - $this->setDistinct(true, $result); - $this->addLeftJoin(['teams', 'teamsAccess'], $result); - - if ($this->hasAssignedUsersField()) { - $this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result); - $result['whereClause'][] = [ - 'OR' => [ - 'teamsAccess.id' => $this->getUser()->getLinkMultipleIdList('teams'), - 'assignedUsersAccess.id' => $this->getUser()->getId() - ] - ]; - return; - } - - $or = [ - 'teamsAccess.id' => $this->getUser()->getLinkMultipleIdList('teams') - ]; - if ($this->hasAssignedUserField()) { - $or['assignedUserId'] = $this->getUser()->getId(); - } else if ($this->hasCreatedByField()) { - $or['createdById'] = $this->getUser()->getId(); - } - $result['whereClause'][] = [ - 'OR' => $or - ]; - } - - protected function accessPortalOnlyOwn(&$result) - { - if ($this->getSeed()->hasAttribute('createdById')) { - $result['whereClause'][] = [ - 'createdById' => $this->getUser()->getId() - ]; - } else { - $result['whereClause'][] = [ - 'id' => null - ]; - } - } - - protected function accessPortalOnlyContact(&$result) - { - $or = []; - - $contactId = $this->getUser()->get('contactId'); - - if ($contactId) { - if ( - $this->getSeed()->hasAttribute('contactId') && - $this->getSeed()->getRelationParam('contact', RelationParam::ENTITY) === 'Contact' - ) { - $or['contactId'] = $contactId; - } - - if ( - $this->getSeed()->hasRelation('contacts') && - $this->getSeed()->getRelationParam('contacts', RelationParam::ENTITY) === 'Contact' - ) { - $this->addLeftJoin(['contacts', 'contactsAccess'], $result); - $this->setDistinct(true, $result); - $or['contactsAccess.id'] = $contactId; - } - } - - if ($this->getSeed()->hasAttribute('createdById')) { - $or['createdById'] = $this->getUser()->getId(); - } - - if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) { - $contactId = $this->getUser()->get('contactId'); - if ($contactId) { - $or[] = [ - 'parentType' => 'Contact', - 'parentId' => $contactId - ]; - } - } - - if (!empty($or)) { - $result['whereClause'][] = [ - 'OR' => $or - ]; - } else { - $result['whereClause'][] = [ - 'id' => null - ]; - } - } - - protected function accessPortalOnlyAccount(&$result) - { - $or = []; - - $accountIdList = $this->getUser()->getLinkMultipleIdList('accounts'); - $contactId = $this->getUser()->get('contactId'); - - if (count($accountIdList)) { - if ( - $this->getSeed()->hasAttribute('accountId') && - $this->getSeed()->getRelationParam('account', RelationParam::ENTITY) === 'Account' - ) { - $or['accountId'] = $accountIdList; - } - if ( - $this->getSeed()->hasRelation('accounts') && - $this->getSeed()->getRelationParam('accounts', RelationParam::ENTITY) === 'Account' - ) { - $this->addLeftJoin(['accounts', 'accountsAccess'], $result); - $this->setDistinct(true, $result); - $or['accountsAccess.id'] = $accountIdList; - } - if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) { - $or[] = [ - 'parentType' => 'Account', - 'parentId' => $accountIdList - ]; - if ($contactId) { - $or[] = [ - 'parentType' => 'Contact', - 'parentId' => $contactId - ]; - } - } - } - - if ($contactId) { - if ( - $this->getSeed()->hasAttribute('contactId') && - $this->getSeed()->getRelationParam('contact', RelationParam::ENTITY) === 'Contact' - ) { - $or['contactId'] = $contactId; - } - if ( - $this->getSeed()->hasRelation('contacts') && - $this->getSeed()->getRelationParam('contacts', RelationParam::ENTITY) === 'Contact' - ) { - $this->addLeftJoin(['contacts', 'contactsAccess'], $result); - $this->setDistinct(true, $result); - $or['contactsAccess.id'] = $contactId; - } - } - - if ($this->getSeed()->hasAttribute('createdById')) { - $or['createdById'] = $this->getUser()->getId(); - } - - if (!empty($or)) { - $result['whereClause'][] = [ - 'OR' => $or - ]; - } else { - $result['whereClause'][] = [ - 'id' => null - ]; - } - } - - protected function hasAssignedUsersField() : bool - { - if ($this->getSeed()->hasRelation('assignedUsers') && $this->getSeed()->hasAttribute('assignedUsersIds')) { - return true; - } - return false; - } - - protected function hasAssignedUserField() : bool - { - if ($this->getSeed()->hasAttribute('assignedUserId')) { - return true; - } - return false; - } - - protected function hasCreatedByField() : bool - { - if ($this->getSeed()->hasAttribute('createdById')) { - return true; - } - return false; - } - - protected function hasTeamsField() : bool - { - if ($this->getSeed()->hasRelation('teams') && $this->getSeed()->hasAttribute('teamsIds')) { - return true; - } - return false; - } - - public function getAclParams() : array - { - $result = []; - $this->applyAccess($result); - return $result; - } - - public function buildSelectParams( - array $params, - bool $withAcl = false, - bool $checkWherePermission = false, - bool $forbidComplexExpressions = false - ) : array { - - return $this->getSelectParams($params, $withAcl, $checkWherePermission, $forbidComplexExpressions); - } - - /** - * The same as buildSelectParams. - */ - public function getSelectParams( - array $params, - bool $withAcl = false, - bool $checkWherePermission = false, - bool $forbidComplexExpressions = false - ) : array { - - $builder = $this->selectBuilderFactory - ->create() - ->forUser($this->user) - ->from($this->entityType); - - if ($withAcl) { - $builder->withAccessControlFilter(); - } - - if ($checkWherePermission) { - $builder->withWherePermissionCheck(); - } - - if ($forbidComplexExpressions) { - $builder->withComplexExpressionsForbidden(); - } - - $builder->withSearchParams(SearchParams::fromRaw($params)); - - $raw = $builder->build()->getRaw(); - - $this->prepareResult($raw); - - return $raw; - } - - /** - * Apply default order to select parameters. - */ - public function applyDefaultOrder(array &$result) - { - $orderBy = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'orderBy']); - $order = $result['order'] ?? null; - - if (!$order && !is_array($orderBy)) { - $order = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'order']) ?? null; - } - - if ($orderBy) { - $this->applyOrder($orderBy, $order, $result); - } else { - $result['order'] = $order; - } - } - - public function checkWhere(array $where, bool $checkWherePermission = true, bool $forbidComplexExpressions = false) - { - foreach ($where as $w) { - $attribute = null; - if (isset($w['field'])) { - $attribute = $w['field']; - } - if (isset($w['attribute'])) { - $attribute = $w['attribute']; - } - - $type = null; - if (isset($w['type'])) { - $type = $w['type']; - } - - if ($forbidComplexExpressions) { - if ($type && in_array($type, ['subQueryIn', 'subQueryNotIn', 'not'])) { - throw new Forbidden("SelectManager::checkWhere: Sub-queries are forbidden."); - } - } - - if ($attribute && $forbidComplexExpressions) { - if (strpos($attribute, '.') !== false || strpos($attribute, ':')) { - throw new Forbidden("SelectManager::checkWhere: Complex expressions are forbidden."); - } - } - - if ($attribute && $checkWherePermission) { - $argumentList = QueryComposer::getAllAttributesFromComplexExpression($attribute); - foreach ($argumentList as $argument) { - $this->checkWhereArgument($argument, $type); - } - } - - if (!empty($w['value']) && is_array($w['value'])) { - $this->checkWhere($w['value'], $checkWherePermission, $forbidComplexExpressions); - } - } - } - - protected function checkWhereArgument($attribute, $type) - { - $entityType = $this->getEntityType(); - - if (strpos($attribute, '.')) { - list($link, $attribute) = explode('.', $attribute); - if (!$this->getSeed()->hasRelation($link)) { - // TODO allow alias - throw new Forbidden("SelectManager::checkWhere: Unknown relation '{$link}' in where."); - } - $entityType = $this->getSeed()->getRelationParam($link, RelationParam::ENTITY); - if (!$entityType) { - throw new Forbidden("SelectManager::checkWhere: Bad relation."); - } - if (!$this->getAcl()->checkScope($entityType)) { - throw new Forbidden(); - } - } - - if ($type && in_array($type, ['isLinked', 'isNotLinked', 'linkedWith', 'notLinkedWith', 'isUserFromTeams'])) { - if (in_array($attribute, $this->getAcl()->getScopeForbiddenFieldList($entityType))) { - throw new Forbidden(); - } - if ( - $this->getSeed()->hasRelation($attribute) - && - in_array($attribute, $this->getAcl()->getScopeForbiddenLinkList($entityType)) - ) { - throw new Forbidden(); - } - } else { - if (in_array($attribute, $this->getAcl()->getScopeForbiddenAttributeList($entityType))) { - throw new Forbidden(); - } - } - } - - public function getUserTimeZone() : string - { - if (empty($this->userTimeZone)) { - $preferences = $this->getEntityManager()->getEntity('Preferences', $this->getUser()->getId()); - if ($preferences) { - $timeZone = $preferences->get('timeZone'); - $this->userTimeZone = $timeZone; - } else { - $this->userTimeZone = 'UTC'; - } - - if (!$this->userTimeZone) { - $this->userTimeZone = 'UTC'; - } - } - - return $this->userTimeZone; - } - - public function transformDateTimeWhereItem(array $item) : array - { - $format = 'Y-m-d H:i:s'; - - $attribute = $item['attribute'] ?? null; - $value = $item['value'] ?? null; - $timeZone = $item['timeZone'] ?? 'UTC'; - $type = $item['type'] ?? null; - - // for backward compatibility - if (!$attribute && isset($item['field'])) { - $attribute = $item['field']; - } - - if (!$attribute) { - throw new BadRequest("Bad datetime where item, empty 'attribute'."); - } - - if (!$type) { - throw new BadRequest("Bad datetime where item, empty 'type'."); - } - - if (empty($value) && in_array($type, ['on', 'before', 'after'])) { - return []; - } - - $where = [ - 'attribute' => $attribute, - ]; - - $dt = new DateTime('now', new DateTimeZone($timeZone)); - - switch ($type) { - case 'today': - $where['type'] = 'between'; - $dt->setTime(0, 0, 0); - $dtTo = clone $dt; - $dtTo->modify('+1 day -1 second'); - $dt->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $from = $dt->format($format); - $to = $dtTo->format($format); - $where['value'] = [$from, $to]; - break; - - case 'past': - $where['type'] = 'before'; - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'future': - $where['type'] = 'after'; - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'lastSevenDays': - $where['type'] = 'between'; - - $dtFrom = clone $dt; - - $dt->setTimezone(new DateTimeZone('UTC')); - $to = $dt->format($format); - - $dtFrom->modify('-7 day'); - $dtFrom->setTime(0, 0, 0); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - - $from = $dtFrom->format($format); - - $where['value'] = [$from, $to]; - break; - - case 'lastXDays': - $where['type'] = 'between'; - - $dtFrom = clone $dt; - - $dt->setTimezone(new DateTimeZone('UTC')); - $to = $dt->format($format); - - $number = strval(intval($item['value'])); - $dtFrom->modify('-'.$number.' day'); - $dtFrom->setTime(0, 0, 0); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - - $from = $dtFrom->format($format); - - $where['value'] = [$from, $to]; - break; - - case 'nextXDays': - $where['type'] = 'between'; - - $dtTo = clone $dt; - - $dt->setTimezone(new DateTimeZone('UTC')); - $from = $dt->format($format); - - $number = strval(intval($item['value'])); - $dtTo->modify('+'.$number.' day'); - $dtTo->setTime(24, 59, 59); - $dtTo->setTimezone(new DateTimeZone('UTC')); - - $to = $dtTo->format($format); - - $where['value'] = [$from, $to]; - break; - - case 'olderThanXDays': - $where['type'] = 'before'; - $number = strval(intval($item['value'])); - $dt->modify('-'.$number.' day'); - $dt->setTime(0, 0, 0); - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'afterXDays': - $where['type'] = 'after'; - $number = strval(intval($item['value'])); - $dt->modify('+'.$number.' day'); - $dt->setTime(0, 0, 0); - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'on': - $where['type'] = 'between'; - $dt = new DateTime($value, new DateTimeZone($timeZone)); - $dtTo = clone $dt; - if (strlen($value) <= 10) { - $dtTo->modify('+1 day -1 second'); - } - $dt->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $from = $dt->format($format); - $to = $dtTo->format($format); - $where['value'] = [$from, $to]; - break; - - case 'before': - $where['type'] = 'before'; - $dt = new DateTime($value, new DateTimeZone($timeZone)); - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'after': - $where['type'] = 'after'; - $dt = new DateTime($value, new DateTimeZone($timeZone)); - if (strlen($value) <= 10) - $dt->modify('+1 day -1 second'); - - $dt->setTimezone(new DateTimeZone('UTC')); - $where['value'] = $dt->format($format); - break; - - case 'between': - $where['type'] = 'between'; - if (is_array($value)) { - $dt = new DateTime($value[0], new DateTimeZone($timeZone)); - $dt->setTimezone(new DateTimeZone('UTC')); - $from = $dt->format($format); - - $dt = new DateTime($value[1], new DateTimeZone($timeZone)); - $dt->setTimezone(new DateTimeZone('UTC')); - if (strlen($value[1]) <= 10) - $dt->modify('+1 day -1 second'); - $to = $dt->format($format); - - $where['value'] = [$from, $to]; - } - break; - - case 'currentMonth': - case 'lastMonth': - case 'nextMonth': - $where['type'] = 'between'; - $dtFrom = new DateTime('now', new DateTimeZone($timeZone)); - $dtFrom = $dt->modify('first day of this month')->setTime(0, 0, 0); - - if ($type == 'lastMonth') { - $dtFrom->modify('-1 month'); - } else if ($type == 'nextMonth') { - $dtFrom->modify('+1 month'); - } - - $dtTo = clone $dtFrom; - $dtTo->modify('+1 month'); - - $dtFrom->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - - $where['value'] = [$dtFrom->format($format), $dtTo->format($format)]; - break; - - case 'currentQuarter': - case 'lastQuarter': - $where['type'] = 'between'; - $dt = new DateTime('now', new DateTimeZone($timeZone)); - $quarter = ceil($dt->format('m') / 3); - - $dtFrom = clone $dt; - $dtFrom->modify('first day of January this year')->setTime(0, 0, 0); - - if ($type === 'lastQuarter') { - $quarter--; - if ($quarter == 0) { - $quarter = 4; - $dtFrom->modify('-1 year'); - } - } - - $dtFrom->add(new DateInterval('P'.(($quarter - 1) * 3).'M')); - $dtTo = clone $dtFrom; - $dtTo->add(new DateInterval('P3M')); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $where['value'] = [ - $dtFrom->format($format), - $dtTo->format($format) - ]; - break; - - case 'currentYear': - case 'lastYear': - $where['type'] = 'between'; - $dtFrom = new DateTime('now', new DateTimeZone($timeZone)); - $dtFrom->modify('first day of January this year')->setTime(0, 0, 0); - if ($type == 'lastYear') { - $dtFrom->modify('-1 year'); - } - $dtTo = clone $dtFrom; - $dtTo = $dtTo->modify('+1 year'); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $where['value'] = [ - $dtFrom->format($format), - $dtTo->format($format) - ]; - break; - - case 'currentFiscalYear': - case 'lastFiscalYear': - $where['type'] = 'between'; - $dtToday = new DateTime('now', new DateTimeZone($timeZone)); - $dt = clone $dtToday; - $fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0); - $dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months')->setTime(0, 0, 0); - if (intval($dtToday->format('m')) < $fiscalYearShift + 1) { - $dt->modify('-1 year'); - } - if ($type === 'lastFiscalYear') { - $dt->modify('-1 year'); - } - $dtFrom = clone $dt; - $dtTo = clone $dt; - $dtTo = $dtTo->modify('+1 year'); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $where['value'] = [ - $dtFrom->format($format), - $dtTo->format($format) - ]; - break; - - case 'currentFiscalQuarter': - case 'lastFiscalQuarter': - $where['type'] = 'between'; - $dtToday = new DateTime('now', new DateTimeZone($timeZone)); - $dt = clone $dtToday; - $fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0); - $dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months')->setTime(0, 0, 0); - $month = intval($dtToday->format('m')); - $quarterShift = floor(($month - $fiscalYearShift - 1) / 3); - if ($quarterShift) { - if ($quarterShift >= 0) { - $dt->add(new DateInterval('P'.($quarterShift * 3).'M')); - } else { - $quarterShift *= -1; - $dt->sub(new DateInterval('P'.($quarterShift * 3).'M')); - } - } - if ($type === 'lastFiscalQuarter') { - $dt->modify('-3 months'); - } - $dtFrom = clone $dt; - $dtTo = clone $dt; - $dtTo = $dtTo->modify('+3 months'); - $dtFrom->setTimezone(new DateTimeZone('UTC')); - $dtTo->setTimezone(new DateTimeZone('UTC')); - $where['value'] = [ - $dtFrom->format($format), - $dtTo->format($format) - ]; - break; - - default: - $where['type'] = $type; - } - - $where['originalType'] = $type; - - return $where; - } - - public function convertDateTimeWhere(array $item) : ?array - { - $where = $this->transformDateTimeWhereItem($item); - $result = $this->getWherePart($where); - return $result; - } - - protected function getWherePart(array $item, array &$result = []) : array - { - $type = $item['type'] ?? null; - $value = $item['value'] ?? null; - $attribute = $item['attribute'] ?? null; - - // for backward compatibility - if (!$attribute && !empty($item['field'])) { - $attribute = $item['field']; - } - - if ($attribute && !is_string($attribute)) { - throw new BadRequest("Bad 'attribute' in where item."); - } - - if (!empty($item['dateTime'])) { - return $this->convertDateTimeWhere($item); - } - - if (!$type) { - throw new BadRequest("No 'type' in where item."); - } - - if ($attribute && $type) { - $methodName = 'getWherePart' . ucfirst($attribute) . ucfirst($type); - if (method_exists($this, $methodName)) { - return $this->$methodName($value, $result); - } - } - - $part = []; - - switch ($type) { - case 'or': - case 'and': - if (!is_array($value)) break; - - $sqWhereClause = []; - foreach ($value as $sqWhereItem) { - $sqWherePart = $this->getWherePart($sqWhereItem, $result); - foreach ($sqWherePart as $left => $right) { - if (!empty($right) || is_null($right) || $right === '' || $right === 0 || $right === false) { - $sqWhereClause[] = [$left => $right]; - } - } - } - $part[strtoupper($type)] = $sqWhereClause; - - break; - - case 'not': - case 'subQueryNotIn': - case 'subQueryIn': - if (!is_array($value)) break; - - $sqWhereClause = []; - $sqResult = $this->getEmptySelectParams(); - foreach ($value as $sqWhereItem) { - $sqWherePart = $this->getWherePart($sqWhereItem, $sqResult); - foreach ($sqWherePart as $left => $right) { - if (!empty($right) || is_null($right) || $right === '' || $right === 0 || $right === false) { - $sqWhereClause[] = [$left => $right]; - } - } - } - - $this->applyLeftJoinsFromWhere($value, $sqResult); - $key = $type === 'subQueryIn' ? 'id=s' : 'id!=s'; - $part[$key] = [ - 'selectParams' => [ - 'select' => ['id'], - 'whereClause' => $sqWhereClause, - 'leftJoins' => $sqResult['leftJoins'] ?? [], - 'joins' => $sqResult['joins'] ?? [], - ] - ]; - - break; - - case 'expression': - $key = $attribute; - if (substr($key, -1) !== ':') $key .= ':'; - $part[$key] = null; - break; - - case 'like': - $part[$attribute . '*'] = $value; - break; - - case 'notLike': - $part[$attribute . '!*'] = $value; - break; - - case 'equals': - case 'on': - $part[$attribute . '='] = $value; - break; - - case 'startsWith': - $part[$attribute . '*'] = $value . '%'; - break; - - case 'endsWith': - $part[$attribute . '*'] = '%' . $value; - break; - - case 'contains': - $part[$attribute . '*'] = '%' . $value . '%'; - break; - - case 'notContains': - $part[$attribute . '!*'] = '%' . $value . '%'; - break; - - case 'notEquals': - case 'notOn': - $part[$attribute . '!='] = $value; - break; - - case 'greaterThan': - case 'after': - $part[$attribute . '>'] = $value; - break; - - case 'lessThan': - case 'before': - $part[$attribute . '<'] = $value; - break; - - case 'greaterThanOrEquals': - $part[$attribute . '>='] = $value; - break; - - case 'lessThanOrEquals': - $part[$attribute . '<='] = $value; - break; - - case 'in': - $part[$attribute . '='] = $value; - break; - - case 'notIn': - $part[$attribute . '!='] = $value; - break; - - case 'isNull': - $part[$attribute . '='] = null; - break; - - case 'isNotNull': - case 'ever': - $part[$attribute . '!='] = null; - break; - - case 'isTrue': - $part[$attribute . '='] = true; - break; - - case 'isFalse': - $part[$attribute . '='] = false; - break; - - case 'today': - $part[$attribute . '='] = date('Y-m-d'); - break; - - case 'past': - $part[$attribute . '<'] = date('Y-m-d'); - break; - - case 'future': - $part[$attribute . '>='] = date('Y-m-d'); - break; - - case 'lastSevenDays': - $dt1 = new DateTime(); - $dt2 = clone $dt1; - $dt2->modify('-7 days'); - $part['AND'] = [ - $attribute . '>=' => $dt2->format('Y-m-d'), - $attribute . '<=' => $dt1->format('Y-m-d'), - ]; - break; - - case 'lastXDays': - $dt1 = new DateTime(); - $dt2 = clone $dt1; - $number = strval(intval($value)); - - $dt2->modify('-'.$number.' days'); - $part['AND'] = [ - $attribute . '>=' => $dt2->format('Y-m-d'), - $attribute . '<=' => $dt1->format('Y-m-d'), - ]; - break; - - case 'nextXDays': - $dt1 = new DateTime(); - $dt2 = clone $dt1; - $number = strval(intval($value)); - $dt2->modify('+'.$number.' days'); - $part['AND'] = [ - $attribute . '>=' => $dt1->format('Y-m-d'), - $attribute . '<=' => $dt2->format('Y-m-d'), - ]; - break; - - case 'olderThanXDays': - $dt1 = new DateTime(); - $number = strval(intval($value)); - $dt1->modify('-'.$number.' days'); - $part[$attribute . '<'] = $dt1->format('Y-m-d'); - break; - - case 'afterXDays': - $dt1 = new DateTime(); - $number = strval(intval($value)); - $dt1->modify('+'.$number.' days'); - $part[$attribute . '>'] = $dt1->format('Y-m-d'); - break; - - case 'currentMonth': - $dt = new DateTime(); - $part['AND'] = [ - $attribute . '>=' => $dt->modify('first day of this month')->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1M'))->format('Y-m-d'), - ]; - break; - - case 'lastMonth': - $dt = new DateTime(); - $part['AND'] = [ - $attribute . '>=' => $dt->modify('first day of last month')->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1M'))->format('Y-m-d'), - ]; - break; - - case 'nextMonth': - $dt = new DateTime(); - $part['AND'] = [ - $attribute . '>=' => $dt->modify('first day of next month')->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1M'))->format('Y-m-d'), - ]; - break; - - case 'currentQuarter': - $dt = new DateTime(); - $quarter = ceil($dt->format('m') / 3); - $dt->modify('first day of January this year'); - $part['AND'] = [ - $attribute . '>=' => $dt->add(new DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P3M'))->format('Y-m-d'), - ]; - break; - - case 'lastQuarter': - $dt = new DateTime(); - $quarter = ceil($dt->format('m') / 3); - $dt->modify('first day of January this year'); - $quarter--; - if ($quarter == 0) { - $quarter = 4; - $dt->modify('-1 year'); - } - $part['AND'] = [ - $attribute . '>=' => $dt->add(new DateInterval('P'.(($quarter - 1) * 3).'M'))->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P3M'))->format('Y-m-d'), - ]; - break; - - case 'currentYear': - $dt = new DateTime(); - $part['AND'] = [ - $attribute . '>=' => $dt->modify('first day of January this year')->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1Y'))->format('Y-m-d'), - ]; - break; - - case 'lastYear': - $dt = new DateTime(); - $part['AND'] = [ - $attribute . '>=' => $dt->modify('first day of January last year')->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1Y'))->format('Y-m-d'), - ]; - break; - - case 'currentFiscalYear': - case 'lastFiscalYear': - $dtToday = new DateTime(); - $dt = new DateTime(); - $fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0); - $dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months'); - if (intval($dtToday->format('m')) < $fiscalYearShift + 1) { - $dt->modify('-1 year'); - } - if ($type === 'lastFiscalYear') { - $dt->modify('-1 year'); - } - $part['AND'] = [ - $attribute . '>=' => $dt->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P1Y'))->format('Y-m-d') - ]; - break; - - case 'currentFiscalQuarter': - case 'lastFiscalQuarter': - $dtToday = new DateTime(); - $dt = new DateTime(); - $fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0); - $dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months'); - $month = intval($dtToday->format('m')); - $quarterShift = floor(($month - $fiscalYearShift - 1) / 3); - if ($quarterShift) { - if ($quarterShift >= 0) { - $dt->add(new DateInterval('P'.($quarterShift * 3).'M')); - } else { - $quarterShift *= -1; - $dt->sub(new DateInterval('P'.($quarterShift * 3).'M')); - } - } - if ($type === 'lastFiscalQuarter') { - $dt->modify('-3 months'); - } - $part['AND'] = [ - $attribute . '>=' => $dt->format('Y-m-d'), - $attribute . '<' => $dt->add(new DateInterval('P3M'))->format('Y-m-d') - ]; - break; - - case 'between': - if (is_array($value)) { - $part['AND'] = [ - $attribute . '>=' => $value[0], - $attribute . '<=' => $value[1], - ]; - } - break; - - case 'columnLike': - case 'columnIn': - case 'columnIsNull': - case 'columnNotIn': - $link = $this->getMetadata()->get(['entityDefs', $this->entityType, 'fields', $attribute, 'link']); - $column = $this->getMetadata()->get(['entityDefs', $this->entityType, 'fields', $attribute, 'column']); - $alias = $link . 'Filter' . strval(rand(10000, 99999)); - $this->setDistinct(true, $result); - $this->addLeftJoin([$link, $alias], $result); - $columnKey = $alias . 'Middle.' . $column; - if ($type === 'columnIn') { - $part[$columnKey] = $value; - } else if ($type === 'columnNotIn') { - $part[$columnKey . '!='] = $value; - } else if ($type === 'columnIsNull') { - $part[$columnKey] = null; - } else if ($type === 'columnIsNotNull') { - $part[$columnKey . '!='] = null; - } else if ($type === 'columnLike') { - $part[$columnKey . '*'] = $value; - } else if ($type === 'columnStartsWith') { - $part[$columnKey . '*'] = $value . '%'; - } else if ($type === 'columnEndsWith') { - $part[$columnKey . '*'] = '%' . $value; - } else if ($type === 'columnContains') { - $part[$columnKey . '*'] = '%' . $value . '%'; - } else if ($type === 'columnEquals') { - $part[$columnKey . '='] = $value; - } else if ($type === 'columnNotEquals') { - $part[$columnKey . '!='] = $value; - } - break; - - case 'isNotLinked': - $part['id!=s'] = [ - 'selectParams' => [ - 'select' => ['id'], - 'joins' => [$attribute], - ] - ]; - break; - - case 'isLinked': - if (!$result) break; - $alias = $attribute . 'IsLinkedFilter' . strval(rand(10000, 99999)); - $part[$alias . '.id!='] = null; - $this->setDistinct(true, $result); - $this->addLeftJoin([$attribute, $alias], $result); - break; - - case 'linkedWith': - $seed = $this->getSeed(); - $link = $attribute; - if (!$seed->hasRelation($link)) break; - - $alias = $link . 'Filter' . strval(rand(10000, 99999)); - - if (is_null($value) || !$value && !is_array($value)) break; - - $relationType = $seed->getRelationType($link); - - if ($relationType == 'manyMany') { - $this->addLeftJoin([$link, $alias], $result); - $midKeys = $seed->getRelationParam($link, 'midKeys'); - - if (!empty($midKeys)) { - $key = $midKeys[1]; - $part[$alias . 'Middle.' . $key] = $value; - } - - } else if ($relationType == 'hasMany') { - $this->addLeftJoin([$link, $alias], $result); - - $part[$alias . '.id'] = $value; - - } else if ($relationType == 'belongsTo') { - $key = $seed->getRelationParam($link, 'key'); - if (!empty($key)) { - $part[$key] = $value; - } - - } else if ($relationType == 'hasOne') { - $this->addLeftJoin([$link, $alias], $result); - $part[$alias . '.id'] = $value; - - } else { - break; - } - - $this->setDistinct(true, $result); - break; - - case 'notLinkedWith': - $seed = $this->getSeed(); - $link = $attribute; - if (!$seed->hasRelation($link)) break; - - if (is_null($value)) break; - - $relationType = $seed->getRelationType($link); - - $alias = $link . 'NotLinkedFilter' . strval(rand(10000, 99999)); - - if ($relationType == 'manyMany') { - $key = $seed->getRelationParam($link, 'midKeys')[1]; - - $this->addLeftJoin( - [ - $link, $alias, [$key => $value], - ], - $result - ); - - $part[$alias . 'Middle.' . $key] = null; - - } else if ($relationType == 'hasMany') { - $this->addLeftJoin( - [ - $link, $alias, ['id' => $value] - ], - $result - ); - - $part[$alias . '.id'] = null; - - } else if ($relationType == 'belongsTo') { - $key = $seed->getRelationParam($link, 'key'); - - if (!empty($key)) { - $part[$key . '!='] = $value; - } - - } else if ($relationType == 'hasOne') { - $this->addLeftJoin([$link, $alias], $result); - - $part[$alias . '.id!='] = $value; - - } else { - break; - } - - $this->setDistinct(true, $result); - - break; - - case 'arrayAnyOf': - case 'arrayNoneOf': - case 'arrayIsEmpty': - case 'arrayIsNotEmpty': - case 'arrayAllOf': - if (!$result) break; - - $arrayValueAlias = 'arrayFilter' . rand(10000, 99999); - $arrayAttribute = $attribute; - $arrayEntityType = $this->getEntityType(); - $idPart = 'id'; - - $seed = $this->getSeed(); - - if (strpos($attribute, '.') > 0 || $seed->getAttributeType($attribute) === AttributeType::FOREIGN) { - if ($seed->getAttributeType($attribute) === AttributeType::FOREIGN) { - $arrayAttributeLink = $seed->getAttributeParam($attribute, 'relation'); - $arrayAttribute = $seed->getAttributeParam($attribute, 'foreign'); - } else { - list($arrayAttributeLink, $arrayAttribute) = explode('.', $attribute); - } - - $arrayEntityType = $seed->getRelationParam($arrayAttributeLink, RelationParam::ENTITY); - - $arrayLinkAlias = $arrayAttributeLink . 'Filter' . rand(10000, 99999); - $idPart = $arrayLinkAlias . '.id'; - - $this->addLeftJoin([$arrayAttributeLink, $arrayLinkAlias], $result); - - $relationType = $seed->getRelationType($arrayAttributeLink); - if ($relationType === 'manyMany' || $relationType === 'hasMany') { - $this->setDistinct(true, $result); - } - } - - if ($type === 'arrayAnyOf') { - if (is_null($value) || !$value && !is_array($value)) break; - $this->addLeftJoin(['ArrayValue', $arrayValueAlias, [ - $arrayValueAlias . '.entityId:' => $idPart, - $arrayValueAlias . '.entityType' => $arrayEntityType, - $arrayValueAlias . '.attribute' => $arrayAttribute - ]], $result); - $part[$arrayValueAlias . '.value'] = $value; - - $this->setDistinct(true, $result); - } else if ($type === 'arrayNoneOf') { - if (is_null($value) || !$value && !is_array($value)) break; - $this->addLeftJoin(['ArrayValue', $arrayValueAlias, [ - $arrayValueAlias . '.entityId:' => $idPart, - $arrayValueAlias . '.entityType' => $arrayEntityType, - $arrayValueAlias . '.attribute' => $arrayAttribute, - $arrayValueAlias . '.value=' => $value - ]], $result); - $part[$arrayValueAlias . '.id'] = null; - - $this->setDistinct(true, $result); - } else if ($type === 'arrayIsEmpty') { - $this->addLeftJoin(['ArrayValue', $arrayValueAlias, [ - $arrayValueAlias . '.entityId:' => $idPart, - $arrayValueAlias . '.entityType' => $arrayEntityType, - $arrayValueAlias . '.attribute' => $arrayAttribute - ]], $result); - $part[$arrayValueAlias . '.id'] = null; - - $this->setDistinct(true, $result); - } else if ($type === 'arrayIsNotEmpty') { - $this->addLeftJoin(['ArrayValue', $arrayValueAlias, [ - $arrayValueAlias . '.entityId:' => $idPart, - $arrayValueAlias . '.entityType' => $arrayEntityType, - $arrayValueAlias . '.attribute' => $arrayAttribute - ]], $result); - $part[$arrayValueAlias . '.id!='] = null; - - $this->setDistinct(true, $result); - } else if ($type === 'arrayAllOf') { - if (is_null($value) || !$value && !is_array($value)) break; - - if (!is_array($value)) { - $value = [$value]; - } - - foreach ($value as $arrayValue) { - $part[] = [ - $idPart .'=s' => [ - 'entityType' => 'ArrayValue', - 'selectParams' => [ - 'select' => ['entityId'], - 'whereClause' => [ - 'value' => $arrayValue, - 'attribute' => $arrayAttribute, - 'entityType' => $arrayEntityType, - ], - ], - ] - ]; - } - } - } - - return $part; - } - - /** - * Apply an order to select parameters. - */ - public function applyOrder(string $sortBy, $desc, array &$result) - { - $this->prepareResult($result); - $this->order($sortBy, $desc, $result); - } - - /** - * Apply a limit to select parameters. - */ - public function applyLimit(?int $offset, ?int $maxSize, array &$result) - { - $this->prepareResult($result); - $this->limit($offset, $maxSize, $result); - } - - /** - * Fallback for backward compatibility. - */ - public function hasInheritedAccessMethod() : bool - { - $method = new ReflectionMethod($this, 'access'); - - return $method->getDeclaringClass()->getName() !== SelectManager::class; - } - - /** - * Fallback for backward compatibility. - */ - public function applyAccessToQueryBuilder(OrmSelectBuilder $queryBuilder) - { - $result = $queryBuilder->build()->getRaw(); - - $this->access($result); - - $queryBuilder->setRawParams($result); - } - - /** - * Fallback for backward compatibility. - */ - public function hasInheritedAccessFilterMethod(string $filterName) : bool - { - if ( - $this->metadata->get( - ['selectDefs', $this->entityType, 'accessControlFilterClassNameMap', $filterName] - ) - ) { - return false; - } - - $methodName = 'access' . ucfirst($filterName); - - if (!method_exists($this, $methodName)) { - return false; - } - - $method = new ReflectionMethod($this, $methodName); - - return $method->getDeclaringClass()->getName() !== SelectManager::class; - } - - /** - * Fallback for backward compatibility. - */ - public function applyAccessFilterToQueryBuilder(OrmSelectBuilder $queryBuilder, string $filterName) - { - $methodName = 'access' . ucfirst($filterName); - - $result = $queryBuilder->build()->getRaw(); - - $this->$methodName($result); - - $queryBuilder->setRawParams($result); - } - - /** - * Fallback for backward compatibility. - */ - public function hasBoolFilter(string $filter) : bool - { - $method = 'boolFilter' . ucfirst($filter); - - return method_exists($this, $method); - } - - /** - * Fallback for backward compatibility. - */ - public function applyBoolFilterToQueryBuilder(OrmSelectBuilder $queryBuilder, string $filter) : array - { - $result = $queryBuilder->build()->getRaw(); - - $method = 'boolFilter' . ucfirst($filter); - - if (!method_exists($this, $method)) { - throw new BadRequest("Bool filter '{$filter}' does not exist."); - } - - $rawWhereClause = $this->$method($result) ?? []; - - $queryBuilder->setRawParams($result); - - return $rawWhereClause; - } - - /** - * Fallback for backward compatibility. - */ - public function hasPrimaryFilter(string $filter) : bool - { - if ( - method_exists($this, 'filter' . ucfirst($filter)) - ) { - return true; - } - - if ( - $this->getMetadata()->get( - ['entityDefs', $this->entityType, 'collection', 'filters', $filter, 'className'] - ) - ) { - return true; - } - - return false; - } - - /** - * Fallback for backward compatibility. - */ - public function applyPrimaryFilterToQueryBuilder(OrmSelectBuilder $queryBuilder, string $filter) - { - $result = $queryBuilder->build()->getRaw(); - - $this->applyPrimaryFilter($filter, $result); - - $queryBuilder->setRawParams($result); - } - - /** - * Apply a primary filter to select parameters. - */ - public function applyPrimaryFilter(string $filter, array &$result) - { - $this->prepareResult($result); - - $method = 'filter' . ucfirst($filter); - - if (method_exists($this, $method)) { - $this->$method($result); - - return; - } - - $className = $this->getMetadata() - ->get(['entityDefs', $this->entityType, 'collection', 'filters', $filter, 'className']); - - if ($className) { - $impl = $this->getInjectableFactory()->create($className); - - $impl->applyFilter($this->entityType, $filter, $result, $this); - - return; - } - - $result['whereClause'][] = ['id' => null]; - } - - public function applyFilter(string $filter, array &$result) - { - $this->applyPrimaryFilter($filter, $result); - } - - /** - * Apply a bool filter to select parameters. - */ - public function applyBoolFilter(string $filter, array &$result) - { - $this->prepareResult($result); - - $method = 'boolFilter' . ucfirst($filter); - if (method_exists($this, $method)) { - $wherePart = $this->$method($result); - if ($wherePart) { - $result['whereClause'][] = $wherePart; - } - } - } - - /** - * Apply a list of bool filters to select parameters. - */ - public function applyBoolFilterList(array $filterList, array &$result) - { - $this->prepareResult($result); - - $wherePartList = []; - - foreach ($filterList as $filter) { - $method = 'boolFilter' . ucfirst($filter); - if (method_exists($this, $method)) { - $wherePart = $this->$method($result); - if ($wherePart) { - $wherePartList[] = $wherePart; - } - } - } - - if (count($wherePartList)) { - if (count($wherePartList) === 1) { - $result['whereClause'][] = $wherePartList; - } else { - $result['whereClause'][] = ['OR' => $wherePartList]; - } - } - } - - /** - * Apply a text filter to select parameters. - */ - public function applyTextFilter(string $textFilter, array &$result) - { - $this->prepareResult($result); - $this->textFilter($textFilter, $result); - } - - public function applyAdditional(array $params, array &$result) - { - - } - - /** - * Check whether a link is already in JOINs. If an existing join has alias, then the alias is checked, the link is ignored. - */ - public function hasJoin($join, array &$result) - { - $list = $result['joins'] ?? []; - - if (in_array($join, $list)) { - return true; - } - - foreach ($list as $item) { - if (is_array($item) && count($item) > 1) { - if ($item[1] == $join) { - return true; - } - } - } - - return false; - } - - /** - * Check whether a link is already in LEFT JOINs. If an existing join has alias, then the alias is checked, - * the link is ignored. - */ - public function hasLeftJoin($leftJoin, array &$result) - { - $list = $result['leftJoins'] ?? []; - - if (in_array($leftJoin, $list)) { - return true; - } - - foreach ($list as $item) { - if (is_array($item) && count($item) > 1) { - if ($item[1] == $leftJoin) { - return true; - } - } - } - - return false; - } - - /** - * Check whether a link is already joined. If an existing join has alias, then the alias is checked, the link is ignored. - */ - public function hasLinkJoined($join, array &$result) - { - if (in_array($join, $result['joins'])) { - return true; - } - - foreach ($result['joins'] as $item) { - if (is_array($item) && count($item) > 1) { - if ($item[0] == $join) { - return true; - } - } - } - - if (in_array($join, $result['leftJoins'])) { - return true; - } - - foreach ($result['leftJoins'] as $item) { - if (is_array($item) && count($item) > 1) { - if ($item[0] == $join) { - return true; - } - } - } - - return false; - } - - /** - * Add JOIN. - * - * @param string|array $join Format used for array: [link, alias, conditions]. - */ - public function addJoin($join, array &$result) - { - if (empty($result['joins'])) { - $result['joins'] = []; - } - - $alias = $join; - if (is_array($join)) { - if (count($join) > 1) { - $alias = $join[1]; - } else { - $alias = $join[0]; - } - } - foreach ($result['joins'] as $j) { - $a = $j; - if (is_array($j)) { - if (count($j) > 1) { - $a = $j[1]; - } else { - $a = $j[0]; - } - } - if ($a === $alias) { - return; - } - } - - $result['joins'][] = $join; - } - - /** - * Add LEFT JOIN. - * - * @param string|array $join Format used for array: [link, alias, conditions]. - */ - public function addLeftJoin($leftJoin, array &$result) - { - if (empty($result['leftJoins'])) { - $result['leftJoins'] = []; - } - - $alias = $leftJoin; - if (is_array($leftJoin)) { - if (count($leftJoin) > 1) { - $alias = $leftJoin[1]; - } else { - $alias = $leftJoin[0]; - } - } - foreach ($result['leftJoins'] as $j) { - $a = $j; - if (is_array($j)) { - if (count($j) > 1) { - $a = $j[1]; - } else { - $a = $j[0]; - } - } - if ($a === $alias) { - return; - } - } - - $result['leftJoins'][] = $leftJoin; - } - - public function setJoinCondition(string $join, $condition, array &$result) - { - $result['joinConditions'][$join] = $condition; - } - - /** - * Set DISTINCT. - */ - public function setDistinct(bool $distinct, array &$result) - { - $result['distinct'] = (bool) $distinct; - } - - public function addAndWhere(array $whereClause, array &$result) - { - $result['whereClause'][] = $whereClause; - } - - public function addOrWhere(array $whereClause, array &$result) - { - $result['whereClause'][] = [ - 'OR' => $whereClause - ]; - } - - public function getFullTextSearchDataForTextFilter($textFilter, $isAuxiliaryUse = false) - { - if (array_key_exists($textFilter, $this->fullTextSearchDataCacheHash)) { - return $this->fullTextSearchDataCacheHash[$textFilter]; - } - - if ($this->getConfig()->get('fullTextSearchDisabled')) { - return null; - } - - $result = null; - - $fieldList = $this->getTextFilterFieldList(); - - if ($isAuxiliaryUse) { - $textFilter = str_replace('%', '', $textFilter); - } - - $fullTextSearchColumnList = $this->getEntityManager()->getMetadata()->get( - $this->getEntityType(), ['fullTextSearchColumnList'] - ); - - $useFullTextSearch = false; - - if ( - $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'collection', 'fullTextSearch']) - && - !empty($fullTextSearchColumnList) - ) { - $fullTextSearchMinLength = $this->getConfig()->get('fullTextSearchMinLength', self::MIN_LENGTH_FOR_FULL_TEXT_SEARCH); - if (!$fullTextSearchMinLength) { - $fullTextSearchMinLength = 0; - } - $textFilterWoWildcards = str_replace('*', '', $textFilter); - if (mb_strlen($textFilterWoWildcards) >= $fullTextSearchMinLength) { - $useFullTextSearch = true; - } - } - - $fullTextSearchFieldList = []; - - if ($useFullTextSearch) { - foreach ($fieldList as $field) { - if (strpos($field, '.') !== false) { - continue; - } - - $defs = $this->getMetadata()->get(['entityDefs', $this->getEntityType(), 'fields', $field], []); - if (empty($defs['type'])) continue; - $fieldType = $defs['type']; - if (!empty($defs['notStorable'])) continue; - if (!$this->getMetadata()->get(['fields', $fieldType, 'fullTextSearch'])) continue; - $fullTextSearchFieldList[] = $field; - } - if (!count($fullTextSearchFieldList)) { - $useFullTextSearch = false; - } - - if (substr_count($textFilter, '\'') % 2 != 0) { - $useFullTextSearch = false; - } - if (substr_count($textFilter, '"') % 2 != 0) { - $useFullTextSearch = false; - } - } - - if (empty($fullTextSearchColumnList)) { - $useFullTextSearch = false; - } - - if ($isAuxiliaryUse) { - if (mb_strpos($textFilter, '@') !== false) { - $useFullTextSearch = false; - } - } - - if ($useFullTextSearch) { - $textFilter = str_replace(['(', ')'], '', $textFilter); - - if ( - $isAuxiliaryUse && mb_strpos($textFilter, '*') === false - || - mb_strpos($textFilter, ' ') === false - && - mb_strpos($textFilter, '+') === false - && - mb_strpos($textFilter, '-') === false - && - mb_strpos($textFilter, '*') === false - ) { - $function = 'MATCH_NATURAL_LANGUAGE'; - } else { - $function = 'MATCH_BOOLEAN'; - } - - $textFilter = str_replace('"*', '"', $textFilter); - $textFilter = str_replace('*"', '"', $textFilter); - - $textFilter = str_replace('\'', '\'\'', $textFilter); - - while (strpos($textFilter, '**')) { - $textFilter = str_replace('**', '*', $textFilter); - $textFilter = trim($textFilter); - } - - while (mb_substr($textFilter, -2) === ' *') { - $textFilter = mb_substr($textFilter, 0, mb_strlen($textFilter) - 2); - $textFilter = trim($textFilter); - } - - $where = $function . ':(' . implode(', ', $fullTextSearchColumnList) . ', ' . "'{$textFilter}'" . ')'; - - $result = [ - 'where' => $where, - 'fieldList' => $fullTextSearchFieldList, - 'columnList' => $fullTextSearchColumnList, - ]; - } - - $this->fullTextSearchDataCacheHash[$textFilter] = $result; - - return $result; - } - - protected function textFilter($textFilter, array &$result, $noFullText = false) - { - $fieldList = $this->getTextFilterFieldList(); - - $group = []; - - $textFilterContainsMinLength = $this->getConfig() - ->get('textFilterContainsMinLength', self::MIN_LENGTH_FOR_CONTENT_SEARCH); - - $fullTextSearchData = null; - - $forceFullTextSearch = false; - - $useFullTextSearch = !empty($result['useFullTextSearch']); - - if (mb_strpos($textFilter, 'ft:') === 0) { - $textFilter = mb_substr($textFilter, 3); - $useFullTextSearch = true; - $forceFullTextSearch = true; - } - - $textFilterForFullTextSearch = $textFilter; - - $skipWidlcards = false; - - if (mb_strpos($textFilter, '*') !== false) { - $skipWidlcards = true; - $textFilter = str_replace('*', '%', $textFilter); - } - - $textFilterForFullTextSearch = str_replace('%', '*', $textFilterForFullTextSearch); - - $skipFullTextSearch = false; - - if (!$forceFullTextSearch) { - if (mb_strpos($textFilterForFullTextSearch, '*') === 0) { - $skipFullTextSearch = true; - } else if (mb_strpos($textFilterForFullTextSearch, ' *') !== false) { - $skipFullTextSearch = true; - } - } - - if ($noFullText) { - $skipFullTextSearch = true; - } - - $fullTextSearchData = null; - - if (!$skipFullTextSearch) { - $fullTextSearchData = $this->getFullTextSearchDataForTextFilter($textFilterForFullTextSearch, !$useFullTextSearch); - } - - $fullTextGroup = []; - - $fullTextSearchFieldList = []; - - if ($fullTextSearchData) { - if ($this->fullTextRelevanceThreshold) { - $fullTextGroup[] = [$fullTextSearchData['where'] . '>=' => $this->fullTextRelevanceThreshold]; - } else { - $fullTextGroup[] = $fullTextSearchData['where']; - } - - $fullTextSearchFieldList = $fullTextSearchData['fieldList']; - - $relevanceExpression = $fullTextSearchData['where']; - - $fullTextOrderType = $this->fullTextOrderType; - - $orderTypeMap = [ - 'combined' => self::FT_ORDER_COMBINTED, - 'relevance' => self::FT_ORDER_RELEVANCE, - 'original' => self::FT_ORDER_ORIGINAL, - ]; - - $mOrderType = $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'fullTextSearchOrderType']); - - if ($mOrderType) { - $fullTextOrderType = $orderTypeMap[$mOrderType]; - } - - if (!isset($result['orderBy']) || $fullTextOrderType === self::FT_ORDER_RELEVANCE) { - $result['orderBy'] = [[$relevanceExpression, 'desc']]; - $result['order'] = null; - } else { - if ($fullTextOrderType === self::FT_ORDER_COMBINTED) { - $relevanceExpression = - 'ROUND:(DIV:(' . $fullTextSearchData['where'] . ','.$this->fullTextOrderRelevanceDivider.'))'; - - if (is_string($result['orderBy'])) { - $result['orderBy'] = [ - [$relevanceExpression, 'desc'], - [$result['orderBy'], $result['order'] ?? 'asc'], - ]; - } else if (is_array($result['orderBy'])) { - $result['orderBy'] = array_merge( - [[$relevanceExpression, 'desc']], - $result['orderBy'] - ); - } - } - } - - $result['hasFullTextSearch'] = true; - } - - foreach ($fieldList as $field) { - if ($useFullTextSearch) { - if (in_array($field, $fullTextSearchFieldList)) { - continue; - } - } - - if ($forceFullTextSearch) { - continue; - } - - $seed = $this->getSeed(); - - $attributeType = null; - - if (strpos($field, '.') !== false) { - list($link, $foreignField) = explode('.', $field); - - $foreignEntityType = $seed->getRelationParam($link, 'entity'); - $seed = $this->getEntityManager()->getEntity($foreignEntityType); - - $this->addLeftJoin($link, $result); - - if ($seed->getRelationParam($link, 'type') === $seed::HAS_MANY) { - $this->setDistinct(true, $result); - } - - $attributeType = $seed->getAttributeType($foreignField); - } else { - $attributeType = $seed->getAttributeType($field); - - if ($attributeType === AttributeType::FOREIGN) { - $link = $seed->getAttributeParam($field, 'relation'); - - if ($link) { - $this->addLeftJoin($link, $result); - } - } - } - - if ($attributeType === 'int') { - if (is_numeric($textFilter)) { - $group[$field] = intval($textFilter); - } - - continue; - } - - if (!$skipWidlcards) { - if ( - mb_strlen($textFilter) >= $textFilterContainsMinLength - && - ( - $attributeType == AttributeType::TEXT - || - in_array($field, $this->textFilterUseContainsAttributeList) - || - $attributeType == AttributeType::VARCHAR && $this->getConfig()->get('textFilterUseContainsForVarchar') - ) - ) { - $expression = '%' . $textFilter . '%'; - } else { - $expression = $textFilter . '%'; - } - } else { - $expression = $textFilter; - } - - if ($fullTextSearchData) { - if (!$useFullTextSearch) { - if (in_array($field, $fullTextSearchFieldList)) { - continue; - } - } - } - - $group[$field . '*'] = $expression; - } - - if (!$forceFullTextSearch) { - $this->applyAdditionalToTextFilterGroup($textFilter, $group, $result); - } - - if (!empty($fullTextGroup)) { - $group['AND'] = $fullTextGroup; - } - - if (count($group) === 0) { - $result['whereClause'][] = [ - 'id' => null - ]; - } - - $result['whereClause'][] = [ - 'OR' => $group - ]; - } - - protected function applyAdditionalToTextFilterGroup(string $textFilter, array &$group, array &$result) - { - } - - public function applyAccess(array &$result) - { - $result['from'] = $this->entityType; - - $query = SelectQuery::fromRaw($result); - - $result = $this->selectBuilderFactory - ->create() - ->clone($query) - ->forUser($this->user) - ->withAccessControlFilter() - ->build() - ->getRaw(); - } - - protected function boolFilters(array $params, array &$result) - { - if (!empty($params['boolFilterList']) && is_array($params['boolFilterList'])) { - foreach ($params['boolFilterList'] as $filterName) { - $this->applyBoolFilter($filterName, $result); - } - } - } - - protected function getBoolFilterWhere(string $filterName) - { - $method = 'getBoolFilterWhere' . ucfirst($filterName); - - if (method_exists($this, $method)) { - return $this->$method(); - } - - return null; - } - - protected function boolFilterOnlyMy(&$result) - { - if (!$this->checkIsPortal()) { - if ($this->hasAssignedUsersField()) { - $this->setDistinct(true, $result); - $this->addLeftJoin(['assignedUsers', 'assignedUsersOnlyMyFilter'], $result); - $wherePart = [ - 'assignedUsersOnlyMyFilter.id' => $this->getUser()->getId() - ]; - } else if ($this->hasAssignedUserField()) { - $wherePart = [ - 'assignedUserId' => $this->getUser()->getId() - ]; - } else { - $wherePart = [ - 'createdById' => $this->getUser()->getId() - ]; - } - } else { - $wherePart = [ - 'createdById' => $this->getUser()->getId() - ]; - } - - return $wherePart; - } - - protected function boolFilterOnlyMyTeam(&$result) - { - $teamIdList = $this->getUser()->getLinkMultipleIdList('teams'); - - if (count($teamIdList) === 0) { - return [ - 'id' => null - ]; - } - - $this->addLeftJoin(['teams', 'teamsOnlyMyFilter'], $result); - $this->setDistinct(true, $result); - return [ - 'teamsOnlyMyFilterMiddle.teamId' => $teamIdList - ]; - } - - protected function filterFollowed(&$result) - { - $this->addJoin([ - StreamSubscription::ENTITY_TYPE, - 'subscription', - [ - 'subscription.entityType' => $this->getEntityType(), - 'subscription.entityId=:' => 'id', - 'subscription.userId' => $this->getUser()->getId(), - ] - ], $result); - } - - protected function boolFilterFollowed(&$result) - { - $this->addLeftJoin([ - StreamSubscription::ENTITY_TYPE, - 'subscription', - [ - 'subscription.entityType' => $this->getEntityType(), - 'subscription.entityId=:' => 'id', - 'subscription.userId' => $this->getUser()->getId(), - ] - ], $result); - - return ['subscription.id!=' => null]; - } - - public function mergeSelectParams(array $selectParams1, ?array $selectParams2) : array - { - if (!$selectParams2) { - return $selectParams1; - } - if (!isset($selectParams1['whereClause'])) { - $selectParams1['whereClause'] = []; - } - if (!empty($selectParams2['whereClause'])) { - $selectParams1['whereClause'][] = $selectParams2['whereClause']; - } - - if (!isset($selectParams1['havingClause'])) { - $selectParams1['havingClause'] = []; - } - if (!empty($selectParams2['havingClause'])) { - $selectParams1['havingClause'][] = $selectParams2['havingClause']; - } - - - if (!empty($selectParams2['joins'])) { - foreach ($selectParams2['joins'] as $item) { - $this->addJoin($item, $selectParams1); - } - } - - if (!empty($selectParams2['leftJoins'])) { - foreach ($selectParams2['leftJoins'] as $item) { - if ($this->hasJoin($item, $selectParams1)) { - continue; - } - - $this->addLeftJoin($item, $selectParams1); - } - } - - if (isset($selectParams2['select'])) { - $selectParams1['select'] = $selectParams2['select']; - } - - if (isset($selectParams2['customJoin'])) { - if (!isset($selectParams1['customJoin'])) { - $selectParams1['customJoin'] = ''; - } - $selectParams1['customJoin'] .= ' ' . $selectParams2['customJoin']; - } - - if (isset($selectParams2['customWhere'])) { - if (!isset($selectParams1['customWhere'])) { - $selectParams1['customWhere'] = ''; - } - $selectParams1['customWhere'] .= ' ' . $selectParams2['customWhere']; - } - - if (isset($selectParams2['additionalSelectColumns'])) { - if (!isset($selectParams1['additionalSelectColumns'])) { - $selectParams1['additionalSelectColumns'] = []; - } - foreach ($selectParams2['additionalSelectColumns'] as $key => $item) { - $selectParams1['additionalSelectColumns'][$key] = $item; - } - } - - if (isset($selectParams2['joinConditions'])) { - if (!isset($selectParams1['joinConditions'])) { - $selectParams1['joinConditions'] = []; - } - foreach ($selectParams2['joinConditions'] as $key => $item) { - $selectParams1['joinConditions'][$key] = $item; - } - } - - if (isset($selectParams2['orderBy'])) { - $selectParams1['orderBy'] = $selectParams2['orderBy']; - } - if (isset($selectParams2['order'])) { - $selectParams1['order'] = $selectParams2['order']; - } - - if (!empty($selectParams2['distinct'])) { - $selectParams1['distinct'] = true; - } - - return $selectParams1; - } - - public function applyLeftJoinsFromWhere($where, array &$result) - { - if (!is_array($where)) return; - - foreach ($where as $item) { - $this->applyLeftJoinsFromWhereItem($item, $result); - } - } - - public function applyLeftJoinsFromWhereItem($item, array &$result) - { - $type = $item['type'] ?? null; - - if ($type) { - if (in_array($type, ['subQueryNotIn', 'subQueryIn', 'not'])) return; - - if (in_array($type, ['or', 'and', 'having'])) { - $value = $item['value'] ?? null; - if (!is_array($value)) return; - foreach ($value as $listItem) { - $this->applyLeftJoinsFromWhereItem($listItem, $result); - } - return; - } - } - - $attribute = $item['attribute'] ?? null; - if (!$attribute) return; - - $this->applyLeftJoinsFromAttribute($attribute, $result); - } - - protected function applyLeftJoinsFromAttribute(string $attribute, array &$result) - { - if (strpos($attribute, ':') !== false) { - $argumentList = QueryComposer::getAllAttributesFromComplexExpression($attribute); - foreach ($argumentList as $argument) { - $this->applyLeftJoinsFromAttribute($argument, $result); - } - return; - } - - if (strpos($attribute, '.') !== false) { - list($link, $attribute) = explode('.', $attribute); - if ($this->getSeed()->hasRelation($link) && !$this->hasLeftJoin($link, $result)) { - $this->addLeftJoin($link, $result); - if ($this->getSeed()->getRelationType($link) === Entity::HAS_MANY) { - $result['distinct'] = true; - } - } - return; - } - - $attributeType = $this->getSeed()->getAttributeType($attribute); - if ($attributeType === AttributeType::FOREIGN) { - $relation = $this->getSeed()->getAttributeParam($attribute, 'relation'); - if ($relation) { - $this->addLeftJoin($relation, $result); - } - } - } - - public function getSelectAttributeList(array $params) : ?array - { - if (array_key_exists('select', $params)) { - $passedAttributeList = $params['select']; - } else { - return null; - } - - $seed = $this->getSeed(); - - $attributeList = []; - if (!in_array(Attribute::ID, $passedAttributeList)) { - $attributeList[] = Attribute::ID; - } - - $aclAttributeList = $this->aclAttributeList; - if ($this->getUser()->isPortal()) { - $aclAttributeList = $this->aclPortalAttributeList; - } - - foreach ($aclAttributeList as $attribute) { - if (!in_array($attribute, $passedAttributeList) && $seed->hasAttribute($attribute)) { - $attributeList[] = $attribute; - } - } - - foreach ($passedAttributeList as $attribute) { - if (!in_array($attribute, $attributeList) && $seed->hasAttribute($attribute)) { - $attributeList[] = $attribute; - } - } - - $sortByField = $params['orderBy'] ?? $this->getMetadata()->get(['entityDefs', $this->entityType, 'collection', 'orderBy']); - - if ($sortByField) { - $sortByAttributeList = $this->getFieldUtil()->getAttributeList($this->getEntityType(), $sortByField); - foreach ($sortByAttributeList as $attribute) { - if (!in_array($attribute, $attributeList) && $seed->hasAttribute($attribute)) { - $attributeList[] = $attribute; - } - } - } - - $map = $this->selectAttributesDependancyMap; - - $map = array_merge( - $map, - $this->metadata->get(['selectDefs', $this->entityType, 'selectAttributesDependencyMap']) ?? [] - ); - - foreach ($map as $attribute => $dependantAttributeList) { - if (in_array($attribute, $attributeList)) { - foreach ($dependantAttributeList as $dependantAttribute) { - if (!in_array($dependantAttribute, $attributeList)) { - $attributeList[] = $dependantAttribute; - } - } - } - } - - return $attributeList; - } - - protected function hasInOrderBy(string $attribute, array &$result) - { - $orderBy = $result['orderBy'] ?? null; - - if (!$orderBy) return false; - - if (is_string($orderBy)) { - return $attribute === $orderBy; - } - - if (is_array($orderBy)) { - foreach ($orderBy as $item) { - if (is_array($item) && count($item)) { - if ($item[0] === $attribute) { - return true; - } - } - } - } - - return false; - } -} diff --git a/application/Espo/Core/Select/SelectManagerFactory.php b/application/Espo/Core/Select/SelectManagerFactory.php deleted file mode 100644 index 29e7d5424e..0000000000 --- a/application/Espo/Core/Select/SelectManagerFactory.php +++ /dev/null @@ -1,103 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\Select; - -use Espo\Core\Utils\Acl\UserAclManagerProvider; - -use Espo\Core\Acl; -use Espo\Core\InjectableFactory; -use Espo\Core\Utils\ClassFinder; - -use Espo\Entities\User; - -/** - * @deprecated Use SelectBuilder instead. - * - * Creates select managers for specific entity types. You can specify a user whose ACL will be applied to queries. - * If user is not specified, then the current one will be used. - */ -class SelectManagerFactory -{ - /** - * @var class-string - */ - protected string $defaultClassName = SelectManager::class; - - private $user; - - private $acl; - - private $aclManagerProvider; - - private $injectableFactory; - - private $classFinder; - - public function __construct( - User $user, - Acl $acl, - UserAclManagerProvider $aclManagerProvider, - InjectableFactory $injectableFactory, - ClassFinder $classFinder - ) { - $this->user = $user; - $this->acl = $acl; - $this->aclManagerProvider = $aclManagerProvider; - $this->injectableFactory = $injectableFactory; - $this->classFinder = $classFinder; - } - - public function create(string $entityType, ?User $user = null): SelectManager - { - $className = $this->classFinder->find('SelectManagers', $entityType); - - if (!$className || !class_exists($className)) { - $className = $this->defaultClassName; - } - - /** @var class-string $className */ - - if ($user) { - $acl = $this->aclManagerProvider->get($user)->createUserAcl($user); - } else { - $acl = $this->acl; - $user = $this->user; - } - - $selectManager = $this->injectableFactory->createWith($className, [ - 'user' => $user, - 'acl' => $acl, - ]); - - $selectManager->setEntityType($entityType); - - return $selectManager; - } -} diff --git a/application/Espo/Core/SelectManagers/Base.php b/application/Espo/Core/SelectManagers/Base.php deleted file mode 100644 index 5eb8ef45de..0000000000 --- a/application/Espo/Core/SelectManagers/Base.php +++ /dev/null @@ -1,38 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\SelectManagers; - -/** - * @deprecated - * @todo Remove in v10.0. - */ -class Base extends \Espo\Core\Select\SelectManager -{ -} diff --git a/application/Espo/Core/Templates/SelectManagers/Event.php b/application/Espo/Core/Templates/SelectManagers/Event.php deleted file mode 100644 index 223347195c..0000000000 --- a/application/Espo/Core/Templates/SelectManagers/Event.php +++ /dev/null @@ -1,36 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace Espo\Core\Templates\SelectManagers; - -/** - * @deprecated As of v7.0. For backward compatibility. - */ -class Event extends \Espo\Core\Select\SelectManager -{} diff --git a/tests/integration/Espo/Core/Select/LegacyTest.php b/tests/integration/Espo/Core/Select/LegacyTest.php deleted file mode 100644 index d285479a6d..0000000000 --- a/tests/integration/Espo/Core/Select/LegacyTest.php +++ /dev/null @@ -1,129 +0,0 @@ -. - * - * The interactive user interfaces in modified source and object code versions - * of this program must display Appropriate Legal Notices, as required under - * Section 5 of the GNU Affero General Public License version 3. - * - * In accordance with Section 7(b) of the GNU Affero General Public License version 3, - * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. - ************************************************************************/ - -namespace tests\integration\Espo\Core\Select; - -use Espo\Core\Application; -use Espo\Core\Select\SelectManagerFactory; -use tests\integration\Core\BaseTestCase; - -class LegacyTest extends BaseTestCase -{ - /** - * @var SelectManagerFactory - */ - private $selectManagerFactory; - - - protected function setUp(): void - { - parent::setUp(); - - $injectableFactory = $this->getContainer()->get('injectableFactory'); - - $this->selectManagerFactory = $injectableFactory->create(SelectManagerFactory::class); - } - - protected function initTest(array $aclData = [], bool $skipLogin = false, bool $isPortal = false): Application - { - $this->createUser('tester', [ - 'data' => $aclData, - ]); - - if (!$skipLogin) { - $this->auth('tester'); - } - - $app = $this->createApplication(); - - $injectableFactory = $app->getContainer()->get('injectableFactory'); - - $this->selectManagerFactory = $injectableFactory->create(SelectManagerFactory::class); - - $app->getContainer()->get('user'); - - return $app; - } - - - public function testAccess1(): void - { - $app = $this->initTest( - [ - 'Account' => [ - 'read' => 'own', - ], - ] - ); - - $container = $app->getContainer(); - - $userId = $container->get('user')->getId(); - - $selectManager = $this->selectManagerFactory->create('Account'); - - $result = $selectManager->getEmptySelectParams(); - - $selectManager->applyAccess($result); - - $this->assertEquals(['assignedUserId' => $userId], $result['whereClause']); - } - - public function testGetSelectParams(): void - { - $app = $this->initTest( - [ - 'Opportunity' => [ - 'read' => 'own', - ], - ] - ); - - $container = $app->getContainer(); - - $userId = $container->get('user')->getId(); - - $selectManager = $this->selectManagerFactory->create('Opportunity'); - - $params = [ - 'primaryFilter' => 'open', - ]; - - $result = $selectManager->getSelectParams($params, true, true, true); - - - $this->assertEquals( - [ - 'assignedUserId' => $userId, - 'stage!=' => ['Closed Won', 'Closed Lost'], - ], - $result['whereClause'] - ); - } -} diff --git a/tests/unit/Espo/Core/Select/Applier/Appliers/AccessControlFilterApplierTest.php b/tests/unit/Espo/Core/Select/Applier/Appliers/AccessControlFilterApplierTest.php index d1e64569cf..b71deee7c0 100644 --- a/tests/unit/Espo/Core/Select/Applier/Appliers/AccessControlFilterApplierTest.php +++ b/tests/unit/Espo/Core/Select/Applier/Appliers/AccessControlFilterApplierTest.php @@ -34,7 +34,6 @@ use Espo\Core\Select\AccessControl\Filter as AccessControlFilter; use Espo\Core\Select\AccessControl\FilterFactory as AccessControlFilterFactory; use Espo\Core\Select\AccessControl\FilterResolver; use Espo\Core\Select\AccessControl\FilterResolverFactory as AccessControlFilterResolverFactory; -use Espo\Core\Select\SelectManager; use Espo\Entities\User; use Espo\ORM\Query\SelectBuilder as QueryBuilder; @@ -45,7 +44,6 @@ class AccessControlFilterApplierTest extends TestCase private $filterFactory; private $filterResolverFactory; private $user; - private $selectManager; private $queryBuilder; private $filterResolver; private $filter; @@ -58,7 +56,6 @@ class AccessControlFilterApplierTest extends TestCase $this->filterFactory = $this->createMock(AccessControlFilterFactory::class); $this->filterResolverFactory = $this->createMock(AccessControlFilterResolverFactory::class); $this->user = $this->createMock(User::class); - $this->selectManager = $this->createMock(SelectManager::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->filterResolver = $this->createMock(FilterResolver::class); $this->filter = $this->createMock(AccessControlFilter::class); @@ -67,11 +64,10 @@ class AccessControlFilterApplierTest extends TestCase $this->entityType = 'Test'; $this->applier = new AccessControlFilterApplier( - $this->entityType, - $this->user, - $this->filterFactory, - $this->filterResolverFactory, - $this->selectManager + entityType: $this->entityType, + user: $this->user, + accessControlFilterFactory: $this->filterFactory, + accessControlFilterResolverFactory: $this->filterResolverFactory, ); } @@ -98,11 +94,6 @@ class AccessControlFilterApplierTest extends TestCase protected function initApplierTest(bool $resolve, bool $hasFilter) { - $this->selectManager - ->expects($this->once()) - ->method('hasInheritedAccessMethod') - ->willReturn(false); - $this->filterResolverFactory ->expects($this->once()) ->method('create') @@ -128,12 +119,6 @@ class AccessControlFilterApplierTest extends TestCase return; } - $this->selectManager - ->expects($this->once()) - ->method('hasInheritedAccessFilterMethod') - ->with('test') - ->willReturn(false); - $this->filterFactory ->expects($this->once()) ->method('has') diff --git a/tests/unit/Espo/Core/Select/Applier/Appliers/BoolFilterListApplierTest.php b/tests/unit/Espo/Core/Select/Applier/Appliers/BoolFilterListApplierTest.php index 136767564d..4adc2accaa 100644 --- a/tests/unit/Espo/Core/Select/Applier/Appliers/BoolFilterListApplierTest.php +++ b/tests/unit/Espo/Core/Select/Applier/Appliers/BoolFilterListApplierTest.php @@ -33,7 +33,6 @@ use Espo\Core\Exceptions\BadRequest; use Espo\Core\Select\Bool\Applier as BoolFilterListApplier; use Espo\Core\Select\Bool\Filter as BoolFilter; use Espo\Core\Select\Bool\FilterFactory as BoolFilterFactory; -use Espo\Core\Select\SelectManager; use Espo\Entities\User; use Espo\ORM\Query\Part\Where\OrGroupBuilder; @@ -45,7 +44,6 @@ class BoolFilterListApplierTest extends TestCase { private $boolFilterFactory; private $user; - private $selectManager; private $queryBuilder; private $entityType; private $applier; @@ -54,16 +52,14 @@ class BoolFilterListApplierTest extends TestCase { $this->boolFilterFactory = $this->createMock(BoolFilterFactory::class); $this->user = $this->createMock(User::class); - $this->selectManager = $this->createMock(SelectManager::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->entityType = 'Test'; $this->applier = new BoolFilterListApplier( - $this->entityType, - $this->user, - $this->boolFilterFactory, - $this->selectManager + entityType: $this->entityType, + user: $this->user, + boolFilterFactory: $this->boolFilterFactory, ); } @@ -104,12 +100,6 @@ class BoolFilterListApplierTest extends TestCase $this->initApplierTest($boolFilterList, [null], [false]); - $this->selectManager - ->expects($this->once()) - ->method('hasBoolFilter') - ->with('test1') - ->willReturn(false); - $this->expectException(BadRequest::class); $this->applier->apply($this->queryBuilder, $boolFilterList); diff --git a/tests/unit/Espo/Core/Select/Applier/Appliers/PrimaryFilterApplierTest.php b/tests/unit/Espo/Core/Select/Applier/Appliers/PrimaryFilterApplierTest.php index f0929ccde1..7270e24923 100644 --- a/tests/unit/Espo/Core/Select/Applier/Appliers/PrimaryFilterApplierTest.php +++ b/tests/unit/Espo/Core/Select/Applier/Appliers/PrimaryFilterApplierTest.php @@ -33,7 +33,6 @@ use Espo\Core\Exceptions\BadRequest; use Espo\Core\Select\Primary\Applier as PrimaryFilterApplier; use Espo\Core\Select\Primary\Filter as PrimaryFilter; use Espo\Core\Select\Primary\FilterFactory as PrimaryFilterFactory; -use Espo\Core\Select\SelectManager; use Espo\Entities\User; use Espo\ORM\Query\SelectBuilder as QueryBuilder; @@ -43,7 +42,6 @@ class PrimaryFilterApplierTest extends TestCase { private $filterFactory; private $user; - private $selectManager; private $queryBuilder; private $entityType; private $applier; @@ -52,16 +50,14 @@ class PrimaryFilterApplierTest extends TestCase { $this->filterFactory = $this->createMock(PrimaryFilterFactory::class); $this->user = $this->createMock(User::class); - $this->selectManager = $this->createMock(SelectManager::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->entityType = 'Test'; $this->applier = new PrimaryFilterApplier( - $this->entityType, - $this->user, - $this->filterFactory, - $this->selectManager + entityType: $this->entityType, + user: $this->user, + primaryFilterFactory: $this->filterFactory, ); } @@ -95,8 +91,6 @@ class PrimaryFilterApplierTest extends TestCase { $filterName = 'test'; - $filter = $this->createMock(PrimaryFilter::class); - $this->filterFactory ->expects($this->once()) ->method('has') @@ -107,12 +101,6 @@ class PrimaryFilterApplierTest extends TestCase ->expects($this->never()) ->method('create'); - $this->selectManager - ->expects($this->once()) - ->method('hasPrimaryFilter') - ->with($filterName) - ->willReturn(false); - $this->expectException(BadRequest::class); $this->applier->apply($this->queryBuilder, $filterName); diff --git a/tests/unit/Espo/Core/Select/Applier/FactoryTest.php b/tests/unit/Espo/Core/Select/Applier/FactoryTest.php index aa4e24858f..35587e41e2 100644 --- a/tests/unit/Espo/Core/Select/Applier/FactoryTest.php +++ b/tests/unit/Espo/Core/Select/Applier/FactoryTest.php @@ -43,8 +43,6 @@ use Espo\Core\Select\Bool\Applier as BoolFilterListApplier; use Espo\Core\Select\Order\Applier as OrderApplier; use Espo\Core\Select\Primary\Applier as PrimaryFilterApplier; use Espo\Core\Select\Select\Applier as SelectApplier; -use Espo\Core\Select\SelectManager; -use Espo\Core\Select\SelectManagerFactory; use Espo\Core\Select\Text\Applier as TextFilterApplier; use Espo\Core\Select\Where\Applier as WhereApplier; @@ -57,19 +55,14 @@ class FactoryTest extends TestCase private $aclManager; private $acl; private $injectableFactory; - private $selectManagerFactory; private $user; - private $selectManager; private $factory; protected function setUp(): void { $this->injectableFactory = $this->createMock(InjectableFactory::class); - $this->selectManagerFactory = $this->createMock(SelectManagerFactory::class); $this->user = $this->createMock(User::class); - $this->selectManager = $this->createMock(SelectManager::class); - $userAclManagerProvider = $this->createMock(UserAclManagerProvider::class); $this->aclManager = $this->createMock(AclManager::class); @@ -82,7 +75,6 @@ class FactoryTest extends TestCase $this->factory = new ApplierFactory( $this->injectableFactory, $userAclManagerProvider, - $this->selectManagerFactory ); $this->acl = $this->createMock(Acl::class); @@ -145,12 +137,6 @@ class FactoryTest extends TestCase { $entityType = 'Test'; - $this->selectManagerFactory - ->expects($this->once()) - ->method('create') - ->with('Test', $this->user) - ->willReturn($this->selectManager); - $applierClassName = $className ?? $defaultClassName; $applier = $this->createMock($defaultClassName); @@ -161,12 +147,10 @@ class FactoryTest extends TestCase $binder ->bindInstance(User::class, $this->user) - ->bindInstance(SelectManager::class, $this->selectManager) ->bindInstance(AclManager::class, $this->aclManager) ->bindInstance(Acl::class, $this->acl) ->for($applierClassName) - ->bindValue('$entityType', $entityType) - ->bindValue('$selectManager', $this->selectManager); + ->bindValue('$entityType', $entityType); $bindingContainer = new BindingContainer($bindingData);