I am trying to do a GET request to retrieve a specific film via the id /GET 'film/{id}'
etc
film_table
— id
— description
this is what is part of the response, what if I’ve many-to-many relationships within the film model as shown in the film
model
public function languages(): BelongsToMany { return $this->belongsToMany( 'AppModelsLanguage', 'film_languages', 'film_id', 'language_code' ); } public function categories(): BelongsToMany { return $this->belongsToMany( 'AppModelsCategory', 'film_categories', 'film_id', 'category_id' ); }
is there a way you can include these tables as part of the response I came across something called eager loading in the Laravel docs but unsure if this covers what I need I have an example below but I’m lost if I’m on the right tracks?
FilmController
public function show(string $id): string { /** @var Film $film*/ $film = film::findOrFail($id) ->with( 'languages', 'categories', )->get(); return $film->toJson();
I am trying to write a PHPUnit test to ensure that when a film is grabbed via the id it returns the id
, description
as well as the options choosing from the many-to-many relations.
This is the test I’ve started
FilmControllerTest
public function setUp(): void { parent::setUp(); $this->film = factory(Film::class)->create(); $languages = factory(Language::class)->create(); $categories = factory(Category::class)->create(); } /** * @test */ public function it_should_get_film() { $response = $this->json('GET', '/film/' . $this->film->id); $film= Film::findOrFail($this->film->id); $response->assertJson([ 'id' => $film->id, 'description' => 'This is my favourite film' ]); }
can you include these relationships into a factory?
FilmFactory
$factory->define(AppModelsFilm::class, function (Faker $faker) { return [ 'id' => $faker->uuid, 'description' => $faker->paragraph ]; });
LanguagesFactory
$factory->define(AppModelsLanguage::class, function (Faker $faker){ $langCode = $faker->languageCode; return [ 'code' => $langCode, 'name' => $langCode, ]; });
CategoriesFactory
$factory->define(AppModelsCategory::class, function (Faker $faker){ return [ 'main' => $faker->text, 'sub' => $faker->text, ]; });
Can i get some help with this please i’ve hit a brick wall some help and examples would be great 🙂 thanks!
Advertisement
Answer
You are very much on the right track. There are, however, some syntax errors.
This is how you grab a film, eager load required relationships and return it as JSON:
public function show($id) { $film = Film::with(['languages', 'categories'])->findOrFail($id); return $film; // will automatically convert it to JSON }
And this is how you test it:
public function testShowFilm() { $film = factory(Film::class)->create(); $language = factory(Language::class)->create(); $film->languages()->attach($language->id); // associate the film with the language $category = factory(Category::class)->create(); $film->categories()->attach($category->id); // associate the film with the category $url = '/films/' . $film->id; $this->json('GET', $url) ->assertStatus(200) ->assertJsonPath(['id' => $film->id]) ->assertJsonPath(['description' => $film->description]) ->assertJsonPath(['languages.0.id' => $language->id]) ->assertJsonPath(['categories.0.id' => $category->id]); }
Note that in your scenario you should have:
- 3 model tables: films, categories, languages;
- a factory for each model table;
- 2 relationship tables: film_categories and film_languages.
Then you can either set relationships as part of your test using the attach
method as in the example above, or you can use factory callbacks:
https://laravel.com/docs/6.x/database-testing#factory-callbacks