Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Relation.php
Строк: 530
<?php

namespace IlluminateDatabaseEloquentRelations;

use 
Closure;
use 
IlluminateContractsDatabaseEloquentBuilder as BuilderContract;
use 
IlluminateDatabaseEloquentBuilder;
use 
IlluminateDatabaseEloquentCollection;
use 
IlluminateDatabaseEloquentModel;
use 
IlluminateDatabaseEloquentModelNotFoundException;
use 
IlluminateDatabaseMultipleRecordsFoundException;
use 
IlluminateDatabaseQueryExpression;
use 
IlluminateSupportTraitsForwardsCalls;
use 
IlluminateSupportTraitsMacroable;

abstract class 
Relation implements BuilderContract
{
    use 
ForwardsCallsMacroable {
        
Macroable::__call as macroCall;
    }

    
/**
     * The Eloquent query builder instance.
     *
     * @var IlluminateDatabaseEloquentBuilder
     */
    
protected $query;

    
/**
     * The parent model instance.
     *
     * @var IlluminateDatabaseEloquentModel
     */
    
protected $parent;

    
/**
     * The related model instance.
     *
     * @var IlluminateDatabaseEloquentModel
     */
    
protected $related;

    
/**
     * Indicates whether the eagerly loaded relation should implicitly return an empty collection.
     *
     * @var bool
     */
    
protected $eagerKeysWereEmpty false;

    
/**
     * Indicates if the relation is adding constraints.
     *
     * @var bool
     */
    
protected static $constraints true;

    
/**
     * An array to map class names to their morph names in the database.
     *
     * @var array
     */
    
public static $morphMap = [];

    
/**
     * Prevents morph relationships without a morph map.
     *
     * @var bool
     */
    
protected static $requireMorphMap false;

    
/**
     * The count of self joins.
     *
     * @var int
     */
    
protected static $selfJoinCount 0;

    
/**
     * Create a new relation instance.
     *
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @param  IlluminateDatabaseEloquentModel  $parent
     * @return void
     */
    
public function __construct(Builder $queryModel $parent)
    {
        
$this->query $query;
        
$this->parent $parent;
        
$this->related $query->getModel();

        
$this->addConstraints();
    }

    
/**
     * Run a callback with constraints disabled on the relation.
     *
     * @param  Closure  $callback
     * @return mixed
     */
    
public static function noConstraints(Closure $callback)
    {
        
$previous = static::$constraints;

        static::
$constraints false;

        
// When resetting the relation where clause, we want to shift the first element
        // off of the bindings, leaving only the constraints that the developers put
        // as "extra" on the relationships, and not original relation constraints.
        
try {
            return 
$callback();
        } finally {
            static::
$constraints $previous;
        }
    }

    
/**
     * Set the base constraints on the relation query.
     *
     * @return void
     */
    
abstract public function addConstraints();

    
/**
     * Set the constraints for an eager load of the relation.
     *
     * @param  array  $models
     * @return void
     */
    
abstract public function addEagerConstraints(array $models);

    
/**
     * Initialize the relation on a set of models.
     *
     * @param  array  $models
     * @param  string  $relation
     * @return array
     */
    
abstract public function initRelation(array $models$relation);

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

    
/**
     * Get the results of the relationship.
     *
     * @return mixed
     */
    
abstract public function getResults();

    
/**
     * Get the relationship for eager loading.
     *
     * @return IlluminateDatabaseEloquentCollection
     */
    
public function getEager()
    {
        return 
$this->eagerKeysWereEmpty
                    
$this->query->getModel()->newCollection()
                    : 
$this->get();
    }

    
/**
     * Execute the query and get the first result if it's the sole matching record.
     *
     * @param  array|string  $columns
     * @return IlluminateDatabaseEloquentModel
     *
     * @throws IlluminateDatabaseEloquentModelNotFoundException<IlluminateDatabaseEloquentModel>
     * @throws IlluminateDatabaseMultipleRecordsFoundException
     */
    
public function sole($columns = ['*'])
    {
        
$result $this->take(2)->get($columns);

        
$count $result->count();

        if (
$count === 0) {
            throw (new 
ModelNotFoundException)->setModel(get_class($this->related));
        }

        if (
$count 1) {
            throw new 
MultipleRecordsFoundException($count);
        }

        return 
$result->first();
    }

    
/**
     * Execute the query as a "select" statement.
     *
     * @param  array  $columns
     * @return IlluminateDatabaseEloquentCollection
     */
    
public function get($columns = ['*'])
    {
        return 
$this->query->get($columns);
    }

    
/**
     * Touch all of the related models for the relationship.
     *
     * @return void
     */
    
public function touch()
    {
        
$model $this->getRelated();

        if (! 
$model::isIgnoringTouch()) {
            
$this->rawUpdate([
                
$model->getUpdatedAtColumn() => $model->freshTimestampString(),
            ]);
        }
    }

    
/**
     * Run a raw update against the base query.
     *
     * @param  array  $attributes
     * @return int
     */
    
public function rawUpdate(array $attributes = [])
    {
        return 
$this->query->withoutGlobalScopes()->update($attributes);
    }

    
/**
     * Add the constraints for a relationship count query.
     *
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @param  IlluminateDatabaseEloquentBuilder  $parentQuery
     * @return IlluminateDatabaseEloquentBuilder
     */
    
public function getRelationExistenceCountQuery(Builder $queryBuilder $parentQuery)
    {
        return 
$this->getRelationExistenceQuery(
            
$query$parentQuery, new Expression('count(*)')
        )->
setBindings([], 'select');
    }

    
/**
     * Add the constraints for an internal relationship existence query.
     *
     * Essentially, these queries compare on column names like whereColumn.
     *
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @param  IlluminateDatabaseEloquentBuilder  $parentQuery
     * @param  array|mixed  $columns
     * @return IlluminateDatabaseEloquentBuilder
     */
    
public function getRelationExistenceQuery(Builder $queryBuilder $parentQuery$columns = ['*'])
    {
        return 
$query->select($columns)->whereColumn(
            
$this->getQualifiedParentKeyName(), '='$this->getExistenceCompareKey()
        );
    }

    
/**
     * Get a relationship join table hash.
     *
     * @param  bool  $incrementJoinCount
     * @return string
     */
    
public function getRelationCountHash($incrementJoinCount true)
    {
        return 
'laravel_reserved_'.($incrementJoinCount ? static::$selfJoinCount++ : static::$selfJoinCount);
    }

    
/**
     * Get all of the primary keys for an array of models.
     *
     * @param  array  $models
     * @param  string|null  $key
     * @return array
     */
    
protected function getKeys(array $models$key null)
    {
        return 
collect($models)->map(function ($value) use ($key) {
            return 
$key $value->getAttribute($key) : $value->getKey();
        })->
values()->unique(nulltrue)->sort()->all();
    }

    
/**
     * Get the query builder that will contain the relationship constraints.
     *
     * @return IlluminateDatabaseEloquentBuilder
     */
    
protected function getRelationQuery()
    {
        return 
$this->query;
    }

    
/**
     * Get the underlying query for the relation.
     *
     * @return IlluminateDatabaseEloquentBuilder
     */
    
public function getQuery()
    {
        return 
$this->query;
    }

    
/**
     * Get the base query builder driving the Eloquent builder.
     *
     * @return IlluminateDatabaseQueryBuilder
     */
    
public function getBaseQuery()
    {
        return 
$this->query->getQuery();
    }

    
/**
     * Get a base query builder instance.
     *
     * @return IlluminateDatabaseQueryBuilder
     */
    
public function toBase()
    {
        return 
$this->query->toBase();
    }

    
/**
     * Get the parent model of the relation.
     *
     * @return IlluminateDatabaseEloquentModel
     */
    
public function getParent()
    {
        return 
$this->parent;
    }

    
/**
     * Get the fully qualified parent key name.
     *
     * @return string
     */
    
public function getQualifiedParentKeyName()
    {
        return 
$this->parent->getQualifiedKeyName();
    }

    
/**
     * Get the related model of the relation.
     *
     * @return IlluminateDatabaseEloquentModel
     */
    
public function getRelated()
    {
        return 
$this->related;
    }

    
/**
     * Get the name of the "created at" column.
     *
     * @return string
     */
    
public function createdAt()
    {
        return 
$this->parent->getCreatedAtColumn();
    }

    
/**
     * Get the name of the "updated at" column.
     *
     * @return string
     */
    
public function updatedAt()
    {
        return 
$this->parent->getUpdatedAtColumn();
    }

    
/**
     * Get the name of the related model's "updated at" column.
     *
     * @return string
     */
    
public function relatedUpdatedAt()
    {
        return 
$this->related->getUpdatedAtColumn();
    }

    
/**
     * Add a whereIn eager constraint for the given set of model keys to be loaded.
     *
     * @param  string  $whereIn
     * @param  string  $key
     * @param  array  $modelKeys
     * @param  IlluminateDatabaseEloquentBuilder  $query
     * @return void
     */
    
protected function whereInEager(string $whereInstring $key, array $modelKeys$query null)
    {
        (
$query ?? $this->query)->{$whereIn}($key$modelKeys);

        if (
$modelKeys === []) {
            
$this->eagerKeysWereEmpty true;
        }
    }

    
/**
     * Get the name of the "where in" method for eager loading.
     *
     * @param  IlluminateDatabaseEloquentModel  $model
     * @param  string  $key
     * @return string
     */
    
protected function whereInMethod(Model $model$key)
    {
        return 
$model->getKeyName() === last(explode('.'$key))
                    && 
in_array($model->getKeyType(), ['int''integer'])
                        ? 
'whereIntegerInRaw'
                        
'whereIn';
    }

    
/**
     * Prevent polymorphic relationships from being used without model mappings.
     *
     * @param  bool  $requireMorphMap
     * @return void
     */
    
public static function requireMorphMap($requireMorphMap true)
    {
        static::
$requireMorphMap $requireMorphMap;
    }

    
/**
     * Determine if polymorphic relationships require explicit model mapping.
     *
     * @return bool
     */
    
public static function requiresMorphMap()
    {
        return static::
$requireMorphMap;
    }

    
/**
     * Define the morph map for polymorphic relations and require all morphed models to be explicitly mapped.
     *
     * @param  array  $map
     * @param  bool  $merge
     * @return array
     */
    
public static function enforceMorphMap(array $map$merge true)
    {
        static::
requireMorphMap();

        return static::
morphMap($map$merge);
    }

    
/**
     * Set or get the morph map for polymorphic relations.
     *
     * @param  array|null  $map
     * @param  bool  $merge
     * @return array
     */
    
public static function morphMap(?array $map null$merge true)
    {
        
$map = static::buildMorphMapFromModels($map);

        if (
is_array($map)) {
            static::
$morphMap $merge && static::$morphMap
                            
$map + static::$morphMap $map;
        }

        return static::
$morphMap;
    }

    
/**
     * Builds a table-keyed array from model class names.
     *
     * @param  string[]|null  $models
     * @return array|null
     */
    
protected static function buildMorphMapFromModels(?array $models null)
    {
        if (
is_null($models) || ! array_is_list($models)) {
            return 
$models;
        }

        return 
array_combine(array_map(function ($model) {
            return (new 
$model)->getTable();
        }, 
$models), $models);
    }

    
/**
     * Get the model associated with a custom polymorphic type.
     *
     * @param  string  $alias
     * @return string|null
     */
    
public static function getMorphedModel($alias)
    {
        return static::
$morphMap[$alias] ?? null;
    }

    
/**
     * Handle dynamic method calls to the relationship.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    
public function __call($method$parameters)
    {
        if (static::
hasMacro($method)) {
            return 
$this->macroCall($method$parameters);
        }

        return 
$this->forwardDecoratedCallTo($this->query$method$parameters);
    }

    
/**
     * Force a clone of the underlying query builder when cloning.
     *
     * @return void
     */
    
public function __clone()
    {
        
$this->query = clone $this->query;
    }
}
Онлайн: 0
Реклама