I can't display embedded, nested form in Symfony 3

Clément MARTZLOFF

I have a big issue because I can't find any solutions for my problem on Internet. I work on a Post Entity from which I want to add Images Entities. The idea is when I log in my app, I can write a post and upload one or n images. After that, the user will allow to see the images from his posts for example.

I am at the step one, It seems I can't display my CollectionClass::Class of my ImageType::Class in my PostType.php. I haven't errors, it's simply not displayed in the view. Thanks in advance!

PostType.php

<?php

    namespace UserBundle\Form;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\CollectionType;
    use UserBundle\Entity\Post;


    class PostType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('title')
                ->add('content')
                ->add('images', CollectionType::class, [
                    'entry_type' => ImageType::class,
                    'entry_options' => array('label' => false),
                    'allow_add' => true,
                ]);
            ;
        }
        
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => Post::class,
            ));
        }

        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'userbundle_post';
        }
    }

ImageType.php

<?php

    namespace UserBundle\Form;

    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\FileType;
    use UserBundle\Entity\Image;

    class ImageType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('file', FileType::class, ['required' => false, 'data_class' => null]);
        }
        
        /**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => Image::class,
            ));
        }

        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'userbundle_image';
        }
    }

Post.php

<?php

    namespace UserBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    use Doctrine\Common\Collections\ArrayCollection;

    /**
     * Post
     *
     * @ORM\Table(name="post")
     * @ORM\Entity(repositoryClass="UserBundle\Repository\PostRepository")
     */
    class Post
    {
        /**
         * @var int
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

        /**
         * @var string
         *
         * @ORM\Column(name="Title", type="string", length=255)
         */
        private $title;

        /**
         * @var string
         *
         * @ORM\Column(name="Content", type="text")
         */
        private $content;


        /**
         * @ORM\ManyToOne(targetEntity="User", inversedBy="posts")
         * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
        */
        private $user;

        /**
         * @ORM\OneToMany(targetEntity="Image", mappedBy="post", cascade={"persist"})
         */
        private $images;

        /**
         * Get id
         *
         * @return int
         */
        public function getId()
        {
            return $this->id;
        }

        /**
         * Set title
         *
         * @param string $title
         *
         * @return Post
         */
        public function setTitle($title)
        {
            $this->title = $title;

            return $this;
        }

        /**
         * Get title
         *
         * @return string
         */
        public function getTitle()
        {
            return $this->title;
        }

        /**
         * Set content
         *
         * @param string $content
         *
         * @return Post
         */
        public function setContent($content)
        {
            $this->content = $content;

            return $this;
        }

        /**
         * Get content
         *
         * @return string
         */
        public function getContent()
        {
            return $this->content;
        }

        /**
         * Set post
         *
         * @param \
         *
         * @return Post
         */
        public function setUser($user)
        {
            $this->user = $user;

            return $this;
        }

        /**
         * Get post
         *
         * @return \?
         */
        public function getUser()
        {
            return $this->user;
        }
        /**
         * Constructor
         */
        public function __construct()
        {
            $this->images = new \Doctrine\Common\Collections\ArrayCollection();
        }

        /**
         * Add image
         *
         * @param \UserBundle\Entity\Image $image
         *
         * @return Post
         */
        public function addImage(\UserBundle\Entity\Image $image)
        {
            $this->images[] = $image;

            return $this;
        }

        /**
         * Remove image
         *
         * @param \UserBundle\Entity\Image $image
         */
        public function removeImage(\UserBundle\Entity\Image $image)
        {
            $this->images->removeElement($image);
        }

        /**
         * Get images
         *
         * @return \Doctrine\Common\Collections\Collection
         */
        public function getImages()
        {
            return $this->images;
        }
    }

Image.php

<?php
    // src/UserformBundle/Entity/Image

    namespace UserBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;

    /**
     * @ORM\Entity(repositoryClass="UserBundle\Entity\ImageRepository")
     */
    class Image
    {
      /**
       * @ORM\Column(name="id", type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;

      /**
       * @ORM\Column(name="url", type="string", length=255)
       */
      private $url;

      /**
       * @ORM\Column(name="alt", type="string", length=255)
       */
      private $alt;

      private $file;
      
      public function getFile()
      {
        return $this->file;
      }

      public function setFile(UploadedFile $file = null)
      {
        $this->file = $file;
      }
      

      /**
       * @ORM\ManyToOne(targetEntity="Post", inversedBy="images")
       * @ORM\JoinColumn(name="post_id", referencedColumnName="id")
      */
      private $post;
      

      /**
       * Get id
       *
       * @return integer
       */
      public function getId()
      {
          return $this->id;
      }

      /**
       * Set url
       *
       * @param string $url
       *
       * @return Image
       */
      public function setUrl($url)
      {
          $this->url = $url;

          return $this;
      }

      /**
       * Get url
       *
       * @return string
       */
      public function getUrl()
      {
          return $this->url;
      }

      /**
       * Set alt
       *
       * @param string $alt
       *
       * @return Image
       */
      public function setAlt($alt)
      {
          $this->alt = $alt;

          return $this;
      }

      /**
       * Get alt
       *
       * @return string
       */
      public function getAlt()
      {
          return $this->alt;
      }

      /**
       * Set post
       *
       * @param \UserBundle\Entity\Post $post
       *
       * @return Image
       */
      public function setPost(\UserBundle\Entity\Post $post = null)
      {
          $this->post = $post;

          return $this;
      }

      /**
       * Get post
       *
       * @return \UserBundle\Entity\Post
       */
      public function getPost()
      {
          return $this->post;
      }
    }

EDIT
My Post New action view: new.html.twig

    {% extends 'base.html.twig' %}
        {% block javascripts %}
            <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
            {# Voici le script en question : #}
            <script type="text/javascript">
                $(document).ready(function() {
                    // On récupère la balise <div> en question qui contient l'attribut « data-prototype » qui nous intéresse.
                    var $container = $('div#userbundle_post_images');

                    // On définit un compteur unique pour nommer les champs qu'on va ajouter dynamiquement
                    var index = $container.find(':input').length;

                    // On ajoute un nouveau champ à chaque clic sur le lien d'ajout.
                    $('#add_category').click(function(e) {
                        addImage($container);
                        e.preventDefault(); // évite qu'un # apparaisse dans l'URL
                        return false;
                    });
                    // On ajoute un premier champ automatiquement s'il n'en existe pas déjà un (cas d'une nouvelle annonce par exemple).
                    if (index == 0) {
                        addImage($container);
                    } else {
                        // S'il existe déjà des catégories, on ajoute un lien de suppression pour chacune d'entre elles
                        $container.children('div').each(function() {
                            addDeleteLink($(this));
                        });
                    }

                    // La fonction qui ajoute un formulaire CategoryType
                    function addImage($container) {
                        // Dans le contenu de l'attribut « data-prototype », on remplace :
                        // - le texte "__name__label__" qu'il contient par le label du champ
                        // - le texte "__name__" qu'il contient par le numéro du champ
                        var template = $container.attr('data-prototype')
                            .replace(/__name__label__/g, 'Catégorie n°' + (index+1))
                            .replace(/__name__/g,        index)
                        ;

                        // On crée un objet jquery qui contient ce template
                        var $prototype = $(template);

                        // On ajoute au prototype un lien pour pouvoir supprimer la catégorie
                        addDeleteLink($prototype);

                        // On ajoute le prototype modifié à la fin de la balise <div>
                        $container.append($prototype);

                        // Enfin, on incrémente le compteur pour que le prochain ajout se fasse avec un autre numéro
                        index++;
                    }

                    // La fonction qui ajoute un lien de suppression d'une catégorie
                    function addDeleteLink($prototype) {
                        // Création du lien
                        var $deleteLink = $('<a href="#" class="btn btn-danger">Supprimer l\'image</a>');

                        // Ajout du lien
                        $prototype.append($deleteLink);

                        // Ajout du listener sur le clic du lien pour effectivement supprimer la catégorie
                        $deleteLink.click(function(e) {
                            $prototype.remove();

                            e.preventDefault(); // évite qu'un # apparaisse dans l'URL
                            return false;
                        });
                    }
                });
            </script>
        {% endblock %}

        {% block body %}
            <h1>Post creation</h1>
            {{ form_start(form) }}
                {{ form_row(form.title) }}
                {{ form_row(form.content) }}
                <a href="#" id="add_category" class="btn btn-default">Ajouter une Image</a>
                {{ form_row(form.images) }}
                <br/>
                <input type="submit" value="Create" />
            {{ form_end(form) }}

            <ul>
                <li>
                    <a href="{{ path('post_index') }}">Back to the list</a>
                </li>
            </ul>
        {% endblock %}

EDIT: PostController.php

    /**
     * Creates a new post entity.
     *
     * @Route("/new", name="post_new")
     * @Method({"GET", "POST"})
     */
    public function newAction(Request $request)
    {
        $post = new Post();
        //dump($post);
        
        $user = $this->getUser();
        if (!is_object($user) || !$user instanceof UserInterface) {
            throw new AccessDeniedException('This user does not have access to this section.');
        }

        $form = $this->createForm('UserBundle\Form\PostType', $post);
        dump($form);
        //die();
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            
            // relate this post to the owner user
            $user->addPost($post);
            // relate the owner user to this post
            $post->setUser($user);

            $em = $this->getDoctrine()->getManager();
            $em->persist($post);
            $em->persist($user);
            $em->flush();

            return $this->redirectToRoute('post_show', array('id' => $post->getId()));
        }

        return $this->render('post/new.html.twig', array(
            'post' => $post,
            'form' => $form->createView(),
        ));
    }
netsuo

It would be useful to see your view but just a reminder: to be able to add new images your form needs some javascript, please look here: https://symfony.com/doc/current/form/form_collections.html#allowing-new-tags-with-the-prototype

Without javascript, by default it would only render already added collection objects. If you have none in your entity, it will display nothing by default.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Can I display validation errors above of an embedded form in Rails?

From Dev

I can't write into database with embebed form in symfony2

From Dev

Can't handle form with symfony

From Dev

Nested 1:M form display issue - Symfony2

From Dev

Don't display element label, but display element in a nested html form

From Dev

Processing Symfony Form in Embedded Controller

From Dev

Access embedded form data symfony

From Dev

How can I avoid a nested form situation?

From Dev

how can I find display libraries on embedded linux

From Dev

Can't use nested form on belongs_to Model - how should I handle this?

From Dev

I can't extend Form

From Dev

How can I display a Delphi form in a panel?

From Dev

Symfony2 File upload form don't display errors

From Dev

Symfony2 File upload form don't display errors

From Dev

Can't embed File Form to another Form In Symfony 2.8

From Dev

symfony 3 + FosUserBundle firewalled pages do not display login form

From Dev

symfony 3 + FosUserBundle firewalled pages do not display login form

From Dev

Rails - nested form won't display in edit template

From Dev

How can I best display this nested collection? (Can you tell me why my code isn't working?)

From Dev

Symfony 3: can't overwrite repository

From Dev

Maximum number of saved embedded form in Symfony 1.4

From Dev

Symfony2 embedded form labels

From Dev

symfony 2 error on multiple embedded form

From Dev

Symfony 2.3.6. nested form

From Dev

Why can't I see nested args?

From Dev

Why can't I use 'Type' as the name of an enum embedded in a struct?

From Dev

Can't get Symfony 2 toolbar to display on website

From Dev

Can't get Symfony 2 toolbar to display on website

From Dev

How do I display an empty field form for an embedded relationship in Rails Forms?

Related Related

  1. 1

    Can I display validation errors above of an embedded form in Rails?

  2. 2

    I can't write into database with embebed form in symfony2

  3. 3

    Can't handle form with symfony

  4. 4

    Nested 1:M form display issue - Symfony2

  5. 5

    Don't display element label, but display element in a nested html form

  6. 6

    Processing Symfony Form in Embedded Controller

  7. 7

    Access embedded form data symfony

  8. 8

    How can I avoid a nested form situation?

  9. 9

    how can I find display libraries on embedded linux

  10. 10

    Can't use nested form on belongs_to Model - how should I handle this?

  11. 11

    I can't extend Form

  12. 12

    How can I display a Delphi form in a panel?

  13. 13

    Symfony2 File upload form don't display errors

  14. 14

    Symfony2 File upload form don't display errors

  15. 15

    Can't embed File Form to another Form In Symfony 2.8

  16. 16

    symfony 3 + FosUserBundle firewalled pages do not display login form

  17. 17

    symfony 3 + FosUserBundle firewalled pages do not display login form

  18. 18

    Rails - nested form won't display in edit template

  19. 19

    How can I best display this nested collection? (Can you tell me why my code isn't working?)

  20. 20

    Symfony 3: can't overwrite repository

  21. 21

    Maximum number of saved embedded form in Symfony 1.4

  22. 22

    Symfony2 embedded form labels

  23. 23

    symfony 2 error on multiple embedded form

  24. 24

    Symfony 2.3.6. nested form

  25. 25

    Why can't I see nested args?

  26. 26

    Why can't I use 'Type' as the name of an enum embedded in a struct?

  27. 27

    Can't get Symfony 2 toolbar to display on website

  28. 28

    Can't get Symfony 2 toolbar to display on website

  29. 29

    How do I display an empty field form for an embedded relationship in Rails Forms?

HotTag

Archive