entityType = $entityType; $this->entityManager = $entityManager; $this->acl = $acl; } public function check(Item $item, Params $params): void { $this->checkItem($item, $params); } private function checkItem(Item $item, Params $params): void { $type = $item->getType(); $attribute = $item->getAttribute(); $value = $item->getValue(); $forbidComplexExpressions = $params->forbidComplexExpressions(); $checkWherePermission = $params->applyPermissionCheck(); if ($forbidComplexExpressions) { if (in_array($type, $this->subQueryTypeList)) { throw new Forbidden("Sub-queries are forbidden in where."); } } if ($attribute && $forbidComplexExpressions) { if ( QueryUtil::isComplexExpression($attribute) ) { throw new Forbidden("Complex expressions are forbidden in where."); } } if ($attribute) { $argumentList = QueryComposer::getAllAttributesFromComplexExpression($attribute); foreach ($argumentList as $argument) { $this->checkAttributeExistence($argument, $type); if ($checkWherePermission) { $this->checkAttributePermission($argument, $type); } } } if (in_array($type, $this->nestingTypeList) && is_array($value)) { foreach ($value as $subItem) { $this->checkItem(Item::fromRaw($subItem), $params); } } } private function checkAttributeExistence(string $attribute, string $type): void { if (strpos($attribute, '.') !== false) { // @todo Check existance of foreign attributes. return; } if (in_array($type, $this->linkTypeList)) { if (!$this->getSeed()->hasRelation($attribute)) { throw new BadRequest("Not existing relation '{$attribute}' in where."); } return; } if (!$this->getSeed()->hasAttribute($attribute)) { throw new BadRequest("Not existing attribute '{$attribute}' in where."); } } private function checkAttributePermission(string $attribute, string $type): void { $entityType = $this->entityType; if (strpos($attribute, '.') !== false) { list($link, $attribute) = explode('.', $attribute); if (!$this->getSeed()->hasRelation($link)) { // TODO allow alias throw new Forbidden("Bad relation '{$link}' in where."); } $foreignEntityType = $this->getSeed()->getRelationParam($link, 'entity'); if (!$foreignEntityType) { throw new Forbidden("Bad relation '{$link}' in where."); } if ( !$this->acl->checkScope($foreignEntityType) || in_array($link, $this->acl->getScopeForbiddenLinkList($entityType)) ) { throw new Forbidden("Forbidden relation '{$link}' in where."); } if (in_array($attribute, $this->acl->getScopeForbiddenAttributeList($foreignEntityType))) { throw new Forbidden("Forbidden attribute '{$link}.{$attribute}' in where."); } return; } if (in_array($type, $this->linkTypeList)) { $link = $attribute; if (!$this->getSeed()->hasRelation($link)) { throw new Forbidden("Bad relation '{$link}' in where."); } $foreignEntityType = $this->getSeed()->getRelationParam($link, 'entity'); if (!$foreignEntityType) { throw new Forbidden("Bad relation '{$link}' in where."); } if ( in_array($link, $this->acl->getScopeForbiddenFieldList($entityType)) || !$this->acl->checkScope($foreignEntityType) || in_array($link, $this->acl->getScopeForbiddenLinkList($entityType)) ) { throw new Forbidden("Forbidden relation '{$link}' in where."); } return; } if (in_array($attribute, $this->acl->getScopeForbiddenAttributeList($entityType))) { throw new Forbidden("Forbidden attribute '{$attribute}' in where."); } } private function getSeed(): Entity { return $this->seed ?? $this->entityManager->getEntity($this->entityType); } }