Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Form] Sometimes checking for form.parent view in Twig is wrong #24892

Copy link
Copy link
Closed
@yceruto

Description

@yceruto
Issue body actions
Q A
Bug report? yes
Feature request? no
BC Break report? no
RFC? no
Symfony version 2.7

Hi there!

This morning I faced an issue in EasyAdminBundle related to form themes and form.parent check in Twig.

Briefly, the problem happen if we have a simple form with a field named parent. The situation gets worse depending on whether the parent field has children or not.

First, let's see the FormView class, especially the parent property and \ArrayAccess methods:

class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
{
/**
* The variables assigned to this view.
*/
public $vars = array(
'value' => null,
'attr' => array(),
);
/**
* The parent view.
*/
public $parent;
/**
* The child views.
*
* @var FormView[]
*/
public $children = array();
/**
* Is the form attached to this renderer rendered?
*
* Rendering happens when either the widget or the row method was called.
* Row implicitly includes widget, however certain rendering mechanisms
* have to skip widget rendering when a row is rendered.
*
* @var bool
*/
private $rendered = false;
private $methodRendered = false;
public function __construct(FormView $parent = null)
{
$this->parent = $parent;
}
/**
* Returns whether the view was already rendered.
*
* @return bool Whether this view's widget is rendered
*/
public function isRendered()
{
if (true === $this->rendered || 0 === count($this->children)) {
return $this->rendered;
}
foreach ($this->children as $child) {
if (!$child->isRendered()) {
return false;
}
}
return $this->rendered = true;
}
/**
* Marks the view as rendered.
*
* @return $this
*/
public function setRendered()
{
$this->rendered = true;
return $this;
}
/**
* @return bool
*/
public function isMethodRendered()
{
return $this->methodRendered;
}
public function setMethodRendered()
{
$this->methodRendered = true;
}
/**
* Returns a child by name (implements \ArrayAccess).
*
* @param string $name The child name
*
* @return self The child view
*/
public function offsetGet($name)
{
return $this->children[$name];
}
/**
* Returns whether the given child exists (implements \ArrayAccess).
*
* @param string $name The child name
*
* @return bool Whether the child view exists
*/
public function offsetExists($name)
{
return isset($this->children[$name]);
}

In PHP context there's no problem, the main form view has the $form->parent property and its children's fields ($form['parent']), each one accessible unmistakably by syntax. But, in Twig context, this access/check {% if form.parent is null/empty %} causes a naming collision. The parent attribute is resolved by Twig following the steps below:

https://twig.symfony.com/doc/2.x/templates.html#variables
For convenience's sake form.parent does the following things on the PHP layer:

Therefore, the parent child field view is returned instead of the real parent view (which is null in this case)!

There's some place in the source where this kind of check is done and surely in many bundles and apps:
form_parent

I'm not sure if there's a workaround for current projects/bundles rely on the Symfony form themes templates. I don't think it is a bug of Twig either, but a design error of the FormView class, which is specially designed to work in Twig context.

We may need a getter method for this parent property by now and check {% if form.getParent %} everywhere avoiding the first rule. Wdyt? thoughts?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.