Closed jhon100 closed 5 years ago
Indeed, order of events should be the same.
Do you want to try fixing it?
Well, as I mentioned above, when the request is normal or ajax, the event is fired from the run() function of yii\web\Application.
On the other hand, if the request is Pjax, the event is triggered from the end() function of yii yii\base\Application, but only under this conditions:
public function end($status = 0, $response = null)
{
if ($this->state === self::STATE_BEFORE_REQUEST || $this->state === self::STATE_HANDLING_REQUEST) {
$this->state = self::STATE_AFTER_REQUEST;
$this->trigger(self::EVENT_AFTER_REQUEST);
}
So in the same way as in the run() function of yii\web\Application, before firing the event I set the variable 'state'. (This ensures that the event will not be fired twice)
yii\widgets\Pjax.php
public function run()
{
[...]
Yii::$app->state = Yii::$app::STATE_AFTER_REQUEST;
Yii::$app->trigger(Yii::$app::EVENT_AFTER_REQUEST);
[...]
$response->send();
Yii::$app->end();
}
Now the order of events is the same regardless of the type of request, but I'm not familiar with the core code, so I don't know if this change can affect anything else or if some other widget has the same problem. I did a search for $response->send() and I found the codes below that, apparently, also send the response without first triggering EVENT_AFTER_REQUEST.
\yii\filters\HostControl > function denyAccess($action) \yii\web\ErrorHandler > function renderException($exception)
So I don't know if the problem is unique to Pjax or also in other parts of the framework that call response ->send() without first firing EVENT_AFTER_REQUEST
Verified in 2.0.24
: this bug exists.
Events run as described below:
ajax or normal request trigger event: afterRequest trigger event: beforeSend trigger event: afterPrepare trigger event: afterSend
pjax request trigger event: beforeSend trigger event: afterPrepare trigger event: afterSend trigger event: afterRequest
This causes the problem: https://github.com/yiisoft/yii2/blob/90d46298addda275b5ad5afb4e399b768083b5e6/framework/widgets/Pjax.php#L164-L173
I find this solution a bit weird :)
I'm working on this bug.
@jhon100 plase test this fix: https://github.com/yiisoft/yii2/pull/17526
The docs for yii\web\Application says that:
However in a pjax request, the event is being triggered AFTER the response is sent out. You can test it with this code:
Do a request, you will see in debug:
ajax or normal request trigger event: afterRequest trigger event: beforeSend trigger event: afterPrepare trigger event: afterSend
pjax request trigger event: beforeSend trigger event: afterPrepare trigger event: afterSend trigger event: afterRequest
So, you'll fail to change something in response (like cookies) if you are listening to this event and the request is Pjax.
Executing step by step I can see this:
ajax or normal request ...yii\web\Application run method (all code inside run method is executed)
pjax request ...yii\web\Application run method
For Pjax, the following calls are made after
'$response = $this->handleRequest($this->getRequest());'
for brevity some calls are omitted go to yii\base\View phprenderPhpFile() _ calls require $file; go to view file calls Pjax::end() go to yii\base\Widget\ end() calls $result = $widget->run(); go to yii\widgets\Pjax run() _ calls $response->send(); // no EVENT_AFTERREQUEST triggered calls Yii::$app->end(); go to yii\base\Application end() _ calls $this->trigger(self::EVENT_AFTERREQUEST); calls $response->send(); // again go to \yii2\web\Response.php send()
go to \yii\base\Application.php _ calls exit($status);
Suggestion Maybe add
Yii::$app->trigger(Yii::$app::EVENT_AFTER_REQUEST);
in yii\ widgets\Pjax run () before $response->send (); be enough?. In this case it would be interesting some logic to prevent the event from being triggered twice ...Additional info