/** * Get related objects from the database * * Supports the following signatures: * * - getRelated( object|array $source , string $relationName ) * - getRelated( object|array $source , string $relationName , $query ) * - getRelated( object|array $source , string $relationName , Meta $meta ) * - getRelated( object|array $source , string $relationName , $query, Meta $meta ) * * @return object[] */ public function getRelated($source, $relationName, $query = null, $meta = null) { if (!$source) { return; } $sourceIsArray = false; $test = $source; if (is_array($test) || $test instanceof \Traversable) { $sourceIsArray = true; $test = $test[0]; } if (!$meta) { if ($query instanceof Meta) { list($meta, $query) = [$query, null]; } else { $meta = $this->mapper->getMeta(get_class($test)); } } else { $meta = $meta instanceof Meta ? $meta : $this->mapper->getMeta($meta); } if (!isset($meta->relations[$relationName])) { throw new Exception("Unknown relation {$relationName} on {$meta->class}"); } $relation = $meta->relations[$relationName]; $relator = $this->getRelator($relation); if ($query) { // need to support both Query\Criteria and Query\Select // this is a cheeky hack - the API doesn't declare support for // Select in Relators because it carries promises of things like // 'fields' and whatnot that we'll never be able to satisfy. // That whole hierarchy needs to be cleaned // up into a bunch of traits so we can have RelatorCriteria or something. $query = $query instanceof Query\Criteria ? $query : Query\Select::fromParamArgs([$query]); $stack = $query->stack; } else { $stack = []; } $stack[$meta->class] = true; if ($sourceIsArray) { return $relator->getRelatedForList($meta, $source, $relation, $query ?: null, $stack); } else { return $relator->getRelated($meta, $source, $relation, $query ?: null, $stack); } }