Yii2:定义“ID”以外的REST API参数

时间:2017-03-15 14:43:59

标签: yii2 yii2-advanced-app

我正在尝试使用YII2 REST API(基于高级模板)来创建自己的服务。我目前正在使用以下URL成功返回一条“文章”记录:

http://service/articles/view?id=1

我现在正在尝试复制此代码,因此它适用于其他记录类型。我的新记录有一个名为' key '的主键,我想搜索一下。因此,我需要将参数名称“ id ”更改为“ key ”。

有人可以解释如何在此网址上指定“ id ”以外的参数吗?每当我省略id作为参数时,我得到一个“错误请求:缺少必需参数:id ”。我不明白这个必需参数的来源以及如何更改或添加它。

相关课程如下:

class ArticleController extends ActiveController
{
    /**
     * @var string
     */
    public $modelClass = 'frontend\modules\api\v1\resources\Article';
    /**
     * @var array
     */
    public $serializer = [
        'class' => 'yii\rest\Serializer',
        'collectionEnvelope' => 'items'
    ];

    /**
     * @inheritdoc
     */
    public function actions()
    {
        return [
            'index' => [
                'class' => 'yii\rest\IndexAction',
                'modelClass' => $this->modelClass,
                'prepareDataProvider' => [$this, 'prepareDataProvider']
            ],
            'view' => [
                'class' => 'yii\rest\ViewAction',
                'modelClass' => $this->modelClass,
                'findModel' => [$this, 'findModel']
            ],
            'options' => [
                'class' => 'yii\rest\OptionsAction'
            ]
        ];
    }

    /**
     * @return ActiveDataProvider
     */
    public function prepareDataProvider()
    {
        return new ActiveDataProvider(array(
            'query' => Article::find()->published()
        ));
    }

    /**
     * @param $id
     * @return array|null|\yii\db\ActiveRecord
     * @throws HttpException
     */
    public function findModel($id)
    {
        $model = Article::find()
            ->published()
            ->andWhere(['id' => (int) $id])
            ->one();
        if (!$model) {
            throw new HttpException(404);
        }
        return $model;
    }
}

class Article extends \common\models\Article implements Linkable
{
    public function fields()
    {
        return ['id', 'slug', 'category_id', 'title', 'body', 'published_at'];
    }

    public function extraFields()
    {
        return ['category'];
    }

    /**
     * Returns a list of links.
     *
     * @return array the links
     */
    public function getLinks()
    {
        return [
            Link::REL_SELF => Url::to(['article/view', 'id' => $this->id], true)
        ];
    }
}

提前致谢。

编辑:'frontend'文件夹结构中urlManager的规范如下:

<?php
return [
    'class'=>'yii\web\UrlManager',
    'enablePrettyUrl'=>true,
    'showScriptName'=>false,
    'rules'=> [
        // Pages
        ['pattern'=>'page/<slug>', 'route'=>'page/view'],

        // Articles
        ['pattern'=>'article/index', 'route'=>'article/index'],
        ['pattern'=>'article/attachment-download', 'route'=>'article/attachment-download'],
        ['pattern'=>'article/<slug>', 'route'=>'article/view'],

        // Api
        ['class' => 'yii\rest\UrlRule', 'controller' => 'api/v1/article', 'only' => ['index', 'view', 'options']],
        ['class' => 'yii\rest\UrlRule', 'controller' => 'api/v1/user', 'only' => ['index', 'view', 'options']]
    ]
];

3 个答案:

答案 0 :(得分:1)

我不知道这是否是官方的做法,但我已经创建了一个额外的Action来处理这种情况。似乎“id”参数来自于反映Action中的“run”方法调用,因此我可以使用一个名为“key”的不同参数的唯一方法是通过完全相同的方式定义函数:

class ExtraAction extends Action  // in yii/rest
{
    public function run($key)  // NOTE: The name 'key' is reflected and then becomes an expected parameter
    {
        $model = $this->findModel($key);

        if (!$model) {
            throw new HttpException(404);
        }
        return $model;
    }
}

完成后,我需要更改我的actions()定义,如下所示:

    'view' => [
        'class' => 'yii\rest\ExtraAction',
        'modelClass' => $this->modelClass,
        'findModel' => [$this, 'findModel']
    ],
控制器中的

findModel($ id)将接收GET URL中定义的'key'参数(例如,api / v1 / article?key = blah123)。

然后我可以根据我拥有的不同唯一键执行查找:

public function findModel($id)
{
    $model = Record::find()
    ->andWhere(['key_field' => $id])
    ->one();    
} 

我不知道这是否是正确的做法,但它确实适用于这种情况。

答案 1 :(得分:1)

这可以通过在配置文档中向urlmanager添加规则来实现here

示例:

'rules' => [
    [   'class' => 'yii\rest\UrlRule',
        'pluralize' => false,
        'controller' => [
            'yourController',
        ],
        'patterns' => [
            'PUT,PATCH {id}' => 'update',
            'DELETE {id}' => 'delete',
            'GET,HEAD {id}' => 'view',
            'GET,HEAD {key}' => 'view',
            'POST' => 'create',
            'GET,HEAD' => 'index',
            '{id}' => 'options',
            'OPTIONS' => 'options',
            'PUT,PATCH {key}' => 'update',
        ],
         'tokens' => [
            '{id}' => '<id:\\d[\\d,]*>',
            '{type}' => '<type:\\w[\\w,]*>',
            '{key}' => '<key:\\w[\\w,]*>',
        ],
    ],
]

将动作映射添加到yourController

class YourController extends ActiveController {

    public $modelClass = 'your\model\Class';

    public function actions() {
        return array_merge(parent::actions(), [
            'view' => [
                'class' => \rest\your\ViewAction',
                'modelClass' => $this->modelClass,
            ],
        ]);
    }
}

并将密钥参数添加到您的操作

class ViewAction  extends \yii\rest\ViewAction {

    public function run($id = null, $key = null)
    {
        // your code
    }
}

现在你应该能够做到这一点

GET your/{keyparam} -> wil resolve to yourController -> ViewAction

答案 2 :(得分:0)

像往常一样在public function actionView2($your_desired_parameter) { $article = Article::find()->where(['your_desired_parameter'=>$your_desired_parameter]); if (!$article->exists()) throw new NotFoundHttpException(); return $article->one(); } 内创建新方法:

?v