Filters by a relationship that isn't joined by using that relation's ModelFilter.

@param $related
438710
public function filterUnjoinedRelation($related)
    {
        $this->query->whereHas($related, function ($q) use ($related) {
            $this->callRelatedLocalSetup($related, $q);

            // If we defined it locally then we're running the closure on the related model here right.
            foreach ($this->getLocalRelation($related) as $closure) {
                // Run in context of the related model locally
                $closure($q);
            }

            if (count($filterableRelated = $this->getRelatedFilterInput($related)) > 0) {
                $q->filter($filterableRelated);
            }

            return $q;
        });
    }
473552
public function hasMany($related, $parentKey = null, $localKey = null)
    {
        $parentKey = $parentKey ?: $this->getParentKey();
        $localKey = $localKey ?: $this->getKeyName();

        $instance = new $related;

        return new Relations\Relation($instance, $this, $parentKey, $localKey);
    }
1294008
private function stripRelationPrefix(array $records, $prefix)
    {
        //Strip the relation prefix from the columns
        foreach ($records as $record) {
            yield Utils::filterPrefixedElements(
                $record,
                $prefix,
                Utils::FILTER_REMOVE_PREFIX | Utils::FILTER_USE_KEYS
            );
        }
    }
1254938
public function ownedBy(Model $related = null, ?string $key = null): bool
    {
        if (\is_null($related)) {
            return false;
        }

        if (\is_null($key)) {
            $key = $related->getForeignKey();
        }

        return $this->getAttribute($key) == $related->getKey();
    }
129259
protected function filterChains()
    {
        foreach ($this->chains as $key => $chain) {
            $filterResult = $this->getFilterResult($key, $chain);
            if ($filterResult->isNotEmpty()) {
                $this->data->set(
                    $key,
                    $filterResult->getFilteredValue()
                );
            } else {
                $this->data->remove($key);
            }
        }
    }
308601
private function isRelationship($model, $conditions)
    {
        /**
         * A valid relationship must:
         * - Be a method
         * - Not appear in the 'except' list
         * - Appear in the 'only' list (if used)
         * - Extend Illuminate\Database\Eloquent\Relations\Relation
         */
        return (
            method_exists($this, $model) &&
            $this->filterRelationshipByConditions($model, $conditions) &&
            is_subclass_of($this->{Str::camel($model)}(), 'Illuminate\Database\Eloquent\Relations\Relation')
        );
    }
298055
public function including($includes)
	{
		if($includes === false)
		{
			$this->model->setIncludes([]);
		}
		else
		{
			$includes = (array) $includes;

			$currentIncludes = $this->model->getIncludes();

			if(!empty($currentIncludes))
			{
				$withCriterion = array_filter(array_keys($includes), 'is_string');

				if(!empty($withCriterion))
				{
					foreach($currentIncludes as $key => $value)
					{
						if(in_array($value, $withCriterion))
						{
							unset($currentIncludes[$key]); // Unset relations that have previously been set without a criterion closure
						}
					}
				}

				$includes = array_merge($currentIncludes, $includes);
			}

			$this->model->setIncludes(array_unique($includes, SORT_REGULAR));
		}

		return $this;
	}
274466
public function belongsTo(Model $relatedModel, $foreignKey)
    {
        if ($relatedModel->isIgnored()) {
            return;
        }

        $this->relations->add(
            new Relations\BelongsTo($this, $relatedModel, $foreignKey)
        );
    }
95595
public function ini($related, $model, $local = null, $remote = null)
    {
        $this->checkModels($related, $model);
        //
        $relationVal = $this->relationValue($related, $model, $local);
        $relationColumn = $this->relationColumn($related, $model, $remote);
        //
        $mod = $this->first($related, $relationColumn, $relationVal);
        //
        return $this->prepare($mod, $related);
    }
491069
protected function filterRelation($key, $value)
    {
        $key = str_replace('~', '.', $key);
        $parts = explode('.', $key);

        $realKey = array_pop($parts);
        $relation = implode('.', $parts);

        if (! in_array($relation, array_keys($this->with))) {
            return;
        }

        extract($this->formatParam($realKey, $value));

        if (! $this->canFilter($column)) {
            return;
        }

        $this->builder->whereHas($relation, function ($q) use ($column, $comparator, $value) {
            if ($comparator == 'IN') {
                $values = explode(',', $value);
                $q->whereIn($column, $values);
            } elseif ($comparator == 'NOT IN') {
                $values = explode(',', $value);
                $q->whereNotIn($column, $values);
            } else {
                $values = explode('|', $value);
                if (count($values) > 1) {
                    $q->where(function ($query) use ($column, $comparator, $values) {
                        foreach ($values as $value) {
                            if ($comparator == 'LIKE' || $comparator == 'NOT LIKE') {
                                $value = preg_replace('/(^\*|\*$)/', '%', $value);
                            }
                            // Link the filters with AND of there is a "not" and with OR if there's none
                            if ($comparator == '!=' || $comparator == 'NOT LIKE') {
                                $query->where($column, $comparator, $value);
                            } else {
                                $query->orWhere($column, $comparator, $value);
                            }
                        }
                    });
                } else {
                    $value = $values[0];
                    if ($comparator == 'LIKE' || $comparator == 'NOT LIKE') {
                        $value = preg_replace('/(^\*|\*$)/', '%', $value);
                    }
                    if ($comparator == 'NULL' || $comparator == 'NOT NULL') {
                        $q->whereNull($column, 'and', $comparator == 'NOT NULL');
                    } else {
                        $q->where($column, $comparator, $value);
                    }
                }
            }
        });
    }
341681
public function hasOne($related, $foreignKey = null, $localKey = null)
    {
        $args = func_get_args();
        $args['type'] = 'hasOne';
        return $this->setRelationship(json_encode($args));
    }
798035
protected function detachRelatedModelsForOneOrMany($models, Relation $relation)
    {
        if ($models instanceof Model) {
            $models = new Collection([ $models ]);
        }

        if ( ! $this->allowDetachingOfOneOrMany() || ! count($models)) {
            return;
        }

        // If models that were previously attached but no longer should be
        // have nullable foreign keys, we can 'detach' them safely by dissociating
        // the reverse relation (if we know which relation that is, or nullifying the keys).

        // Get the foreign key(s) (id/type for morph, otherwise just the id)
        $foreignKeyNames = $this->getForeignKeyNamesForRelation($relation);

        $nullableKey = $this->explicitlyConfiguredForeignKeysNullable();
        if (null === $nullableKey) {
            $nullableKey = $this->hasNullableForeignKeys($relation, $models->first(), $foreignKeyNames);
        }

        if ($nullableKey) {
            // We can detach the models by setting their keys to null.
            foreach ($models as $model) {
                $this->setForeignKeysToNull($model, $relation, $foreignKeyNames);
            }

            return;
        }

        // If the related models do not have nullable keys, we cannot detach them
        // without deleting them. This must be explicitly configured to prevent accidental deletions.
        if ( ! $this->allowDeletionOfDetachedModels()) return;

        // We can delete the previously related models entirely
        foreach ($models as $model) {
            $model->delete();

            // todo: log?
        }
    }
261243
protected function joinRelation(Relation $relationClass)
    {
        switch (get_class($relationClass)) {
            case BelongsToMany::class:
                /* @var BelongsToMany $relationClass */
                $this->joinBelongsToMany($relationClass);
                break;
            case BelongsTo::class:
                /* @var BelongsTo $relationClass */
                $this->joinBelongsTo($relationClass);
                break;
            case HasOne::class:
            case HasMany::class:
                /* @var HasOneOrMany $relationClass */
                $this->joinHasOneOrMany($relationClass);
                break;
        }
    }
167001
public function belongsToMany($related, $table = null, $foreignKey = null, $relatedKey = null, $relation = null)
    {
        // If no relationship name was passed, we will pull backtraces to get the
        // name of the calling function. We will use that function name as the
        // title of this relation since that is a great convention to apply.
        if (is_null($relation)) {
            $relation = $this->guessBelongsToManyRelation();
        }

        // First, we'll need to determine the foreign key and "other key" for the
        // relationship. Once we have determined the keys we'll make the query
        // instances as well as the relationship instances we need for this.
        $instance = $this->newRelatedInstance($related);

        $foreignKey = $foreignKey ?: $this->getForeignKey();

        $relatedKey = $relatedKey ?: $instance->getForeignKey();

        // If no table name was provided, we can guess it by concatenating the two
        // models using underscores in alphabetical order. The two model names
        // are transformed to snake case from their default CamelCase also.
        if (is_null($table)) {
            $table = $this->joiningTable($related);
        }

        return new BelongsToMany(
            $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation
        );
    }
1132619
public function setRelation($name, $related_object)
    {
        //if no related object is supplied, set it to false (an array
        //value of null will not pass an isset() check on the
        //relation_objects array).
        if (!$related_object) {
            $related_object = false;
        }

        $this->relation_objects[$name] = $related_object;
    }
750903
public function filterModelsByIndex($indexes)
    {
        $this->filteredIndexes = array_merge($this->filteredIndexes, $indexes);
        $this->filteredIndexCount = count($this->filteredIndexes);
    }
1091179
public static function related_class($relation)
	{
		$class = get_called_class();

		foreach (static::$_valid_relations as $rel_name => $rel_class)
		{
			if (property_exists($class, '_'.$rel_name))
			{
				if (isset(static::${'_'.$rel_name}[$relation]))
				{
					return static::${'_'.$rel_name}[$relation]['model_to'];
				}
			}
		}

		return null;
	}