Symfony — Объединение Файлов Gridfs С Объектами Orm

В предыдущая статья Я писал про загрузку файлов в GridFS. Там мы создали документ MongoDB со свойством $файл , аннотировано как @MongoDB\Файл .

Поскольку я использую сущности ORM чаще, чем документы ODM, я искал простой способ доступа к документу из сущности.

Прямую связь между сущностью и документом установить невозможно, и я подумал, что было бы неплохо создать свой собственный тип поля.

Определив тип настраиваемого поля, мы можем контролировать способ хранения ссылки на документ и в то же время возвращать эту ссылку с помощью вызова свойства сущности.



Давайте создадим класс нашего собственного типа поля

Начнем с создания класса Тип загрузки который определяет столбец типа загрузить :
  
  
  
  
  
  
  
   

namespace Dennis\UploadBundle\Types; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Platforms\AbstractPlatform; class UploadType extends Type { const UPLOAD = 'upload'; public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { return $platform->getClobTypeDeclarationSQL($fieldDeclaration); } public function getName() { return self::UPLOAD; } public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } }

Чтобы запросить ссылку на документ Загрузить , для создания такой ссылки нам понадобится Doctrine ODM DocumentManager, для этого мы добавим сеттер.



use Doctrine\ODM\MongoDB\DocumentManager; // .

private $dm; public function setDocumentManager(DocumentManager $dm) { $this->dm = $dm; }

Чтобы убедиться, что в базе данных сохраняется только идентификатор документа.

Загрузить , мы переопределим метод конвертироватьтобасевалуе так что он возвращает только идентификатор документа.



use Dennis\UploadBundle\Document\Upload; use Doctrine\DBAL\Types\ConversionException; // .

public function convertToDatabaseValue($value, AbstractPlatform $platform) { if (empty($value)) { return null; } if ($value instanceof Upload) { return $value->getId(); } throw ConversionException::conversionFailed($value, self::UPLOAD); }

Чтобы вернуть ссылку на документ Загрузить , после того как сущность получила его от базы, мы переопределяем метод конвертироватьToPHPValue .

Как вы можете видеть ниже, создание ссылки — это просто передача идентификатора класса и документа методу.

получитьСсылку() сорт Менеджер Документов .

Потому что в методе конвертироватьтобасевалуе мы решили вернуть идентификатор документа Загрузить , то вы можете использовать его немедленно.



// .

public function convertToPHPValue($value, AbstractPlatform $platform) { if (empty($value)) { return null; } return $this->dm->getReference('Dennis\UploadBundle\Document\Upload', $value); }

Стоит отметить, что большим преимуществом создания ссылки на документ вместо использования репозитория является DennisUploadBundle:Загрузить для получения документа заключается в том, что документ будет извлечен из базы данных и инициализирован только тогда, когда будет запрошено поле с этим документом.

Когда вы используете репозиторий DennisUploadBundle:Загрузить чтобы найти документ и назначить его свойству сущности, для каждой сущности будет создан экземпляр документа Изображение , который будет возвращен ORM EntityManager. То есть на 100 субъектов будет создано одинаковое количество документов, что, конечно, неэффективно.

Создание ссылки гарантирует, что документ будет создан только по вашему запросу.



Регистрация собственного типа поля

Теперь, когда наш Тип загрузки может правильно преобразовать документ Загрузить , пришло время использовать его в нашем приложении Symfony. В соответствии с эта статья Матиаса Нобака , лучшее место для добавления нового типа в Doctrine — это конструктор пакета, откуда зависимости ODM DocumentManager затем будут загружены в наш Тип загрузки

namespace Dennis\UploadBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; use Doctrine\DBAL\Types\Type; class DennisUploadBundle extends Bundle { public function __construct() { if (!Type::hasType('upload')) { Type::addType('upload', 'Dennis\UploadBundle\Types\UploadType'); } } public function boot() { $dm = $this->container->get('doctrine.odm.mongodb.document_manager'); /* @var $type \Dennis\UploadBundle\Types\UploadType */ $type = Type::getType('upload'); $type->setDocumentManager($dm); } }



Использование типа загрузки

Чтобы продемонстрировать использование нашего нового поля загрузить , я начну с создания сущности Изображение :

namespace Acme\DemoBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Image { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=100) */ protected $name; /** * @ORM\Column(type="upload") */ protected $image; public function getId() { return $this->id; } public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } public function setImage($image) { $this->image = $image; } public function getImage() { return $this->image; } }

Если вы посмотрите на абстрактное @ORM\Столбец поля $изображение , то ясно, что в параметре тип просто добавьте название нашего типа Тип загрузки ( "загрузить" ) и Doctrine будет использовать объект класса Тип загрузки при чтении или записи поля в базу данных $изображение .



Обработка форм

Обработка формы, созданной для нашей сущности Изображение примерно так же, как и любая форма, основанная на сущности.

Единственное дополнение – необходимо убедиться, что скачанный файл сохранен в GridFS и созданный документ Загрузить назначено на поле $изображение сущность Изображение .



namespace Acme\DemoBundle\Controller; use Dennis\UploadBundle\Document\Upload; class ImageController extends Controller { public function newAction(Request $request) { // .

$form->bind($request); if ($form->isValid()) { /** @var $upload \Symfony\Component\HttpFoundation\File\UploadedFile */ $upload = $image->getImage(); $document = new Upload(); $document->setFile($upload->getPathname()); $document->setFilename($upload->getClientOriginalName()); $document->setMimeType($upload->getClientMimeType()); $dm = $this->get('doctrine.odm.mongodb.document_manager'); $dm->persist($document); $dm->flush(); $image->setImage($document); $em = $this->getDoctrine()->getManager(); $em->persist($image); $em->flush(); } } }

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



Получение изображения из базы данных

Приведенный ниже метод почти такой же, как метод шоуДействие контроллер Контроллер загрузки от предыдущая статья .

Единственная разница в том, что вы можете использовать репозиторий.

AcmeDemoBundle:Изображение чтобы получить объект Image, а затем получить документ Upload, просто вызвав getImage().

Опять же, документ загрузки будет получен из MongoDB и создан только при вызове метода getImage().



/** * @Route("/{id}", name="image_show") */ public function showAction($id) { $image = $this->getDoctrine()->getManager() ->getRepository('AcmeDemoBundle:Image') ->find($id); $response = new Response(); $response->headers->set('Content-Type', $image->getImage()->getMimeType()); $response->setContent($image->getImage()->getFile()->getBytes()); return $response; }

Вот и все! Теперь у нас есть свои Тип загрузки , который обрабатывает ссылки на документы Загрузить наша сущность Изображение .

Я убеждён, что такой подход к созданию своего класса Тип обеспечивает простой способ объединения документов ODM и объектов ORM. Единственным огромным недостатком является то, что вам придется вручную сохранять() документ перед сохранением объекта.

Это точно не то, что хотелось бы повторить в каждом подобном контроллере с такой комбинацией.

В своей следующей статье я постараюсь решить эту проблему.

Теги: #php #mongodb #symfony #Doctrine ORM #php #symfony #mongodb

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.