Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/danschmidt5189/yii-rest

Create RESTful controllers in Yii with smart action parameter bindings and request validation.
https://github.com/danschmidt5189/yii-rest

Last synced: about 1 month ago
JSON representation

Create RESTful controllers in Yii with smart action parameter bindings and request validation.

Awesome Lists containing this project

README

        

# Yii REST

The Yii REST extension adds classes and filters that help you write RESTful controllers. Each RESTController has three components:

1. An Adaptor. This maps client data to your action parameters, e.g. `$_GET['Customer'] =>"data"`.
2. A Params model. This validates action parameters and loads your underlying ActiveRecord (or other) models.
3. The controller. This ties the above two together along with actions and filters.

The result is a controller that can describe its interface (via the Adaptor) and easily respond with detailed error messages (via
the params model). The controller and its actions are extremely thin and each component can be swapped out given a different user/
request scenario.

## Overview

Key components:

- RESTAdaptor: An adaptor layer translating raw client request data to a format understood by your
controller actions. An OOP version of `CController::getActionParams()`.
- RESTParams: A form model responsible for validating and loaded your action parameters based on the
raw data parsed by the adaptor. An OOP version of `loadModel()`.
- RESTController: A base controller that ties together the two components above along with sensible
default filters, e.g. verbs and validation filtering.
- RESTAction(s): A set of lightweight actions that handle all of your CRUD needs.

The ultimate goal is to create controllers and actions that are extremely thin, with swappable components
for both their public interface and parameter generation, and that can be described programatically for later
documentation via the HTTP OPTIONS method.

In addition, the controllers should be format-agnostic. Actions should only expose raw data via `RESTAction::getResult()`,
which the controller can translate (through delegation) to a response that converts the raw data into a type
allowed by the user. (E.g. JSON, HTML, XML, ...) However this is not currently implemented, as it is a feature
much more easily handled using the upcoming Yii2.

## Installation

Copy or clone the folder into your extensions directory and add the following alias to your application:

```php

```

The file `yii-rest/components/RESTController.php` inherits from a custom base controller assumed to live at
`application.components.Controller`. You must modify this if your base controller is located elsewhere, named differently,
or if you do not use a custom base controller.

## Components

### RESTController

The RESTController introduces two new properties:

- `$_restParams`: A form model representing the parameters passed to your controller actions. This is analogous
to the `loadModel()` method in the standard Gii crud controllers, but in an OOP fashion.
- `$_restAdaptor`: A class that maps client request data to `$_restParams` attributes. This is analogous to
`CController::getActionParams()` in that it returns the raw request data bound to your action parameters.

There are several benefits to including these new components:

- `RESTParams` makes it trivial to render API error messages back to users
- `RESTAdaptor` describes the public interface for the controller
- To change the public interface, change the adaptor model
- To change the action parameters, change the params model. (E.g. swap out "Admin" and "User" models depending
on the current user.)

#### Example: CustomersController.php

```php

```

### RESTAdaptor

The RESTAdaptor maps client request data to the attributes of your RESTParams model.

For example, RESTActionSave expects to receive a parameter called 'data'. Your forms
likely submit data with a key like 'Customer'. You can use the adaptor to map the
'Customer' key generated by CActiveForm to the 'data' attribute expected by the params.

The RESTAdaptor allows you to configure:

- What client params the controller will check for data
- Where the controller will look for that data. (E.g. GET, POST, ...)
- What internal attribute that data is mapped to. (I.e. RESTParams attribute names)

The RESTController uses the RESTAdaptor to parse the raw request for model attributes
and to populate the RESTParams model with those attributes.

#### Example: CustomersAdaptor.php

```php
backend adaptor for the CustomersController
*/
class CustomersAdaptor extends RESTAdaptor
{
/**
* @return array RESTAdaptorParam configuration arrays
* @see RESTAdaptor::loadParams() for how to specify these
*/
public $interface = array(
// These public and private keys are identical
array(RESTSource::GET, 'id'),
array(RESTSource::GET, 'type'),
// Here the client provides the 'Customer' parameter, which is mapped
// to the 'data' property of the params model
array(RESTSource::ANY, 'Customer' =>'data'),
);
}
?>
```

### RESTParams

RESTParams validates and processes raw request parameters extracted by the adaptor and makes them available to your actions.
`RESTParams::$scenario` should correspond to an action ID.

This class serves as the action parameter provider and validator for your controller. It's similar to the standard `loadModel()`
method generated by Gii, but more powerful and reusable.

If implementing RESTParams, you must implement the `loadModel()` method. However, you do not have to implement RESTParams;
any CFormModel will also work, with its public properties used to bind action parameters. But if you find yourself adding a 'model'
or 'data' property to your form model, RESTParams is probably an easier choice.

#### Example: CustomersParams.php

```php
getUser();

$model = new Customer();
// Apply scopes first
$model->scopeByOwner($user->id)->scopeByStatus(Customer::STATUS_ACTIVE);
if ($this->type) {
$model->scopeByType($this->type);
}
// Scenario-specific rules
if ('list' === $this->scenario) {
$model->setScenario('search');
$model->unsetAttributes();
} else if ('create' === $this->scenario) {
$model->owner_id = $user->id;
}
// Attempt to retrieve a specific customer
if ($this->id) {
$model = $model->findByPk($this->id);
}
return $model;
}

/**
* Returns validation rules
*
* Scenario names are action IDs.
*
* @return array validation rule configurations
*/
public function rules()
{
return CMap::mergeArray(
array(
// ID is only valid on actions dealing with a specific customer
array(
'id',
'required',
'on' =>array('view', 'update', 'delete'),
),
array(
'type',
'in',
'range' =>array(Customer::ACTIVE, Customer::DISABLED),
'on' =>array('list'),
),
array(
'data',
'type',
'type' =>'array',
),
),
// Merge parent rules so that [model] is loaded, required, and declared unsafe.
parent::rules()
);
}
}
?>
```

### RESTActions

This extension ships with four basic CRUD actions:

- RESTActionLoad Loads data into a model and renders a view. Works for 'list'
or plain 'view' actions.
- RESTActionValidate Loads data into a model and validates it. Works well for 'new'
and 'edit' actions which present forms.
- RESTActionSave Loads data into a model and saves it. Works well for 'create'
and 'update' actions that actually modify the database.
- RESTActionDelete Deletes a model.

Each action can be configured with its own `$view` and `$params`, which determines
the view into with the action's result and parameters are rendered.

### Filters

Two filters are bundled with this extension:

- RESTVerbsFilter, which filters requests which use the wrong HTTP method
- RESTParamsFilter, which filters requests where `$_restParams` is invalid

(There is an empty base `yii-rest.components.RESTFilter` that you can override as you see fit.)

These are pre-configured in the RESTController as follows:

```php
array('update'), 'verbs' =>array('PUT', 'PATCH')),
array('RESTVerbsFilter', 'actions' =>array('create'), 'verbs' =>array('POST')),
array('RESTVerbsFilter', 'actions' =>array('delete'), 'verbs' =>array('DELETE')),
array('RESTParamsFilter'),
);
}
...
}
?>
```