Derivation
This chapter describes the concept of file derivation and the pipe & filter
pattern applied to FileInterface
.
Derivation
FileInterface
supports what we call 'derivation'. A file can have one or more
derivations of itself. For example, an image file can have a thumbnail, medium,
and large derivation. A derived file can also be derived further. For example, a
thumbnail can be in the original aspect ratio, or square-cropped.
FileInterface
provides the method getDerivation()
that returns a
FilePointer
to the derived file. Our File
objects ensure that a derivation
cannot be made if the file is in the local filesystem, or in an ad-hoc
filesystem, to avoid cluttering the local filesystem with unwanted files.
Low-Level Implementation
At the low level, a derivation is created simply by appending the derivation ID to the original file's key. For example, if the original file's key is:
entity/ffa87ef3fc5388bc8b666e2cec17d27cc493d0c1/image/e5/80/72/6d/31337
then, with the derivation ID '100px', the derived file's key becomes:
entity/ffa87ef3fc5388bc8b666e2cec17d27cc493d0c1/image/e5/80/72/6d/31337.d/100px
Deleting the original file will also result in the deletion of all of its derivations.
Derivation can be nested. Suppose the derived file above will be derived further with the derivation ID of 'square', then the derived file's key becomes:
entity/ffa87ef3fc5388bc8b666e2cec17d27cc493d0c1/image/e5/80/72/6d/31337.d/100px.d/square
Because each derivation step requires a round trip to the storage backend, it is not recommended to nest derivations too deep.
Pipes & Filters Pattern
Derivation can be used as the building block of filters. A filter is a service that performs opportunistic creation and caching of a derived file from a source file.
A filter can be applied to a FileInterface
and does the following:
- Obtain the original file.
- Determine the derivation ID from the parameters provided by the caller. For example, if the caller wants to get a square thumbnail of an image, the filter can use the derivation ID like 'thumbnail-square'.
- Call
FileInterface::getDerivation()
to get a pointer to the derived file. - Call
FileRepository::get()
to get the derived file.- If the derived file does not exist, produce the derived file, and write to the pointer.
- If the derived file exists and is newer than the original file, return it.
- If the derived file exists and is older than the original file, produce the derived file, then overwrite the old derived file.
The caller can then use the filter to create a modified version of the original file without having to worry about the details.
We provide the package
rekalogika/file-derivation
to
streamline the creation of filters within the Symfony framework.