1
|
|
|
<?php |
2
|
|
|
namespace MOC\ImageOptimizer\Aspects; |
3
|
|
|
|
4
|
|
|
use Neos\Eel\CompilingEvaluator; |
5
|
|
|
use Neos\Eel\Exception; |
6
|
|
|
use Neos\Eel\Utility; |
7
|
|
|
use Neos\Flow\Annotations as Flow; |
8
|
|
|
use Neos\Flow\Aop\JoinPointInterface; |
9
|
|
|
use Neos\Flow\Log\Utility\LogEnvironment; |
10
|
|
|
use Neos\Flow\Package\Exception\UnknownPackageException; |
11
|
|
|
use Neos\Flow\Package\PackageManager; |
12
|
|
|
use Neos\Flow\ResourceManagement\ResourceManager; |
13
|
|
|
use Neos\Media\Domain\Model\Thumbnail; |
14
|
|
|
use Psr\Log\LoggerInterface; |
15
|
|
|
use Psr\Log\LogLevel; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @Flow\Scope("singleton") |
19
|
|
|
* @Flow\Aspect |
20
|
|
|
*/ |
21
|
|
|
class ThumbnailAspect |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* @var LoggerInterface |
25
|
|
|
* @Flow\Inject |
26
|
|
|
*/ |
27
|
|
|
protected $systemLogger; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @Flow\Inject |
31
|
|
|
* @var PackageManager |
32
|
|
|
*/ |
33
|
|
|
protected $packageManager; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @Flow\Inject |
37
|
|
|
* @var ResourceManager |
38
|
|
|
*/ |
39
|
|
|
protected $resourceManager; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @Flow\Inject |
43
|
|
|
* @var CompilingEvaluator |
44
|
|
|
*/ |
45
|
|
|
protected $eelEvaluator; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var array |
49
|
|
|
*/ |
50
|
|
|
protected $settings; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param array $settings |
54
|
|
|
* @return void |
55
|
|
|
*/ |
56
|
|
|
public function injectSettings(array $settings) |
57
|
|
|
{ |
58
|
|
|
$this->settings = $settings; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* After a thumbnail has been refreshed the resource is optimized, meaning the |
63
|
|
|
* image is only optimized once when created. |
64
|
|
|
* |
65
|
|
|
* A new resource is generated for every thumbnail, meaning the original is |
66
|
|
|
* never touched. |
67
|
|
|
* |
68
|
|
|
* Only local file system target is supported to keep it from being blocking. |
69
|
|
|
* It would however be possible to create a local copy of the resource, |
70
|
|
|
* process it, import it and set that as the thumbnail resource. |
71
|
|
|
* |
72
|
|
|
* @Flow\AfterReturning("method(Neos\Media\Domain\Model\Thumbnail->refresh())") |
73
|
|
|
* @param JoinPointInterface $joinPoint The current join point |
74
|
|
|
* @return void |
75
|
|
|
* @throws Exception |
76
|
|
|
* @throws UnknownPackageException |
77
|
|
|
*/ |
78
|
|
|
public function optimizeThumbnail(JoinPointInterface $joinPoint) |
79
|
|
|
{ |
80
|
|
|
/** @var Thumbnail $thumbnail */ |
81
|
|
|
$thumbnail = $joinPoint->getProxy(); |
82
|
|
|
$thumbnailResource = $thumbnail->getResource(); |
83
|
|
|
if (!$thumbnailResource) { |
84
|
|
|
return; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
$streamMetaData = stream_get_meta_data($thumbnailResource->getStream()); |
88
|
|
|
$pathAndFilename = $streamMetaData['uri']; |
89
|
|
|
|
90
|
|
|
$useGlobalBinary = $this->settings['useGlobalBinary']; |
91
|
|
|
$binaryRootPath = 'Private/Library/node_modules/'; |
92
|
|
|
$file = escapeshellarg($pathAndFilename); |
93
|
|
|
$imageType = $thumbnailResource->getMediaType(); |
94
|
|
|
|
95
|
|
|
if (!array_key_exists($imageType, $this->settings['formats'])) { |
96
|
|
|
$this->systemLogger->info(sprintf('Unsupported type "%s" skipped in optimizeThumbnail', $imageType), LogEnvironment::fromMethodName(__METHOD__)); |
97
|
|
|
return; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
$librarySettings = $this->settings['formats'][$imageType]; |
101
|
|
|
|
102
|
|
|
if ($librarySettings['enabled'] === false) { |
103
|
|
|
return; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
if ($librarySettings['useGlobalBinary'] === true) { |
107
|
|
|
$useGlobalBinary = true; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
$library = $librarySettings['library']; |
111
|
|
|
$binaryPath = $librarySettings['binaryPath']; |
112
|
|
|
$eelExpression = $librarySettings['arguments']; |
113
|
|
|
$parameters = array_merge($librarySettings['parameters'], ['file' => $file]); |
114
|
|
|
$arguments = Utility::evaluateEelExpression($eelExpression, $this->eelEvaluator, $parameters); |
115
|
|
|
|
116
|
|
|
$binaryPath = $useGlobalBinary === true ? $this->settings['globalBinaryPath'] . $library : $this->packageManager->getPackage('MOC.ImageOptimizer')->getResourcesPath() . $binaryRootPath . $binaryPath; |
|
|
|
|
117
|
|
|
$cmd = escapeshellcmd($binaryPath) . ' ' . $arguments; |
118
|
|
|
$output = []; |
119
|
|
|
exec($cmd, $output, $result); |
120
|
|
|
$failed = (int)$result !== 0; |
121
|
|
|
|
122
|
|
|
$this->systemLogger->log($failed ? LogLevel::ERROR : LogLevel::INFO, $cmd . ' (' . ($failed ? 'Error: ' . $result : 'OK') . ')', array_merge(LogEnvironment::fromMethodName(__METHOD__), $output)); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: