Passed
Push — develop ( 658993...45f656 )
by Andrew
03:50
created

ImageOptimize::getSettingsResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
/**
3
 * ImageOptimize plugin for Craft CMS 3.x
4
 *
5
 * Automatically optimize images after they've been transformed
6
 *
7
 * @link      https://nystudio107.com
8
 * @copyright Copyright (c) 2017 nystudio107
9
 */
10
11
namespace nystudio107\imageoptimize;
12
13
use nystudio107\imageoptimize\fields\OptimizedImages;
14
use nystudio107\imageoptimize\imagetransforms\ImageTransformInterface;
15
use nystudio107\imageoptimize\models\Settings;
16
use nystudio107\imageoptimize\services\Optimize as OptimizeService;
17
use nystudio107\imageoptimize\services\OptimizedImages as OptimizedImagesService;
18
use nystudio107\imageoptimize\services\Placeholder as PlaceholderService;
19
use nystudio107\imageoptimize\variables\ImageOptimizeVariable;
20
21
use Craft;
22
use craft\base\Element;
23
use craft\base\Field;
24
use craft\base\Plugin;
25
use craft\base\Volume;
26
use craft\console\Application as ConsoleApplication;
27
use craft\elements\Asset;
28
use craft\events\AssetTransformImageEvent;
29
use craft\events\ElementEvent;
30
use craft\events\FieldEvent;
31
use craft\events\GetAssetUrlEvent;
32
use craft\events\GenerateTransformEvent;
33
use craft\events\PluginEvent;
34
use craft\events\RegisterComponentTypesEvent;
35
use craft\events\ReplaceAssetEvent;
36
use craft\events\VolumeEvent;
37
use craft\helpers\UrlHelper;
38
use craft\models\FieldLayout;
39
use craft\services\Assets;
40
use craft\services\AssetTransforms;
41
use craft\services\Elements;
42
use craft\services\Fields;
43
use craft\services\Plugins;
44
use craft\services\Volumes;
45
use craft\web\twig\variables\CraftVariable;
46
use craft\web\Controller;
47
48
use yii\base\Event;
49
50
/** @noinspection MissingPropertyAnnotationsInspection */
51
52
/**
53
 * Class ImageOptimize
54
 *
55
 * @author    nystudio107
56
 * @package   ImageOptimize
57
 * @since     1.0.0
58
 *
59
 * @property OptimizeService        optimize
60
 * @property PlaceholderService     placeholder
61
 * @property OptimizedImagesService optimizedImages
62
 * @property Settings               $settings
63
 * @method   Settings               getSettings()
64
 */
65
class ImageOptimize extends Plugin
66
{
67
    // Static Properties
68
    // =========================================================================
69
70
    /**
71
     * @var ImageOptimize
72
     */
73
    public static $plugin;
74
75
    /**
76
     * @var ImageTransformInterface
77
     */
78
    public static $transformClass;
79
80
    /**
81
     * @var array
82
     */
83
    public static $transformParams;
84
85
    /**
86
     * @var bool
87
     */
88
    public static $generatePlacholders = true;
89
90
    // Public Methods
91
    // =========================================================================
92
93
    /**
94
     * @inheritdoc
95
     */
96
    public function init()
97
    {
98
        parent::init();
99
        self::$plugin = $this;
100
        // Handle any console commands
101
        if (Craft::$app instanceof ConsoleApplication) {
102
            $this->controllerNamespace = 'nystudio107\imageoptimize\console\controllers';
103
        }
104
        // Cache some settings
105
        $settings = $this->getSettings();
106
        self::$transformClass = ImageTransformInterface::IMAGE_TRANSFORM_MAP[$settings->transformMethod];
107
        self::$transformParams = self::$transformClass::getTransformParams();
108
        // Add in our Craft components
109
        $this->addComponents();
110
        // Install our global event handlers
111
        $this->installEventHandlers();
112
        // Log that the plugin has loaded
113
        Craft::info(
114
            Craft::t(
115
                'image-optimize',
116
                '{name} plugin loaded',
117
                ['name' => $this->name]
118
            ),
119
            __METHOD__
120
        );
121
    }
122
123
    /**
124
     * @inheritdoc
125
     */
126
    public function getSettingsResponse()
127
    {
128
        $view = Craft::$app->getView();
129
        $namespace = $view->getNamespace();
130
        $view->setNamespace('settings');
131
        $settingsHtml = $this->settingsHtml();
132
        $view->setNamespace($namespace);
133
        /** @var Controller $controller */
134
        $controller = Craft::$app->controller;
135
136
        return $controller->renderTemplate('image-optimize/_settings', [
137
            'plugin'       => $this,
138
            'settingsHtml' => $settingsHtml,
139
        ]);
140
    }
141
142
    /**
143
     * @inheritdoc
144
     */
145
    public function settingsHtml()
146
    {
147
        $imageProcessors = ImageOptimize::$plugin->optimize->getActiveImageProcessors();
148
        $variantCreators = ImageOptimize::$plugin->optimize->getActiveVariantCreators();
149
        // Get only the user-editable settings
150
        $settings = $this->getSettings();
151
152
        // Render the settings template
153
        return Craft::$app->getView()->renderTemplate(
154
            'image-optimize/settings',
155
            [
156
                'settings'        => $settings,
157
                'imageProcessors' => $imageProcessors,
158
                'variantCreators' => $variantCreators,
159
                'gdInstalled'     => function_exists('imagecreatefromjpeg'),
160
            ]
161
        );
162
    }
163
164
    // Protected Methods
165
    // =========================================================================
166
167
    /**
168
     * @inheritdoc
169
     */
170
    protected function createSettingsModel()
171
    {
172
        return new Settings();
173
    }
174
175
    /**
176
     * Add in our Craft components
177
     */
178
    protected function addComponents()
179
    {
180
        // Register our variables
181
        Event::on(
182
            CraftVariable::class,
183
            CraftVariable::EVENT_INIT,
184
            function (Event $event) {
185
                /** @var CraftVariable $variable */
186
                $variable = $event->sender;
187
                $variable->set('imageOptimize', ImageOptimizeVariable::class);
188
            }
189
        );
190
191
        // Register our Field
192
        Event::on(
193
            Fields::class,
194
            Fields::EVENT_REGISTER_FIELD_TYPES,
195
            function (RegisterComponentTypesEvent $event) {
196
                Craft::debug(
197
                    'Fields::EVENT_REGISTER_FIELD_TYPES',
198
                    __METHOD__
199
                );
200
                $event->types[] = OptimizedImages::class;
201
            }
202
        );
203
    }
204
205
    /**
206
     * Install our event handlers
207
     */
208
    protected function installEventHandlers()
209
    {
210
        $this->installAssetEventHandlers();
211
        $this->installElementEventHandlers();
212
        $this->installMiscEventHandlers();
213
    }
214
215
    /**
216
     * Install our miscellaneous event handlers
217
     */
218
    protected function installMiscEventHandlers()
219
    {
220
        // Handler: Fields::EVENT_AFTER_SAVE_FIELD
221
        Event::on(
222
            Fields::class,
223
            Fields::EVENT_AFTER_SAVE_FIELD,
224
            function (FieldEvent $event) {
225
                Craft::debug(
226
                    'Fields::EVENT_AFTER_SAVE_FIELD',
227
                    __METHOD__
228
                );
229
                $settings = $this->getSettings();
230
                /** @var Field $field */
231
                if (!$event->isNew && $settings->automaticallyResaveImageVariants) {
232
                    $this->checkForOptimizedImagesField($event);
233
                }
234
            }
235
        );
236
237
        // Handler: Plugins::EVENT_AFTER_SAVE_PLUGIN_SETTINGS
238
        Event::on(
239
            Plugins::class,
240
            Plugins::EVENT_AFTER_SAVE_PLUGIN_SETTINGS,
241
            function (PluginEvent $event) {
242
                if ($event->plugin === $this) {
243
                    Craft::debug(
244
                        'Plugins::EVENT_AFTER_SAVE_PLUGIN_SETTINGS',
245
                        __METHOD__
246
                    );
247
                    $settings = $this->getSettings();
248
                    if ($settings->automaticallyResaveImageVariants) {
249
                        // After they have changed the settings, resave all of the assets
250
                        ImageOptimize::$plugin->optimizedImages->resaveAllVolumesAssets();
251
                    }
252
                }
253
            }
254
        );
255
256
        // Handler: Volumes::EVENT_AFTER_SAVE_VOLUME
257
        Event::on(
258
            Volumes::class,
259
            Volumes::EVENT_AFTER_SAVE_VOLUME,
260
            function (VolumeEvent $event) {
261
                Craft::debug(
262
                    'Volumes::EVENT_AFTER_SAVE_VOLUME',
263
                    __METHOD__
264
                );
265
                $settings = $this->getSettings();
266
                // Only worry about this volume if it's not new
267
                if (!$event->isNew && $settings->automaticallyResaveImageVariants) {
268
                    /** @var Volume $volume */
269
                    $volume = $event->volume;
270
                    if (is_subclass_of($volume, Volume::class)) {
271
                        ImageOptimize::$plugin->optimizedImages->resaveVolumeAssets($volume);
272
                    }
273
                }
274
            }
275
        );
276
277
        // Do something after we're installed
278
        Event::on(
279
            Plugins::class,
280
            Plugins::EVENT_AFTER_INSTALL_PLUGIN,
281
            function (PluginEvent $event) {
282
                if ($event->plugin === $this) {
283
                    $request = Craft::$app->getRequest();
284
                    if (($request->isCpRequest) && (!$request->isConsoleRequest)) {
285
                        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('image-optimize/welcome'))->send();
286
                    }
287
                }
288
            }
289
        );
290
    }
291
292
    /**
293
     * Install our Asset event handlers
294
     */
295
    protected function installAssetEventHandlers()
296
    {
297
298
        // Handler: Assets::EVENT_GET_ASSET_URL
299
        Event::on(
300
            Assets::class,
301
            Assets::EVENT_GET_ASSET_URL,
302
            function (GetAssetUrlEvent $event) {
303
                Craft::debug(
304
                    'Assets::EVENT_GET_ASSET_URL',
305
                    __METHOD__
306
                );
307
                // Return the URL to the asset URL or null to let Craft handle it
308
                $event->url = ImageOptimize::$plugin->optimize->handleGetAssetUrlEvent(
309
                    $event
310
                );
311
            }
312
        );
313
314
        // Handler: AssetTransforms::EVENT_GENERATE_TRANSFORM
315
        Event::on(
316
            AssetTransforms::class,
317
            AssetTransforms::EVENT_GENERATE_TRANSFORM,
318
            function (GenerateTransformEvent $event) {
319
                Craft::debug(
320
                    'AssetTransforms::EVENT_GENERATE_TRANSFORM',
321
                    __METHOD__
322
                );
323
                // Return the path to the optimized image to _createTransformForAsset()
324
                $event->tempPath = ImageOptimize::$plugin->optimize->handleGenerateTransformEvent(
325
                    $event
326
                );
327
            }
328
        );
329
330
        // Handler: AssetTransforms::EVENT_AFTER_DELETE_TRANSFORMS
331
        Event::on(
332
            AssetTransforms::class,
333
            AssetTransforms::EVENT_AFTER_DELETE_TRANSFORMS,
334
            function (AssetTransformImageEvent $event) {
335
                Craft::debug(
336
                    'AssetTransforms::EVENT_AFTER_DELETE_TRANSFORMS',
337
                    __METHOD__
338
                );
339
                // Clean up any stray variant files
340
                ImageOptimize::$plugin->optimize->handleAfterDeleteTransformsEvent(
341
                    $event
342
                );
343
            }
344
        );
345
346
        // Handler: Assets::EVENT_BEFORE_REPLACE_ASSET
347
        Event::on(
348
            Assets::class,
349
            Assets::EVENT_BEFORE_REPLACE_ASSET,
350
            function (ReplaceAssetEvent $event) {
351
                Craft::debug(
352
                    'Assets::EVENT_BEFORE_REPLACE_ASSET',
353
                    __METHOD__
354
                );
355
                /** @var Asset $element */
356
                $element = $event->asset;
357
                // Purge the URL
358
                $purgeUrl = ImageOptimize::$transformClass::getPurgeUrl(
359
                    $element,
360
                    ImageOptimize::$transformParams
361
                );
362
                if ($purgeUrl) {
363
                    ImageOptimize::$transformClass::purgeUrl($purgeUrl, ImageOptimize::$transformParams);
364
                }
365
            }
366
        );
367
368
        // Handler: Assets::EVENT_AFTER_REPLACE_ASSET
369
        Event::on(
370
            Assets::class,
371
            Assets::EVENT_AFTER_REPLACE_ASSET,
372
            function (ReplaceAssetEvent $event) {
373
                Craft::debug(
374
                    'Assets::EVENT_AFTER_REPLACE_ASSET',
375
                    __METHOD__
376
                );
377
                /** @var Asset $element */
378
                $element = $event->asset;
379
                if (!empty($element->id)) {
380
                    ImageOptimize::$plugin->optimizedImages->resaveAsset($element->id);
381
                }
382
            }
383
        );
384
    }
385
386
    /**
387
     * Install our Element event handlers
388
     */
389
    protected function installElementEventHandlers()
390
    {
391
        // Handler: Elements::EVENT_BEFORE_SAVE_ELEMENT
392
        Event::on(
393
            Assets::class,
394
            Elements::EVENT_BEFORE_SAVE_ELEMENT,
395
            function (ElementEvent $event) {
396
                Craft::debug(
397
                    'Elements::EVENT_BEFORE_SAVE_ELEMENT',
398
                    __METHOD__
399
                );
400
                /** @var Asset $asset */
401
                $asset = $event->element;
402
                if (!$event->isNew) {
403
                    // Purge the URL
404
                    $purgeUrl = ImageOptimize::$transformClass::getPurgeUrl(
405
                        $asset,
406
                        ImageOptimize::$transformParams
407
                    );
408
                    if ($purgeUrl) {
409
                        ImageOptimize::$transformClass::purgeUrl($purgeUrl, ImageOptimize::$transformParams);
410
                    }
411
                }
412
            }
413
        );
414
415
        // Handler: Elements::EVENT_BEFORE_DELETE_ELEMENT
416
        Event::on(
417
            Asset::class,
418
            Elements::EVENT_BEFORE_DELETE_ELEMENT,
419
            function (ElementEvent $event) {
420
                Craft::debug(
421
                    'Elements::EVENT_BEFORE_DELETE_ELEMENT',
422
                    __METHOD__
423
                );
424
                /** @var Asset $asset */
425
                $asset = $event->element;
426
                // Purge the URL
427
                $purgeUrl = ImageOptimize::$transformClass::getPurgeUrl(
428
                    $asset,
429
                    ImageOptimize::$transformParams
430
                );
431
                if ($purgeUrl) {
432
                    ImageOptimize::$transformClass::purgeUrl($purgeUrl, ImageOptimize::$transformParams);
433
                }
434
            }
435
        );
436
    }
437
438
    /**
439
     * If the Field being saved is an OptimizedImages field, re-save the responsive
440
     * image variants automatically
441
     *
442
     * @param FieldEvent $event
443
     *
444
     * @throws \yii\base\InvalidConfigException
445
     */
446
    protected function checkForOptimizedImagesField(FieldEvent $event)
447
    {
448
        $thisField = $event->field;
449
        if ($thisField instanceof OptimizedImages) {
450
            $volumes = Craft::$app->getVolumes()->getAllVolumes();
451
            foreach ($volumes as $volume) {
452
                $needToReSave = false;
453
                /** @var FieldLayout $fieldLayout */
454
                /** @var Volume $volume */
455
                $fieldLayout = $volume->getFieldLayout();
456
                // Loop through the fields in the layout to see if it contains our field
457
                if ($fieldLayout) {
458
                    $fields = $fieldLayout->getFields();
459
                    foreach ($fields as $field) {
460
                        if ($thisField->handle == $field->handle) {
461
                            $needToReSave = true;
462
                        }
463
                    }
464
                    if ($needToReSave) {
465
                        ImageOptimize::$plugin->optimizedImages->resaveVolumeAssets($volume);
466
                    }
467
                }
468
            }
469
        }
470
    }
471
}
472