|

Adding Game Reviews With Eloquent Relationships

Adding Game Reviews With Eloquent Relationships

Let’s keep building out our simple games application with Laravel. In this tutorial we will do a few things, in addition to adding the ability to add a review for any given game. First off though, we’ll need to clean up the main games listing view so it looks a little better. That may include tweaking the master layout page a bit as well. We’ll take a moment to discuss how relationships work in Laravel, create a new model and migration, update our models, and then test things out. Let’s get started.


Cleaning Up the index.blade.php view

Currently when we fetch all resources, or games in this case, we are just displaying the title of the games in an un ordered list. Let’s update that view file to make it a little more pleasant to look at. We’ll use some simple bootstrap card markup to achieve this.


resources/views/games/index.blade.php

It turns out, if you’re using the navbar component in Bootstrap, you sometimes need to manually add some padding to your container element in order to give some space to breathe in the layout. We can update the master template file to accomplish this like so.


resources/views/layouts/master.blade.php

With these two simple tweaks, our main games page looks a bit nicer.
listing all games looks good


A Game hasMany() Reviews

We now start to look at working with relationships in Eloquent. Specifically, relationships exist between models. We’ve been working a lot with video games, and what do most video games online have a lot of. Yes, Reviews! People love to play all the latest games, or maybe some of the retro ones like what the Nintendo Classic offers – then offer up their reviews. We’re going to implement this very thing in our little games app. So far we have a Game model which represents the games in our system. Well now we want to work with reviews so what will the model be? That’s right, we’re going to need a Review Model. Ok, let’s whip up a model and a migration in one shot using artisan.
php artisan make model Review m

This command created a new Review model for us, as well as a new migration. Let’s open up that migration file and add a couple of fields to hold our review data. We are going to add a body field of type string, and this is simply the field which will hold the text of a review. Since we are now going to work with relationships between models as well, we are going to add a game_id field to this reviews database table.


database/migrations/xxxx_xx_xxxxxx_create_reviews_table.php

With our migration file updated for the new reviews table that we would like to add, we can now migrate the database with php artisan migrate.
php artisan migrate reviews table


Updating our Models For Relationships

hasMany()

We now have a Game model and a Review model. How do these two relate to each other? A game can have one or more reviews. So we need to update our Game model to reflect this. In Laravel, we use the hasMany() method in our model to do this. Since a game can have many reviews, we name the method plural in the Game model like so: reviews().


app/Game.php

We still have the cool little query scope we talked about in a prior tutorial, and we can leave it right in place. We simply add our relationship right above in the reviews() method. There is a convention at work here. It reads like, “This Game has many Reviews”.


belongsTo()

With our Game model updated to reflect that any game may have many reviews, we now need to update or Review model. A given review will always be for a specific game. In other words, a review will belong to a game. To represent that in our model, Laravel provides the belongsTo() method. Again there is a convention in play. We can read this relationship as, “This review belongs to a specific game”. So this is why we see that in the belongsTo scenario, our method name is singular: game(). Let’s see how to implement that right here.


app/Review.php


Add a game review to the database

We need to actually add a review into the database before we can test our relationship logic out. Using phpMyAdmin that we had installed in our getting a database set up for Laravel tutorial, we can add a review like so.
insert a new review into the database


Testing The Relationship in Tinker

If we jump into tinker at the command line, we can now test out the relationships of our model. First, let’s use our Game model and find the game with an id of 1. We do this like with the command, $game = App\Game::find(1); This will store an instance of that game in our $game variable. From there, we can call the reviews() method as a property, as in $game->reviews. This tells Laravel to eager load the relationship. Let’s try it out.
call relationship method as a property

Awesome! This tells us that our hasMany relationship is working great. What about the belongsTo relationship? We can test that as well. In this case of our belongsTo relationship, we had defined a game() method. So this means we can find a particular review in the database, and then again, call that game() method as a property to eager load the relationship. We’ll find a review in the database with $review = App\Review::first(); and then find out what game this review belongs to with $review->game;
belongsto relationship in action


Display reviews in show.blade.php

In the background, we’ve added a few more reviews into the database for each game. Now let’s update our view file so that when we click on to a specific record, or game, we will be able to see any associated reviews about the game as well.


resources/views/games/show.blade.php

Check it out!
game reviews via eloquent

The relationship methods are very convenient and make it easy to work with related models. If we have an instance of a Game, we can easily fetch all associated reviews with $game->reviews; Conversely, if we have an instance of a Review, we an easily see which game it belongs to with $review->game; Very nice.


Add A Form To Add Game Reviews

Now that we have everything working in terms of fetching related models in our database, then displaying them to the user, let’s go ahead and add a form to our show.blade.php view so that we can add a new review for a game if we like and not have to manually insert data with phpMyAdmin. First off, we’re going to need that form, so here is a snippet to get us that.


resources/views/games/show.blade.php


Create a Reviews Controller To Process Reviews

We’re going to need a way to store the reviews in our database. It makes sense to put this logic in a dedicated controller, so let’s create that new controller and add a store() method that will store new reviews for us.
php artisan make controller


app/Http/Controllers/ReviewsController.php


Add a Route To the Routes file

With the ReviewsController setup along with our new store() method, we are going to need the routes file to be updated as well. We can add a new route like so:


Update The Review Model For Mass Assignment

Notice that in the ReviewsController we are making use of the Eloquent create() method on our model. When this is the case, Laravel is going to check for mass assignment violations. We need to update our Review model like so to make use of this approach to inserting data.


Try Adding A Review

We can try to add a review now to a given game. Check it out!
add game review works


Adding Validation To Review Submissions

We saw above that we have now gotten everything working great, but there is no validation for when a user submits a review on a game. We should add that in. Also, remember how we had extracted our display errors markup to a partial? This is very beneficial for us now, because when we update the form for adding reviews, all we nee to do is to include that partial that deals with form errors to display any validation failures. First let’s update the store() method on the ReviewsController.


app/Http/Controllers/ReviewsController.php

This says that the body field must be filled out, and it also must be at least 3 characters long. Let’s now include the partial in our add review form like so.

We can try adding a review that has less than 3 characters, and now that our store() method and view are updated for validation, we get a nice error message lettings us know what went wrong.
validation failures on add review


Refactor ReviewsController

The final thing we can take a look at is doing a small amount of refactoring in the ReviewsController. Refactoring is the process of changing how the code is written, while leaving the same functionality in place. The end result is the same, but the person reading the code sees it differently. We do this in an attempt to make our code more readable and easier to understand. It might be nice if in our store() method, we can make an adjustment to the code to something like $game->addReview(request(‘body’)); It turns out, that is something we can do. We just need to make a small update to our Game Model and ReviewsController. We need to add a new method to Game Model of addReview() and we need to update the store() method in our ReviwsController to make use of that new method.


app/Game.php

With the addition of the addReview() method above, we can now call it in our ReviewsController very easily. Check it out.

Wow! Look at how nicely that store method reads now. We have an instance of a game, and we add a review to it. Pretty nice. Does it work? Let’s see!
insert after refactor


Adding Game Reviews With Eloquent Relationships Summary

Our little games app has really taken shape at this point. In this tutorial we cleaned up our layouts and then moved on to using Eloquent Relationships to add reviews to our games. We added a new Review model to complement our existing Game model and set up the belongsTo() and hasMany() relationships on these models. We discussed that a Game can have one or more reviews, but a review should only belong to one game. From there we added some reviews manually to the database, and tested out fetching them with Tinker. Then we added a new form on the page which shows an individual game so that we could add a review. Once we got everything working great, we finished with a small refactoring session to make our ReviewsController very terse and easy to read.