bztang-admin/app/framework/Database/Eloquent/Builder.php

104 lines
3.9 KiB
PHP

<?php
/**
* Created by PhpStorm.
* User: shenyang
* Date: 2018/9/20
* Time: 上午9:19
*/
namespace app\framework\Database\Eloquent;
use app\framework\Pagination\LengthAwarePaginator;
use BadMethodCallException;
use Illuminate\Database\Eloquent\RelationNotFoundException;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Pagination\Paginator;
class Builder extends \Illuminate\Database\Eloquent\Builder
{
public function expansionEagerLoadRelations(array $models)
{
foreach ($this->eagerLoad as $name => $constraints) {
// For nested eager loads we'll skip loading them here and they will be set as an
// eager load on the query to retrieve the relation so that they will be eager
// loaded on that query, because that is where they get hydrated as models.
if (strpos($name, '.') === false) {
$models = $this->expansionLoadRelation($models, $name, $constraints);
}
}
return $models;
}
/**
* @param array $models
* @param string $name
* @param \Closure $constraints
* @return array
*/
protected function expansionLoadRelation(array $models, $name, \Closure $constraints)
{
// First we will "back up" the existing where conditions on the query so we can
// add our eager constraints. Then we will merge the wheres that were on the
// query back to it in order that any where conditions might be specified.
$relation = $this->expansionGetRelation($name);
$relation->addEagerConstraints($models);
$constraints($relation);
$models = $relation->initRelation($models, $name);
// Once we have the results, we just match those back up to their parent models
// using the relationship instance. Then we just return the finished arrays
// of models which have been eagerly hydrated and are readied for return.
$results = $relation->expansionGet();
return $relation->match($models, $results, $name);
}
public function expansionGetRelation($name){
// We want to run a relationship query without any constrains so that we will
// not have to remove these where clauses manually which gets really hacky
// and is error prone while we remove the developer's own where clauses.
$relation = Relation::noConstraints(function () use ($name) {
try {
if(method_exists($this->getModel(),$name)){
$model = $this->getModel()->$name();
}else{
$model = $this->getModel()->expansionMethod($name,get_class($this->getModel()));
}
return $model;
} catch (BadMethodCallException $e) {
throw RelationNotFoundException::make($this->getModel(), $name);
}
});
// $nested = $this->nestedRelations($name);
$nested = $this->relationsNestedUnder($name);
// If there are nested relationships set on the query, we will put those onto
// the query instances so that they can be handled after this relationship
// is loaded. In this way they will all trickle down as they are loaded.
if (count($nested) > 0) {
$relation->getQuery()->with($nested);
}
return $relation;
}
public function expansionGet($columns = ['*'])
{
$builder = $this->applyScopes();
$models = $builder->getModels($columns);
// If we actually found models we will also eager load any relationships that
// have been specified as needing to be eager loaded, which will solve the
// n+1 query issue for the developers to avoid running a lot of queries.
if (count($models) > 0) {
$models = $builder->expansionEagerLoadRelations($models);
}
return $builder->getModel()->newCollection($models);
}
}