Что-то ест мои объекты между веткой и субконтроллером

Хорошо, прежде всего отказ от ответственности. Я работаю над своим первым проектом Sf2 и работаю над существующим проектом sf1, рефакторингом его в Sf2, чтобы понять, куда были перемещены все ящики.

Теперь происходит что-то странное, и я вырываю последние волосы.

--- TL;DR: резюме ---

Я визуализирую контроллер из шаблона ветки и передаю массив этому субконтроллеру. Одно из значений массива является объектом, но этот объект исчезает еще до того, как попадает в контроллер.

Я преследовал его в потоке Symfony2, насколько это возможно, и насколько я могу отследить, объект не поврежден. Затем я теряюсь, но где-то между Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer::render() и моим (суб)контроллером объект исчезает.

Это фича, баг или я просто схожу с ума?

--- Подробно ---

У меня есть шаблон ветки, который имеет дело с объектом объекта (назначенным переменной "коллекция" ветки), который содержит связанные объекты, такие как imageItem и linkedPageItem).

Мои объекты были настроены для расширения базового класса, который реализует ArrayAccess, поэтому я могу получить доступ к значениям, используя нотацию массива, независимо от того, гидратированы ли объекты или нет. (Следуя методологии варианта № 1, описанной здесь: http://docs.doctrine-project.org/en/latest/cookbook/implementing-arrayaccess-for-domain-objects.html).

В twig у меня есть такая строка, которая передает некоторые объекты субконтроллеру для рендеринга блока изображения. Субконтроллер renderImage управляет очисткой всего перед рендерингом собственного блока веток.

Вот код из основного файла ветки:

{# 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']
        }
    }
)) -}}
...

Однако субконтроллер renderImage никогда не получает значение $options['link_page'].

Это было странно, поэтому я углубился в детали. Я нашел файл PHP, в который twig преобразует blockLinks.html.twig, и углубился в него.

Там мы находим:

// /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")
        )
    )
));
...

Хорошо, выглядит нормально.

Чтобы выяснить, что происходит, я сделал \Doctrine\Common\Util\Debug::dump($this->getAttribute($_collection_, "linkedPageItem", array(), "array"));, и он сообщает, что это действительно возвращает объект Page.

то есть он сообщает что-то вроде:

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

Начиная с скомпилированного php-файла twig в кеше
-> Symfony\Bridge\Twig\Extension\HttpKernelExtension::renderFragment()
-> Symfony\Component\HttpKernel\Fragment\FragmentHandler::render()
-> Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer::render()

На данный момент объект все еще не поврежден (что видно по дампу $subRequest->attributes->get('options') непосредственно перед вызовом $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); в строке 62 InlineFragmentRenderer)

Я не уверен, куда это пойдет дальше. Я думал, что он ушел в [\vendor\symfony\symfony\src]Symfony\Bundle\FrameworkBundle\HttpKernel, но я не могу отследить там какую-либо активность.

Однако, если я загляну в контроллер renderImage и выгружу такие параметры:

// 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
    ...
}

Я получаю это:

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

Другими словами, объект 'link_page' был удален из опций - кажется, что-то голодное (и довольно страшное) скрывается в глубинах Symfony и поедает мои объекты!

Это особенность? (То, что вы не можете передать объект внутри массива в подзапрос... возможно, это злит сверхстрогих богов MVC?)
Или это ошибка? (Что-то ест то, чего не должно?)
Или я просто взял не тот конец палки?

Я надеюсь, что кто-нибудь может помочь, прежде чем я потеряю последние пряди волос...

C


person caponica    schedule 10.04.2013    source источник
comment
Вы используете {{- или {{ в своем шаблоне ветки?   -  person cheesemacfly    schedule 10.04.2013
comment
Я использую {{- в показанной части (некоторые другие части шаблона не используют элемент управления пробелами)   -  person caponica    schedule 10.04.2013
comment
Это может быть глупый вопрос, но почему вы используете {{- вместо {{? Для чего там -?   -  person cheesemacfly    schedule 10.04.2013
comment
Он предназначен для управления пробелами (см. twig.sensiolabs.org/doc/templates.html#). whitespace-control), - удаляет предшествующие (или следующие) пробелы в сочетании с {{, }}, {% или %}   -  person caponica    schedule 10.04.2013
comment
Просто нашел его в документации ветки. Очень жаль, что не могу помочь, но спасибо, я кое-что узнал :)   -  person cheesemacfly    schedule 10.04.2013
comment
Я не могу помочь вам с деталями, но я предполагаю, что это связано с тем, что Sf выполняет подзапрос в фоновом режиме, который похож на обычный HTTP-запрос, но пропускает часть http. Вместо этого попробуйте передать идентификатор объекта и получить его в контроллере подзапроса.   -  person Maerlyn    schedule 11.04.2013
comment
@Maerlyn, значит, вы не можете передать массив объектов контроллеру Symfony?   -  person caponica    schedule 11.04.2013
comment
Я считаю, что вы можете передавать массивы, но не объекты.   -  person Maerlyn    schedule 11.04.2013
comment
Это ограничение где-нибудь задокументировано?   -  person caponica    schedule 11.04.2013
comment
Не то, что я знаю из. Это скорее догадка, чем определенный ответ, поэтому это просто комментарий.   -  person Maerlyn    schedule 12.04.2013


Ответы (1)


Вы можете передавать объекты при использовании функции рендеринга в сочетании с функцией контроллера. Я имею в виду, что он должен поддерживаться и должен работать так, как вы это сделали.

Но, возможно, вы столкнулись с той же ошибкой, что и этот парень, которая, похоже, связана именно с объектами Doctrine2: https://github.com/symfony/symfony/issues/7124

person Pierre-Yves    schedule 04.06.2013