Simple example of the entity file to be uploaded with OneupUploaderBundle

Amine Jallouli picture Amine Jallouli · Oct 13, 2014 · Viewed 8.4k times · Source

I am try to use OneupUploaderBundle for uploading files. I read the documentation of this bundle many times but I did not manage to find any simple example of an entity for the file to be uploaded. My expectation is a class definition similar to the VichUploaderBundle:

<?php

namespace Minn\AdsBundle\Entity;

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

/**
 * @ORM\Entity
 * @Vich\Uploadable
 */
class MotorsAdsFile {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * @Assert\File(
     *     maxSize="5M",
     *     mimeTypes={"image/png", "image/jpeg"}
     * )
     * @Vich\UploadableField(mapping="motors_files", fileNameProperty="filename")
     * note: This is not a mapped field of entity metadata, just a simple property.
     * @var File $file
     */
    protected $file;

    /**
     * @ORM\Column(type="string", length=255, name="filename")
     * @var string $filename
     */
    protected $filename;

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

    // ... 
}

Hope my question is clear...

I am really interested by this bundle since it supports jQuery.

Thanks,

Answer

devsheeep picture devsheeep · Oct 15, 2014

There is no such thing as a predefined entity or ORM-handling. This has several reasons. This bundle can not foresee the projects need in terms of upload logic. If someone wants to store files to the database or not is entirely their own choice and should not be forced by a third party bundle. The thing the OneupUploaderBundle provides is a backend for the most common frontend uploaders there are.


Disclaimer: I've shorty copied and extended an answer that was already present in the GitHub issue tracker of this bundle. There you'll find quite a lot of insights on how and why this bundle is what it is now.


Given that you have already installed a working Symfony2 project, follow the installation instructions of the this bundle. I think step 1 and 2 should not be a problem, so lets hook directly to step 3, the configuration.

You said, you tried to integrate the jQuery File Uploader, so lets create a mapping for it. Open the file app/config/config.yml and add the following lines to the end of it.

oneup_uploader:
    mappings:
        gallery:
            frontend: blueimp

And of course, don't forget to add the following lines to app/config/routing.yml.

oneup_uploader:
    resource: .
    type: uploader

So much for the configuration. For the sake of simplicity we will alter the AcmeDemoBundle.

Open the file src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig and delete everything between {% block content %} and {% endblock %}. We don't need this anymore.

Now insert the following:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/vendor/jquery.ui.widget.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/jquery.fileupload.js"></script>

<script type="text/javascript">
$(document).ready(function() {
    $('#fileupload').fileupload({});
});
</script>

<input id="fileupload" type="file" name="files[]" data-url="{{ oneup_uploader_endpoint('gallery') }}" multiple />

Point your browser to the root directory of this application (app_dev.php). You'll see an input field just like expected and you can now upload some images (for example). The files will be stored in web/uploads/gallery every single one with a unique filename. Note that we used some CDNs to serve the JavaScript files needed for this.

At this point, you already have a working upload form. But besides uploading files to the uploads directory, it does nothing. This is where the Next step section in the documentation comes in handy.

As I understand your question, you want to create an entity which stores a file path of a related file in it. To do so, create your Entity class including all required fields.

<?php

namespace Minn\AdsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class MotorsAdsFile {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    public $id;
    /**
     * @ORM\Column(type="string", length=255, name="filename")
     * @var string $filename
     */
    protected $filename;

    // ... 
}

Then create an EventListener as described in the documentation of this bundle.

<?php

namespace Acme\HelloBundle\EventListener;

use Oneup\UploaderBundle\Event\PostPersistEvent;
use Minn\AdsBundle\Entity\MotorsAdsFile;

class UploadListener
{
    protected $manager;

    public function __construct(EntityManager $manager)
    {
        $this->manager = $manager;
    }

    public function onUpload(PostPersistEvent $event)
    {
        $file = $event->getFile();

        $object = new MotorsAdsFile();
        $object->setFilename($file->getPathName());

        $this->manager->persist($object);
        $this->manager->flush();
    }
}

And of course register your event listener.

<services>
    <service id="acme_hello.upload_listener" class="Acme\HelloBundle\EventListener\UploadListener">
        <argument type="service" id="doctrine.orm.entity_manager" />
        <tag name="kernel.event_listener" event="oneup_uploader.post_persist" method="onUpload" />
    </service>
</services>

At this point the EventListener will be called as soon as a new file was uploaded through the configured mapping. It takes this file, creates a new object of MotorsAdsFile and stores the file path to the filename property, persists and flushes it to the underlying database.

As I can't predict your actual logic, this is the most basic example I can think of. You're of course free to do whatever is needed in the event listener. (In case you need to store this object to another entity or the like.)

You'll find a bunch of other topics in the Next steps section of the documentation. For example how you'd change the naming strategy of the uploaded files or how to enable chunked uploads in case you need to upload big files.