-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NEW Allow file variants with different extensions #585
NEW Allow file variants with different extensions #585
Conversation
f75efd4
to
473f384
Compare
// If no asset container was passed in, create a new uncached image backend | ||
if (!$assetContainer) { | ||
return $this->creator->create($service, $params); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed so that developers can get an instance of the injected Image_Backend
when they don't have a valid AssetContainer
instance that contains an image file. The example in the "manual testing steps" section of the PR description simply won't work without this.
return $this->creator->create($service, $params); | ||
} | ||
|
||
if (!($assetContainer instanceof AssetContainer)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This used to be if (!$assetContainer instanceof AssetContainer)
- which actually checks if ((!$assetContainer) instanceof AssetContainer)
. In other words it was checking if a boolean was an instance of a class, which will always evaluate to false.
// Make sure we're using the extension of the variant file, which can differ from the original file | ||
$url = $assetStore->getAsURL($filename, $hash, $variant, false); | ||
$extension = pathinfo($url, PATHINFO_EXTENSION); | ||
// Save file | ||
$extension = pathinfo($filename ?? '', PATHINFO_EXTENSION); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is vital if using InterventionImage::writeToStore()
to store (and encode) the variant. Without this, it will think it's meant to store it using the original file extension which will be wrong at best and outright fail if the original file wasn't an image.
* @param string $filename Original filename without variant | ||
* @param int $extIndex One of self::EXT_ORIGINAL or self::EXT_VARIANT | ||
*/ | ||
private function swapExtension(string $filename, string $variant, int $extIndex): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swapping the extension is necessary so we can correctly identify the file on the filesystem. Without this, the original file extension is used when searching for the variant file in the filesystem.
e.g. you have an original file myfile.mp4
, and a variant myfile__extRewriteWyJtcDQiLCJqcGciXQ.jpg
.
Without this method, if would look for myfile__extRewriteWyJtcDQiLCJqcGciXQ.mp4
on the filesystem, and obviously it wouldn't find it.
473f384
to
a5580a2
Compare
tests/php/ImageTest.php
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the description of c8f0c29 for changes in this file
return array_merge([$matches['format']], $args[0]); | ||
return array_merge([$matches['format']], $args); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the description of c8f0c29
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm finding this too hard too peer review despite it being split into different commits. I'm jumping between the 'commits' tab and the 'files changed' tab where I want to put my comments and loosing track of things.
Please split this PR into two different PRs, one for refactoring and one for the original issue. In the future please refrain from doing large amount of refactoring in PRs that also contain new functionality / fix a bug .
Moved the refactoring into #587 Marking this as draft because it'll have conflicts once that is merged. |
a5580a2
to
c8f0c29
Compare
@@ -2,8 +2,6 @@ | |||
|
|||
namespace SilverStripe\Assets\FilenameParsing; | |||
|
|||
use SilverStripe\Core\Injector\Injectable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this in the refactor PR - it's not used anymore
$subVariants = explode('_', $variant); | ||
|
||
// Split our filename into a filename and extension part | ||
if (!preg_match('/(?<basename>.+)\.(?<ext>[a-z\d]+)$/i', $filename, $matches)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use pathinfo() instead of your own regex, there may be some weird filenames this doesn't work on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
$variant = isset($matches['variant']) ? $matches['variant'] : ''; | ||
|
||
if (isset($variant)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$variant = isset($matches['variant']) ? $matches['variant'] : ''; | |
if (isset($variant)) { | |
$variant = $matches['variant'] ?: ''; | |
if ($variant) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't new code (it's just moved from below) but I'll validate and make a change here to avoid PR ping pong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
// Split variant string in variant list | ||
$subVariants = explode('_', $variant); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the original filename has underscores in it? You'll need to add a unit test for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't match the variant regex and so it will be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added underscores to file names in the test scenarios.
/** | ||
* A variant type for encoding a variant filename with a different extension than the original. | ||
*/ | ||
public const EXTENSION_REWRITE_VARIANT = 'extRewrite'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public const EXTENSION_REWRITE_VARIANT = 'extRewrite'; | |
public const EXTENSION_REWRITE_VARIANT = 'ExtRewrite'; |
All the other variants types have initial caps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's just a fluke because the method names start with a capital letter - but I'll change this to avoid PR ping pong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* @param string $filename Original filename without variant | ||
* @param int $extIndex One of self::EXT_ORIGINAL or self::EXT_VARIANT | ||
*/ | ||
private function swapExtension(string $filename, string $variant, int $extIndex): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming on these three methods seems really inconsistent, the words they start with are
"rewrite"
"restore"
"swap"
Yet they all do the same thing?
Just get rid of the first two methods just make this method public and also the EXT_* constants public
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just lifted these straight from the POC as they were, since they did what they needed to do.
Done - but made protected since they're only used by subclasses (and used reflection in tests)
/** | ||
* use the original file's extension | ||
*/ | ||
private const EXT_ORIGINAL = 0; | ||
|
||
/** | ||
* use the variant file's extension | ||
*/ | ||
private const EXT_VARIANT = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** | |
* use the original file's extension | |
*/ | |
private const EXT_ORIGINAL = 0; | |
/** | |
* use the variant file's extension | |
*/ | |
private const EXT_VARIANT = 1; | |
/** | |
* Use the original file's extension | |
*/ | |
private const EXTENSION_ORIGINAL = 0; | |
/** | |
* Use the variant file's extension | |
*/ | |
private const EXTENSION_VARIANT = 1; |
Make the naming consistent with other contant above and also make it slightly clearer. Also initial caps for "Use"
Will also need to update references to consts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
$variant = isset($matches['variant']) ? $matches['variant'] : ''; | ||
|
||
if (isset($variant)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$variant = isset($matches['variant']) ? $matches['variant'] : ''; | |
if (isset($variant)) { | |
$variant = $matches['variant'] ?: ''; | |
if ($variant) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
c8f0c29
to
1bfa91e
Compare
Without this, trying to pass any variant name into variantParts() will result in `TypeError: array_merge(): Argument silverstripe#2 must be of type array, string given` This wasn't caught until now because `variantParts()` isn't actually used anywhere in our codebase.
1bfa91e
to
d9d5dac
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally, works good
Won't block merging on this, though just a question really - is it expected to have intermediatory files stay on the file system, for instance I followed the DOC PR instructions for creating a webp image $MyFile.format('webp').ScaleWidth(150)
, though I ended up with this in the filesystem
Ideally we wouldn't have the unused webp image persisted instead only have the webp+ScaleWidth image, is it viable to have the intermediatory image not persist? OK to make this a new card if it's viable though complex
I'm not even sure if that's viable, to be honest. Each variant is a file. Here you have one variant for the file conversion, and another variant for scaling the image - and because those are discrete steps, they create discrete files. I'm pretty sure the same thing would happen if you scaled and then rotated an image - you'd have one variant (and therefore one file) for the scaling operation and one for the rotation operation. I don't think changing that is really feasible - or at least with my current limited understanding of the assets system I can't think of a way to tackle it. |
Description
Provides a low-level API for generating a file variant which has a different extension than the original file.
e.g. could be used for:
Manual testing steps
PageController
.Replace
/var/www/html/.eddev/samples/snickers.jpg
with the absolute path to some arbitrary image file your site can access (or replace that logic with something to actually generate a file from the video - I'm taking some shortcuts in that regard)Replace
/var/www/html/.eddev/samples/client-pdf2.pdf
with the absolute path to some arbitrary pdf file your site can access (or replace that logic with something to actually generate a pdf from the document - I'm taking some shortcuts in that regard)You can also try the documentation example of converting one image to another image (e.g. a
.jpg
to.webp
) and see that it also works correctly, even with chained image manipulations.Issues
Pull request checklist