2
votes

OK, first of all a disclaimer. I'm working on my first Sf2 project and working through an existing sf1 project, refactoring it to Sf2 to gain an understanding of where all the drawers have been moved to.

Now, something odd is happening and it has me tearing out the last of my hair.

--- TL;DR: summary ---

I am rendering a controller from a twig template and passing an array through to that sub-controller. One of the array values is an object, but that object is disappearing before it ever gets to the controller.

I've chased it through the Symfony2 flow as far as a I can and the object is intact as far as I can trace. I then get lost, but somewhere between Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer::render() and my (sub)controller the object disappears.

Is this a feature, a bug or just me going crazy?

--- In detail ---

I have a twig template that is dealing with an entity object (assigned to the twig variable 'collection') which contains linked entities such as imageItem and linkedPageItem).

My entities have been set up to extend a base class which implements ArrayAccess so I can access the values using array notation whether the objects are hydrated or not. (Following the option #1 methodology outlined here: http://docs.doctrine-project.org/en/latest/cookbook/implementing-arrayaccess-for-domain-objects.html ).

In twig I have a line like this which passes some objects through to a sub-controller to render an image block. The renderImage sub-controller manages the cleaning up of everything before rendering a twig block of its own.

Here's the code from the main twig file:

{# blockLinks.html.twig #}
...
{{- render(controller(
    'MyBundle:Helper:renderImage',
    {
        'image': collection['imageItem'], 
        'options': {
            'html_options': { 'class': 'foo' },
            'link_options': { 'class': 'bar' },
            'link_url':     collection['item_link_url'],
            'link_page':    collection['linkedPageItem']
        }
    }
)) -}}
...

However, the renderImage sub-controller never receives the value of $options['link_page'].

This was odd so I dug into it in more detail. I found the PHP file that twig renders blockLinks.html.twig into, and delved into that.

In there we find:

// /app/cache/dev/twig/01/30/lotsofnumbers.php
...
echo $this->env->getExtension('http_kernel')->renderFragment($this->env->getExtension('http_kernel')->controller(
    "CaponicaFdsWebsiteBundle:Helper:renderImage", 
    array(
        "image" => $this->getAttribute($_collection_, "imageItem", array(), "array"), 
        "options" => array(
            "html_options" => array("class" => "foo"), 
            "link_options" => array("class" => "bar"),
            "link_url" => $this->getAttribute($_collection_, "item_link_url", array(), "array"), 
            "link_page" => $this->getAttribute($_collection_, "linkedPageItem", array(), "array")
        )
    )
));
...

OK, looks fine.

To figure out what's going on I did \Doctrine\Common\Util\Debug::dump($this->getAttribute($_collection_, "linkedPageItem", array(), "array")); and it reports that this does, indeed, return a Page object.

i.e. it reports something like:

object(stdClass)[874]
  public '__CLASS__' => string 'MyBundle\Entity\Page'
...

Starting from the compiled twig php file in cache
-> Symfony\Bridge\Twig\Extension\HttpKernelExtension::renderFragment()
-> Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
-> Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer::render()

At this point the object is still intact (seen by dumping $subRequest->attributes->get('options') just before the call to $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); on line 62 of InlineFragmentRenderer)

I'm not sure where it goes next. I thought it went to [\vendor\symfony\symfony\src]Symfony\Bundle\FrameworkBundle\HttpKernel but I can't seem to track any activity there.

However, if I look in the renderImage controller and dump the options like this:

// MyBundle\Controller\HelperController.php

public function renderImageAction($image, $options = array()) {
    print_r(\Doctrine\Common\Util\Debug::dump($options)); // I'm sure there's a 1337 way to use the logger/toolbar for this, I'll figure that out some other day
    ...
}

I get this:

array (size=2)
  'html_options' => 
    array (size=1)
      'class' => string 'foo' (length=3)
  'link_options' => 
    array (size=1)
      'class' => string 'bar' (length=3)

In other words, the 'link_page' object has been removed from the options - something hungry (and quite scary) seems to be lurking in the depths of Symfony and eating my objects!

Is this a feature? (That you cannot pass an object inside an array to a sub-request... perhaps that angers the super-strict MVC gods?)
Or is it a bug? (Something is eating things it shouldn't?)
Or have I just got completely the wrong end of this particular stick?

I hope somebody can help, before I lose the last strands of hair...

C

1
Are you using {{- or {{ in your twig template?cheesemacfly
I'm using {{- in the part shown (some other parts of the template don't use the whitespace control)caponica
That might be a silly question but why are you using {{- instead of {{? What's the - there for?cheesemacfly
It's for managing whitespace (see twig.sensiolabs.org/doc/templates.html#whitespace-control ), the - removes preceding (or following) whitespace when combined with {{, }}, {% or %}caponica
Just found it in twig documentation. Really sorry I can't help but thanks, I learned something :)cheesemacfly

1 Answers

0
votes

You can pass objects when using the render function in combination with the controller function. I mean, it is supposed to be supported, and should work the way you did it.

But maybe you encounter the same bug as this guy, which seems to be specifically related to Doctrine2 objects: https://github.com/symfony/symfony/issues/7124