Nested controllers

Nested controllers is a new feature in Laravel 5 and is used to handle all of the RESTful actions that deal with relationships. For example, we can take advantage of this feature for the relationship between accommodations and rooms.

The relationship between accommodation and room is as follows:

  • An accommodation may have one or more rooms (one-to-many)
  • A room belongs to one and only one accommodation (one-to-one)

In our models, we will now write the code to enable the one-to-one and one-to-many relationships to be skillfully handled by Laravel.

Accommodation hasMany rooms

First, we will add the code that is needed by the Accomodation.php file that represents theaccommodation model as follows:

class Accommodation extends Model {
    public function rooms(){
        return $this->hasMany('\MyCompany\Accommodation\Room');
    }
}

The rooms() method creates an easy way to access the relationship from inside the accommodation model. The relation states that “the accommodation hasMany rooms”. The hasMany function, when residing inside the Accommodation class, without any additional parameters, expects a column named accommodation_id to exist in the Room model’s table, which in this case is rooms.

Room belongsTo accommodation

Now, we will add the code that is needed by the Room.php file that represents the Room model:

class Room extends Model
{
    public function accommodation(){
        return $this->belongsTo('\MyCompany\Accommodation');
    }
}

This code states that “a room belongsTo an accommodation”. The belongsTo method inside the Roomclass, without any additional parameters, expects a field in the room model’s table; in this case,rooms, named accommodation_id.

Tip

If the tables in the application database have followed the active record conventions, then most of the eloquent relation functionalities will automatically function. All of the parameters can be easily configured.

The command to create a nested controller is as follows:

$php artisan make:controller AccommodationsRoomsController

Then, the following line would be added to the app/Http/routes.php file:

Route::resource('accommodations.rooms', 'AccommodationsRoomsController');

To display the routes created, the following command should be executed:

$php artisan route:list

The following table lists the HTTP verbs and their functions:

HTTP verb Function URL
1 GET This shows the accommodation and room relations /accommodations/{accommodations}/rooms
2 GET This shows an accommodation and room relation /accommodations/{accommodations}/rooms/{rooms}
3 POST This creates a new accommodation and room relation /accommodations/{accommodations}/rooms
4 PUT This entirely modifies (updates) an accommodation and room relation /accommodations/{accommodations}/rooms/{rooms}
5 PATCH This partially modifies (updates) an accommodation and room relation /accommodations/{accommodations}/rooms/{rooms}
6 DELETE This deletes an accommodation and room relation /accommodations/{accommodations}/rooms/{rooms}

Eloquent relations

A nice mechanism used to illustrate an Eloquent relation directly inside the controller is performed through the use of a nested relation, where two models are connected firstly through the route and secondly through their controller method’s parameters via model dependency injection.

Nested update

Let’s investigate the update/modify PUT nested controller command. The URL looks like this:http://www.hotelwebsite.com/accommodations/21/rooms/13.

Here, 21 would be the ID of the accommodation and 13 would be ID of the room. The parameters are the type-hinted models. This allows us to easily update the relationship as follows:

public function update(Accommodation $accommodation, Room $room)
{
    $room->accommodation()->associate($accommodation);
    $room->save();
}

Nested create

Similarly, it is easy to perform the nested create operation with a POST body tohttp://www.hotelwebsite.com/accommodations/21/rooms. The POST body is a JSON formatted object:

{"roomNumber":"123"}

Note that there is no ID needed for the room since we are creating it:

public function store(Accommodation $accommodation)
{
    $input = \Input::json();
    $room = new Room();
    $room->room_number = $input->get('roomNumber');
    $room->save();
    $accommodation->rooms()->save($room);
}