TransformsToResourceCollection.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. namespace Illuminate\Support\Traits;
  3. use Illuminate\Database\Eloquent\Attributes\UseResource;
  4. use Illuminate\Database\Eloquent\Attributes\UseResourceCollection;
  5. use Illuminate\Database\Eloquent\Model;
  6. use Illuminate\Http\Resources\Json\ResourceCollection;
  7. use LogicException;
  8. use ReflectionClass;
  9. trait TransformsToResourceCollection
  10. {
  11. /**
  12. * Create a new resource collection instance for the given resource.
  13. *
  14. * @param class-string<\Illuminate\Http\Resources\Json\JsonResource>|null $resourceClass
  15. * @return \Illuminate\Http\Resources\Json\ResourceCollection
  16. *
  17. * @throws \Throwable
  18. */
  19. public function toResourceCollection(?string $resourceClass = null): ResourceCollection
  20. {
  21. if ($resourceClass === null) {
  22. return $this->guessResourceCollection();
  23. }
  24. return $resourceClass::collection($this);
  25. }
  26. /**
  27. * Guess the resource collection for the items.
  28. *
  29. * @return \Illuminate\Http\Resources\Json\ResourceCollection
  30. *
  31. * @throws \Throwable
  32. */
  33. protected function guessResourceCollection(): ResourceCollection
  34. {
  35. if ($this->isEmpty()) {
  36. return new ResourceCollection($this);
  37. }
  38. $model = $this->items[0] ?? null;
  39. throw_unless(is_object($model), LogicException::class, 'Resource collection guesser expects the collection to contain objects.');
  40. /** @var class-string<Model> $className */
  41. $className = get_class($model);
  42. throw_unless(method_exists($className, 'guessResourceName'), LogicException::class, sprintf('Expected class %s to implement guessResourceName method. Make sure the model uses the TransformsToResource trait.', $className));
  43. $useResourceCollection = $this->resolveResourceCollectionFromAttribute($className);
  44. if ($useResourceCollection !== null && class_exists($useResourceCollection)) {
  45. return new $useResourceCollection($this);
  46. }
  47. $useResource = $this->resolveResourceFromAttribute($className);
  48. if ($useResource !== null && class_exists($useResource)) {
  49. return $useResource::collection($this);
  50. }
  51. $resourceClasses = $className::guessResourceName();
  52. foreach ($resourceClasses as $resourceClass) {
  53. $resourceCollection = $resourceClass.'Collection';
  54. if (is_string($resourceCollection) && class_exists($resourceCollection)) {
  55. return new $resourceCollection($this);
  56. }
  57. }
  58. foreach ($resourceClasses as $resourceClass) {
  59. if (is_string($resourceClass) && class_exists($resourceClass)) {
  60. return $resourceClass::collection($this);
  61. }
  62. }
  63. throw new LogicException(sprintf('Failed to find resource class for model [%s].', $className));
  64. }
  65. /**
  66. * Get the resource class from the class attribute.
  67. *
  68. * @param class-string<\Illuminate\Http\Resources\Json\JsonResource> $class
  69. * @return class-string<*>|null
  70. */
  71. protected function resolveResourceFromAttribute(string $class): ?string
  72. {
  73. if (! class_exists($class)) {
  74. return null;
  75. }
  76. $attributes = (new ReflectionClass($class))->getAttributes(UseResource::class);
  77. return $attributes !== []
  78. ? $attributes[0]->newInstance()->class
  79. : null;
  80. }
  81. /**
  82. * Get the resource collection class from the class attribute.
  83. *
  84. * @param class-string<\Illuminate\Http\Resources\Json\ResourceCollection> $class
  85. * @return class-string<*>|null
  86. */
  87. protected function resolveResourceCollectionFromAttribute(string $class): ?string
  88. {
  89. if (! class_exists($class)) {
  90. return null;
  91. }
  92. $attributes = (new ReflectionClass($class))->getAttributes(UseResourceCollection::class);
  93. return $attributes !== []
  94. ? $attributes[0]->newInstance()->class
  95. : null;
  96. }
  97. }