/** * built for hasMany relationships * in cases where the related record itself refers to a parent record, * write a custom query to load the related record including it's parent * * depends on the existance of a primaryKeyValue * * @param Relation|PhalconRelation $relation * @return array */ protected function getHasManyRecords(Relation $relation) { $query = $this->buildRelationQuery($relation); $config = $this->getDI()->get('config'); if (!array_deep_key($config, 'feature_flags.fastHasMany')) { // feature flag is disabled, only looking for one parent record // determine the key to search against $field = $relation->getFields(); if (isset($this->baseRecord[$field])) { $fieldValue = $this->baseRecord[$field]; } else { // fall back to using the primaryKeyValue $fieldValue = $this->primaryKeyValue; } $fieldName = $relation->getReferencedModel() . '.' . $relation->getReferencedFields(); $query->where("{$fieldName} = \"{$fieldValue}\""); } else { // feature flag is enabled, pulling from register instead $foreign_keys = array_unique($this->hasManyRegistry[$relation->getReferencedModel()]); //name space the referenced field otherwise you might get ambigious errors $query->inWhere($relation->getReferencedModel() . '.' . $relation->getReferencedFields(), $foreign_keys); } $result = $query->getQuery()->execute(); return $this->loadRelationRecords($result, $relation); }
/** * help $this->queryBuilder to construct a PHQL object * apply join conditions and return query object * * * @param BuilderInterface $query * @return BuilderInterface */ public function queryJoinHelper(BuilderInterface $query) { $config = $this->getDI()->get('config'); $modelNameSpace = $config['namespaces']['models']; $columns = []; // join all active hasOne and belongTo instead of just the parent hasOne foreach ($this->entity->activeRelations as $relation) { // be sure to skip any relationships that are marked for custom processing $relationOptions = $relation->getOptions(); if (isset($relationOptions) && (array_key_exists('customProcessing', $relationOptions) && $relationOptions['customProcessing'] === true)) { continue; } // refer to alias or model path to prefix each relationship // prefer alias over model path in case of collisions $alias = $relation->getAlias(); $referencedModel = $relation->getReferencedModel(); if (!$alias) { $alias = $referencedModel; } // structure to always join in belongsTo just in case the query filters by a related field $type = $relation->getType(); switch ($type) { case Relation::BELONGS_TO: // process feature flag for belongsTo // attempt to join "simple" in side loaded belongsTo records that do not themselves have parents if (array_deep_key($config, 'feature_flags.fastBelongsTo')) { // create both sides of the join $left = "[{$alias}]." . $relation->getReferencedFields(); $right = $modelNameSpace . $this->model->getModelName() . '.' . $relation->getFields(); // create and alias join $query->leftJoin($referencedModel, "{$left} = {$right}", $alias); $columns[] = "[{$alias}].*"; } break; case Relation::HAS_ONE: // create both sides of the join $left = "[{$alias}]." . $relation->getReferencedFields(); $right = $modelNameSpace . $this->model->getModelName() . '.' . $relation->getFields(); // create and alias join $query->leftJoin($referencedModel, "{$left} = {$right}", $alias); // add all parent AND hasOne joins to the column list $columns[] = "[{$alias}].*"; break; // stop processing these types of joins with the main query. They might return "n" number of related records // case Relation::HAS_MANY_THROUGH: // $alias2 = $alias . '_intermediate'; // $left1 = $modelNameSpace . $this->model->getModelName() . '.' . $relation->getFields(); // $right1 = "[$alias2]." . $relation->getIntermediateFields(); // $query->leftJoin($relation->getIntermediateModel(), "$left1 = $right1", $alias2); // // $left2 = "[$alias2]." . $relation->getIntermediateReferencedFields(); // $right2 = "[$alias]." . $relation->getReferencedFields(); // $query->leftJoin($referencedModel, "$left2 = $right2", $alias); // break; // stop processing these types of joins with the main query. They might return "n" number of related records // case Relation::HAS_MANY_THROUGH: // $alias2 = $alias . '_intermediate'; // $left1 = $modelNameSpace . $this->model->getModelName() . '.' . $relation->getFields(); // $right1 = "[$alias2]." . $relation->getIntermediateFields(); // $query->leftJoin($relation->getIntermediateModel(), "$left1 = $right1", $alias2); // // $left2 = "[$alias2]." . $relation->getIntermediateReferencedFields(); // $right2 = "[$alias]." . $relation->getReferencedFields(); // $query->leftJoin($referencedModel, "$left2 = $right2", $alias); // break; default: $this->di->get('logger')->warning("Relationship was ignored during join: {$this->model->getModelName()}.{$alias}, type #{$type}"); } } $query->columns($columns); return $query; }