-
Notifications
You must be signed in to change notification settings - Fork 69
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 File converter API #595
NEW File converter API #595
Conversation
1f18d36
to
57bc27d
Compare
20539db
to
2a8a715
Compare
/** | ||
* An exception that represents a failure to convert a file in a FileConverter class. | ||
*/ | ||
class FileConversionException extends LogicException |
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 allows us and developers to catch exceptions that were intentionally thrown for conversion failures - while still correctly getting errors in their faces if there are unexpected exceptions.
* Note that if a converter supports the conversion generally but doesn't support these options, that converter will not be used. | ||
* @throws FileConversionException if the conversion failed or there were no converters available. | ||
*/ | ||
public function convert(DBFile $from, string $toFormat, array $options = []): DBFile |
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.
Providing $options
here gives a higher level of control for developers (and converters) which might require it.
return $problems; | ||
} | ||
|
||
private function supportedByIntervention(string $from, string $to, string $driver): bool |
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.
Intervention Image doesn't currently tell you what it supports. It might in the future but for now we have to check for ourselves.
src/ImageManipulation.php
Outdated
* exceptions for end users. | ||
* @throws FileConversionException If the conversion fails and $returnNullOnFailure is false. | ||
*/ | ||
public function convert(string $toFormat, bool $returnNullOnFailure = false): ?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.
I originally had $returnOriginalOnFailure
instead of $returnNullOnFailure
, and it would return $this
if the conversion failed. But null
is more consistent with how other methods in this file behave, and in many cases it would be more desirable to display nothing in the template instead of the wrong thing.
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.
We could optionally remove that parameter and just always return null
on failure. I'll leave it as is for now pending review.
The main benefit of removing the parameter is that it is more consistent with other methods here. We'd probably want to at least log the failure though if we did that.
The main benefit of keeping it is that silent failing is an explicit decision developers have to make, which makes it safer.
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 think remove the param and just return null
You have written this "This is useful if calling this method from a template, for example, where you don't want to be throwing for end users."
That sounds like the main scenario this method will be called in? In which case let's not force the developer to have to put in a param, which they don't have to add in for any other template methods.
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 don't like that personally but I don't feel strongly enough about it to have peer review ping pong about it.
That sounds like the main scenario this method will be called in?
There are all PHP methods and can be called from PHP. Any time you're dealing with an image (or file in this case) in PHP for any reason, you'll call these methods. File conversion will I suspect be just as common in PHP as it will in templates, for things like converting files before attaching to emails, etc.
That said, I've made the requested change and logged the error as a compromise.
cb08b83
to
bf86a3f
Compare
} catch (ImageException $e) { | ||
throw new FileConversionException('Failed to convert: ' . $e->getMessage(), $e->getCode(), $e); | ||
} | ||
// This is very unlikely but the API for `manipulateExtension()` allows for it | ||
if ($result === null) { | ||
throw new FileConversionException('File conversion resulted in null. Check whether original file actually exists.'); | ||
} |
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 can't find a way to test either of these - I think all of the scenarios that would normally result in these are being explicitly validated against already. This is just here as some defensive programming.
src/ImageManipulation.php
Outdated
* exceptions for end users. | ||
* @throws FileConversionException If the conversion fails and $returnNullOnFailure is false. | ||
*/ | ||
public function convert(string $toFormat, bool $returnNullOnFailure = false): ?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.
Note that this is in the ImageManipulation
trait because this trait is shared in both the File
and DBFile
class. The issue originally had some comments about this that I wanted to have as part of the ACs but it was decided that they were not relevant - so we're stuck with putting a file-thing into an image trait.
bf86a3f
to
047acbd
Compare
✅ I haven't done any functional testing so won't do a full PR approval but in general this looks good to me. |
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.
As usual my main thing is naming :-)
- Change FileConversionManager to FileConverterManager
- Change FileConversionException to FileConverterException
- Change $fromFormat to $fromExtension
- Change $toFormat to $toExtension
- convert() should be Convert() to match convention when used from templates
Also make corresponding naming changes in silverstripe/developer-docs#491
Also, I had this in my template: $MyFile.convert('webp')
- however the html rendered had the original png file as the alt tag. I would have expected a webp file in the alt tag.
src/ImageManipulation.php
Outdated
* exceptions for end users. | ||
* @throws FileConversionException If the conversion fails and $returnNullOnFailure is false. | ||
*/ | ||
public function convert(string $toFormat, bool $returnNullOnFailure = false): ?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.
I think remove the param and just return null
You have written this "This is useful if calling this method from a template, for example, where you don't want to be throwing for end users."
That sounds like the main scenario this method will be called in? In which case let's not force the developer to have to put in a param, which they don't have to add in for any other template methods.
if ($driver === 'gd' && !function_exists('imagewebp')) { | ||
return false; | ||
} | ||
if ($driver === 'imagick' && !\Imagick::queryFormats('WEBP')) { |
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.
if ($driver === 'imagick' && !\Imagick::queryFormats('WEBP')) { | |
if ($driver === 'imagick' && !Imagick::queryFormats('WEBP')) { |
Import Imagick up the top. Remove the trailing slash for other examples in this file
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
047acbd
to
a5574b5
Compare
Done, though I think the first two are not as good as the original names. Naming is always subjective though so 🤷♀️
This was suggested in #595 (comment) and I provided reasoning why I didn't do that in that comment thread. Please read that - and if you still want this change after you have that context, I'll make the change at that stage to avoid additional ping pong.
This is unrelated to this API - that's a bug with the low-level API and will need to be logged as a separate issue. |
Yes it's not following our own best practice for PHP methods ... however when we wrote those we probably didn't consider methods intended to called from template. The convention there very much is initial caps for method names unfortunately and we should follow the existing convention. ImageManipulation is full of public methods named like that. End users will be expecting to use |
Methods are just methods. Some methods can be called from templates. Especially in this case, it is not exclusively intended to be used in templates. Nevertheless, I will rename this method to avoid additional unnecessary ping pong - but in the future I will be more resistant to this sort of change because it does go against our best practices (which do not and should not make exceptions for methods which can be called from templates). Done. |
a5574b5
to
145e9a8
Compare
Description
Provides:
File
andDBFile
to leverage available convertersNote that one AC is self-fulfilling:
Converters can validate whatever the heck they want. If they don't have the stuff they need, they should just return
false
from the method that checks if they support a given conversion.Issue