Can't reset $this->response in Controller. Where $this->response is taken from and when?

Hi all! i'm back again.

I'm having trouble in understanding where and when the $this->response in a controller is populated.

My question come up from the development of unit-tests. Actually in the setup method (run before each test case), i instantiate a NEW app passing to it a new DI container where i force the 'response' object to reset with this cose

    $di=DI::getDefault();
    $resp=new \Phalcon\Http\Response();
    $di->remove("response");
    $di->setShared("response", $resp);

and infact this work as in the debugger, when i'm in an action method, i see that response object is empty... but just can't understand why $this->response contain the response returned by the previous test case...

i'm pretty sure the Phalcon Application object that execute the action method is brand new as the first lines of my test case is the following

    $app=new Application($this->getDI());
    $resp=$app->handle("/controller1/action1");
    $cont=$resp->getContent();

where getDI return the $di object just resetted by the setup method.

Any idea?



2.0k

It seems a controller has property response.

    public function indexAction()
    {
        $this->response->setContent('test');
        var_dump($this->response);

        $resp = new \Phalcon\Http\Response();
        $this->di->setShared('response', $resp);

        var_dump($this->response);
        var_dump($this->di->get('response'));
        exit;
    }

The results:

object(Phalcon\Http\Response)[44]
...
object(Phalcon\Http\Response)[44]
...
object(Phalcon\Http\Response)[45]
...

Hi Kenjis, thanks for your reply! maybe i wasn't to clear in my first post but i'm aware that controller have a response property...

the problem is to understand where that property get populated and where values are taken from... the scope is to try reset it from outside the controller, not from inside.



2.0k

I got the behaivior.

A controller propertyresponse is created when you access $this->response at the first time in the controller. It was injected by Phalcon\Di\Injectable using DI container.

So after it, if you change the service in DI container, there is no change $this->response in the controller.

All you have to do is to set value to the response. You can do it anywhere, because response is public property.

$controller->response = new \Phalcon\Http\Response();
edited Jan '15

Well, after your hint i've just got it browsing the C code on the GIT repo and you are right!

I think the important part is here https://github.com/phalcon/cphalcon/blob/master/ext/di/injectable.c#L143

Well, first of all i can't really yet explain why the response property of controller is persisted also when the Application object that handle it is created brand new with a new clean DI container with this code ...

$app=new Application($this->getDI());

in the C code i see some comment relative to persistent property that seems to be stored in a local SessionBag... https://github.com/phalcon/cphalcon/blob/master/ext/di/injectable.c#L179 if i understood correctly this could explain the problem... but i'm not a C expert so it's not very clear to me what happens there.

Now, i think we should vote this as a bug. I think that in the DI pattern a magic method of php shouldn't be allowed to create a property getting a service only once and ignoring any future update. This make DI just unuseful. Could we call this anti-pattern?

Also i think a parent bug is that controller->response is used as the object sent back to browser instaed of taking it directly from the DI container.

What do you think about?



2.0k

Well, first of all i can't really yet explain why the response property of controller is persisted also when the Application object that handle it is created brand new with a new clean DI container with this code ...

It is because the controller object is shared in DI container. https://github.com/phalcon/cphalcon/blob/master/ext/dispatcher.c#L720

You have only one DI container and one shared controller object in it, don't you?

How about this?

$di = new Phalcon\DI();
$app = new Application($di);
$resp = $app->handle("/controller1/action1");
$cont = $resp->getContent();

I'm not sure this is a bug or not, I feel your test code might be no good, instead.

If you show simple working test code which we could run, we can see more.

edited Feb '15

Hi kenjis! Thanks much for your answer and sorry for the late. i had very intense time.

Well, your reply forced my to check something i was erroneusly convinced of: the fact that i was regenerating the DI each time (i mean for each test) - on the contrary for a bug in my code it was generated only once for each unit test class. In the end your answer solve my specific problem and now for each unit test i use a new Application and DI object that seems to be clean and brand new.

Anyway i would like to understand more the way Phalcon manage Controllers. With debugger i've tried to retrive from the DI the last used controller (while my bug , and so the problem too, were still there) with something like $di->get("HomeController") or $di->HomeController or $di->has("HomeController") but non of this gave me any result... so i wonder where the DI cache controllers invoked by the dispatcher are cached. do you have any clue?

Regarding what i would like to vote as a bug... I think the problem is logical and we don't need deep test code to say it is a bug. In general, if the scope of DI is to concentrate in one place (updatable) dependencies but via a shortcut to DI i risk to access a non-updated copy of the services... i think it appears a bit a nonsense...