throughClass; } /** * Set the join table name or junction model class * * @param string $through * * @return $this */ public function through($through) { $this->throughClass = $through; return $this; } /** * Get the junction model * * @return Model|Junction */ public function getThrough() { if ($this->through === null) { $throughClass = $this->getThroughClass(); if (class_exists($throughClass)) { $this->through = new $throughClass(); } else { $this->through = (new Junction()) ->setTableName($throughClass); } } return $this->through; } /** * Set the junction model * * @param Model $through * * @return $this */ public function setThrough($through) { $this->through = $through; return $this; } /** * Get the column name(s) of the target model's foreign key found in the join table * * @return string|array Array if the foreign key is compound, string otherwise */ public function getTargetForeignKey() { return $this->targetForeignKey; } /** * Set the column name(s) of the target model's foreign key found in the join table * * @param string|array $targetForeignKey Array if the foreign key is compound, string otherwise * * @return $this */ public function setTargetForeignKey($targetForeignKey) { $this->targetForeignKey = $targetForeignKey; return $this; } /** * Get the candidate key column name(s) in the target table which references the target foreign key * * @return string|array Array if the foreign key is compound, string otherwise */ public function getTargetCandidateKey() { return $this->targetCandidateKey; } /** * Set the candidate key column name(s) in the target table which references the target foreign key * * @param string|array $targetCandidateKey Array if the foreign key is compound, string otherwise * * @return $this */ public function setTargetCandidateKey($targetCandidateKey) { $this->targetCandidateKey = $targetCandidateKey; return $this; } public function resolve() { $source = $this->getSource(); $possibleCandidateKey = [$this->getCandidateKey()]; $possibleForeignKey = [$this->getForeignKey()]; $target = $this->getTarget(); $possibleTargetCandidateKey = [$this->getTargetForeignKey() ?: static::getDefaultForeignKey($target)]; $possibleTargetForeignKey = [$this->getTargetCandidateKey() ?: static::getDefaultCandidateKey($target)]; $junction = $this->getThrough(); if (! $junction instanceof Junction) { $relations = new Relations(); $junction->createRelations($relations); if ($relations->has($source->getTableName())) { $sourceRelation = $relations->get($source->getTableName()); $possibleCandidateKey[] = $sourceRelation->getForeignKey(); $possibleForeignKey[] = $sourceRelation->getCandidateKey(); } if ($relations->has($target->getTableName())) { $targetRelation = $relations->get($target->getTableName()); $possibleTargetCandidateKey[] = $targetRelation->getCandidateKey(); $possibleTargetForeignKey[] = $targetRelation->getForeignKey(); } } $toJunction = (new HasMany()) ->setName($junction->getTableName()) ->setSource($source) ->setTarget($junction) ->setCandidateKey($this->extractKey($possibleCandidateKey)) ->setForeignKey($this->extractKey($possibleForeignKey)); $toTarget = (new HasMany()) ->setName($this->getName()) ->setSource($junction) ->setTarget($target) ->setCandidateKey($this->extractKey($possibleTargetCandidateKey)) ->setForeignKey($this->extractKey($possibleTargetForeignKey)); foreach ($toJunction->resolve() as $k => $v) { yield $k => $v; } foreach ($toTarget->resolve() as $k => $v) { yield $k => $v; } } protected function extractKey(array $possibleKey) { $filtered = array_filter($possibleKey); return array_pop($filtered); } }