1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Twigpack plugin for Craft CMS 3.x |
4
|
|
|
* |
5
|
|
|
* Twigpack is the conduit between Twig and webpack, with manifest.json & |
6
|
|
|
* webpack-dev-server HMR support |
7
|
|
|
* |
8
|
|
|
* @link https://nystudio107.com/ |
9
|
|
|
* @copyright Copyright (c) 2018 nystudio107 |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace nystudio107\twigpack; |
13
|
|
|
|
14
|
|
|
use nystudio107\twigpack\services\Manifest as ManifestService; |
15
|
|
|
use nystudio107\twigpack\models\Settings; |
16
|
|
|
use nystudio107\twigpack\variables\ManifestVariable; |
17
|
|
|
|
18
|
|
|
use Craft; |
19
|
|
|
use craft\base\Plugin; |
20
|
|
|
use craft\events\DeleteTemplateCachesEvent; |
21
|
|
|
use craft\events\PluginEvent; |
22
|
|
|
use craft\events\RegisterCacheOptionsEvent; |
23
|
|
|
use craft\events\TemplateEvent; |
24
|
|
|
use craft\services\Plugins; |
25
|
|
|
use craft\services\TemplateCaches; |
26
|
|
|
use craft\utilities\ClearCaches; |
27
|
|
|
use craft\web\twig\variables\CraftVariable; |
28
|
|
|
use craft\web\Application; |
29
|
|
|
use craft\web\View; |
30
|
|
|
|
31
|
|
|
use yii\base\Event; |
32
|
|
|
use yii\web\NotFoundHttpException; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Class Twigpack |
36
|
|
|
* |
37
|
|
|
* @author nystudio107 |
38
|
|
|
* @package Twigpack |
39
|
|
|
* @since 1.0.0 |
40
|
|
|
* |
41
|
|
|
* @property ManifestService $manifest |
42
|
|
|
*/ |
43
|
|
|
class Twigpack extends Plugin |
44
|
|
|
{ |
45
|
|
|
// Static Properties |
46
|
|
|
// ========================================================================= |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var Twigpack |
50
|
|
|
*/ |
51
|
|
|
public static $plugin; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var string |
55
|
|
|
*/ |
56
|
|
|
public static $templateName; |
57
|
|
|
|
58
|
|
|
// Static Methods |
59
|
|
|
// ========================================================================= |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @inheritdoc |
63
|
|
|
*/ |
64
|
|
|
public function __construct($id, $parent = null, array $config = []) |
65
|
|
|
{ |
66
|
|
|
$config['components'] = [ |
67
|
|
|
'manifest' => ManifestService::class, |
68
|
|
|
]; |
69
|
|
|
|
70
|
|
|
parent::__construct($id, $parent, $config); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
// Public Properties |
74
|
|
|
// ========================================================================= |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @var string |
78
|
|
|
*/ |
79
|
|
|
public $schemaVersion = '1.0.0'; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @var bool |
83
|
|
|
*/ |
84
|
|
|
public $hasCpSection = false; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @var bool |
88
|
|
|
*/ |
89
|
|
|
public $hasCpSettings = false; |
90
|
|
|
|
91
|
|
|
// Public Methods |
92
|
|
|
// ========================================================================= |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @inheritdoc |
96
|
|
|
*/ |
97
|
|
|
public function init() |
98
|
|
|
{ |
99
|
|
|
parent::init(); |
100
|
|
|
self::$plugin = $this; |
101
|
|
|
// Install our event listeners |
102
|
|
|
$this->installEventListeners(); |
103
|
|
|
// Log that we've loaded |
104
|
|
|
Craft::info( |
105
|
|
|
Craft::t( |
106
|
|
|
'twigpack', |
107
|
|
|
'{name} plugin loaded', |
108
|
|
|
['name' => $this->name] |
109
|
|
|
), |
110
|
|
|
__METHOD__ |
111
|
|
|
); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Clear all the caches! |
116
|
|
|
*/ |
117
|
|
|
public function clearAllCaches() |
118
|
|
|
{ |
119
|
|
|
// Clear all of Twigpack's caches |
120
|
|
|
self::$plugin->manifest->invalidateCaches(); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Inject the error entry point JavaScript for auto-reloading of Twig error |
125
|
|
|
* pages |
126
|
|
|
*/ |
127
|
|
|
public function injectErrorEntry() |
128
|
|
|
{ |
129
|
|
|
if (Craft::$app->getResponse()->isServerError || Craft::$app->getResponse()->isClientError) { |
130
|
|
|
$settings = self::$plugin->getSettings(); |
131
|
|
|
if (!empty($settings->errorEntry) && $settings->useDevServer) { |
132
|
|
|
try { |
133
|
|
|
$errorEntry = $settings->errorEntry; |
134
|
|
|
if (is_string($errorEntry)) { |
135
|
|
|
$errorEntry = [$errorEntry]; |
136
|
|
|
} |
137
|
|
|
foreach ($errorEntry as $entry) { |
138
|
|
|
$tag = self::$plugin->manifest->getJsModuleTags($entry, false); |
139
|
|
|
if ($tag !== null) { |
140
|
|
|
echo $tag; |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
} catch (NotFoundHttpException $e) { |
144
|
|
|
// That's okay, Twigpack will have already logged the error |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
// Protected Methods |
151
|
|
|
// ========================================================================= |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Install our event listeners. |
155
|
|
|
*/ |
156
|
|
|
protected function installEventListeners() |
157
|
|
|
{ |
158
|
|
|
// Remember the name of the currently rendering template |
159
|
|
|
// Handler: View::EVENT_BEFORE_RENDER_PAGE_TEMPLATE |
160
|
|
|
Event::on( |
161
|
|
|
View::class, |
162
|
|
|
View::EVENT_BEFORE_RENDER_PAGE_TEMPLATE, |
163
|
|
|
function (TemplateEvent $event) { |
164
|
|
|
self::$templateName = $event->template; |
165
|
|
|
} |
166
|
|
|
); |
167
|
|
|
// Handler: CraftVariable::EVENT_INIT |
168
|
|
|
Event::on( |
169
|
|
|
CraftVariable::class, |
170
|
|
|
CraftVariable::EVENT_INIT, |
171
|
|
|
function (Event $event) { |
172
|
|
|
/** @var CraftVariable $variable */ |
173
|
|
|
$variable = $event->sender; |
174
|
|
|
$variable->set('twigpack', ManifestVariable::class); |
175
|
|
|
} |
176
|
|
|
); |
177
|
|
|
// Handler: TemplateCaches::EVENT_AFTER_DELETE_CACHES |
178
|
|
|
Event::on( |
179
|
|
|
TemplateCaches::class, |
180
|
|
|
TemplateCaches::EVENT_AFTER_DELETE_CACHES, |
|
|
|
|
181
|
|
|
function (DeleteTemplateCachesEvent $event) { |
|
|
|
|
182
|
|
|
// Invalidate the caches when template caches are deleted |
183
|
|
|
$this->clearAllCaches(); |
184
|
|
|
} |
185
|
|
|
); |
186
|
|
|
// Handler: Plugins::EVENT_AFTER_INSTALL_PLUGIN |
187
|
|
|
Event::on( |
188
|
|
|
Plugins::class, |
189
|
|
|
Plugins::EVENT_AFTER_INSTALL_PLUGIN, |
190
|
|
|
function (PluginEvent $event) { |
191
|
|
|
if ($event->plugin === $this) { |
192
|
|
|
// Invalidate our caches after we've been installed |
193
|
|
|
$this->clearAllCaches(); |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
); |
197
|
|
|
// Handler: ClearCaches::EVENT_REGISTER_CACHE_OPTIONS |
198
|
|
|
Event::on( |
199
|
|
|
ClearCaches::class, |
200
|
|
|
ClearCaches::EVENT_REGISTER_CACHE_OPTIONS, |
201
|
|
|
function (RegisterCacheOptionsEvent $event) { |
202
|
|
|
Craft::debug( |
203
|
|
|
'ClearCaches::EVENT_REGISTER_CACHE_OPTIONS', |
204
|
|
|
__METHOD__ |
205
|
|
|
); |
206
|
|
|
// Register our caches for the Clear Cache Utility |
207
|
|
|
$event->options = array_merge( |
208
|
|
|
$event->options, |
209
|
|
|
$this->customAdminCpCacheOptions() |
210
|
|
|
); |
211
|
|
|
} |
212
|
|
|
); |
213
|
|
|
// delay attaching event handler to the view component after it is fully configured |
214
|
|
|
$app = Craft::$app; |
215
|
|
|
if ($app->getConfig()->getGeneral()->devMode) { |
216
|
|
|
$app->on(Application::EVENT_BEFORE_REQUEST, function () use ($app) { |
217
|
|
|
$app->getView()->on(View::EVENT_END_BODY, [$this, 'injectErrorEntry']); |
218
|
|
|
}); |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Returns the custom Control Panel cache options. |
224
|
|
|
* |
225
|
|
|
* @return array |
226
|
|
|
*/ |
227
|
|
|
protected function customAdminCpCacheOptions(): array |
228
|
|
|
{ |
229
|
|
|
return [ |
230
|
|
|
// Manifest cache |
231
|
|
|
[ |
232
|
|
|
'key' => 'twigpack-manifest-cache', |
233
|
|
|
'label' => Craft::t('twigpack', 'Twigpack Manifest Cache'), |
234
|
|
|
'action' => [$this, 'clearAllCaches'], |
235
|
|
|
], |
236
|
|
|
]; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* @inheritdoc |
241
|
|
|
*/ |
242
|
|
|
protected function createSettingsModel() |
243
|
|
|
{ |
244
|
|
|
return new Settings(); |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.