PendingHasThroughRelationship.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. <?php
  2. namespace Illuminate\Database\Eloquent;
  3. use BadMethodCallException;
  4. use Illuminate\Database\Eloquent\Relations\HasMany;
  5. use Illuminate\Support\Str;
  6. class PendingHasThroughRelationship
  7. {
  8. /**
  9. * The root model that the relationship exists on.
  10. *
  11. * @var \Illuminate\Database\Eloquent\Model
  12. */
  13. protected $rootModel;
  14. /**
  15. * The local relationship.
  16. *
  17. * @var \Illuminate\Database\Eloquent\Relations\HasMany|\Illuminate\Database\Eloquent\Relations\HasOne
  18. */
  19. protected $localRelationship;
  20. /**
  21. * Create a pending has-many-through or has-one-through relationship.
  22. *
  23. * @param \Illuminate\Database\Eloquent\Model $rootModel
  24. * @param \Illuminate\Database\Eloquent\Relations\HasMany|\Illuminate\Database\Eloquent\Relations\HasOne $localRelationship
  25. */
  26. public function __construct($rootModel, $localRelationship)
  27. {
  28. $this->rootModel = $rootModel;
  29. $this->localRelationship = $localRelationship;
  30. }
  31. /**
  32. * Define the distant relationship that this model has.
  33. *
  34. * @param string|(callable(\Illuminate\Database\Eloquent\Model): (\Illuminate\Database\Eloquent\Relations\HasOne|\Illuminate\Database\Eloquent\Relations\HasMany)) $callback
  35. * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough|\Illuminate\Database\Eloquent\Relations\HasOneThrough
  36. */
  37. public function has($callback)
  38. {
  39. if (is_string($callback)) {
  40. $callback = fn () => $this->localRelationship->getRelated()->{$callback}();
  41. }
  42. $distantRelation = $callback($this->localRelationship->getRelated());
  43. if ($distantRelation instanceof HasMany) {
  44. return $this->rootModel->hasManyThrough(
  45. $distantRelation->getRelated()::class,
  46. $this->localRelationship->getRelated()::class,
  47. $this->localRelationship->getForeignKeyName(),
  48. $distantRelation->getForeignKeyName(),
  49. $this->localRelationship->getLocalKeyName(),
  50. $distantRelation->getLocalKeyName(),
  51. );
  52. }
  53. return $this->rootModel->hasOneThrough(
  54. $distantRelation->getRelated()::class,
  55. $this->localRelationship->getRelated()::class,
  56. $this->localRelationship->getForeignKeyName(),
  57. $distantRelation->getForeignKeyName(),
  58. $this->localRelationship->getLocalKeyName(),
  59. $distantRelation->getLocalKeyName(),
  60. );
  61. }
  62. /**
  63. * Handle dynamic method calls into the model.
  64. *
  65. * @param string $method
  66. * @param array $parameters
  67. * @return mixed
  68. */
  69. public function __call($method, $parameters)
  70. {
  71. if (Str::startsWith($method, 'has')) {
  72. return $this->has(Str::of($method)->after('has')->lcfirst()->toString());
  73. }
  74. throw new BadMethodCallException(sprintf(
  75. 'Call to undefined method %s::%s()', static::class, $method
  76. ));
  77. }
  78. }