/** * Get's the unique identifiers required for the matching filters and loads the data into * the cache for performance reasons. * * @param Collection $list * @param int $unfetchedRowCount * @param array $relationshipNavigationPropertiesToAutoHydrate * @return array */ public function getUniqueIdentifiersForDataList(Collection $list, &$unfetchedRowCount = 0, $relationshipNavigationPropertiesToAutoHydrate = []) { $this->lastSortsUsed = []; $schema = $this->schema; $table = $schema->schemaName; $whereClause = ""; $filter = $list->getFilter(); $namedParams = []; $propertiesToAutoHydrate = $relationshipNavigationPropertiesToAutoHydrate; $filteredExclusivelyByRepository = true; if ($filter !== null) { $filterSql = $filter->filterWithRepository($this, $namedParams, $propertiesToAutoHydrate); if ($filterSql != "") { $whereClause .= " WHERE " . $filterSql; } $filteredExclusivelyByRepository = $filter->wasFilteredByRepository(); } $relationships = SolutionSchema::getAllRelationshipsForModel($this->getModelClass()); $aggregateColumnClause = ""; $aggregateColumnClauses = []; $aggregateColumnAliases = []; $aggregateRelationshipPropertiesToAutoHydrate = []; foreach ($list->getAggregates() as $aggregate) { $clause = $aggregate->aggregateWithRepository($this, $aggregateRelationshipPropertiesToAutoHydrate); if ($clause != "") { $aggregateColumnClauses[] = $clause; $aggregateColumnAliases[] = $aggregate->getAlias(); } } if (sizeof($aggregateColumnClauses) > 0) { $aggregateColumnClause = ", " . implode(", ", $aggregateColumnClauses); } $aggregateRelationshipPropertiesToAutoHydrate = array_unique($aggregateRelationshipPropertiesToAutoHydrate); $joins = []; $groups = []; foreach ($aggregateRelationshipPropertiesToAutoHydrate as $joinRelationship) { /** * @var OneToMany $relationship */ $relationship = $relationships[$joinRelationship]; $targetModelName = $relationship->getTargetModelName(); $targetModelClass = SolutionSchema::getModelClass($targetModelName); /** * @var Model $targetModel */ $targetModel = new $targetModelClass(); $targetSchema = $targetModel->getSchema(); $joins[] = "LEFT JOIN `{$targetSchema->schemaName}` AS `{$joinRelationship}` ON `{$this->schema->schemaName}`.`" . $relationship->getSourceColumnName() . "` = `{$joinRelationship}`.`" . $relationship->getTargetColumnName() . "`"; $groups[] = "`{$table}`.`" . $relationship->getSourceColumnName() . '`'; } $joinColumns = []; $joinOriginalToAliasLookup = []; $joinColumnsByModel = []; $sorts = $list->getSorts(); $possibleSorts = []; $columns = $schema->getColumns(); foreach ($sorts as $columnName => $ascending) { if (!isset($columns[$columnName])) { // If this is a one to one relationship we can still sort by using auto hydration. $parts = explode(".", $columnName); $relationshipProperty = $parts[0]; $escapedColumnName = '`' . implode('`.`', $parts) . '`'; if (isset($relationships[$relationshipProperty]) && $relationships[$relationshipProperty] instanceof OneToOne) { $propertiesToAutoHydrate[] = $relationshipProperty; $possibleSorts[] = $escapedColumnName . " " . ($ascending ? "ASC" : "DESC"); $this->lastSortsUsed[] = $columnName; } else { // If the request sorts contain any that we can't sort by we must only sort by those // after this column. $possibleSorts = []; $this->lastSortsUsed = []; } } else { $possibleSorts[] = '`' . str_replace('.', '`.`', $columnName) . "` " . ($ascending ? "ASC" : "DESC"); $this->lastSortsUsed[] = $columnName; } } $propertiesToAutoHydrate = array_unique($propertiesToAutoHydrate); foreach ($propertiesToAutoHydrate as $joinRelationship) { /** * @var OneToMany $relationship */ $relationship = $relationships[$joinRelationship]; $targetModelName = $relationship->getTargetModelName(); $targetModelClass = SolutionSchema::getModelClass($targetModelName); /** * @var Model $targetModel */ $targetModel = new $targetModelClass(); $targetSchema = $targetModel->getSchema(); $columns = $targetSchema->getColumns(); foreach ($columns as $columnName => $column) { $joinColumns[$targetModelName . $columnName] = "`{$joinRelationship}`.`{$columnName}`"; $joinOriginalToAliasLookup[$targetModelName . "." . $columnName] = $targetModelName . $columnName; if (!isset($joinColumnsByModel[$targetModelName])) { $joinColumnsByModel[$targetModelName] = []; } $joinColumnsByModel[$targetModelName][$targetModelName . $columnName] = $columnName; } $joins[] = "LEFT JOIN `{$targetSchema->schemaName}` AS `{$joinRelationship}` ON `{$this->schema->schemaName}`.`" . $relationship->getSourceColumnName() . "` = `{$joinRelationship}`.`" . $relationship->getTargetColumnName() . "`"; } $joinString = ""; $joinColumnClause = ""; if (sizeof($joins)) { $joinString = " " . implode(" ", $joins); $joinClauses = []; foreach ($joinColumns as $aliasName => $columnName) { $joinClauses[] = "{$columnName} AS `{$aliasName}`"; } if (sizeof($joinClauses)) { $joinColumnClause = ", " . implode(", ", $joinClauses); } } $groupClause = ""; if (sizeof($groups)) { $groupClause = " GROUP BY " . implode(", ", $groups); } $orderBy = ""; if (sizeof($possibleSorts)) { $orderBy .= " ORDER BY " . implode(", ", $possibleSorts); } $sql = "SELECT `{$table}`.*{$joinColumnClause}{$aggregateColumnClause} FROM `{$table}`" . $joinString . $whereClause . $groupClause . $orderBy; $ranged = false; if ($filteredExclusivelyByRepository && sizeof($possibleSorts) == sizeof($sorts)) { $range = $list->getRange(); if ($range != false) { $ranged = true; $sql .= " LIMIT " . $range[0] . ", " . $range[1]; $sql = preg_replace("/^SELECT /", "SELECT SQL_CALC_FOUND_ROWS ", $sql); } } $statement = self::executeStatement($sql, $namedParams); $results = $statement->fetchAll(\PDO::FETCH_ASSOC); $uniqueIdentifiers = []; if (sizeof($joinColumns)) { foreach ($joinColumnsByModel as $joinModel => $modelJoinedColumns) { $model = SolutionSchema::getModel($joinModel); $repository = $model->getRepository(); foreach ($results as &$result) { $aliasedUniqueIdentifierColumnName = $joinOriginalToAliasLookup[$joinModel . "." . $model->UniqueIdentifierColumnName]; if (isset($result[$aliasedUniqueIdentifierColumnName]) && !isset($repository->cachedObjectData[$result[$aliasedUniqueIdentifierColumnName]])) { $joinedData = array_intersect_key($result, $modelJoinedColumns); $modelData = array_combine($modelJoinedColumns, $joinedData); $repository->cachedObjectData[$modelData[$model->UniqueIdentifierColumnName]] = $modelData; } $result = array_diff_key($result, $modelJoinedColumns); } unset($result); } } foreach ($results as $result) { $uniqueIdentifier = $result[$schema->uniqueIdentifierColumnName]; $result = $this->transformDataFromRepository($result); // Store the data in the cache and add the unique identifier to our list. $this->cachedObjectData[$uniqueIdentifier] = $result; $uniqueIdentifiers[] = $uniqueIdentifier; } if ($ranged) { $foundRows = Mysql::returnSingleValue("SELECT FOUND_ROWS()"); $unfetchedRowCount = $foundRows - sizeof($uniqueIdentifiers); } return $uniqueIdentifiers; }