sowiq
sowiq

Reputation: 422

Symfony EntityType - How to use custom layout?

In my Symfony 3.x project, I have 3 entities:

  1. Project
  2. Property
  3. Category

Assumptions:

I would like to render Symfony form for Project entity. I'm using EntityType field for properties. However, instead of displaying them in one, long list, I would like to divide them in columns, with Categories as headers.

Regular way of displaying EntityType field:

enter image description here

What I would like to get:

enter image description here

How do I do that? - Without using dirty hacks in entities or views.

Upvotes: 1

Views: 800

Answers (1)

sowiq
sowiq

Reputation: 422

So the only way I found it working was:

In Repository class (pulling list of all properties with child properties and categories):

$this->getEntityManager()
    ->createQueryBuilder()
    ->select('t, category, children')
    ->join('t.category', 'category')
    ->leftJoin('t.children', 'children')
    ->where('t.parent IS NULL')
    ->orderBy('category.sortOrder', 'ASC')
    ->addOrderBy('t.sortOrder', 'ASC')
    ->addOrderBy('t.name', 'ASC');

$entities = $query->getResult();

$options = [];
/** @var Property $entity */
foreach ($entities as $entity) {
    $options[$entity->getCategory()->getName()][] = $entity;
}

In Entity class (pulling the list of IDs of selected properties, to preselect checkboxes in the view file):

public function getPropertyIds() {
    $properties = $this->getProperties();

    $propertyIds = [];
    foreach ($properties as $property) {
        $propertyIds[] = $property->getId();
    }

    return $propertyIds;
}

Edition form class, so the data can be validated:

$builder
    ->add(
        'properties',
        EntityType::class,
        [
            'label' => 'Properties',
            'class' => Property::class,
            'choice_label' => 'name',
            'placeholder' => '',
            'expanded' => true,
            'multiple' => true,
            'required' => false,
        ]
    );

And finally, the view file:

{% for categoryName, items in properties %}
    <h2>{{ categoryName }}</h2>

    <ul>
        {% for property in items %}  
            <li>
                <input type="checkbox"
                       name="{{ form.properties.vars.full_name }}[]"
                       value="{{ property.id }}"
                       id="{{ form.properties.vars.id }}_{{ property.id }}">
                <label for="{{ form.properties.vars.id }}_{{ property.id }}">
                    {{ property.name }}
                </label>
            </li>
        {% endfor %}
    </ul>
{% endfor %}

{% do form.properties.setRendered %}

(I omitted the "checked" and "children" part in the view)

However this solution is not ideal in my point of view. I would rather to get rid of manually generating <input...> in the view - I would rather want to use some helper functions.

Anyway, this is some kind of low-level solution to my problem. Hope that helps.

Upvotes: 2

Related Questions