protected static function canAggregateInMySql(Repository $repository, $columnName, &$relationshipsToAutoHydrate)
 {
     $schema = $repository->getSchema();
     $columns = $schema->getColumns();
     if (isset($columns[$columnName])) {
         return true;
     }
     if (strpos($columnName, ".") !== false) {
         // If the column name contains a dot, the part before the dot is the name of a relationship to another model
         list($relationship, $columnName) = explode(".", $columnName, 2);
         $relationships = SolutionSchema::getAllRelationshipsForModel($repository->getModelClass());
         // Check for the name being that of a relationship
         if (isset($relationships[$relationship]) && $relationships[$relationship] instanceof OneToMany) {
             $targetModelName = $relationships[$relationship]->getTargetModelName();
             $targetSchema = SolutionSchema::getModelSchema($targetModelName);
             $targetColumns = $targetSchema->getColumns();
             // Check for the column name in the schema of the related model
             if (isset($targetColumns[$columnName])) {
                 $relationshipsToAutoHydrate[] = $relationship;
                 return true;
             }
         }
     }
     return false;
 }
 protected static function doFilterWithRepository(Repository $repository, Filter $originalFilter, &$params, &$relationshipsToAutoHydrate)
 {
     $relationshipsToAutoHydrate[] = $originalFilter->collectionProperty;
     // Get the relationship
     $relationships = SolutionSchema::getAllRelationshipsForModel($repository->getModelClass());
     /**
      * @var OneToMany $relationship
      */
     $relationship = $relationships[$originalFilter->collectionProperty];
     $columnName = $relationship->getNavigationPropertyName() . "`.`" . $originalFilter->columnName;
     $paramName = uniqid() . str_replace("`.`", "", $columnName);
     $params[$paramName] = $originalFilter->equalTo;
     $originalFilter->filteredByRepository = true;
     return "`{$columnName}` = :{$paramName}";
 }
 public function setFilterValuesOnModel(Model $model)
 {
     // Create a row in the intermediate collection so that if the filter was ran again the model
     // would now qualify.
     $relationships = SolutionSchema::getAllRelationshipsForModel("\\" . get_class($model));
     /**
      * @var OneToMany $relationship
      */
     $relationship = $relationships[$this->collectionProperty];
     $modelName = $relationship->getTargetModelName();
     $newModel = SolutionSchema::getModel($modelName);
     $newModel[$model->UniqueIdentifierColumnName] = $model->UniqueIdentifier;
     $newModel[$this->columnName] = $this->equalTo;
     $newModel->save();
     return $newModel;
 }
예제 #4
0
 /**
  * Determines if $columnName could be filtered with the MySql repository.
  *
  * If $columnName contains a dot (.) then we will check to see if we can auto hydrate the navigation
  * property.
  *
  * Note $propertiesToAutoHydrate is passed by reference as this how the filtering stack is able to
  * communication back to the repository which properties require auto hydration (if supported).
  *
  * @param Repository $repository
  * @param $columnName
  * @param $propertiesToAutoHydrate
  * @return bool True if the MySql Repository can add this filter to it's where clause.
  */
 protected static function canFilter(Repository $repository, $columnName, &$propertiesToAutoHydrate)
 {
     $schema = $repository->getSchema();
     $columns = $schema->getColumns();
     if (!isset($columns[$columnName])) {
         if (stripos($columnName, ".") !== false) {
             $parts = explode(".", $columnName);
             if (sizeof($parts) == 2) {
                 $relationship = $parts[0];
                 $relationships = SolutionSchema::getAllRelationshipsForModel($repository->getModelClass());
                 if (isset($relationships[$relationship]) && $relationships[$relationship] instanceof OneToOne) {
                     // This is a foreign field and as the __isset() returned true there must be a relationship for this
                     $propertiesToAutoHydrate[] = $relationship;
                 }
             } else {
                 return false;
             }
         } else {
             return false;
         }
     }
     return true;
 }
예제 #5
0
 /**
  * Computes the given aggregates and returns an array of answers
  *
  * An answer will be null if the repository is unable to answer it.
  *
  * @param \Rhubarb\Stem\Aggregates\Aggregate[] $aggregates
  * @param \Rhubarb\Stem\Collections\Collection $collection
  *
  * @return array
  */
 public function calculateAggregates($aggregates, Collection $collection)
 {
     $propertiesToAutoHydrate = [];
     if (!$this->canFilterExclusivelyByRepository($collection, $namedParams, $propertiesToAutoHydrate)) {
         return null;
     }
     $relationships = SolutionSchema::getAllRelationshipsForModel($this->getModelClass());
     $propertiesToAutoHydrate = array_unique($propertiesToAutoHydrate);
     $joins = [];
     $joinColumns = [];
     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 = "";
     if (sizeof($joins)) {
         $joinString = " " . implode(" ", $joins);
         $joinClauses = [];
         foreach ($joinColumns as $aliasName => $columnName) {
             $joinClauses[] = "`" . str_replace('.', '`.`', $columnName) . "` AS `" . $aliasName . "`";
         }
     }
     $clauses = [];
     $clausePositions = [];
     $results = [];
     $i = -1;
     $c = -1;
     $relationships = [];
     foreach ($aggregates as $aggregate) {
         $i++;
         $clause = $aggregate->aggregateWithRepository($this, $relationships);
         if ($clause != "") {
             $c++;
             $clauses[] = str_replace('.', '`.`', $clause);
             $clausePositions[$c] = $i;
         } else {
             $results[$i] = null;
         }
     }
     if (sizeof($clauses)) {
         $schema = $this->getSchema();
         $namedParams = [];
         $propertiesToAutoHydrate = [];
         $groupClause = "";
         if ($joinString) {
             $groupClause = " GROUP BY `{$schema->schemaName}`.`{$schema->uniqueIdentifierColumnName}`";
         }
         $sql = "SELECT " . implode(", ", $clauses) . " FROM `{$schema->schemaName}`" . $joinString;
         $filter = $collection->getFilter();
         if ($filter !== null) {
             $filterSql = $filter->filterWithRepository($this, $namedParams, $propertiesToAutoHydrate);
             if ($filterSql != "") {
                 $sql .= " WHERE " . $filterSql;
             }
         }
         $sql .= $groupClause;
         $row = array_values(self::returnFirstRow($sql, $namedParams));
         foreach ($clausePositions as $rowPosition => $resultPosition) {
             $results[$resultPosition] = $row[$rowPosition];
         }
     }
     return $results;
 }
예제 #6
0
 public function __isset($propertyName)
 {
     if (parent::__isset($propertyName)) {
         return true;
     }
     $schema = $this->getSchema();
     $columns = $schema->getColumns();
     // Check for schema columns
     if (isset($columns[$propertyName])) {
         return true;
     }
     // Check for dot operator
     if (strpos($propertyName, ".") !== false) {
         $parts = explode(".", $propertyName);
         $firstStep = $this[$parts[0]];
         if ($firstStep === null || !$firstStep instanceof Model) {
             // If the next item in the chain is not model object we can't ask it to
             // set it's value.
             return false;
         }
         if (isset($firstStep[$parts[1]])) {
             return true;
         }
     }
     // Check for relationships
     $className = get_class($this);
     if (!isset(self::$relationships[$className])) {
         self::$relationships[$className] = SolutionSchema::getAllRelationshipsForModel($this->modelName);
     }
     if (isset(self::$relationships[$className][$propertyName])) {
         return true;
     }
     return false;
 }
예제 #7
0
 public function addAggregateColumn(Aggregate $aggregate)
 {
     $columnName = $aggregate->getAggregateColumnName();
     if (strpos($columnName, ".") === false) {
         throw new AggregateNotSupportedException("Sorry, addAggregateColumn requires that the aggregate operate on a one-to-many relationship property");
     }
     $parts = explode(".", $columnName);
     $relationship = $parts[0];
     // Aggregate Columns must be added on properties that are one to many relationships as we need
     // to put group bys into the query.
     $relationships = SolutionSchema::getAllRelationshipsForModel($this->getModelClassName());
     if (!isset($relationships[$relationship])) {
         throw new AggregateNotSupportedException("Sorry, addAggregateColumn requires that the aggregate operate on a one-to-many relationship property");
     }
     if (!$relationships[$relationship] instanceof OneToMany) {
         throw new AggregateNotSupportedException("Sorry, addAggregateColumn requires that the aggregate operate on a one-to-many relationship property");
     }
     $this->aggregates[] = $aggregate;
     return $this;
 }