-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Twig templates render function & Doctrine proxy object - symfony 2.2.0 #7124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
can you try with the latest 2.2 branch ? |
I use symfony / symfony-standard as my starting repo. I merged tag 2.2.0-RC2 when this issue appeared, now I merged 2.2 branch and the same issue is still there. |
The same issue is still present in 2.2.0-RC3. I don't know how symfony2 processes internal requests but for some reasons it converts doctrine proxy object to array. When I use old method for embedding controllers |
@dalibor983 look at the newest post on symfony.com which explains the new fragment sub framework. Also since you are doing a subrequest you should pass the item id instead of the object, you cant pass object through hinclude, esi etc. so the internal request system does not allow it either. |
@henrikbjorn Hinclude performs caching on the browser (ajax request is used to load some part of the page and that part is cached by the browser; when you open the same page again cached parts is loaded from browser and there is't request sent to the server), esi & ssi perform caching by another service on the same machine where application is placed or on some another machine (when some parts is cached by some service e.g. varnish service, those parts is taken from that service, request is not sent to original server). But internal request is not for caching it is there to not repeat yourself (to not duplicate your code). Internal request is processed by symfony itself (this is the same process, request is not sent to other service). If I must pass only id to "render" function in twig template this means that I must perform the same SQL query to find object with that id (I must duplicate requests to database, and duplicate memory usage because it is the same process and in this way I get two same objects in memory). This is ridiculous. Caching is another story. There is't processing, evaluations, sending requests to database, caching service simple returns cached content. |
you don't get 2 same objects as Doctrine reuses them. and if you use |
If I need to pass only id through "require" twig function why does my first example work when I pass whole entity object like this |
@dalibor983 internal requests are handled in the exact same way as the hinclude, esi, ssi. So that they are for not repeating yourself isn't exactly true. |
@henrikbjorn not exactly. the controller notation supports passing objects around |
I upgraded my project to 2.2.0 version and this bug is still present. Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer::render($uri, Request $request, array $options = array())
$reference = null;
// if uri is instance of ControllerReference - in my situation it is
if ($uri instanceof ControllerReference) {
// $reference become $uri
$reference = $uri;
// generation of $uri string - the problem is in this methode
$uri = $this->generateFragmentUri($uri, $request);
}
$subRequest = $this->createSubRequest($uri, $request);
// override Request attributes as they can be objects (which are not supported by the generated URI)
if (null !== $reference) {
$subRequest->attributes->add($reference->attributes);
}
$level = ob_get_level();
try {
// request handling replaces all attributes in $subRequest->attributes->add($reference->attributes);
// with attributes from $uri
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
... Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer::generateFragmentUri(ControllerReference $reference, Request $request)
...
// avery object in $reference->attributes will be stringfyed with public attributes
// @see http://php.net/manual/en/function.http-build-query.php
// string http_build_query ( mixed $query_data [, string $numeric_prefix [, string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )
// query_data
// If query_data is an object, then only public properties will be incorporated into the result.
$reference->query['_path'] = http_build_query($reference->attributes, '', '&');
... So in my case I have doctrine proxy object in antributes with public option __isInitialized__ in this case $uri = $this->generateFragmentUri($uri, $request); will generate string like this // this is url decoded string
http://<domain>/app_dev.php/_fragment?_path=desc=Change current city&cityDef[__isInitialized__]=1&_format=html&_controller=ZugmeFrontendBundle:Default:cityFinder In $subRequest->attributes I also have "cityDef" doctrine proxy object, so $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); will send "cityDef" parameter to my controller action not like doctrine proxy object but like array $cityDef = array (
"__isInitialized__" => 1
) This will happen for all objects with public parameters not only with doctrine proxy object!!! One solution is the method Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer::generateFragmentUri(ControllerReference $reference, Request $request) processes only standard types (integers, strings, arrays, booleans) not complex objects, and complex objects should be processed by $subRequest->attributes->add($reference->attributes); |
If this cannot be fixed is there something like COMPONENTS from symfony 1.x (http://symfony.com/legacy/doc/book/1_0/en/07-Inside-the-View-Layer#chapter_07_sub_components) in symfony 2.x.x |
any news on this issue? |
I think I'm encountering the same bug. Can I do something to help get this patch in production?`` |
If the twig render() function isn't primarily for internal internal requests then I'm not sure why it appears to be the new center piece of embedding controllers (per the symfony2 docs)? @stof : can you explain please? Code like the following now appears to be useless:
If you could make sense of this apparent regression in capability it would be most appreciated. Is there another function to use instead? |
@ErichHartmann Your code should work as expected. What does not work is when your render this controller as an ESI or HInclude for instance. The possibility to use objects for the inline rendering strategy was fixed before the release of 2.2.0 (see #6942). I've just tried just to double-check, and it works well. If it does not work for you, can you fork the Symfony Standard Edition and add the minimal amount of code there to exhibit the issue that you have? |
@stof is it possible using a combination of both objects and other data types for the inline rendering strategy breaks things ? I am rendering a controller inline and it works fine when I give an object or object collection as argument. When for example I pass both a simple integer variable and an object(collection) the passed in data just disappears. |
@codeMonkeysBe I've just tested with a combination of objects and scalars and it works for me. So, I'm pretty sure that there is something else going on but I don't know what it is. |
@ErichHartmann your code will working if your 'entity' does not have any public properties. If it has, it will be replaced with array with property - value pairs. Sometimes results from doctrine queries or many to one relations are returned like doctrine proxy objects (strategy to reduce requests sent to database, in some other frameworks this strategy is called 'deferred execution'). Doctrine proxy object has 'isInitialized' public property so in this case you will lose all data. In your controller you will get only $entity = array (
"__isInitialized__" => 1
) The reason for this is: $reference->query['_path'] = http_build_query($reference->attributes, '', '&'); in 'Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer::generateFragmentUri(ControllerReference $reference, Request $request)' |
@fabpot I forked the standard edition and added some code to break things. git@github.com:codeMonkeysBe/symfony-standard.git In the InlineTestController I pass an array with 2 elements to the template. An object and a scalar. In the template I pass this array to an inline controller. In that inline controller I just print_r the contents of that array and the entity disappeared, the scalar is still there. Strange behavior. Sorry if the way of forking/adding code is a bit funky. This is my first time doing so . |
@dalibor983 You are right but for the inline strategy, passing objects works. I've just added a unit test to prove that: cc75831 @codeMonkeysBe Thanks, I'm going to have a look at your code. |
@fabpot this issue really occurs. We got same problem with |
@codeMonkeysBe Thanks for your code. I'm now able to reproduce your issue. @Koc That's why tests are not always the panacea ;) Now that I have a reproducible test case, I will be able to investiguate further. |
ok, I've identified the problem and I think I have a working patch. Can you test again after applying this patch (https://github.com/symfony/symfony/pull/8438.patch)? |
This fixes it for me. Thanks! |
This PR was merged into the 2.2 branch. Discussion ---------- Render objects fix | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #7124 | License | MIT | Doc PR | n/a Commits ------- 82dbaee [HttpKernel] fixed the inline renderer when passing objects as attributes (closes #7124)
@dalibor983, et al, thanks for the correction. I was confused, because the following prototype code was adding another, redundant DB query to retrieve every Comment entity in entities despite passing the fully populated object to the controller. One purpose of passing the entity was to avoid re-calling the DB. I misunderstood stof's above comment to read that object was not actually passed; given my own tests concluded that the re-query is happening somewhere between twig's render function and the entity's arrival at the controller.
|
* 2.2: Update JsonResponse.php [HttpKernel] fixed the inline renderer when passing objects as attributes (closes #7124) [WebProfiler] fix content-type parameter Replace romaji period characters with Japanese style zenkaku period characters Passed the config when building the Configuration in ConfigurableExtension Conflicts: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
* 2.3: Update JsonResponse.php [HttpKernel] fixed the inline renderer when passing objects as attributes (closes #7124) CookieJar remove unneeded var, Client remove unneeded else [DI] Fixed bug requesting non existing service from dumped frozen container Update validators.sk.xlf [WebProfiler] fix content-type parameter Replace romaji period characters with Japanese style zenkaku period characters fixed CS fixed CS [Console] Avoided an unnecessary check. Added missing French validator translations typo first->second Passed the config when building the Configuration in ConfigurableExtension removed unused code Fixed variable name used in translation cache Conflicts: src/Symfony/Component/Console/Event/ConsoleCommandEvent.php
@fabpot I've installed the above patch, but I am still seeing what appears to be the Sensio\Bundle\FrameworkExtraBundle\EventListener\ParamConverterListener re-instigating doctrine queries to the already passed and populated entity as invoked by the kernel.controller event. When the kernel.controller is done, the re-queried entity is passed to the controller called in the render function. I apologize if this makes little sense, but I am trying to interpret the profiler and its timeline. This may be another issue unrelated to above, or no issue at all. I notice this behavior, however, is new with the new render function. |
* 2.2: Update JsonResponse.php [HttpKernel] fixed the inline renderer when passing objects as attributes (closes symfony#7124) [WebProfiler] fix content-type parameter Replace romaji period characters with Japanese style zenkaku period characters Passed the config when building the Configuration in ConfigurableExtension Conflicts: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
* 2.3: Update JsonResponse.php [HttpKernel] fixed the inline renderer when passing objects as attributes (closes symfony#7124) CookieJar remove unneeded var, Client remove unneeded else [DI] Fixed bug requesting non existing service from dumped frozen container Update validators.sk.xlf [WebProfiler] fix content-type parameter Replace romaji period characters with Japanese style zenkaku period characters fixed CS fixed CS [Console] Avoided an unnecessary check. Added missing French validator translations typo first->second Passed the config when building the Configuration in ConfigurableExtension removed unused code Fixed variable name used in translation cache Conflicts: src/Symfony/Component/Console/Event/ConsoleCommandEvent.php
When you pass doctrine proxy object to twig render function e.g.
where "md" is entity with property "item" that represent object of many to one relationship, render function converts proxy object to array and "indexAction" of "ExampleController" gets that array instead of proxy object and you lose all access to getters and setters.
See this issue #7122;
The text was updated successfully, but these errors were encountered: