Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Extensions Laravel Package

byteincoffee/doctrine-extensions

Laravel package integrating Doctrine Extensions with Eloquent models, adding behaviors like timestampable, sluggable, soft delete, and more. Provides easy configuration, listeners/subscribers, and seamless use of Doctrine-style extensions in Laravel apps.

View on GitHub
Deep Wiki
Context7

Uploadable - Uploadable behavioral extension for Doctrine 2

Uploadable will automate for you storing files as a field of entity.

Features:

  • it uses Gaufrette in background (https://github.com/KnpLabs/Gaufrette) so you can use all of its adapters (local. amazon s3, opencloud and many more)
  • multiple filesystems even in scope of one entity (so you can store each file in different filesystem)

Creating and attaching the UploadableListener to the event manager

Filesystems

First argument must be an array with filesystems, where keys are later identifiers of filesystems. Each filesystem must be instance of Gaufrette\Filesystem.

<?php

use Gaufrette\Filesystem;
use Gaufrette\Adapter;

$filesystem1 = new Filesystem(new Adapter\Local('/some/path'));
$filesystem2 = new Filesystem(new Adapter\Ftp('/other/path', 'example.com'));

$filesystems = array(
    'filesystem1' => $filesystem1,
    'filesystem2' => $filesystem2,
);

FileHandler

Second argument defines class, that will handle conversion of anything you put as file into instance of FSi\DoctrineExtensions\Uploadable\File.

You can define default file handler as:

<?php

use FSi\DoctrineExtensions\Uploadable\FileHandler;

$handler = new FileHandler\ChainHandler(array(
    new FileHandler\GaufretteHandler(),
    new FileHandler\SplFileInfoHandler(),
));

This configuration will allow you to handle instances of Gaufrette\File (including FSi\DoctrineExtensions\Uploadable\File) and SplFileInfo.

File handler must be instance of FSi\DoctrineExtensions\Uploadable\FileHandler\FileHandlerInterface.

Result


use Doctrine\Common\EventManager;
use FSi\DoctrineExtensions\Uploadable\UploadableListener
use FSi\DoctrineExtensions\Uploadable\Keymaker\Entity;

$evm = new EventManager();

$uploadableListener = new UploadableListener($filesystems, $fileHandler, $keymaker);
$evm->addEventSubscriber($uploadableListener);
// now this event manager should be passed to entity manager constructor

// It's good idea to set default filesystem if you want to use uploadable without
// specifying filesystem.
$uploadableListener->setDefaultFilesystem($filesystem1);

// It's also good idea to set default keymaker if you want to use uploadable without
// specifying keymaker.
$keymaker = new Entity();
$uploadableListener->setDefaultKeymaker($keymaker);
// It must be instance of FSi\DoctrineExtensions\Uploadable\Keymaker\KeymakerInterface.

You can find documentation to keymaker shipped with uploadable extension here /doc/uploadable/keymaker.md.

Uploadable options

  • targetField - Required. Attribute of entity, the file object will be loaded to.
  • filesystem - Filesystem name. If not set, default filesystem will be chosen.
  • keymaker - Strategy for creating file keys, null by default. Instance of FSi\DoctrineExtensions\Uploadable\Keymaker\KeymakerInterface
  • keyLength - Allowed key length, 255 by default.
  • keyPattern - Pattern of key. Depend on keymaker, can contain replaceable variables.

Simple entity annotations and usage example

Here is an example of an entity with uploadable property:

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FSi\DoctrineExtensions\Uploadable\Mapping\Annotation\Uploadable;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * [@ORM](https://github.com/ORM)\Table()
 * [@ORM](https://github.com/ORM)\Entity()
 */
class User
{
    /**
     * [@var](https://github.com/var) integer
     *
     * [@ORM](https://github.com/ORM)\Column(type="integer")
     * [@ORM](https://github.com/ORM)\Id
     * [@ORM](https://github.com/ORM)\GeneratedValue(strategy="AUTO")
     */
    public $id;

    /**
     * [@var](https://github.com/var) string
     *
     * [@ORM](https://github.com/ORM)\Column(length=255)
     */
    public $name;

    /**
     * [@ORM](https://github.com/ORM)\Column(length=255, nullable=true)
     * [@Uploadable](https://github.com/Uploadable)(targetField="file", filesystem="filesystem1")
     */
    protected $fileKey;

    protected $file;

    public function setFileKey($key)
    {
        $this->fileKey = $key;
    }

    public function getFileKey()
    {
        return $this->fileKey;
    }

    public function setFile($file)
    {
        if (!empty($file)) {
            $this->file = $file;
        }
    }

    public function getFile()
    {
        return $this->file;
    }

    public function removeFile()
    {
        $this->file = null;
    }
}

Note that both $fileKey and $file properties MUST have defined getters and setters.

There is also example with xml mapping - /doc/uploadable/xml.md and yaml mapping /doc/uploadable/yaml.md.

Uploadable options

  • targetField - Required. Attribute of entity, the file object will be loaded to.
  • filesystem - Filesystem name. If not set, default filesystem will be chosen.
  • keymaker - Strategy for creating file keys, null by default. Instance of FSi\DoctrineExtensions\Uploadable\Keymaker\KeymakerInterface
  • keyLength - Allowed key length, 255 by default.
  • keyPattern - Pattern of key. Depend on keymaker, can contain replaceable variables.

Usage

In every exeample below class Acme\DemoBundle\Entity\User is as defined above.

Adding files when inserting new entity.

<?php

use Acme\DemoBundle\Entity\User;

$user = new User();
$user->setFile($file); // $file must be instances of something, that $fileHandler can handle.

$entityManager->persist($user);
$entityManager->flush();

$user->getFileKey(); // Returns new key of file.
$user->getFile()->getKey(); // Returns the same as line above, but you must check if getFile doesn't return null.
$tmpFile1 = $user->getFile(); // Instance of FSi\DoctrineExtensions\Uploadable\File.
$tmpFile1->exists(); // true

Updating uploadable property with new file.

<?php

use Acme\DemoBundle\Entity\User;

// $user = (...) // Obtain instance of User from database.

$file1 = $user->getFile();
$user->setFile($file2);
$entityManager->flush();
$file1->exists(); // false

Note, that old file, that was attached to entity earlier was automatically deleted.

Deletion of files and entities with files.

You can delete single file from entity.

<?php

use Acme\DemoBundle\Entity\User;

// $user = (...) // Obtain instance of User from database.
$file = $user->getFile();

$user->removeFile();
$entityManager->flush();

$file2->exists(); // false

Or you can just delete whole entity. All its files will be deleted automatically with that entity.

<?php

use Acme\DemoBundle\Entity\User;

// $user = (...) // Obtain instance of User from database.
$file = $user->getFile();

$entityManager->remove($user);
$entityManager->flush();

$file2->exists(); // false

Update of content

If file is already attached, you can modify file directly.

<?php

$user->getFile()->setContent('some content');

Heads up! This way if something fails, changes won't be undone! Remember that replacing it with something new is much more safer, so preferable way is:

<?php

$file = new \SplFileInfo(tempname(sys_get_tmp_dir(), ''));
$fileObj = $file->openFile('a');
$fileObj->fwrite('some content');
$user->setFile($file);

Deletion and update when Doctrine update fails

If you update/delete file and flush will raise an exception, old files will still be present.

<?php

try {
    $file1 = $user->getFile1();
    $user->removeFile();
    $file2 = $user->getFile2();
    $user->setFile2($someFile);

    $entityManager->flush(); // Exception.
} catch (Exception $e) {
    $file1->exists(); // true
    $file2->exists(); // true
}

Heads up! Usually new files (in case of update) will be created, so after such case (like above) there is big chance that new files exists, but aren't bounded to any entity through key.

When preserving old files doesn't work

If you turn of auto commit, it is up to you to backup old files!

<?php

$entityManager->getConnection()->beginTransaction(); // Suspend auto-commit.

try {
    $file1 = $user->getFile1();
    $user->removeFile();
    $file2 = $user->getFile2();
    $user->setFile2($someFile);

    $entityManager->flush(); // Exception.
    $entityManager->getConnection()->commit();
} catch (Exception $e) {
    $entityManager->getConnection()->rollback();
    $entityManager->close();
    $file1->exists(); // false
    $file2->exists(); // false
}

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor