Commit a8c7d36c by Qiang Xue

Finished HATEOAS support.

parent 46d92856
...@@ -12,8 +12,8 @@ In particular, Yii provides support for the following aspects regarding RESTful ...@@ -12,8 +12,8 @@ In particular, Yii provides support for the following aspects regarding RESTful
* Support `OPTIONS` and `HEAD` verbs; * Support `OPTIONS` and `HEAD` verbs;
* Authentication; * Authentication;
* Authorization; * Authorization;
* Support for HATEOAS;
* Caching via `yii\web\HttpCache`; * Caching via `yii\web\HttpCache`;
* Support for HATEOAS: TBD
* Rate limiting: TBD * Rate limiting: TBD
* Searching and filtering: TBD * Searching and filtering: TBD
* Testing: TBD * Testing: TBD
......
...@@ -17,6 +17,8 @@ use yii\helpers\ArrayHelper; ...@@ -17,6 +17,8 @@ use yii\helpers\ArrayHelper;
use yii\helpers\Inflector; use yii\helpers\Inflector;
use yii\validators\RequiredValidator; use yii\validators\RequiredValidator;
use yii\validators\Validator; use yii\validators\Validator;
use yii\web\Link;
use yii\web\Linkable;
/** /**
* Model is the base class for data models. * Model is the base class for data models.
...@@ -876,6 +878,11 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab ...@@ -876,6 +878,11 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
foreach ($this->resolveFields($fields, $expand) as $field => $definition) { foreach ($this->resolveFields($fields, $expand) as $field => $definition) {
$data[$field] = is_string($definition) ? $this->$definition : call_user_func($definition, $field, $this); $data[$field] = is_string($definition) ? $this->$definition : call_user_func($definition, $field, $this);
} }
if ($this instanceof Linkable) {
$data['_links'] = Link::serialize($this->getLinks());
}
return $recursive ? ArrayHelper::toArray($data) : $data; return $recursive ? ArrayHelper::toArray($data) : $data;
} }
......
...@@ -9,6 +9,8 @@ namespace yii\data; ...@@ -9,6 +9,8 @@ namespace yii\data;
use Yii; use Yii;
use yii\base\Object; use yii\base\Object;
use yii\web\Link;
use yii\web\Linkable;
use yii\web\Request; use yii\web\Request;
/** /**
...@@ -65,9 +67,8 @@ use yii\web\Request; ...@@ -65,9 +67,8 @@ use yii\web\Request;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class Pagination extends Object class Pagination extends Object implements Linkable
{ {
const LINK_SELF = 'self';
const LINK_NEXT = 'next'; const LINK_NEXT = 'next';
const LINK_PREV = 'prev'; const LINK_PREV = 'prev';
const LINK_FIRST = 'first'; const LINK_FIRST = 'first';
...@@ -301,7 +302,7 @@ class Pagination extends Object ...@@ -301,7 +302,7 @@ class Pagination extends Object
$currentPage = $this->getPage(); $currentPage = $this->getPage();
$pageCount = $this->getPageCount(); $pageCount = $this->getPageCount();
$links = [ $links = [
self::LINK_SELF => $this->createUrl($currentPage, $absolute), Link::REL_SELF => $this->createUrl($currentPage, $absolute),
]; ];
if ($currentPage > 0) { if ($currentPage > 0) {
$links[self::LINK_FIRST] = $this->createUrl(0, $absolute); $links[self::LINK_FIRST] = $this->createUrl(0, $absolute);
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use yii\base\Arrayable;
use yii\base\Object;
/**
* Link represents a link object as defined in [JSON Hypermedia API Language](https://tools.ietf.org/html/draft-kelly-json-hal-03).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Link extends Object implements Arrayable
{
/**
* The self link.
*/
const REL_SELF = 'self';
/**
* @var string a URI [RFC3986](https://tools.ietf.org/html/rfc3986) or
* URI template [RFC6570](https://tools.ietf.org/html/rfc6570). This property is required.
*/
public $href;
/**
* @var string a secondary key for selecting Link Objects which share the same relation type
*/
public $name;
/**
* @var string a hint to indicate the media type expected when dereferencing the target resource
*/
public $type;
/**
* @var boolean a value indicating whether [[href]] refers to a URI or URI template.
*/
public $templated = false;
/**
* @var string a URI that hints about the profile of the target resource.
*/
public $profile;
/**
* @var string a label describing the link
*/
public $title;
/**
* @var string the language of the target resource
*/
public $hreflang;
/**
* @inheritdoc
*/
public function toArray()
{
return array_filter((array)$this);
}
/**
* Serializes a list of links into proper array format.
* @param array $links the links to be serialized
* @return array the proper array representation of the links.
*/
public static function serialize(array $links)
{
foreach ($links as $rel => $link) {
if (is_array($link)) {
foreach ($link as $i => $l) {
$link[$i] = $l instanceof self ? $l->toArray() : ['href' => $l];
}
$links[$rel] = $link;
} elseif (!$link instanceof self) {
$links[$rel] = ['href' => $link];
}
}
return $links;
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* Linkable is the interface that should be implemented by classes that typically represent locatable resources.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface Linkable
{
/**
* Returns a list of links.
*
* Each link is either a URI or a [[Link]] object. The return value of this method should
* be an array whose keys are the relation names and values the corresponding links.
*
* If a relation name corresponds to multiple links, use an array to represent them.
*
* For example,
*
* ```php
* [
* 'self' => 'http://example.com/users/1',
* 'friends' => [
* 'http://example.com/users/2',
* 'http://example.com/users/3',
* ],
* 'manager' => $managerLink, // $managerLink is a Link object
* ]
* ```
*
* @return array the links
*/
public function getLinks();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment