Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a "Headers already sent" error in Yii when rendering a view in beforeAction

Tags:

yii

yii2

I've read about Yii2's handlers and I don't grasp how to use them properly for this case.

Basically in my SiteController, I have:

class SiteController extends \app\components\Controller
{
    public function beforeAction($action)
    {
        // Makes some checks and if it's true, will render a file and stop execution of any action
        if (...)
            echo $this->render('standby');
            return false;
        }
        return true;
    }

    // All my other actions here
}

This seems to work well and stop the execution, however I get the "Headers already sent" for the render() line, as if it was doing a redirection.

If I write Yii::$app-end() instead of return false, same thing happens.

If I write exit(); instead of return false, no exception shows but the debug panel doesn't show since Yii doesn't terminate correctly.

I tried removing echo $this->render(..) and it results in an empty page, no redirection whatsoever, this seems like it's only Yii complaining that I echo stuff from the Controller.

And of course I can't return the result of render() or return true, since it will execute the page's action, which I'm trying to avoid and end here.

I know returning false in beforeAction() triggers EVENT_BEFORE_ACTION but I don't see where I'm supposed to use that. The events documentation didn't really help me.

So is there a way to display the "standby" view, preventing other actions from executing and avoid the error message for echoing from the Controller?

Please note that I'm trying to make this work without having to duplicate code in each action method to check if the result of beforeAction() was false.

like image 590
Bobs Avatar asked May 15 '18 16:05

Bobs


1 Answers

Since Yii 2.0.14 you cannot echo in controller - response must be returned by action. If you want to generate response in beforeAction() you need to setup Yii::$app->response component instead of echoing content:

public function beforeAction($action) {
    // Makes some checks and if it's true, will render a file and stop execution of any action
    if (...) {
        Yii::$app->response->content = $this->render('standby');
        Yii::$app->response->statusCode = 403; // use real HTTP status code here

        return false;
    }

    return parent::beforeAction($action);
}

Don't forget to call parent::beforeAction($action) - omitting it will result unexpected and hard to debug behavior.

like image 143
rob006 Avatar answered Dec 25 '22 11:12

rob006