diff --git a/src/Resources/BuildoraResource.php b/src/Resources/BuildoraResource.php index e7d6a2e..2f30bd4 100644 --- a/src/Resources/BuildoraResource.php +++ b/src/Resources/BuildoraResource.php @@ -6,6 +6,7 @@ use Ginkelsoft\Buildora\Exceptions\BuildoraException; use Ginkelsoft\Buildora\Resources\Concerns\HasResourceActions; use Ginkelsoft\Buildora\Resources\Concerns\HasResourceNavigation; +use Ginkelsoft\Buildora\Resources\Concerns\HasResourceQuery; use Illuminate\Database\Eloquent\Model; use Ginkelsoft\Buildora\Fields\Field; use Exception; @@ -20,6 +21,7 @@ abstract class BuildoraResource { use HasResourceActions; use HasResourceNavigation; + use HasResourceQuery; protected ?Model $parentModel = null; protected string $modelClass; @@ -196,27 +198,8 @@ public function getModelClass(): string // slug() lives in HasResourceNavigation. - /** - * Return the query builder for this resource WITHOUT eager-loading relations. - * Use this for index/list views for optimal performance. - * - * @return \Ginkelsoft\Buildora\BuildoraQueryBuilder - */ - public static function query(): \Ginkelsoft\Buildora\BuildoraQueryBuilder - { - return QueryFactory::forList(new static()); - } - - /** - * Return the query builder for this resource WITH eager-loading of panel relations. - * Use this for detail/show views where relations are needed. - * - * @return \Ginkelsoft\Buildora\BuildoraQueryBuilder - */ - public static function queryWithRelations(): \Ginkelsoft\Buildora\BuildoraQueryBuilder - { - return QueryFactory::forDetail(new static()); - } + // query() and queryWithRelations() live in HasResourceQuery + // (Resources\Concerns\HasResourceQuery). public function setDetailView(string $view): static { diff --git a/src/Resources/Concerns/HasResourceQuery.php b/src/Resources/Concerns/HasResourceQuery.php new file mode 100644 index 0000000..3c10d83 --- /dev/null +++ b/src/Resources/Concerns/HasResourceQuery.php @@ -0,0 +1,38 @@ + 'comments'], + ]; + } +} + +class HasResourceQueryTest extends TestCase +{ + protected function setUp(): void + { + parent::setUp(); + + Schema::create('rq_articles', function ($t) { + $t->increments('id'); + $t->string('title')->nullable(); + }); + } + + #[Test] + public function query_returns_a_buildora_query_builder(): void + { + $this->assertInstanceOf(BuildoraQueryBuilder::class, RQArticleBuildora::query()); + } + + #[Test] + public function query_does_not_eager_load_panel_relations(): void + { + // Behavioural sanity: query() must skip the panel eager-load path + // (that's the whole point of the list/detail split). + $eagerLoads = RQArticleBuildora::query()->getEagerLoads(); + + $this->assertSame([], array_keys($eagerLoads)); + } + + #[Test] + public function query_with_relations_eager_loads_declared_panels(): void + { + $eagerLoads = RQArticleBuildora::queryWithRelations()->getEagerLoads(); + + $this->assertContains('comments', array_keys($eagerLoads)); + } + + #[Test] + public function buildora_resource_uses_the_query_trait(): void + { + $traits = (new ReflectionClass(BuildoraResource::class))->getTraitNames(); + + $this->assertContains(HasResourceQuery::class, $traits); + } + + #[Test] + public function query_methods_are_no_longer_inlined_in_buildora_resource(): void + { + $resourceSource = file_get_contents( + (new ReflectionClass(BuildoraResource::class))->getFileName() + ); + + foreach (['query', 'queryWithRelations'] as $movedMethod) { + $this->assertStringNotContainsString( + "public static function {$movedMethod}(", + $resourceSource, + "Method '{$movedMethod}' has been re-inlined into BuildoraResource.php — it should live in HasResourceQuery trait." + ); + } + + $traitSource = file_get_contents( + (new ReflectionClass(HasResourceQuery::class))->getFileName() + ); + + foreach (['query', 'queryWithRelations'] as $movedMethod) { + $this->assertStringContainsString( + "function {$movedMethod}(", + $traitSource, + ); + } + } +}