Symfony 3 - CollectionType сохраняет только первый элемент

У меня очень странная проблема. У меня есть объект: Свойство имеет подключение ManyToOne к изображениям

Когда я добавляю больше изображений для формы, когда я сохраняю ее, сохраняется только первое добавленное изображение, остальное - нет. Тем не менее, я могу добавлять новые изображения после каждого сохранения, но только по одному за раз.

Код: объект недвижимости

namespace Ciber\PropertyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use \Ciber\UtilBundle\Entity\Traits as CiberTraits;

/**
 * Property
 *
 * @ORM\Table(name="property")
 * @ORM\Entity(repositoryClass="Ciber\PropertyBundle\Repository\PropertyRepository")
 */
class Property
{
    use ORMBehaviors\Timestampable\Timestampable;
    use CiberTraits\AddressTrait;
    use CiberTraits\PriceTrait;
    use ORMBehaviors\Translatable\Translatable;

    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**
     *
     * @ORM\OneToMany(targetEntity="Ciber\PropertyBundle\Entity\PropertyImage", mappedBy="property", orphanRemoval=true, cascade={"persist"})
     */
    private $propertyImages;

    /**
     *
     * @ORM\OneToMany(targetEntity="Ciber\PropertyBundle\Entity\PropertyPlan", mappedBy="property", orphanRemoval=true, cascade={"persist"})
     */
    private $propertyPlans;


    /**
     * @ORM\ManyToOne(targetEntity="Ciber\UserBundle\Entity\User", inversedBy="properties", cascade={"persist"})
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;


    /**
     * Constructor
     */
    public function __construct()
    {
        $this->propertyImages = new ArrayCollection();
        $this->propertyPlans = new ArrayCollection();
    }

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


    /**
     * Add PropertyImage
     *
     * @param \Ciber\PropertyBundle\Entity\PropertyImage $propertyImage
     * @return Property
     */
    public function addPropertyImage(\Ciber\PropertyBundle\Entity\PropertyImage $propertyImage)
    {

        //$this->propertyImages[] = $propertyImage;
        $this->propertyImages->add($propertyImage);
        $propertyImage->setProperty($this);

        return $this;
    }

    /**
     * Remove propertyImage
     *
     * @param \Ciber\PropertyBundle\Entity\PropertyImage $propertyImage
     */
    public function removePropertyImage(\Ciber\PropertyBundle\Entity\PropertyImage $propertyImage)
    {
        $this->propertyImages->removeElement($propertyImage);
    }

    /**
     * Add propertyPlans
     *
     * @param \Ciber\PropertyBundle\Entity\PropertyPlan $propertyPlans
     * @return Property
     */
    public function addPropertyPlan(\Ciber\PropertyBundle\Entity\PropertyPlan $propertyPlans)
    {
        $this->propertyPlans[] = $propertyPlans;
        $propertyPlans->setProperty($this);

        return $this;
    }

    /**
     * Remove propertyPlans
     *
     * @param \Ciber\PropertyBundle\Entity\PropertyPlan $propertyPlan
     */
    public function removePropertyPlan(\Ciber\PropertyBundle\Entity\PropertyPlan $propertyPlan)
    {
        $this->propertyPlans->removeElement($propertyPlan);
    }

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


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

    /**
     * Gets triggered only on insert

     * @ORM\PrePersist
     */
    public function onPrePersist()
    {
        $this->createdAt = new \DateTime("now");
    }

    public function __call($method, $arguments)
    {
        return $this->proxyCurrentLocaleTranslation($method, $arguments);
    }
}

Сущность Picture

    namespace Ciber\PropertyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File as File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;

/**
 * PropertyImage
 *
 * @ORM\Table(name="property_image")
 * @ORM\Entity
 * @Vich\Uploadable
 */
class PropertyImage
{
    use ORMBehaviors\Timestampable\Timestampable;
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Ciber\PropertyBundle\Entity\Property", inversedBy="propertyImages")
     * @ORM\JoinColumn(name="property_id", referencedColumnName="id")
     */
    private $property;

    /**
     * NOTE: This is not a mapped field of entity metadata, just a simple property.
     *
     * @Vich\UploadableField(mapping="property_images", fileNameProperty="imageName")
     *
     * @var File
     */
    private $imageFile;

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

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


    /**
     *
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
     *
     * @return PropertyImage
     */
    public function setImageFile(File $image = null)
    {
        $this->imageFile = $image;

        if ($image) {
            $this->updatedAt = new \DateTime('now');
        }

        return $this;
    }

    /**
     * @return File
     */
    public function getImageFile()
    {
        return $this->imageFile;
    }

    /**
     * @param string $imageName
     *
     * @return PropertyImage
     */
    public function setImageName($imageName)
    {
        $this->imageName = $imageName;

        return $this;
    }

    /**
     * @return string
     */
    public function getImageName()
    {
        return $this->imageName;
    }

    /**
     * Set property
     *
     * @param \AppBundle\Entity\Property $property
     *
     * @return PropertyImage
     */
    public function setProperty( \Ciber\PropertyBundle\Entity\Property $property = null ) {
        $this->property = $property;

        return $this;
    }

    /**
     * Get property
     *
     * @return \Ciber\PropertyBundle\Entity\Property
     */
    public function getProperty() {
        return $this->property;
    }

    public function __toString()
    {
        return $this->imageName;
    }
}

Форма:

class FlatType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ...

            // Pictures
            ->add('propertyImages', CollectionType::class, array(
                'by_reference' => false,
                'entry_type' => PropertyImageType::class,
                'allow_add'    => true,
                'allow_delete' => true,
            ))
            ->add('propertyPlans', CollectionType::class, array(
                'by_reference' => false,
                'entry_type' => PropertyPlanType::class,
                'allow_add'    => true,
                'allow_delete' => true,
            ))

            ...
        ;
        $builder->add('save', ButtonType::class, array(
            'label' => 'property.form.save'
        ));
    }



    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ciber\PropertyBundle\Entity\Property',
        ));
    }
}

Интересный факт:

if ($request->isMethod('POST')) {
        $form->handleRequest($request);
        $property = $form->getData();
        dump($property); exit();
...

Когда я выбрасываю $ property - после отправки 2 фотографий одновременно, я получаю следующее:

elements: array:2 [▼
0 => PropertyImage {#3937 ▼
  -id: 10
  -isDefault: false
  -title: null
  -property: Property {#2799}
  -imageFile: null
  -imageName: "5939c65692d47.jpg"
  #createdAt: DateTime {#3933 ▶}
  #updatedAt: DateTime {#2605 ▶}
}
1 => PropertyImage {#4225 ▼
  -id: null
  -isDefault: false
  -title: null
  -property: Property {#2799}
  -imageFile: UploadedFile {#14 ▶}
  -imageName: null
  #createdAt: null
  #updatedAt: DateTime {#4224 ▶}
}
]

Я действительно понятия не имею, что здесь произошло (конечно, у меня есть больше полей, таких как заголовок, который, я думаю, не связан с этой проблемой. Однако, как вы видите, у меня также есть "PropertyPlans ArrayCollection, он делает ту же проблему. Только первый сохранился правильно)

РЕДАКТИРОВАТЬ. Вот мой контроллер:

/**
 * @Route("/properties/{property_category}/new", name="propertycreateindex")
 */
public function propertyCreateIndexAction(Request $request)
{

    $entity = new Property();
    $form = $this->createForm(Ciber\PropertyBundle\Form\FlatType, $entity);

    if ($request->isMethod('POST')) {
        $form->handleRequest($request);
        $property = $form->getData();
        $property->setUser($this->getUser());
        $property->setIsActive(1);
        $em = $this->getDoctrine()->getManager();
        $em->persist($property);
        $em->flush();
        $this->addFlash(
            'success',
            $this->get('translator')->trans('success.message.create_successfull')
        );
        return $this->redirectToRoute('dashboard');
    }

    return $this->render(view.html.twig, array(
        'form' => $form->createView(),
        'property' => $entity
    ));

}

И это PropertyImageType.php

namespace Ciber\PropertyBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichImageType;

class PropertyImageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('isDefault')
            ->add('title', TextType::class, array(
                'required' => false
            ))
            ->add('imageFile', VichImageType::class, array(
                'required' => false,
                'allow_delete' => true, // not mandatory, default is true
                'download_link' => false //  default is true
            ));

    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ciber\PropertyBundle\Entity\PropertyImage',
        ));
    }
}

1 ответ

Извините, это моя ошибка. После того, как я проспал несколько часов, я прошел повторное тестирование. Я нашел, я был неправ. Не первое, но последнее изображение сохранилось. Отсюда это был простой способ понять, я пропустил одну строчку из учебника.

newinputs.each(function(){
    $(this).attr('id', $(this).attr('id').replace(/__name__/g, $randomId));
    $(this).attr('name', $(this).attr('name').replace(/__name__/g, $randomId));
});

По умолчанию "property_name" CollectionType - это имя, которое вы должны изменить с помощью javascript после создания нового встраиваемого файла из form.prototype. Необходимо изменить имя во вновь создаваемых полях.

Другие вопросы по тегам