当构建 API 时,你往往需要一个转换层来联结你的 Eloquent 模型和实际返回给用户的 JSON 响应。Laravel 的资源类能够让你以更直观简便的方式将模型和模型集合转化成 JSON。
参考:https://learnku.com/articles/25947#106dba
thinkphp也有类似的Api-Resource功能,Yii2虽然有restful Api功能,但是难以定制其Api的data关联格式,而且关联的字段需要存在于url之中。
不知道Yii2如何实现类似的功能呢?
https://getyii.com/topic/66 能满足你部分需求
@forecho #1楼 我在github提交过相关的问题:https://github.com/yiisoft/yii2/issues/17208 得到的邮件回复是这样的:
This can be done by a trick:
Assume you have a BaseQuery and BaseActiveRecord,
in BaseQuery rewrite all method
public function all($db = null)
{
$records = parent::all($db);
foreach ($records as &$record) {
if ($record instanceof ActiveRecord) {
$record = $record->toArray([], $record->getRelationNames(), 1);
}
}unset($record);
return $records;
}
in BaseActiveRecord define a method
public function getRelationNames()
{
return array_keys($this->relatedRecords);
}
Then never ->asArray()->all() which ignore fields(),
instead directly use find()->...->all(), all relations will be expanded recursively.
This is my BaseQuery:
private static $model;
private $customSelectColumns = [];
private $customAsArray = false;
private $customExtraFields = [];
public function init()
{
parent::init();
$this->baseSelect();
}
/**
* @param bool $value
* @return $this|\yii\db\ActiveQuery
*/
public function asArray($value = true)
{
$this->customAsArray = $value;
parent::asArray(false);
return $this;
}
/**
* @param null $db
* @return array|\yii\db\ActiveRecord[]
*/
public function all($db = null)
{
$records = parent::all($db);
foreach ($records as &$record) {
if ($record instanceof ActiveRecord && $this->customAsArray) {
$record = $record->toArray($this->customSelectColumns, $this->customExtraFields);
}
}
unset($record);
return $records;
}
/**
* @param null $db
* @return array|\yii\db\ActiveRecord|null
*/
public function one($db = null)
{
$record = parent::one($db);
if ($this->customAsArray) {
$record = $record->toArray($this->customSelectColumns, $this->customExtraFields);
}
return $record;
}
/**
* @param array|string|\yii\db\ExpressionInterface $columns
* @param null $option
* @return \yii\db\ActiveQuery
*/
public function select($columns, $option = null)
{
if (is_array($columns) && ! empty($columns)) {
$columns = $this->getRealColumns($columns);
} else {
$columns = array_intersect($this->getModel()->attributes(),
$this->getRealColumns(parent::select($columns, $option)->select));
}
return parent::select($columns, $option);
}
protected function baseSelect()
{
return $this->select([]);
}
private function getRealColumns(array $columns)
{
list($addColumns, $deleteColumns) = $this->devideColumns($columns);
$this->customSelectColumns = array_merge($this->customSelectColumns, $addColumns);
if (! $this->customSelectColumns) {
$this->customSelectColumns = $this->getModel()->attributes();
}
$this->customSelectColumns = array_diff($this->customSelectColumns, $deleteColumns);
return $this->customSelectColumns = array_unique($this->customSelectColumns);
}
private function devideColumns(array $columns)
{
$addAttributes = $this->getModel()->attributes();
$deleteAttributes = array_map(function ($v) {
return '!'.$v;
}, $addAttributes);
$addColumns = $deleteColumns = [];
foreach ($columns as $column) {
if (in_array($column, $addAttributes)) {
$addColumns[] = $column;
} elseif (in_array($column, $deleteAttributes)) {
$deleteColumns[] = ltrim($column, '!');
}
}
return [$addColumns, $deleteColumns];
}
/**
* @return \common\models\BaseActiveRecord
*/
private function getModel()
{
return (static::$model instanceof $this->modelClass)
? static::$model
: (static::$model = new $this->modelClass);
}
/**
* @param array $extraFields
* @return $this
*/
public function extra(array $extraFields)
{
$this->customExtraFields = $extraFields;
return $this;
}
没能看明白具体怎么继承,怎么使用。老大能否尝试指点下。@forecho
@forecho [#1楼](#comment1) 另外不知道现在yii3是个什么样的进度呢?完全的composer不下来,不知道yii3能否默认支持这样的api资源需求呢?