Question

Lets say i have a one to many relation:

  • A company can own several pictures
  • I have company entity and image entity

Now, I want to display all pictures of a company within a template. And i also want to make theese pictures directly editable. I thought of adding a form to each Entity of the DoctrineArrayCollection and pass them to the template. In Template if somebody clicks on a picture the corresponding should be fade in, the should be able to edit the pictures description and pass it through ajax to a controller.

In my entity I added a field without annotations:

    private $form;

    public function setForm(MyPictureForm $form)
    {
        $this->form = $form;
    }

    public function getForm()
    {
        return $this->form;
    }

Now in my controller I add a form instance to every picture of the company:

     //office images with forms
        $officeImages = array();
        foreach($company->getOfficeImages() as $image)
        {
            $form = $this->get('companybundle.imagedescription.form.factory')->createForm();
            $form->setData($image);
            $image->setForm($form->createView());
            array_push($officeImages, $image);
        }


        return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
            'company'         => $company,
            'officeImages'    => $officeImages
        ));

    }

And in my template i render it like this way:

           {% for image in officeImages %}
            <a href="#" title="{% if image.description %}{{ company.description }}{% else %}CLICK HERE FOR EDIT{% endif %}">

                {% if image.image %}
                        <img src="{{ vich_uploader_asset(image, 'image') | imagine_filter('company_office_image_thumb') }}"
                             alt="{% if image.description %}{{ company.description }}{% endif %}"/>
                {% else %}
                    {% image '@UserBundle/Resources/public/img/nopic_logo.jpg' output='/images/nopic_logo.jpg' %}
                    <img src="{{ asset_url }}" alt="Joblogo"/>
                    {% endimage %}
                {% endif %}

            </a>
                {{ form(image.form) }}
            {% else %}
                <p>Es sind noch keine Images vorhanden</p>
            {% endfor %}

At the end there is a lot if javascript stuff which handels the fade in / fade out of the form and their submitting.

Is this the correct way to handle my case? I think not cause passing a form for every picture seems like overhead?

The reason why I am working with forms instead of simply passing data out of a manual added input field is csrf protection and the smart usage of the form component.

Was it helpful?

Solution

As you said keeping form object in entity isn't a good idea. It should represents model data.

I've got two solutions for this:

I. Pass array of forms with image id as a key

$officeImages = array();
$imageForms = array();

foreach($company->getOfficeImages() as $image)
{
    $form = $this->get('companybundle.imagedescription.form.factory')->createForm();
    $form->setData($image);

    $imageForms[$image->getId()] = $form->createView();
}


return $this->render('CompanyBundle:Company:Show/show.html.twig', array(
    'company'         => $company,
    'officeImages'    => $officeImages,
    'imageForms'      => imageForms
));

and in show.html.twig

{% for image in officeImages %}

     {# your image display code #}

     {{ form(imageForms[image.id]) }}
{% endfor %}

II. render partial for single image

in controller

public function showAndEditImageAction(Image $image) 
{
     $form = $this->get('companybundle.imagedescription.form.factory')->createForm();
     $form->setData($image);

     return $this->render(
        'CompanyBundle:Company:Show/showAndEditImage.html.twig', array(
        'image' => $image,
        'imageForm'  => $form->createView()
     ));
}

in twigs

{# CompanyBundle:Company:Show/showAndEditImage.html.twig #}

{# your image display code #}

{{ form(imageform) }}
{# CompanyBundle:Company:Show/show.html.twig #}

{% for image in officeImages %}
    {{ render(controller('CompanyBundle:Company:showAndEditImage', 
        { 'image': image })) }}
{% endfor %}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top