Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2 module custom response class

Tags:

php

yii2

I have defined a custom response class and was trying to use it in a module.

In the controller action i return an array of results, but the custom response class isn't used.

Instead, the class used is the default yii\web\Response

My implementation

The module configuration in config/web.php:

'mymodule' => [
        'class' => 'app\modules\mymod\Mymod',
        'components' => [                
            'response' => [
                'class' => 'app\modules\mymod\components\apiResponse\ApiResponse',
                'format' => yii\web\Response::FORMAT_JSON,
                'charset' => 'UTF-8',
            ],
        ],
    ],

In the controller i edited the behaviors method:

public function behaviors() {
    $behaviors = parent::behaviors();        
    $behaviors['contentNegotiator'] = [
        'class' => 'yii\filters\ContentNegotiator',            
        'response' => $this->module->get('response'),                
        'formats' => [  //supported formats
            'application/json' => \yii\web\Response::FORMAT_JSON,
        ],
    ];
    return $behaviors;
}

In the action if i do:

public function actionIndex() {

    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

    $dataList = [
        ['id' => 1, 'name' => 'John', 'surname' => 'Davis'],
        ['id' => 2, 'name' => 'Marie', 'surname' => 'Baker'],
        ['id' => 3, 'name' => 'Albert', 'surname' => 'Bale'],
    ];
    return $dataList;
}

I get this result (as expected from yii\web\Response):

[
{
    "id": 1,
    "name": "John",
    "surname": "Davis"
},
{
    "id": 2,
    "name": "Marie",
    "surname": "Baker"
},
{
    "id": 3,
    "name": "Albert",
    "surname": "Bale"
}
]

But if i change the action to this:

$dataList = [
    ['id' => 1, 'name' => 'John', 'surname' => 'Davis'],
    ['id' => 2, 'name' => 'Marie', 'surname' => 'Baker'],
    ['id' => 3, 'name' => 'Albert', 'surname' => 'Bale'],
];
//return $dataList;

$resp = $this->module->get('response'); //getting the response component from the module configuration
$resp->data = $dataList;

return $resp;

Then i get the expected result, which is this:

{
"status": {
    "response_code": 0,
    "response_message": "OK",
    "response_extra": null
},
"data": [
    {
        "id": 1,
        "name": "John",
        "surname": "Davis"
    },
    {
        "id": 2,
        "name": "Marie",
        "surname": "Baker"
    },
    {
        "id": 3,
        "name": "Albert",
        "surname": "Bale"
    }
]}

It seems the behaviors i defined aren't doing anything.

What do i need to do to just return the array in the action and the custom response component is used?

Thanks in advance

like image 611
Jepi Avatar asked Aug 05 '16 16:08

Jepi


People also ask

What is controller in yii2?

Controllers are part of the MVC architecture. They are objects of classes extending from yii\base\Controller and are responsible for processing requests and generating responses.

How to set header in yii2?

You can send HTTP headers by manipulating the header collection in the response component. For example, $headers = Yii::$app->response->headers; // add a Pragma header. Existing Pragma headers will NOT be overwritten.


1 Answers

yii\base\Module does not have response component, so your configuration will not work. Instead of adding response component into your module You sould change Yii::$app->response inside MyMod::init() function.

If you want completely replace Yii::$app->response by your own component:

public function init()
{
    parent::init();

    \Yii::configure(\Yii::$app, [
        'components' => [
            'response' => [
                'class' => 'app\modules\mymod\components\apiResponse\ApiResponse',
                'format' => yii\web\Response::FORMAT_JSON,
                'charset' => 'UTF-8',
            ],
        ]
    ]);
}

But i think that this is a bad idea to completely replace Response component of parent application in a module. The better way is modify Response behavior for your needs. For example You can use EVENT_BEFORE_SEND and build your own data structure in response:

public function init()
{
    parent::init();

    // you can use ContentNegotiator at the level of module
    // and remove this behavior declaration from controllers
    \Yii::configure($this, [
        'as contentNegotiator' => [
            'class' => 'yii\filters\ContentNegotiator',
            // if in a module, use the following IDs for user actions
            // 'only' => ['user/view', 'user/index']
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
            ],
        ],
    ]);


    // you can daclare handler as function in you module and pass it as parameter here
    \Yii::$app->response->on(Response::EVENT_BEFORE_SEND, function ($event) {
        $response = $event->sender;
        // here you can get and modify everything in current response 
        // (data, headers, http status etc.)
        $response->data = [
            'status' => 'Okay',
            'data' => $response->data
        ];
    });
}
like image 75
oakymax Avatar answered Oct 13 '22 04:10

oakymax