knuckleswtf / scribe

Generate API documentation for humans from your Laravel codebase.✍
https://scribe.knuckles.wtf/laravel/
MIT License
1.58k stars 280 forks source link

Unable to do nested eager loading using #[ResponseFromApiResource] #786

Open issakujitsuk opened 5 months ago

issakujitsuk commented 5 months ago

Scribe version

4.29.0

PHP version

8.2.8

Framework

Laravel

Framework version

10.17.0

Scribe config

try_it_out.enabled => false
auth.enabled => true
auth.default => true
postman.enabled => false
openapi.enabled => false
last_updated => "Last updated: {date:Y-m-d}"
strategies.urlParameters => added Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLumenAPI
strategies.headers => added Knuckles\Scribe\Extracting\Strategies\Headers\GetFromRouteRules: removed [
    'override',
    [
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
]
strategies.responses => added Knuckles\Scribe\Extracting\Strategies\Responses\ResponseCalls: removed [
    'Knuckles\\Scribe\\Extracting\\Strategies\\Responses\\ResponseCalls',
    [
        'only' => [
            'GET *',
        ],
    ],
]

What happened?

Thanks for Scribe.

I declared an attribute like this.

#[ResponseFromApiResource(
    BookResource::class, 
    Book::class,
    with: ["author.contacts"],
)]

Expected (at BookResource):

$this->resource->relationLoaded("author"); // true
$this->resource->author->relationLoaded("contacts"); // true

As is:

$this->resource->relationLoaded("author"); // πŸ‘ true
$this->resource->author->relationLoaded("contacts"); // πŸ†– false

I see a problem here. https://github.com/knuckleswtf/scribe/blob/695c2a99a70f8c6c1b0dd3bf34d0d70af5ca44fc/src/Extracting/InstantiatesExampleModels.php#L72

I am able to load nested relations as expected until $factory->create()->load($relations), but the contacts relation is lost in refresh().

Sorry if my language is poor and rude.

Docs

shalvah commented 5 months ago

Not to worry, your language isn't poor or rude.

First off, disclaimer: I don't have much experience with API resources, so I can't help much. But here's the PR where we added refresh: https://github.com/knuckleswtf/scribe/pull/753 I don't fully understand, but it looks like there was a good reason. Maybe the refresh should be before the load?πŸ€”

issakujitsuk commented 5 months ago

Hi, @shalvah. Thanks for your reply.

As you guessed, $factory->create()->refresh()->load($relations) worked fine for me πŸ˜ƒ The issues fixed in #753 may have been as follows.

Book table:

CREATE TABLE `books` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8mb4_bin NOT NULL,
  `volume` tinyint unsigned NOT NULL DEFAULT '1',   -- ⚠ volume has default value
  `updated_at` datetime NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
)

BookFactory:

public function definition(): array
{
    return [
        "title" => fake()->sentence(),
        // ⚠ volume is undefined.
    ];
}

Creating a model from a factory:

$book = Book::factory()->create();
/*
= App\Models\Book {
    title: "Eveniet nihil temporibus aut.",
    updated_at: "2024-01-18 00:00:00",
    created_at: "2024-01-18 00:00:00",
    id: 1,
  }
*/
// ⚠ volume is missing

$book->refresh();
/*
= App\Models\Book {
    id: 1,
    title: "Eveniet nihil temporibus aut.",
    volume: 1,
    updated_at: "2024-01-18 00:00:00",
    created_at: "2024-01-18 00:00:00",
  }
*/