Passed
Push — develop ( 33bcc0...1dbb78 )
by Andrew
05:37
created

OptimizedImages::normalizeValue()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 18
rs 9.6111
c 0
b 0
f 0
cc 5
nc 6
nop 2
1
<?php
2
/**
3
 * Image Optimize plugin for Craft CMS 3.x
4
 *
5
 * Automatically optimize images after they've been transformed
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\imageoptimize\fields;
12
13
use craft\fields\Matrix;
14
use nystudio107\imageoptimize\assetbundles\optimizedimagesfield\OptimizedImagesFieldAsset;
15
use nystudio107\imageoptimize\ImageOptimize;
16
use nystudio107\imageoptimize\models\OptimizedImage;
17
18
use Craft;
19
use craft\base\ElementInterface;
20
use craft\base\Field;
21
use craft\elements\Asset;
22
use craft\helpers\Json;
23
use craft\validators\ArrayValidator;
24
25
use yii\base\InvalidConfigException;
26
use yii\db\Exception;
27
use yii\db\Schema;
28
29
use verbb\supertable\fields\SuperTableField;
0 ignored issues
show
Bug introduced by
The type verbb\supertable\fields\SuperTableField was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
31
/** @noinspection MissingPropertyAnnotationsInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
32
33
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
34
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 4
Loading history...
35
 * @package   ImageOptimize
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
36
 * @since     1.2.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 3 spaces but found 5
Loading history...
37
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
38
class OptimizedImages extends Field
39
{
40
    // Constants
41
    // =========================================================================
42
43
    const DEFAULT_ASPECT_RATIOS = [
44
        ['x' => 16, 'y' => 9],
45
    ];
46
    const DEFAULT_IMAGE_VARIANTS = [
47
        [
48
            'width'          => 1200,
49
            'useAspectRatio' => true,
50
            'aspectRatioX'   => 16.0,
51
            'aspectRatioY'   => 9.0,
52
            'retinaSizes'    => ['1'],
53
            'quality'        => 82,
54
            'format'         => 'jpg',
55
        ],
56
    ];
57
58
    // Public Properties
59
    // =========================================================================
60
61
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
62
     * @var bool
63
     */
64
    public $displayOptimizedImageVariants = true;
65
66
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
67
     * @var bool
68
     */
69
    public $displayDominantColorPalette = true;
70
71
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
72
     * @var bool
73
     */
74
    public $displayLazyLoadPlaceholderImages = true;
75
76
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
77
     * @var array
78
     */
79
    public $variants = [];
80
81
    // Private Properties
82
    // =========================================================================
83
84
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
85
     * @var array
86
     */
87
    private $aspectRatios = [];
0 ignored issues
show
Coding Style introduced by
Private member variable "aspectRatios" must be prefixed with an underscore
Loading history...
88
89
    // Static Methods
90
    // =========================================================================
91
92
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $config should have a doc-comment as per coding-style.
Loading history...
93
     * @inheritdoc
94
     */
95
    public function __construct(array $config = [])
96
    {
97
        // Unset any deprecated properties
98
        if (!empty($config)) {
99
            unset($config['transformMethod'], $config['imgixDomain']);
100
        }
101
        parent::__construct($config);
102
    }
103
104
    // Public Methods
105
    // =========================================================================
106
107
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
108
     * @inheritdoc
109
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
110
    public static function displayName(): string
111
    {
112
        return 'OptimizedImages';
113
    }
114
115
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
116
     * @inheritdoc
117
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
118
    public function init()
119
    {
120
        parent::init();
121
122
        // Handle cases where the plugin has been uninstalled
123
        if (ImageOptimize::$plugin !== null) {
124
            $settings = ImageOptimize::$plugin->getSettings();
125
            if ($settings) {
0 ignored issues
show
introduced by
$settings is of type nystudio107\imageoptimize\models\Settings, thus it always evaluated to true.
Loading history...
126
                if (empty($this->variants)) {
127
                    $this->variants = $settings->defaultVariants;
128
                }
129
                $this->aspectRatios = $settings->defaultAspectRatios;
130
            }
131
        }
132
        // If the user has deleted all default aspect ratios, provide a fallback
133
        if (empty($this->aspectRatios)) {
134
            $this->aspectRatios = self::DEFAULT_ASPECT_RATIOS;
135
        }
136
        // If the user has deleted all default variants, provide a fallback
137
        if (empty($this->variants)) {
138
            $this->variants = self::DEFAULT_IMAGE_VARIANTS;
139
        }
140
    }
141
142
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
143
     * @inheritdoc
144
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
145
    public function rules()
146
    {
147
        $rules = parent::rules();
148
        $rules = array_merge($rules, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
149
            ['variants', ArrayValidator::class],
150
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
151
152
        return $rules;
153
    }
154
155
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $asset should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $isNew should have a doc-comment as per coding-style.
Loading history...
156
     * @inheritdoc
157
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
158
    public function afterElementSave(ElementInterface $asset, bool $isNew)
159
    {
160
        parent::afterElementSave($asset, $isNew);
161
        // Update our OptimizedImages Field data now that the Asset has been saved
162
        if ($asset !== null && $asset instanceof Asset && $asset->id !== null) {
163
            // If the scenario is Asset::SCENARIO_FILEOPS or Asset::SCENARIO_ESSENTIALS treat it as a new asset
164
            $scenario = $asset->getScenario();
165
            if ($isNew || $scenario === Asset::SCENARIO_FILEOPS || $asset->propagating) {
166
                /**
167
                 * If this is a newly uploaded/created Asset, we can save the variants
168
                 * via a queue job to prevent it from blocking
169
                 */
170
                ImageOptimize::$plugin->optimizedImages->resaveAsset($asset->id);
171
            } else {
172
                /**
173
                 * If it's not a newly uploaded/created Asset, they may have edited
174
                 * the image with the ImageEditor, so we need to update the variants
175
                 * immediately, so the AssetSelectorHud displays the new images
176
                 */
177
                try {
178
                    ImageOptimize::$plugin->optimizedImages->updateOptimizedImageFieldData($this, $asset);
179
                } catch (Exception $e) {
180
                    Craft::error($e->getMessage(), __METHOD__);
181
                }
182
            }
183
        }
184
    }
185
186
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $asset should have a doc-comment as per coding-style.
Loading history...
187
     * @inheritdoc
188
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
189
    public function normalizeValue($value, ElementInterface $asset = null)
190
    {
191
        // If we're passed in a string, assume it's JSON-encoded, and decode it
192
        if (\is_string($value) && !empty($value)) {
193
            $value = Json::decodeIfJson($value);
194
        }
195
        // If we're passed in an array, make a model from it
196
        if (\is_array($value)) {
197
            // Create a new OptimizedImage model and populate it
198
            $model = new OptimizedImage($value);
199
        } elseif ($value instanceof OptimizedImage) {
200
            $model = $value;
201
        } else {
202
            // Just create a new empty model
203
            $model = new OptimizedImage(null);
204
        }
205
206
        return $model;
207
    }
208
209
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
210
     * @inheritdoc
211
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
212
    public function getContentColumnType(): string
213
    {
214
        return Schema::TYPE_TEXT;
215
    }
216
217
    // Protected Methods
218
    // =========================================================================
219
220
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
221
     * @inheritdoc
222
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
223
    public function getSettingsHtml()
224
    {
225
        $namespace = Craft::$app->getView()->getNamespace();
226
        if (strpos($namespace, Matrix::class) !== false || strpos($namespace, SuperTableField::class) !== false) {
227
            // Render an error template, since the field only works when attached to an Asset
228
            try {
229
                return Craft::$app->getView()->renderTemplate(
230
                    'image-optimize/_components/fields/OptimizedImages_error',
231
                    [
232
                    ]
233
                );
234
            } catch (\Twig_Error_Loader $e) {
235
                Craft::error($e->getMessage(), __METHOD__);
236
            } catch (\yii\base\Exception $e) {
237
                Craft::error($e->getMessage(), __METHOD__);
238
            }
239
        }
240
241
        try {
242
            $reflect = new \ReflectionClass($this);
243
            $thisId = $reflect->getShortName();
244
        } catch (\ReflectionException $e) {
245
            Craft::error($e->getMessage(), __METHOD__);
246
            $thisId = 0;
247
        }
248
        $id = Craft::$app->getView()->formatInputId($thisId);
249
        $namespacedId = Craft::$app->getView()->namespaceInputId($id);
250
        $namespacePrefix = Craft::$app->getView()->namespaceInputName($thisId);
251
        Craft::$app->getView()->registerJs('new Craft.OptimizedImagesInput('.
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
252
            '"'.$namespacedId.'", '.
253
            '"'.$namespacePrefix.'"'.
254
            ');');
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 8 spaces, but found 12.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
255
256
        // Prep our aspect ratios
257
        $aspectRatios = [];
258
        $index = 1;
259
        foreach ($this->aspectRatios as $aspectRatio) {
260
            if ($index % 6 === 0) {
261
                $aspectRatio['break'] = true;
262
            }
263
            $aspectRatios[] = $aspectRatio;
264
            $index++;
265
        }
266
        $aspectRatio = ['x' => 2, 'y' => 2, 'custom' => true];
267
        $aspectRatios[] = $aspectRatio;
268
269
        // Render the settings template
270
        try {
271
            return Craft::$app->getView()->renderTemplate(
272
                'image-optimize/_components/fields/OptimizedImages_settings',
273
                [
274
                    'field'        => $this,
275
                    'aspectRatios' => $aspectRatios,
276
                    'id'           => $id,
277
                    'name'         => $this->handle,
278
                    'namespace'    => $namespacedId,
279
                ]
280
            );
281
        } catch (\Twig_Error_Loader $e) {
282
            Craft::error($e->getMessage(), __METHOD__);
283
        } catch (\yii\base\Exception $e) {
284
            Craft::error($e->getMessage(), __METHOD__);
285
        }
286
287
        return '';
288
    }
289
290
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $element should have a doc-comment as per coding-style.
Loading history...
291
     * @inheritdoc
292
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
293
    public function getInputHtml($value, ElementInterface $element = null): string
294
    {
295
        if ($element !== null && $element instanceof Asset && $this->handle !== null) {
296
            /** @var Asset $element */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
297
            // Register our asset bundle
298
            try {
299
                Craft::$app->getView()->registerAssetBundle(OptimizedImagesFieldAsset::class);
300
            } catch (InvalidConfigException $e) {
301
                Craft::error($e->getMessage(), __METHOD__);
302
            }
303
304
            // Get our id and namespace
305
            $id = Craft::$app->getView()->formatInputId($this->handle);
306
            $nameSpaceId = Craft::$app->getView()->namespaceInputId($id);
307
308
            // Variables to pass down to our field JavaScript to let it namespace properly
309
            $jsonVars = [
310
                'id'        => $id,
311
                'name'      => $this->handle,
312
                'namespace' => $nameSpaceId,
313
                'prefix'    => Craft::$app->getView()->namespaceInputId(''),
314
            ];
315
            $jsonVars = Json::encode($jsonVars);
316
            $view = Craft::$app->getView();
317
            $view->registerJs("$('#{$nameSpaceId}-field').ImageOptimizeOptimizedImages(".$jsonVars.");");
318
319
            $settings = ImageOptimize::$plugin->getSettings();
320
321
            // Render the input template
322
            try {
323
                return Craft::$app->getView()->renderTemplate(
324
                    'image-optimize/_components/fields/OptimizedImages_input',
325
                    [
326
                        'name'        => $this->handle,
327
                        'value'       => $value,
328
                        'variants'    => $this->variants,
329
                        'field'       => $this,
330
                        'settings'    => $settings,
331
                        'elementId'   => $element->id,
332
                        'format'      => $element->getExtension(),
333
                        'id'          => $id,
334
                        'nameSpaceId' => $nameSpaceId,
335
                    ]
336
                );
337
            } catch (\Twig_Error_Loader $e) {
338
                Craft::error($e->getMessage(), __METHOD__);
339
            } catch (\yii\base\Exception $e) {
340
                Craft::error($e->getMessage(), __METHOD__);
341
            }
342
        }
343
344
        // Render an error template, since the field only works when attached to an Asset
345
        try {
346
            return Craft::$app->getView()->renderTemplate(
347
                'image-optimize/_components/fields/OptimizedImages_error',
348
                [
349
                ]
350
            );
351
        } catch (\Twig_Error_Loader $e) {
352
            Craft::error($e->getMessage(), __METHOD__);
353
        } catch (\yii\base\Exception $e) {
354
            Craft::error($e->getMessage(), __METHOD__);
355
        }
356
357
        return '';
358
    }
359
}
360