Passed
Push — develop ( 4ac642...83abb8 )
by Andrew
03:28
created

ImageOptimize::installCraftQLEventHandlers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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