yii2是否有类似于laravel Api-Resource 资源功能呢?

新手提问 · dzoocn · 于 4年前 发布 · 4690 次阅读
当构建 API 时,你往往需要一个转换层来联结你的 Eloquent 模型和实际返回给用户的 JSON 响应。Laravel 的资源类能够让你以更直观简便的方式将模型和模型集合转化成 JSON。

参考:https://learnku.com/articles/25947#106dba

thinkphp也有类似的Api-Resource功能,Yii2虽然有restful Api功能,但是难以定制其Api的data关联格式,而且关联的字段需要存在于url之中。

不知道Yii2如何实现类似的功能呢?

共收到 9 条回复
forecho#14年前 1 个赞

https://getyii.com/topic/66 能满足你部分需求

dzoocn#24年前 0 个赞

@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

dzoocn#34年前 0 个赞

@forecho [#1楼](#comment1) 另外不知道现在yii3是个什么样的进度呢?完全的composer不下来,不知道yii3能否默认支持这样的api资源需求呢?

5楼 已删除.
lesliehuang#83年前 0 个赞

我也试试看,谢谢分享

9楼 已删除.
zx1222#103年前 0 个赞

谢谢分享

zh_111#113年前 0 个赞

@zx1222 #10楼 顶一个

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册