etiennenoel
etiennenoel

Reputation: 575

Embed Symfony file form

I want to embed a form (ImageType) into another (VideoFileType) in Symfony. My first form contains a file input. Basically, it's an image that will uploaded and then resized according to many presets already defined.

My second form will embed the ImageType form. The second form is a VideoFileType form which contains the ImageType form. Basically, the ImageType will act as a thumbnail for the video file. The VideoFileType will also contain a second file input to upload the videoFile and finally a select box to select the corresponding VideoPreset.

So to recap, the VideoFileType will embed an ImageType.

My class structure is similar. I have a VideoFile which has a Thumbnail attribute that is an Image class

When I show only the ImageType and upload an image, everything works perfectly fine.

ImageType:

class ImageType extends AbstractType
{
    private $imageManager;

    public function __construct(ImageManager $imageManager) {
        $this->imageManager = $imageManager;
    }


    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('file', 'file');

        $builder->addEventListener(
            FormEvents::POST_SUBMIT,
            array($this, 'onPostSetData')
        );
    }

    public function getDefaultOptions(array $options) {
        return array('data_class' => 'OSC\MediaBundle\Entity\Image');
    }

    public function onPostSetData(FormEvent $event) {
        $image = $event->getData();
        $form = $event->getForm();

        //We need here to update the video file with the new content
        $image = $this->imageManager->uploadImage($image);
        $event->setData($image);

    }

    public function getName()
    {
        return 'image';
    }
}

VideoFileType

class VideoFileType extends AbstractType
{

    public $container;

    public $videoPresets = [];

    public function __construct(Container $container) {
        $this->container = $container;
        $videoPresets = $container->getParameter('osc_media.video.presets');
        foreach ($videoPresets as $key => $videoPreset) {
            array_push($this->videoPresets, $key);
        }

    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('thumbnail', new ImageType($this->container->get('osc_media.manager.image')));
        $builder->add('file', 'file');
        $builder->add('videoPreset', 'choice', array(
            'choices' => $this->videoPresets,
            'multiple' => false,
            'required' => true
        ));
        $builder->addEventListener(
            FormEvents::POST_SUBMIT,
            array($this, 'onPostSetData')
        );
        $builder->add('save', 'submit');
    }

    public function onPostSetData(FormEvent $event) {
        $videoFile = $event->getData();
        $form = $event->getForm();

    }


    public function getDefaultOptions(array $options) {
        return array('data_class' => 'OSC\MediaBundle\Entity\VideoFile');
    }

    public function getName()
    {
        return 'video_file';
    }
}

VideoFile

class VideoFile
{

    protected $file;

    public function setfile(File $file = null)
    {
        $this->file = $file;

        if ($file) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTime('now');
        }
    }

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

    public function __construct() {
        $this->thumbnail = new Image();
    }


    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $filename;

    /**
     * @var integer
     */
    private $position;

    /**
     * @var string
     */
    private $extension;

    /**
     * @var integer
     */
    private $size;

    /**
     * @var string
     */
    private $videoPreset;

    /**
     * @var integer
     */
    private $duration;

    /**
     * @var \DateTime
     */
    private $createdAt;

    /**
     * @var \DateTime
     */
    private $updatedAt;

    /**
     * @var string
     */
    private $height;

    /**
     * @var string
     */
    private $width;

    /**
     * @var \OSC\MediaBundle\Entity\Image
     */
    private $thumbnail;

    /**
     * @var \OSC\MediaBundle\Entity\Video
     */
    private $video;


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

    /**
     * Set name
     *
     * @param string $name
     * @return VideoFile
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set filename
     *
     * @param string $filename
     * @return VideoFile
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;

        return $this;
    }

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

    /**
     * Set position
     *
     * @param integer $position
     * @return VideoFile
     */
    public function setPosition($position)
    {
        $this->position = $position;

        return $this;
    }

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

    /**
     * Set extension
     *
     * @param string $extension
     * @return VideoFile
     */
    public function setExtension($extension)
    {
        $this->extension = $extension;

        return $this;
    }

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

    /**
     * Set size
     *
     * @param integer $size
     * @return VideoFile
     */
    public function setSize($size)
    {
        $this->size = $size;

        return $this;
    }

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

    /**
     * Set videoPreset
     *
     * @param string $videoPreset
     * @return VideoFile
     */
    public function setVideoPreset($videoPreset)
    {
        $this->videoPreset = $videoPreset;

        return $this;
    }

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

    /**
     * Set duration
     *
     * @param integer $duration
     * @return VideoFile
     */
    public function setDuration($duration)
    {
        $this->duration = $duration;

        return $this;
    }

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

    /**
     * Set createdAt
     *
     * @param \DateTime $createdAt
     * @return VideoFile
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt
     *
     * @return \DateTime 
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     * @return VideoFile
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime 
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /**
     * Set height
     *
     * @param string $height
     * @return VideoFile
     */
    public function setHeight($height)
    {
        $this->height = $height;

        return $this;
    }

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

    /**
     * Set width
     *
     * @param string $width
     * @return VideoFile
     */
    public function setWidth($width)
    {
        $this->width = $width;

        return $this;
    }

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

    /**
     * Set thumbnail
     *
     * @param \OSC\MediaBundle\Entity\Image $thumbnail
     * @return VideoFile
     */
    public function setThumbnail(\OSC\MediaBundle\Entity\Image $thumbnail = null)
    {
        $this->thumbnail = $thumbnail;

        return $this;
    }

    /**
     * Get thumbnail
     *
     * @return \OSC\MediaBundle\Entity\Image 
     */
    public function getThumbnail()
    {
        return $this->thumbnail;
    }

    /**
     * Set video
     *
     * @param \OSC\MediaBundle\Entity\Video $video
     * @return VideoFile
     */
    public function setVideo(\OSC\MediaBundle\Entity\Video $video = null)
    {
        $this->video = $video;

        return $this;
    }

    /**
     * Get video
     *
     * @return \OSC\MediaBundle\Entity\Video 
     */
    public function getVideo()
    {
        return $this->video;
    }
}

Image Class

class Image
{

    protected $file;

    public function setfile(File $file = null)
    {
        $this->file = $file;

        if ($file) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTime('now');
        }
    }

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



    /**
     * @var integer
     */
    private $id;

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    private $imageFiles;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->imageFiles = new \Doctrine\Common\Collections\ArrayCollection();
    }

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

    /**
     * Add imageFiles
     *
     * @param \OSC\MediaBundle\Entity\ImageFile $imageFiles
     * @return Image
     */
    public function addImageFile(\OSC\MediaBundle\Entity\ImageFile $imageFiles)
    {
        $this->imageFiles[] = $imageFiles;

        return $this;
    }

    /**
     * Remove imageFiles
     *
     * @param \OSC\MediaBundle\Entity\ImageFile $imageFiles
     */
    public function removeImageFile(\OSC\MediaBundle\Entity\ImageFile $imageFiles)
    {
        $this->imageFiles->removeElement($imageFiles);
    }

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

ImageFile

class ImageFile
{





    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $filename;

    /**
     * @var string
     */
    private $extension;

    /**
     * @var string
     */
    private $size;

    /**
     * @var string
     */
    private $imagePreset;

    /**
     * @var \DateTime
     */
    private $createdAt;

    /**
     * @var \DateTime
     */
    private $updatedAt;

    /**
     * @var string
     */
    private $height;

    /**
     * @var string
     */
    private $width;


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

    /**
     * Set name
     *
     * @param string $name
     * @return ImageFile
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set filename
     *
     * @param string $filename
     * @return ImageFile
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;

        return $this;
    }

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

    /**
     * Set extension
     *
     * @param string $extension
     * @return ImageFile
     */
    public function setExtension($extension)
    {
        $this->extension = $extension;

        return $this;
    }

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

    /**
     * Set size
     *
     * @param string $size
     * @return ImageFile
     */
    public function setSize($size)
    {
        $this->size = $size;

        return $this;
    }

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

    /**
     * Set imagePreset
     *
     * @param string $imagePreset
     * @return ImageFile
     */
    public function setImagePreset($imagePreset)
    {
        $this->imagePreset = $imagePreset;

        return $this;
    }

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

    /**
     * Set createdAt
     *
     * @param \DateTime $createdAt
     * @return ImageFile
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt
     *
     * @return \DateTime 
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     * @return ImageFile
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime 
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /**
     * Set height
     *
     * @param string $height
     * @return ImageFile
     */
    public function setHeight($height)
    {
        $this->height = $height;

        return $this;
    }

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

    /**
     * Set width
     *
     * @param string $width
     * @return ImageFile
     */
    public function setWidth($width)
    {
        $this->width = $width;

        return $this;
    }

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

However, when I try to create a VideoFileType form, I get the following error:

The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class OSC\MediaBundle\Entity\Image. You can avoid this error by setting the "data_class" option to "OSC\MediaBundle\Entity\Image" or by adding a view transformer that transforms an instance of class OSC\MediaBundle\Entity\Image to scalar, array or an instance of \ArrayAccess.

So, what I want, is the treatment of the ImageFileType (OnPostSetData) to be executed with the same success when embedded in VideoFileType as when used alone.

Then, after completion, I want the Image object to be inserted in the VideoFile as the thumbnail attribute. Afterwards, it should finish the treatment inside VideoFileType's OnPostSetData method.

If it's not feasible, I'll simply recreate ImageType's logic inside the VideoFileType and that is not a big deal. However, I feel that it could be nice if I could reuse the ImageFileType.

Upvotes: 2

Views: 398

Answers (2)

vardius
vardius

Reputation: 6546

This is verry easy if you want to extend formtype,

just do like this:

  1. Define your first form as a service
  2. Extend your second form using getParent method

    public function getParent() { return 'image'; }

doing like this you have the same fields in ur second form as in first and you can add some more.

Upvotes: 0

cb0
cb0

Reputation: 8613

I'm not a 100% sure but try adding this function to your ImageTypeclass.

use Symfony\Component\OptionsResolver\OptionsResolverInterface;
....
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'OSC\MediaBundle\Entity\Image'
    ));
}

And change the configuration for the thumbnail property inside buildForm in class VideoFileType.

$builder->add('thumbnail', 
               new ImageType($this->container->get('osc_media.manager.image')),
               array(
                  'data_class' => 'OSC\MediaBundle\Entity\Image'
               ));

Upvotes: 2

Related Questions