Builder.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: shenyang
  5. * Date: 2018/9/20
  6. * Time: 上午9:19
  7. */
  8. namespace app\framework\Database\Eloquent;
  9. use app\framework\Pagination\LengthAwarePaginator;
  10. use BadMethodCallException;
  11. use Illuminate\Database\Eloquent\RelationNotFoundException;
  12. use Illuminate\Database\Eloquent\Relations\Relation;
  13. use Illuminate\Pagination\Paginator;
  14. class Builder extends \Illuminate\Database\Eloquent\Builder
  15. {
  16. public function expansionEagerLoadRelations(array $models)
  17. {
  18. foreach ($this->eagerLoad as $name => $constraints) {
  19. // For nested eager loads we'll skip loading them here and they will be set as an
  20. // eager load on the query to retrieve the relation so that they will be eager
  21. // loaded on that query, because that is where they get hydrated as models.
  22. if (strpos($name, '.') === false) {
  23. $models = $this->expansionLoadRelation($models, $name, $constraints);
  24. }
  25. }
  26. return $models;
  27. }
  28. /**
  29. * @param array $models
  30. * @param string $name
  31. * @param \Closure $constraints
  32. * @return array
  33. */
  34. protected function expansionLoadRelation(array $models, $name, \Closure $constraints)
  35. {
  36. // First we will "back up" the existing where conditions on the query so we can
  37. // add our eager constraints. Then we will merge the wheres that were on the
  38. // query back to it in order that any where conditions might be specified.
  39. $relation = $this->expansionGetRelation($name);
  40. $relation->addEagerConstraints($models);
  41. $constraints($relation);
  42. $models = $relation->initRelation($models, $name);
  43. // Once we have the results, we just match those back up to their parent models
  44. // using the relationship instance. Then we just return the finished arrays
  45. // of models which have been eagerly hydrated and are readied for return.
  46. $results = $relation->expansionGet();
  47. return $relation->match($models, $results, $name);
  48. }
  49. public function expansionGetRelation($name){
  50. // We want to run a relationship query without any constrains so that we will
  51. // not have to remove these where clauses manually which gets really hacky
  52. // and is error prone while we remove the developer's own where clauses.
  53. $relation = Relation::noConstraints(function () use ($name) {
  54. try {
  55. if(method_exists($this->getModel(),$name)){
  56. $model = $this->getModel()->$name();
  57. }else{
  58. $model = $this->getModel()->expansionMethod($name,get_class($this->getModel()));
  59. }
  60. return $model;
  61. } catch (BadMethodCallException $e) {
  62. throw RelationNotFoundException::make($this->getModel(), $name);
  63. }
  64. });
  65. // $nested = $this->nestedRelations($name);
  66. $nested = $this->relationsNestedUnder($name);
  67. // If there are nested relationships set on the query, we will put those onto
  68. // the query instances so that they can be handled after this relationship
  69. // is loaded. In this way they will all trickle down as they are loaded.
  70. if (count($nested) > 0) {
  71. $relation->getQuery()->with($nested);
  72. }
  73. return $relation;
  74. }
  75. public function expansionGet($columns = ['*'])
  76. {
  77. $builder = $this->applyScopes();
  78. $models = $builder->getModels($columns);
  79. // If we actually found models we will also eager load any relationships that
  80. // have been specified as needing to be eager loaded, which will solve the
  81. // n+1 query issue for the developers to avoid running a lot of queries.
  82. if (count($models) > 0) {
  83. $models = $builder->expansionEagerLoadRelations($models);
  84. }
  85. return $builder->getModel()->newCollection($models);
  86. }
  87. }