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(
'App\Models\Language',
'film_languages',
'film_id',
'language_code'
);
}
public function categories(): BelongsToMany
{
return $this->belongsToMany(
'App\Models\Category',
'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(\App\Models\Film::class, function (Faker $faker) {
return [
'id' => $faker->uuid,
'description' => $faker->paragraph
];
});
LanguagesFactory
$factory->define(\App\Models\Language::class, function (Faker $faker){
$langCode = $faker->languageCode;
return [
'code' => $langCode,
'name' => $langCode,
];
});
CategoriesFactory
$factory->define(\App\Models\Category::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!
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:
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