2017 © Pedro Peláez
 

symfony-bundle doctrine-gaufrette-storable-bundle

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

image

ashleydawson/doctrine-gaufrette-storable-bundle

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

  • Wednesday, May 6, 2015
  • by AshleyDawson
  • Repository
  • 1 Watchers
  • 0 Stars
  • 73 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 1 Forks
  • 0 Open issues
  • 4 Versions
  • 0 % Grown

The README.md

Doctrine Gaufrette Storable Bundle

Build Status, (*1)

knpbundles.com, (*2)

Requirements

 >= PHP 5.4
 >= Symfony Framework 2.3

Doctrine Support

  • Support for Doctrine ORM - Complete
  • Support for Doctrine ODM - Incomplete

Introduction

I built this bundle to extend the excellent filesystem abstraction layer, Knp Lab's Gaufrette. In fact, this library extends the KnpGaufretteBundle., (*3)

This bundle implements an "uploaded file" handler on Doctrine entities, allowing Gaufrette to store the file as a part of the Doctrine entity lifecycle., (*4)

The first class citizen on the bundle is a trait that is applied to any Doctrine entity to give the Gaufrette handler the ability to persist file details along with the entity., (*5)

Installation

You can install the Doctrine Gaufrette Storable Bundle via Composer. To do that, simply require the package in your composer.json file like so:, (*6)

{
    "require": {
        "ashleydawson/doctrine-gaufrette-storable-bundle": "0.8.*"
    }
}

Run composer update to install the package. Then you'll need to register the bundle in your app/AppKernel.php:, (*7)

$bundles = array(
    // ...
    new Knp\Bundle\GaufretteBundle\KnpGaufretteBundle(), // KnpGaufretteBundle is a dependency of this bundle
    new AshleyDawson\DoctrineGaufretteStorableBundle\AshleyDawsonDoctrineGaufretteStorableBundle(),
);

Configuration

Next, you'll need to configure at least one filesystem to store your files in. I'll lay out an example below, however, a better example of this can be found in the Gaufrette Bundle documentation., (*8)

# app/config/config.yml
knp_gaufrette:
    adapters:
        local_adapter:
            local:
                directory: /tmp/sandbox
    filesystems:
            test_local_filesystem:
                adapter: local_adapter

Usage

In order to use this bundle, you must apply the given trait to the entities you'd like to have carry an uploaded file., (*9)

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AshleyDawson\DoctrineGaufretteStorableBundle\Model\UploadedFileTrait;

/**
 * Post
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Post
{
    /**
     * Use the uploaded file trait
     */
    use UploadedFileTrait;

    /**
     * @var integer
     *
     * @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;

    /**
     * Get id
     *
     * @return integer 
     */
    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;
    }

    /**
     * Get the Gaufrette filesystem map id as
     * configured in https://github.com/KnpLabs/KnpGaufretteBundle#configuring-the-filesystems
     *
     * @return string
     */
    public function getFilesystemMapId()
    {
        return 'test_local_filesystem';
    }
}

The trait will add four fields to the entity:, (*10)

  • file_name : string
    • The original name of the file as uploaded by the client
    • E.g. foobar.gif
  • file_storage_path : string
    • The storage path of the file. Defaults to the file name (above)
    • E.g. /path/to/foobar.gif
  • file_mime_type : string
    • The resolved mime type of the file uploaded by the client
    • E.g. image/gif
  • file_size : integer
    • The file size in bytes
    • E.g. 2324

You'll need to update your schema before using this entity., (*11)

app/console doctrine:schema:update [--force | --dump-sql]

The getFilesystemMapId() abstract method defines the Gaufrette filesystem id where you'd like the file associated with this entity to be stored (defined in the knp_gaufrette config)., (*12)

Form Type

An example of using the entity with a form type, (*13)

<?php

namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

/**
 * Class PostType
 * @package Acme\DemoBundle\Form
 */
class PostType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title', 'text')
            ->add('uploaded_file', 'file', [
                'required' => false,
            ])
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver
            ->setDefaults([
                'data_class' => 'Acme\DemoBundle\Entity\Post',
            ])
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'post';
    }
}

Note: the field named "uploaded_file" maps to a parameter within the AshleyDawson\DoctrineGaufretteStorableBundle\Model\UploadedFileTrait. If you'd like to change this, simply add an accessor to your entity to act as a proxy:, (*14)

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AshleyDawson\DoctrineGaufretteStorableBundle\Model\UploadedFileTrait;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * Post
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Post
{
    /**
     * Use the uploaded file trait
     */
    use UploadedFileTrait;   

    // ...

    /**
     * Set my file
     *
     * @param \Symfony\Component\HttpFoundation\File\UploadedFile $file
     * @return $this
     */
    public function setMyFile(UploadedFile $file = null)
    {
        $this->setUploadedFile($file);

        return $this;
    }
}

Then you can add the new name to the form type, like so:, (*15)

    // ...

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title', 'text')
            ->add('my_file', 'file', [
                'required' => false,
            ])
        ;
    }

    // ...

Events

The storage handler, which is a part of the Doctrine entity lifecycle, fires several events on the margins of the file storage activity. These are:, (*16)

  • ad_doctrine_gaufrette_storable.pre_write
    • Dispatched before file is written to filesystem
  • ad_doctrine_gaufrette_storable.post_write
    • Dispatched after file is written to filesystem
  • ad_doctrine_gaufrette_storable.pre_delete
    • Dispatched before file is deleted from filesystem
  • ad_doctrine_gaufrette_storable.post_delete
    • Dispatched after file is deleted from filesystem

These events can be found within the namespace AshleyDawson\DoctrineGaufretteStorableBundle\Event\StorageEvents., (*17)

A good use case for these events is if you want to change any details of the form before it is written, for example (inside a Symfony controller):, (*18)

// Replace the file storage path with a random md5 hash directory structure, name and file extension
$this->get('event_dispatcher')->addListener(StorageEvents::PRE_WRITE, function (WriteUploadedFileEvent $event) {

    // Build a directory structure like "af/9e"
    $fileStoragePath = implode('/', str_split(substr(md5(mt_rand()), 0, 4), 2));
    $event->setFileStoragePath(sprintf('/%s/%s.%s', $fileStoragePath, md5(mt_rand()), $event->getFileExtension()));
});

Of course, this is a crude example - but it does show how a file (or meta information about a file) may be changed. In the example above, I'm building a hash directory structure for the storage path. Something like this:, (*19)

/af/9e/2997f54d953111d222c00a0b6ed94a50.gif

Note: please don't use the example above as a production solution as there is a chance of filename collision., (*20)

It may also be a good idea to mount a subscriber instead of doing a closure-based implementation as I've done above. You should always aim to deliver a system that promotes the single responsibility principal!, (*21)

The Versions

06/05 2015

dev-master

9999999-dev

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

  Sources   Download

MIT

The Requires

 

The Development Requires

by Ashley Dawson

orm file doctrine odm storage gaufrette

06/05 2015

0.8.1

0.8.1.0

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

  Sources   Download

MIT

The Requires

 

The Development Requires

by Ashley Dawson

orm file doctrine odm storage gaufrette

29/09 2014

dev-develop

dev-develop

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

  Sources   Download

The Requires

 

The Development Requires

by Ashley Dawson

orm file doctrine odm storage gaufrette

28/09 2014

0.8.0

0.8.0.0

Symfony2 bundle to add a storable behaviour to doctrine entities to facilitate abstracted file storage

  Sources   Download

The Requires

 

The Development Requires

by Ashley Dawson

orm file doctrine odm storage gaufrette