New controller action

It is very simple to add new actions to the REST API controller. We only need to remember three differences in the web controller:

  • Verb setting for the new action
  • Authenticate the setting for the new action
  • Output for the new action

The first two steps are configured in the behaviors() method of the controller:

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['verbs'] = [
                'class' => yiifiltersVerbFilter::className(),
                'actions' => [
                    'myCustomAction'  => ['get', 'head'],
                ],
        ];
        
        $behaviors['authenticator'] = [
        'except' => 'myCustomAction',
            'class' => HttpBasicAuth::className(),
        ];
      
        return $behaviors;
    }

public function actionMyCustomAction()
{
    …
    …
    
}

In the first part of the behaviors() method, we will only set the get and head HTTP methods to call the myCustomAction action. If we try to call this action with other HTTP methods, we will get a not supported exception.

In the last part of the behaviors() method, we will set it so that myCustomAction has not got authentication, since it is in the except property.

The third difference, output for the new action, states that we have different ways to return data. We can use:

  • A key-value pair array to create a single object from scratch
  • An ActiveRecord instance to create a single object
  • An ActiveRecord array to create a list of objects
  • A data provider

In this last case, the framework will automatically output pagination information and links to other pages (if present).

Example – getting a rooms list for a reservation

In this example, we need to create a Reservation model in the common/models folder using Gii.

Then, we create a new controller in api/controllers/ReservationsController.php:

<?php
namespace apicontrollers;

use Yii;
use yii
estActiveController;
use yiifiltersauthCompositeAuth;
use yiifiltersauthHttpBasicAuth;
use yiifiltersauthQueryParamAuth;

class ReservationsController extends ActiveController
{
    public $modelClass = 'commonmodelsReservation';
     
    public function actionIndexWithRooms()
    {
        $reservations = commonmodelsReservation::find()->all();
        
        $outData = [];
        foreach($reservations as $r)
        {
            $outData[] = array_merge($r->attributes, ['room' => $r->room->attributes]);
        }
        return $outData;        
    }
            
}

Now, let's call http://hostname/yiiadv/api/web/reservations/index-with-rooms, where we will display a list of reservations, in each of which the room property is expanded together with the content of room object related to the reservation.

Note

Take care to ensure that the room relation already exists in the Reservation model. If not, we must add this relation to the Reservation model:

    public function getRoom()
    {
        return $this->hasOne(Room::className(), ['id' => 'room_id']);
    }

However, this solution is inefficient since we always get all the rows and if there are too many of them, this can result in it being too expensive for us. To solve this problem, we could use a DataProvider created from a set of data found, or better yet, a more simple solution automatically provided by Yii.

Indeed, Yii provides some easy ways to display relations and filter returned fields. For example, there could be fields that we do not want to show, such as a password, private data, and so on.

Models have these methods:

  • fields(): By default, classes that extend yiiaseModel::fields() return all the model attributes as fields, while classes that extend yiidbActiveRecord::fields() only return the attributes that have been populated from the DB
  • extraFields(): By default, classes that extend yiiaseModel::extraFields() return nothing, while classes that extend yiidbActiveRecord::extraFields() return the names of the relations that have been populated from the DB

The first method, fields(), is a key-value array where the key is the name of the field returned. The value can be empty if the returned content is the attribute with the same name as the key, a string indicating which attribute to get the returned value from, or a callable PHP function to manipulate the returned value.

The second method, extraFields(), is a string array whose values are relations defined in the model class.

Finally, to dynamically filter the requested field, we append the fields parameter to the requested URL and the expand parameter to get a list of relations from the models.

So, if we call http://hostname/yiiadv/api/web/reservations/index?expand=room, we will get the same result but we will also have the pagination and loaded models that are only necessary for that page.

However, it would be more convenient for us to distribute an URL without special parameters, such as the expand and fields, for example, in order to avoid confusion among developers who will use these APIs.

We can use actionIndexWithRooms as a wrapper for actionIndex with an expanded parameter in this way:

    public function actionIndexWithRooms()
    {
            $_GET['expand'] = 'room';
            return $this->runAction('index');
    }

With this solution, the http://hostname/yiiadv/api/web/reservations/index-with-rooms URL is simply a wrapper for http://hostname/yiiadv/api/web/reservations/index?expand=room but this prevents developers from having to remember which parameters to pass to the URL to obtain the necessary nodes in the response.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.51.36