Вход Регистрация
Файл: system/vendor/illuminate/database/Eloquent/Relations/MorphTo.php
Строк: 295
<?php

namespace IlluminateDatabaseEloquentRelations;

use 
BadMethodCallException;
use 
IlluminateDatabaseEloquentBuilder;
use 
IlluminateDatabaseEloquentCollection;
use 
IlluminateDatabaseEloquentModel;

class 
MorphTo extends BelongsTo
{
    
/**
     * The type of the polymorphic relation.
     *
     * @var string
     */
    
protected $morphType;

    
/**
     * The models whose relations are being eager loaded.
     *
     * @var IlluminateDatabaseEloquentCollection
     */
    
protected $models;

    
/**
     * All of the models keyed by ID.
     *
     * @var array
     */
    
protected $dictionary = [];

    
/**
     * A buffer of dynamic calls to query macros.
     *
     * @var array
     */
    
protected $macroBuffer = [];

    
/**
     * A map of relations to load for each individual morph type.
     *
     * @var array
     */
    
protected $morphableEagerLoads = [];

    
/**
     * Create a new morph to relationship instance.
     *
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @param  IlluminateDatabaseEloquentModel  $parent
     * @param  string  $foreignKey
     * @param  string  $ownerKey
     * @param  string  $type
     * @param  string  $relation
     * @return void
     */
    
public function __construct(Builder $queryModel $parent$foreignKey$ownerKey$type$relation)
    {
        
$this->morphType $type;

        
parent::__construct($query$parent$foreignKey$ownerKey$relation);
    }

    
/**
     * Set the constraints for an eager load of the relation.
     *
     * @param  array  $models
     * @return void
     */
    
public function addEagerConstraints(array $models)
    {
        
$this->buildDictionary($this->models Collection::make($models));
    }

    
/**
     * Build a dictionary with the models.
     *
     * @param  IlluminateDatabaseEloquentCollection  $models
     * @return void
     */
    
protected function buildDictionary(Collection $models)
    {
        foreach (
$models as $model) {
            if (
$model->{$this->morphType}) {
                
$this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model;
            }
        }
    }

    
/**
     * Get the results of the relationship.
     *
     * Called via eager load method of Eloquent query builder.
     *
     * @return mixed
     */
    
public function getEager()
    {
        foreach (
array_keys($this->dictionary) as $type) {
            
$this->matchToMorphParents($type$this->getResultsByType($type));
        }

        return 
$this->models;
    }

    
/**
     * Get all of the relation results for a type.
     *
     * @param  string  $type
     * @return IlluminateDatabaseEloquentCollection
     */
    
protected function getResultsByType($type)
    {
        
$instance $this->createModelByType($type);

        
$ownerKey $this->ownerKey ?? $instance->getKeyName();

        
$query $this->replayMacros($instance->newQuery())
                            ->
mergeConstraintsFrom($this->getQuery())
                            ->
with(array_merge(
                                
$this->getQuery()->getEagerLoads(),
                                (array) (
$this->morphableEagerLoads[get_class($instance)] ?? [])
                            ));

        
$whereIn $this->whereInMethod($instance$ownerKey);

        return 
$query->{$whereIn}(
            
$instance->getTable().'.'.$ownerKey$this->gatherKeysByType($type)
        )->
get();
    }

    
/**
     * Gather all of the foreign keys for a given type.
     *
     * @param  string  $type
     * @return array
     */
    
protected function gatherKeysByType($type)
    {
        return 
array_keys($this->dictionary[$type]);
    }

    
/**
     * Create a new model instance by type.
     *
     * @param  string  $type
     * @return IlluminateDatabaseEloquentModel
     */
    
public function createModelByType($type)
    {
        
$class Model::getActualClassNameForMorph($type);

        return new 
$class;
    }

    
/**
     * Match the eagerly loaded results to their parents.
     *
     * @param  array  $models
     * @param  IlluminateDatabaseEloquentCollection  $results
     * @param  string  $relation
     * @return array
     */
    
public function match(array $modelsCollection $results$relation)
    {
        return 
$models;
    }

    
/**
     * Match the results for a given type to their parents.
     *
     * @param  string  $type
     * @param  IlluminateDatabaseEloquentCollection  $results
     * @return void
     */
    
protected function matchToMorphParents($typeCollection $results)
    {
        foreach (
$results as $result) {
            
$ownerKey = ! is_null($this->ownerKey) ? $result->{$this->ownerKey} : $result->getKey();

            if (isset(
$this->dictionary[$type][$ownerKey])) {
                foreach (
$this->dictionary[$type][$ownerKey] as $model) {
                    
$model->setRelation($this->relationName$result);
                }
            }
        }
    }

    
/**
     * Associate the model instance to the given parent.
     *
     * @param  IlluminateDatabaseEloquentModel  $model
     * @return IlluminateDatabaseEloquentModel
     */
    
public function associate($model)
    {
        
$this->parent->setAttribute(
            
$this->foreignKey$model instanceof Model $model->getKey() : null
        
);

        
$this->parent->setAttribute(
            
$this->morphType$model instanceof Model $model->getMorphClass() : null
        
);

        return 
$this->parent->setRelation($this->relationName$model);
    }

    
/**
     * Dissociate previously associated model from the given parent.
     *
     * @return IlluminateDatabaseEloquentModel
     */
    
public function dissociate()
    {
        
$this->parent->setAttribute($this->foreignKeynull);

        
$this->parent->setAttribute($this->morphTypenull);

        return 
$this->parent->setRelation($this->relationNamenull);
    }

    
/**
     * Touch all of the related models for the relationship.
     *
     * @return void
     */
    
public function touch()
    {
        if (! 
is_null($this->child->{$this->foreignKey})) {
            
parent::touch();
        }
    }

    
/**
     * Make a new related instance for the given model.
     *
     * @param  IlluminateDatabaseEloquentModel  $parent
     * @return IlluminateDatabaseEloquentModel
     */
    
protected function newRelatedInstanceFor(Model $parent)
    {
        return 
$parent->{$this->getRelationName()}()->getRelated()->newInstance();
    }

    
/**
     * Get the foreign key "type" name.
     *
     * @return string
     */
    
public function getMorphType()
    {
        return 
$this->morphType;
    }

    
/**
     * Get the dictionary used by the relationship.
     *
     * @return array
     */
    
public function getDictionary()
    {
        return 
$this->dictionary;
    }

    
/**
     * Specify which relations to load for a given morph type.
     *
     * @param  array  $with
     * @return IlluminateDatabaseEloquentRelationsMorphTo
     */
    
public function morphWith(array $with)
    {
        
$this->morphableEagerLoads array_merge(
            
$this->morphableEagerLoads$with
        
);

        return 
$this;
    }

    
/**
     * Replay stored macro calls on the actual related instance.
     *
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @return IlluminateDatabaseEloquentBuilder
     */
    
protected function replayMacros(Builder $query)
    {
        foreach (
$this->macroBuffer as $macro) {
            
$query->{$macro['method']}(...$macro['parameters']);
        }

        return 
$query;
    }

    
/**
     * Handle dynamic method calls to the relationship.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    
public function __call($method$parameters)
    {
        try {
            
$result parent::__call($method$parameters);

            if (
in_array($method, ['select''selectRaw''selectSub''addSelect''withoutGlobalScopes'])) {
                
$this->macroBuffer[] = compact('method''parameters');
            }

            return 
$result;
        }

        
// If we tried to call a method that does not exist on the parent Builder instance,
        // we'll assume that we want to call a query macro (e.g. withTrashed) that only
        // exists on related models. We will just store the call and replay it later.
        
catch (BadMethodCallException $e) {
            
$this->macroBuffer[] = compact('method''parameters');

            return 
$this;
        }
    }
}
Онлайн: 0
Реклама