Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Uploading Files with Metadata using MongoDB GridFS in a PHP Domain-Driven Design application
<?php
class DefaultGridFSRepository extends DocumentRepository implements GridFSRepository
{
public function uploadFromStream(string $filename, $source, ?UploadOptions $uploadOptions = null)
{
$options = $this->prepareOptions($uploadOptions);
$databaseIdentifier = $this->getDocumentBucket()->uploadFromStream($filename, $source, $options);
$documentIdentifier = $this->class->getPHPIdentifierValue($databaseIdentifier);
return $this->dm->getReference($this->getClassName(), $documentIdentifier);
}
public function uploadFromFile(string $source, ?string $filename = null, ?UploadOptions $uploadOptions = null)
{
$resource = fopen($source, 'r');
if ($resource === false) {
throw MongoDBException::cannotReadGridFSSourceFile($source);
}
if ($filename === null) {
$filename = pathinfo($source, PATHINFO_BASENAME);
}
try {
return $this->uploadFromStream($filename, $resource, $uploadOptions);
} finally {
fclose($resource);
}
}
}
<doctrine-mongo-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping"
xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping
http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd">
<gridfs-file name="InvoiceDocument"
repository-class="MongoInvoiceDocumentRepository"
bucket-name="invoice_documents">
<id field-name="surrogateId" />
<length />
<chunk-size />
<upload-date />
<filename field-name="filename" />
<metadata target-document="InvoiceDocumentMetadata" field-name="metadata" />
</gridfs-file>
</doctrine-mongo-mapping>
<?php
class InvoiceDocument extends SurrogateIdEntity
{
/** @var string */
protected $filename;
/** @var \DateTimeInterface */
protected $uploadDate;
/** @var int */
protected $length;
/** @var int */
protected $chunkSize;
/** @var InvoiceDocumentMetadata */
protected $metadata;
public function __construct()
{
$this->id = Uuid::uuid4()->toString();
}
public function id(): string
{
return $this->metadata->id();
}
public function filename(): string
{
return $this->filename;
}
public function contentType(): string
{
return $this->metadata->contentType();
}
}
<?php
final class InvoiceDocumentFactory
{
/** @var InvoiceDocumentRepository */
private $repository;
public function __construct(InvoiceDocumentRepository $repository)
{
$this->repository = $repository;
}
public function build(
int $invoiceId, Uuid $documentId, $source, $filename, $contentType
): InvoiceDocument
{
$metadata = new InvoiceDocumentMetadata($documentId, $contentType, $invoiceId);
return $this->repository->save($source, $filename, $metadata);
}
}
<doctrine-mongo-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping"
xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping
http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd">
<embedded-document name="InvoiceDocumentMetadata">
<field field-name="id" type="string" />
<field field-name="contentType" type="string" />
<field field-name="invoiceId" type="int" />
</embedded-document>
</doctrine-mongo-mapping>
<?php
final class InvoiceDocumentMetadata
{
/** @var string */
private $id;
/** @var string */
private $contentType;
/** @var int */
protected $invoiceId;
public function __construct(string $id, string $contentType, int $invoiceId)
{
$this->id = $id;
$this->contentType = $contentType;
$this->invoiceId = $invoiceId;
}
public function id(): string
{
return $this->id;
}
public function contentType(): string
{
return $this->contentType;
}
public function invoiceId(): int
{
return $this->invoiceId;
}
}
<?php
interface InvoiceDocumentRepository
{
public function save(string $source, string $filename, InvoiceDocumentMetadata $metadata): InvoiceDocument;
}
<?php
final class MongoInvoiceDocumentRepository extends DefaultGridFSRepository implements InvoiceDocumentRepository
{
public function save(string $source, string $filename, InvoiceDocumentMetadata $metadata): InvoiceDocument
{
$uploadOptions = new UploadOptions();
$uploadOptions->metadata = $metadata;
return $this->uploadFromFile($source, $filename, $uploadOptions);
}
}
<?php
class SurrogateIdEntity extends Entity implements SurrogateIdInterface
{
/**
* @var string
* Surrogate id used internally by ORM or ODM only.
*/
protected $surrogateId;
public function surrogateId(): string
{
return $this->surrogateId;
}
}
<?php
final class UploadInvoiceDocumentHandler
{
/** @var InvoiceDocumentFactory */
protected $invoiceDocumentFactory;
public function __construct(InvoiceDocumentFactory invoiceDocumentFactory)
{
$this->invoiceDocumentFactory = $invoiceDocumentFactory;
}
public function __invoke(UploadInvoiceDocument $command): void
{
/** @var UploadedFile $file */
$file = $command->file();
/** @var InvoiceDocument $document */
$document = $this->invoiceDocumentFactory->build(
$command->invoiceId(),
Uuid::uuid4(),
$file->getPathname(),
$file->getClientOriginalName(),
$file->getClientMimeType()
);
}
}
@webdevilopers

This comment has been minimized.

Copy link
Owner Author

@webdevilopers webdevilopers commented Jan 17, 2020

Feel free to join the discussion:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment