DocumentService
in package
uses
LocatorAwareTrait
Centralized document management service for file uploads, storage, and retrieval.
Uses Flysystem to abstract storage operations across local filesystem, Azure Blob Storage, and S3. Configuration via 'Documents' key in config/app_local.php.
Tags
Table of Contents
Constants
- IMAGE_THUMBNAIL_VERSION : mixed = 1
- IMAGE_THUMBNAIL_JPEG_QUALITY : mixed = 82
- IMAGE_THUMBNAIL_MAX_DIMENSION : mixed = 440
- IMAGE_THUMBNAIL_MAX_SOURCE_BYTES : mixed = 20000000
- IMAGE_THUMBNAIL_MAX_SOURCE_PIXELS : mixed = 25000000
- STORAGE_BASE_PATH : mixed = 'images/uploaded/'
- Base storage path for uploaded documents (for local adapter)
Properties
- $adapter : string
- Storage adapter type ('local', 'azure', or 's3')
- $azureConfig : array<string, mixed>|null
- $Documents : DocumentsTable
- Documents table instance
- $filesystem : Filesystem
- Flysystem filesystem instance
- $localBasePath : string|null
- Base path for local storage
Methods
- __construct() : mixed
- Constructor - initializes Flysystem with configured adapter
- createDocument() : ServiceResult
- Create a document from an uploaded file
- deleteDocument() : ServiceResult
- Delete a document and its associated file
- documentPreviewExists() : bool
- Determine whether a JPEG preview exists for the provided document.
- getDocumentDownloadResponse() : Response|null
- Get a download response for a document
- getDocumentInlineResponse() : Response|null
- Get an inline response for a document (suitable for iframe/object embedding).
- getDocumentPreviewResponse() : Response|null
- Get an inline preview response for a document's generated JPEG preview.
- getImageThumbnailEtag() : string
- Build a strong ETag tied to both the source image and thumbnail algorithm.
- getImageThumbnailInlineResponse() : Response|null
- Return a cached thumbnail, generating it from the original image when needed.
- getImageThumbnailPath() : string
- Build the deterministic path for the current image-thumbnail algorithm.
- updateDocumentEntityId() : ServiceResult
- Update the entity_id of an existing document
- applyExifOrientation() : GdImage
- Apply common camera-orientation metadata before resampling a JPEG.
- azureConfigHasCredential() : bool
- createAzureFilesystem() : Filesystem
- createImageThumbnail() : string|null
- Create a bounded JPEG thumbnail from an encoded source image.
- createInlineStringResponse() : Response
- Create an inline response for in-memory file contents.
- ensureFilesystemReadyForWrite() : void
- Refresh the tenant-bound adapter for writes; infrastructure is provisioned by admin jobs.
- generateUniqueFilename() : string
- Generate a unique filename for storage
- getFilesystemForAdapter() : Filesystem|null
- Get a filesystem instance for a specific storage adapter
- handleUploadError() : ServiceResult
- Handle upload errors and return appropriate ServiceResult
- initializeFilesystem() : void
- Initialize Flysystem with the configured storage adapter
- initializeLocalAdapter() : void
- Initialize local filesystem adapter
- readJpegExifOrientation() : int
- Read the TIFF orientation tag from a JPEG APP1 segment without ext-exif.
- readTiffOrientation() : int
- Read an EXIF orientation tag from a bounded TIFF block.
- readUnsignedLong() : int|null
- Read a four-byte unsigned integer using the TIFF byte order.
- readUnsignedShort() : int|null
- Read a two-byte unsigned integer using the TIFF byte order.
- sanitizePath() : string
- Sanitize file path to prevent directory traversal attacks
- savePreviewFromTemp() : ServiceResult
- Persist a temporary preview image into the configured storage adapter.
Constants
IMAGE_THUMBNAIL_VERSION
public
mixed
IMAGE_THUMBNAIL_VERSION
= 1
IMAGE_THUMBNAIL_JPEG_QUALITY
private
mixed
IMAGE_THUMBNAIL_JPEG_QUALITY
= 82
IMAGE_THUMBNAIL_MAX_DIMENSION
private
mixed
IMAGE_THUMBNAIL_MAX_DIMENSION
= 440
IMAGE_THUMBNAIL_MAX_SOURCE_BYTES
private
mixed
IMAGE_THUMBNAIL_MAX_SOURCE_BYTES
= 20000000
IMAGE_THUMBNAIL_MAX_SOURCE_PIXELS
private
mixed
IMAGE_THUMBNAIL_MAX_SOURCE_PIXELS
= 25000000
STORAGE_BASE_PATH
Base storage path for uploaded documents (for local adapter)
private
mixed
STORAGE_BASE_PATH
= 'images/uploaded/'
Properties
$adapter
Storage adapter type ('local', 'azure', or 's3')
private
string
$adapter
$azureConfig
private
array<string, mixed>|null
$azureConfig
= null
$Documents
Documents table instance
private
DocumentsTable
$Documents
$filesystem
Flysystem filesystem instance
private
Filesystem
$filesystem
$localBasePath
Base path for local storage
private
string|null
$localBasePath
= null
Methods
__construct()
Constructor - initializes Flysystem with configured adapter
public
__construct() : mixed
createDocument()
Create a document from an uploaded file
public
createDocument(UploadedFileInterface $file, string $entityType, int $entityId, int $uploadedBy[, array<string|int, mixed> $metadata = [] ][, string $subDirectory = '' ][, array<string|int, mixed> $allowedExtensions = ['pdf'] ][, string|null $previewTempPath = null ][, string|null $verifiedMimeType = null ][, string|null $verifiedExtension = null ]) : ServiceResult
This method handles the complete document creation workflow:
- Validates the uploaded file
- Generates a unique storage filename
- Stores the physical file
- Creates the document database record
- Returns the document ID
Parameters
- $file : UploadedFileInterface
-
The uploaded file object
- $entityType : string
-
The entity type (e.g., 'Waivers.WaiverTypes')
- $entityId : int
-
The entity ID this document belongs to
- $uploadedBy : int
-
The member ID who uploaded the file
- $metadata : array<string|int, mixed> = []
-
Optional metadata to store with the document
- $subDirectory : string = ''
-
Optional subdirectory within storage base (e.g., 'waiver-templates')
- $allowedExtensions : array<string|int, mixed> = ['pdf']
-
Optional array of allowed file extensions (default: ['pdf'])
- $previewTempPath : string|null = null
-
Optional path to a temporary JPEG preview to store alongside the document
- $verifiedMimeType : string|null = null
-
Server-verified MIME type, when available
- $verifiedExtension : string|null = null
-
Server-verified canonical extension, when available
Return values
ServiceResult —Success with document ID, or failure with error message
deleteDocument()
Delete a document and its associated file
public
deleteDocument(int $documentId) : ServiceResult
This method deletes both the physical file and the database record. It uses the storage_adapter field from the document record to determine which storage backend to use for file deletion.
Parameters
- $documentId : int
-
The document ID to delete
Return values
ServiceResult —Success or failure
documentPreviewExists()
Determine whether a JPEG preview exists for the provided document.
public
documentPreviewExists(Document $document) : bool
Parameters
- $document : Document
-
Document entity reference
Return values
bool —True when preview file can be located, otherwise false
getDocumentDownloadResponse()
Get a download response for a document
public
getDocumentDownloadResponse(Document $document[, string|null $downloadName = null ]) : Response|null
This method handles file retrieval and response generation for downloading documents. It supports both local filesystem and remote storage (Azure Blob Storage, etc) via Flysystem. The method uses the storage_adapter field from the document record to determine which storage backend to use, allowing documents stored with different adapters to coexist.
Parameters
- $document : Document
-
The document entity
- $downloadName : string|null = null
-
Optional custom filename for download
Return values
Response|null —Response with file, or null on error
getDocumentInlineResponse()
Get an inline response for a document (suitable for iframe/object embedding).
public
getDocumentInlineResponse(Document $document[, string|null $inlineName = null ]) : Response|null
Parameters
- $document : Document
-
The document entity
- $inlineName : string|null = null
-
Optional custom filename for inline disposition
Return values
Response|null —Response with file, or null on error
getDocumentPreviewResponse()
Get an inline preview response for a document's generated JPEG preview.
public
getDocumentPreviewResponse(Document $document) : Response|null
Parameters
- $document : Document
-
Document entity with stored file path
Return values
Response|null —Response streaming the preview image, or null if unavailable
getImageThumbnailEtag()
Build a strong ETag tied to both the source image and thumbnail algorithm.
public
getImageThumbnailEtag(Document $document) : string
Parameters
- $document : Document
Return values
stringgetImageThumbnailInlineResponse()
Return a cached thumbnail, generating it from the original image when needed.
public
getImageThumbnailInlineResponse(Document $document[, string|null $inlineName = null ]) : Response|null
Parameters
- $document : Document
-
Source image document
- $inlineName : string|null = null
-
Optional response filename
Return values
Response|null —Thumbnail or original image response
getImageThumbnailPath()
Build the deterministic path for the current image-thumbnail algorithm.
public
getImageThumbnailPath(Document $document) : string
Parameters
- $document : Document
Return values
stringupdateDocumentEntityId()
Update the entity_id of an existing document
public
updateDocumentEntityId(int $documentId, int $entityId) : ServiceResult
This is useful when you need to save the parent entity first to get its ID, then update the document's entity_id reference.
Parameters
- $documentId : int
-
The document ID to update
- $entityId : int
-
The new entity ID
Return values
ServiceResult —Success or failure
applyExifOrientation()
Apply common camera-orientation metadata before resampling a JPEG.
private
applyExifOrientation(GdImage $image, string $sourceContents, int|null $imageType) : GdImage
Parameters
- $image : GdImage
- $sourceContents : string
- $imageType : int|null
Return values
GdImageazureConfigHasCredential()
private
azureConfigHasCredential(array<string, mixed> $azureConfig) : bool
Parameters
- $azureConfig : array<string, mixed>
-
Azure storage config
Return values
boolcreateAzureFilesystem()
private
createAzureFilesystem(array<string, mixed> $azureConfig) : Filesystem
Parameters
- $azureConfig : array<string, mixed>
-
Azure storage config
Return values
FilesystemcreateImageThumbnail()
Create a bounded JPEG thumbnail from an encoded source image.
private
createImageThumbnail(string $sourceContents) : string|null
Parameters
- $sourceContents : string
Return values
string|nullcreateInlineStringResponse()
Create an inline response for in-memory file contents.
private
createInlineStringResponse(string $contents, string $mimeType, string $inlineName) : Response
Parameters
- $contents : string
- $mimeType : string
- $inlineName : string
Return values
ResponseensureFilesystemReadyForWrite()
Refresh the tenant-bound adapter for writes; infrastructure is provisioned by admin jobs.
private
ensureFilesystemReadyForWrite() : void
generateUniqueFilename()
Generate a unique filename for storage
private
generateUniqueFilename(string $extension) : string
Parameters
- $extension : string
-
File extension
Return values
string —Unique filename
getFilesystemForAdapter()
Get a filesystem instance for a specific storage adapter
private
getFilesystemForAdapter(string $adapterType) : Filesystem|null
This method creates a Flysystem instance configured for the specified adapter type. Used when retrieving files that may have been stored with a different adapter than the currently configured one.
Parameters
- $adapterType : string
-
The storage adapter type ('local', 'azure', or 's3')
Return values
Filesystem|null —Filesystem instance or null on error
handleUploadError()
Handle upload errors and return appropriate ServiceResult
private
handleUploadError(int $errorCode) : ServiceResult
Parameters
- $errorCode : int
-
PHP upload error code
Return values
ServiceResultinitializeFilesystem()
Initialize Flysystem with the configured storage adapter
private
initializeFilesystem() : void
initializeLocalAdapter()
Initialize local filesystem adapter
private
initializeLocalAdapter() : void
Tags
readJpegExifOrientation()
Read the TIFF orientation tag from a JPEG APP1 segment without ext-exif.
private
readJpegExifOrientation(string $jpeg) : int
Parameters
- $jpeg : string
Return values
intreadTiffOrientation()
Read an EXIF orientation tag from a bounded TIFF block.
private
readTiffOrientation(string $data, int $start, int $length) : int
Parameters
- $data : string
- $start : int
- $length : int
Return values
intreadUnsignedLong()
Read a four-byte unsigned integer using the TIFF byte order.
private
readUnsignedLong(string $data, int $offset, bool $littleEndian) : int|null
Parameters
- $data : string
- $offset : int
- $littleEndian : bool
Return values
int|nullreadUnsignedShort()
Read a two-byte unsigned integer using the TIFF byte order.
private
readUnsignedShort(string $data, int $offset, bool $littleEndian) : int|null
Parameters
- $data : string
- $offset : int
- $littleEndian : bool
Return values
int|nullsanitizePath()
Sanitize file path to prevent directory traversal attacks
private
sanitizePath(string $path) : string
Parameters
- $path : string
-
The path to sanitize
Return values
string —Sanitized path
savePreviewFromTemp()
Persist a temporary preview image into the configured storage adapter.
private
savePreviewFromTemp(string $relativePdfPath, string $tempPreviewPath) : ServiceResult
Parameters
- $relativePdfPath : string
-
Relative path of stored PDF, used to derive preview path
- $tempPreviewPath : string
-
Temporary JPEG path produced during conversion
Return values
ServiceResult —Result indicating success and stored preview path