itemToList($item); foreach ($itemList as $subItem) { $part = $this->processItem($queryBuilder, Item::fromRaw($subItem)); if (empty($part)) { continue; } $whereClause[] = $part; } $this->scanner->apply($queryBuilder, $item); return WhereClause::fromRaw($whereClause); } /** * @return array * @throws Error */ private function itemToList(Item $item): array { if ($item->getType() !== 'and') { return [ $item->getRaw(), ]; } $list = $item->getValue(); if (!is_array($list)) { throw new Error("Bad where item value."); } return $list; } /** * @return ?array * @throws Error */ private function processItem(QueryBuilder $queryBuilder, Item $item): ?array { $type = $item->getType(); $attribute = $item->getAttribute(); $value = $item->getValue(); if ( $type === self::TYPE_IN_CATEGORY || $type === self::TYPE_IS_USER_FROM_TEAMS ) { // Processing special filters. Only at the top level of the tree. if (!$attribute) { throw new Error("Bad where definition. Missing attribute."); } if (!$value) { return null; } if ($type === self::TYPE_IN_CATEGORY) { return $this->applyInCategory($queryBuilder, $attribute, $value); } return $this->applyIsUserFromTeams($queryBuilder, $attribute, $value); } return $this->itemConverter->convert($queryBuilder, $item)->getRaw(); } /** * @param mixed $value * @return array * @throws Error */ private function applyInCategory(QueryBuilder $queryBuilder, string $attribute, $value): array { $link = $attribute; $entityDefs = $this->ormDefs->getEntity($this->entityType); if (!$entityDefs->hasRelation($link)) { throw new Error("Not existing '{$link}' in where item."); } $defs = $entityDefs->getRelation($link); $foreignEntity = $defs->getForeignEntityType(); $pathName = lcfirst($foreignEntity) . 'Path'; $relationType = $defs->getType(); if ($relationType === Entity::MANY_MANY) { $queryBuilder->distinct(); $alias = $link . 'InCategoryFilter'; $queryBuilder->join($link, $alias); $key = $defs->getForeignMidKey(); $middleName = $alias . 'Middle'; $queryBuilder->join( ucfirst($pathName), $pathName, [ "{$pathName}.descendorId:" => "{$middleName}.{$key}", ] ); return [ $pathName . '.ascendorId' => $value, ]; } if ($relationType === Entity::BELONGS_TO) { $key = $defs->getKey(); $queryBuilder->join( ucfirst($pathName), $pathName, [ "{$pathName}.descendorId:" => "{$key}", ] ); return [ $pathName . '.ascendorId' => $value, ]; } throw new Error("Not supported link '{$link}' in where item."); } /** * @param mixed $value * @return array * @throws Error */ private function applyIsUserFromTeams(QueryBuilder $queryBuilder, string $attribute, $value): array { $link = $attribute; if (is_array($value) && count($value) == 1) { $value = $value[0]; } $entityDefs = $this->ormDefs->getEntity($this->entityType); if (!$entityDefs->hasRelation($link)) { throw new Error("Not existing '{$link}' in where item."); } $defs = $entityDefs->getRelation($link); $relationType = $defs->getType(); $entityType = $defs->getForeignEntityType(); if ($entityType !== User::ENTITY_TYPE) { throw new Error("Not supported link '{$link}' in where item."); } if ($relationType === Entity::BELONGS_TO) { $key = $defs->getKey(); $aliasName = $link . 'IsUserFromTeamsFilter' . $this->randomStringGenerator->generate(); $queryBuilder->leftJoin( Team::RELATIONSHIP_TEAM_USER, $aliasName . 'Middle', [ $aliasName . 'Middle.userId:' => $key, $aliasName . 'Middle.deleted' => false, ] ); $queryBuilder->distinct(); return [ $aliasName . 'Middle.teamId' => $value, ]; } throw new Error("Not supported link '{$link}' in where item."); } }