Здравствуй, %habrauser%


doctrine c 2.5 версии поддерживает встраиваемые объекты, я написал библиотеку которая использует его как ссылка на файла.


Сегодня я расскажу как это облегчит управление загруженными файлами.


Поехали


Привет, %habrauser% ! Я рад что ты читаешь alt картинок, теперь ты обязан читать статью до конца!


Если вы не в курсе что такое встраиваемые объекты в doctrine, пожалуйста сначала прочитайте об этом

Установка


Как обычно, установим через 'composer'
composer require atom-azimov/uploader-bundle


и включаем в AppKernel.php


# app/AppKernel.php
public function registerBundles()
{
    $bundles = [
        ...
        new Atom\UploaderBundle\AtomUploaderBundle(),
        ...
    ];
}

Отлично подходит для RAD приложений !


Мне не нравится RAD подход, но все же ты достоин этой картинки


Допустим у нас есть сущность User и мы хотим дать пользователю возможность загружать свой аватар, c AtomUploaderBundle это реально легко:


# src/Entity/User.php

namespace Acme\Entity;

use Doctrine\ORM\Mapping\Embedded;

class User
{
    ...

    /**
     * @Embedded(class="Atom\Uploader\Model\Embeddable\FileReference")
     */
    private $avatar;
}

Это все что нужно!


Давайте разберёмся что же здесь происходит?


Мы встроили готовый встраиваемый объект в наш сущность, теперь AtomUploaderBundle при сохранении|обновлении сущноста проверяет есть ли там загруженные файлы, если есть генерирует название файла по умолчанию используя uniqid, и сохраняет файла в файловую систему по умолчанию в локальной машине в "%kernel.root_dir%/../web/uploads".


Наш встраиваемый объект 'Atom\Uploader\Model\Embeddable\FileReference' можно считать как ссылка на файла, он в конструкторе принимает экземпляр '\SplFileInfo' чего является файлы в Symfony, а также имеет методы для получения различную информацию о файле таких как относительный пут, публичный адрес или экземпляр '\SplFileInfo' последний отключено по умолчанию.


\SplFileInfo может содержат любой ресурс который поддерживает функция fopen т.е. можно кормит http ссылкой вместо файла.

Отлично настраивается !


Ура ты прочитал alt всех картинок, теперь ты достигал дзен, поздравляю !


Допустим мы хотим:


  • Использовать свой объект вместо готового FileReference.
  • Чтобы названия файла была хэшем оного.
  • Использовать flysystem как абстракцию над файловой системой.

Наш встраиваемый объект будет выглядеть так:


# src/User/Avatar.php

namespace User;

use Doctrine\ORM\Mapping\Column;

class Avatar {

   /**
   * Только это поле должен хранится в БД
   *
   * @Column() 
   */
   private $file;

   private $uri;
}

Getter/Setter-ы не обязательны, в случае их отсутствия будут использоваться рефлексии, а ещё можно изменит стандартные название свойств или использовать методы.

Чтобы определит название файла нужен использовать готовый стратегия нейминга или создать новый,
из готовых пока есть unique_id и basename, а нам нужен хэш, так что наша стратегия нейминга будет выглядеть так:


# src/Naming/HashNamer.php

namespace Naming;

use Atom\Uploader\Naming;

class HashNamer implements INamer {

   /**
     * @param \SplFileInfo $file
     *
     * @return string
     */
    public function name(\SplFileInfo $file): string {
        // вычисляем и вернём хэш файла
    }
}

Его нужно зарегистрировать как сервис и назначить тег 'atom_uploader.namer_repo':


services:
    hash_namer:
        public: false
        class: Namer\HashNamer
        tags:
            -  { name: atom_uploader.namer_repo, strategy: hash }

В теги добавили ключ strategy это название стратегии он будет использоваться при мэппинге.


Меппинг:


# app/config/config.yml
atom_uploader:
    mappings:
        User\Avatar:
            ...
           naming_strategy: hash
           fs_adapter: flysystem # Поддерживается из коробки, только не забывайте его установит :)
           fs_prefix: my_fs_mountpoint # Точка монтирование в flysystem
           ...

Это все, наш встраиваемый объект можно использовать как в первом примере, только теперь файлы хранятся в flysystem, и название файлов будут по другому.


Вот ссылка на github, там же есть более подробная документация на русском.

Понравился ли вам проект?

Проголосовало 9 человек. Воздержалось 14 человек.

Что хотели бы в следующих версиях?

Проголосовало 7 человек. Воздержалось 15 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Поделиться с друзьями
-->

Комментарии (2)


  1. to0n1
    18.05.2016 00:27

    почему не исользовать хеш алгоритм как дефолтный нейминг? ведь всем известны проблемы с псевдо-рандомом!

    hash('SHA256', $filename)
    


    1. cold147
      18.05.2016 08:18

      Можно использовать хэш содержимого, но тогда при хранении больших файлов вычисления хэша может быть медленным, хотя учитывая что большинство файлов маленькие, в этом есть смысл.