Yii 2.0: yii2-nested-rest

Nested routing support to the Yii RESTful API framework
2 followers

Adds nested resources routing support along with related actions and relationship handlers to the Yii RESTful API framework.

Github repo: https://github.com/tunecino/yii2-nested-rest

Requirements

Yii 2 or above

Usage

This extension doesn't replace any of the built-in REST components. It is about a collection of helper actions and a custom UrlRule class designed to be used along with the default one:

'rules' => [
    [
        // Yii defaults UrlRule class
        'class' => 'yii\rest\UrlRule',
        'controller' => ['team','player','skill'],
    ],
    [
        // The custom UrlRule class
        'class' => 'tunecino\nestedrest\UrlRule',
        'modelClass' => 'app\models\Team',
        'relations' => ['players'],
    ],
    [
        'class' => 'tunecino\nestedrest\UrlRule',
        'modelClass' => 'app\models\Player',
        'relations' => ['team','skills'],
    ],
]

To understand how it works, I think it would be better explained within a practical example:

If within the previous configurations we expect team and player to share a one-to-many relationship while player and skill shares a many-to-many relation within a junction table and having an extra column called level in that junction table then this extension may help achieving the following HTTP requests:

# get the players 2, 3 and 4 from team 1
GET /teams/1/players/2,3,4
 
# list all skills of player 5
GET /players/5/skills
 
# put the players 5 and 6 in team 1
PUT /teams/1/players/5,6
 
# create a new player and put him in team 1
POST /teams/1/players
{name: 'Didier Drogba', position: 'FC'}
 
# create a new skill called 'dribble' and assign it to player 9
# with a related level of 10 ('level' should be stored in the junction table)
POST /players/9/skills
{name: 'dribble', level: 10}
 
# remove skill 3 from player 2
DELETE /players/2/skills/3
 
# get all players out of team 2
DELETE /teams/2/players

Installation

The preferred way to install this extension is through composer.

Either run

$ composer require tunecino/yii2-nested-rest

or add

"tunecino/yii2-nested-rest": "*"

to the require section of your composer.json file.

Configuration

By default, all the properties used by the custom UrlRule class in this extension will be used to generate multiple instances of the built-in yii\rest\UrlRule so basically both classes are sharing similar configurations.

Those are all the possible configurations that may be set to the UrlManager in the app config file:

'rules' => [
    [
        /**
         * the custom UrlRule
         */
        'class' => 'tunecino\nestedrest\UrlRule', /* required */
        /**
         * the model class name
         */
        'modelClass' => 'app\models\Player', /* required */
         /**
         * relations names to be nested with this model
         * they should be already defined in the model class.
         */
        'relations' => ['team','skills'], /* required */
        /**
         * used to generate the 'prefix'.
         * default: the model name pluralized
         */
        'resourceName' => 'players', /* optional */
        /**
         * also used with 'prefix'. is the expected foreign key.
         * default: $model_name . '_id'
         */
        'linkAttribute' => 'player_id', /* optional */
        /**
         *  building related rules using 'controller => ['teams' => 'v1/team']' 
         *  instead of 'controller => ['team']'
         */
        'modulePrefix' => 'v1', /* optional */
        /**
         * the default list of tokens that should be replaced for each pattern
         * in case you have a reason to replace them.
        */
        'tokens' = [
            '{id}' => '<id:\\d[\\d,]*>',
            '{IDs}' => '<IDs:\\d[\\d,]*>',
        ], /* optional */
        /**
         *  the default list of patterns. they may all be overridden here
         *  or just edited within $only, $except and $extraPatterns properties
         */
        'patterns' => [ 
            'GET,HEAD {IDs}' => 'nested-view',
            'GET,HEAD' => 'nested-index',
            'POST' => 'nested-create',
            'PUT {IDs}' => 'nested-link',
            'DELETE {IDs}' => 'nested-unlink',
            'DELETE' => 'nested-unlink-all',
            '{id}' => 'options',
            '' => 'options',
        ], /* optional */
        /**
         *  list of acceptable actions.
         */
        'only' => [], /* optional */
        /**
         *  actions that should be excluded.
         */
        'except' => [], /* optional */
        /**
         *  supporting extra actions in addition to those listed in $patterns.
         */
        'extraPatterns' => [] /* optional */
    ],
]

As you may notice; by default; $patterns is pointing to 6 new actions different from the basic CRUD actions attached to the ActiveController class. Those are the helper actions included in this extension and you will need to manually declare them whenever needed inside your controllers or inside a BaseController from which all others should extend. Also note that by default we are expecting an OptionsAction attached to the related controller. That should be the case with any controller extending ActiveController or its child, otherwise you should also implement \yii\rest\OptionsAction.

The following is an example of a full implementation within the controller::actions() function:

public function actions() 
{
    $actions = parent::actions(); 
 
    $actions['nested-index'] = [
        'class' => 'tunecino\nestedrest\IndexAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
    ];
 
    $actions['nested-view'] = [
        'class' => 'tunecino\nestedrest\ViewAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
    ];
 
    $actions['nested-create'] = [
        'class' => 'tunecino\nestedrest\CreateAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
        /**
         * the scenario to be assigned to the new model before it is validated and saved.
         */
        'scenario' => 'default', /* optional */
        /**
         * the scenario to be assigned to the model class responsible 
         * of handling the data stored in the juction table.
         */
        'viaScenario' => 'default', /* optional */
        /**
         * expect junction table related data to be wrapped in a sub object key in the body request.
         * In the example we gave above we would need to do :
         * POST {name: 'dribble', related: {level: 10}}
         * instead of {name: 'dribble', level: 10}
         */
        'viaWrapper' => 'related' /* optional */
    ];
 
    $actions['nested-link'] = [
        'class' => 'tunecino\nestedrest\LinkAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
        /**
         * the scenario to be assigned to the model class responsible 
         * of handling the data stored in the juction table.
         */
        'viaScenario' => 'default', /* optional */
    ];
 
    $actions['nested-unlink'] = [
        'class' => 'tunecino\nestedrest\UnlinkAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
    ];
 
    $actions['nested-unlink-all'] = [
        'class' => 'tunecino\nestedrest\UnlinkAllAction', /* required */
        'modelClass' => $this->modelClass, /* required */
        'checkAccess' => [$this, 'checkAccess'], /* optional */
    ];
 
    return $actions;
}

Documentation

see the README.md file in the Github repository page.

Other Resources

Be the first person to leave a comment

Please to leave your comment.

Create extension
Downloads
No downloadable files yet