Handling multiple file uploads in Sonata Admin Bundle

For your solution to have multiple images for your company admin you have to organize your relation like there will be one junction entity which will point to sonata media entity in a ManyToOne relation and also to your products entity in a ManyToOne relation as well i have created this type of collection for one of needs for footer widgets which can have multiple images so you can map it for your products images as well in a similar way.

Footer Entity contains a property named as links which points to a junction entity FooterWidgetsHasMedia in OneToMany way,junction entity (FooterWidgetsHasMedia ) holds the relation to sonata media in addition i need multiple images for my each footer object and also for each image a in need a hover image too so my junction entity basically holds two properties that points to sonata media

FooterWidgets

/**
 * @Assert\NotBlank()
 * @ORM\OneToMany(targetEntity="Traffic\WidgetsBundle\Entity\FooterWidgetsHasMedia", mappedBy="footerWidget",cascade={"persist","remove"} )
 */
protected $links;


/**
 * Remove widgetImages
 *
 * @param \Application\Sonata\MediaBundle\Entity\Media $widgetImages
 */
public function removeLinks(\Traffic\WidgetsBundle\Entity\FooterWidgetsHasMedia $links)
{
    $this->links->removeElement($links);
}


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


/**
 * {@inheritdoc}
 */
public function setLinks($links)
{
    $this->links = new ArrayCollection();


    foreach ($links as $footerWidget) {
        $this->addLinks($footerWidget);
    }
}

/**
 * {@inheritdoc}
 */
public function addLinks(\Traffic\WidgetsBundle\Entity\FooterWidgetsHasMedia $links)
{
    $links->setFooterWidget($this);


    $this->links[] = $links;
}

Now my junction entity will points back to FooterWidgets and sonata media entity

FooterWidgetsHasMedia

Definitions of properties

/**
 * @var \Application\Sonata\MediaBundle\Entity\Media
 * @Assert\NotBlank()
 * @ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Media", cascade={"persist"}, fetch="LAZY")
 * @ORM\JoinColumn(name="media_id", referencedColumnName="id")
 */
protected $media;

/**
 * @var \Application\Sonata\MediaBundle\Entity\Media
 * @Assert\NotBlank()
 * @ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Media", cascade={"persist"}, fetch="LAZY")
 * @ORM\JoinColumn(name="media_hover_id", referencedColumnName="id")
 */
protected $mediaHover;

/**
 * @var \Traffic\WidgetsBundle\Entity\FooterWidgets
 * @Assert\NotBlank()
 * @ORM\ManyToOne(targetEntity="Traffic\WidgetsBundle\Entity\FooterWidgets", cascade={"persist","remove"} ,inversedBy="links", fetch="LAZY" )
 * @ORM\JoinColumn(name="footer_widget_id", referencedColumnName="id",nullable=true)
 */
protected $footerWidget;
/**
 * @var integer
 * @ORM\Column(name="position", type="integer")
 */
protected $position;


/**
 * @var boolean
 * @ORM\Column(name="enable", type="boolean")
 */
protected $enabled;

Generate getters and setters for above properties

Now you have to create new admin for your collection which references to junction entity FooterWidgetsHasMedia and configureFormFields will look something like below

FooterWidgetsHasMediaAdmin

protected function configureFormFields(FormMapper $formMapper)
{
    $link_parameters = array();

    if ($this->hasParentFieldDescription()) {
        $link_parameters = $this->getParentFieldDescription()->getOption('link_parameters', array());
    }

    if ($this->hasRequest()) {
        $context = $this->getRequest()->get('context', null);

        if (null !== $context) {
            $link_parameters['context'] = $context;
        }
    }

    $formMapper

        ->add('media', 'sonata_type_model_list', array('required' => false), array(
            'link_parameters' => $link_parameters
        ))
        ->add('mediaHover', 'sonata_type_model_list', array('required' => false), array(
            'link_parameters' => $link_parameters
        ))
        ->add('enabled', null, array('required' => false))
        ->add('link', 'text', array('required' => false))
        ->add('position', 'hidden')


    ;
}

And your company admin will have a new field in configureFormFields

FooterWidgetsAdmin

        ->add('links', 'sonata_type_collection', array(
                'cascade_validation' => false,
                'type_options' => array('delete' => false),
            ), array(

                'edit' => 'inline',
                'inline' => 'table',
                'sortable' => 'position',
                'link_parameters' => array('context' => 'widgets'),
                'admin_code' => 'sonata.admin.footer_widgets_has_media' /*here provide service name for junction admin */
            )
        )

Register admin service for your new admin as

sonata.admin.footer_widgets_has_media:
    class: Traffic\WidgetsBundle\Admin\FooterWidgetsHasMediaAdmin
    tags:
        - { name: sonata.admin, manager_type: orm, group: "Widgets", label: "Footer Widgets Section Media" , show_in_dashboard: false }
    arguments:
        - ~
        - Traffic\WidgetsBundle\Entity\FooterWidgetsHasMedia
        - ~
    calls:
        - [ setTranslationDomain, [TrafficWidgetsBundle]]

Demo snap shot

enter image description here

You can find full code demo here Git Hub hope it makes sense

Leave a Comment