1 | <?php |
||
2 | /** |
||
3 | * Autocomplete module for Craft CMS |
||
4 | * |
||
5 | * Provides Twig template IDE autocomplete of Craft CMS & plugin variables |
||
6 | * |
||
7 | * @link https://nystudio107.com |
||
8 | * @link https://putyourlightson.com |
||
9 | * @copyright Copyright (c) nystudio107 |
||
10 | * @copyright Copyright (c) PutYourLightsOn |
||
11 | */ |
||
12 | |||
13 | namespace nystudio107\autocomplete; |
||
14 | |||
15 | use Craft; |
||
16 | use craft\console\Application as CraftConsoleApp; |
||
17 | use craft\events\RegisterComponentTypesEvent; |
||
18 | use craft\services\Globals; |
||
19 | use craft\services\Plugins; |
||
20 | use craft\web\Application as CraftWebApp; |
||
21 | use nystudio107\autocomplete\base\Generator; |
||
22 | use nystudio107\autocomplete\console\controllers\AutocompleteController; |
||
23 | use nystudio107\autocomplete\generators\AutocompleteTwigExtensionGenerator; |
||
24 | use nystudio107\autocomplete\generators\AutocompleteVariableGenerator; |
||
25 | use yii\base\Application as YiiApp; |
||
26 | use yii\base\BootstrapInterface; |
||
27 | use yii\base\Event; |
||
28 | use yii\base\Module; |
||
29 | |||
30 | /** |
||
31 | * Class Autocomplete |
||
32 | * |
||
33 | * @author nystudio107 |
||
34 | * @package Autocomplete |
||
35 | * @since 1.0.0 |
||
36 | * |
||
37 | * @property-read string[] $allAutocompleteGenerators |
||
38 | */ |
||
39 | class Autocomplete extends Module implements BootstrapInterface |
||
40 | { |
||
41 | // Constants |
||
42 | // ========================================================================= |
||
43 | |||
44 | public const ID = 'craft-autocomplete'; |
||
45 | |||
46 | /** |
||
47 | * @event RegisterComponentTypesEvent The event that is triggered when registering |
||
48 | * Autocomplete Generator types |
||
49 | * |
||
50 | * Autocomplete Generator types must implement [[GeneratorInterface]]. [[Generator]] |
||
51 | * provides a base implementation. |
||
52 | * |
||
53 | * ```php |
||
54 | * use nystudio107\autocomplete\Autocomplete; |
||
55 | * use craft\events\RegisterComponentTypesEvent; |
||
56 | * use yii\base\Event; |
||
57 | * |
||
58 | * Event::on(Autocomplete::class, |
||
59 | * Autocomplete::EVENT_REGISTER_AUTOCOMPLETE_GENERATORS, |
||
60 | * function(RegisterComponentTypesEvent $event) { |
||
61 | * $event->types[] = MyAutocompleteGenerator::class; |
||
62 | * } |
||
63 | * ); |
||
64 | * ``` |
||
65 | */ |
||
66 | public const EVENT_REGISTER_AUTOCOMPLETE_GENERATORS = 'registerAutocompleteGenerators'; |
||
67 | |||
68 | public const DEFAULT_AUTOCOMPLETE_GENERATORS = [ |
||
69 | AutocompleteVariableGenerator::class, |
||
70 | AutocompleteTwigExtensionGenerator::class, |
||
71 | ]; |
||
72 | |||
73 | // Private Properties |
||
74 | // ========================================================================= |
||
75 | |||
76 | private $allAutocompleteGenerators; |
||
77 | |||
78 | // Public Methods |
||
79 | // ========================================================================= |
||
80 | |||
81 | /** |
||
82 | * @inerhitdoc |
||
83 | */ |
||
84 | public function __construct($id = self::ID, $parent = null, $config = []) |
||
85 | { |
||
86 | /** |
||
87 | * Explicitly set the $id parameter, as earlier versions of Yii2 look for a |
||
88 | * default parameter, and depend on $id being explicitly set: |
||
89 | * https://github.com/yiisoft/yii2/blob/f3d1534125c9c3dfe8fa65c28a4be5baa822e721/framework/di/Container.php#L436-L448 |
||
90 | */ |
||
91 | parent::__construct($id, $parent, $config); |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * Bootstraps the extension |
||
96 | * |
||
97 | * @param YiiApp $app |
||
98 | */ |
||
99 | public function bootstrap($app) |
||
100 | { |
||
101 | // Set the currently requested instance of this module class, |
||
102 | // so we can later access it with `Autocomplete::getInstance()` |
||
103 | static::setInstance($this); |
||
104 | |||
105 | // Make sure it's Craft |
||
106 | if (!($app instanceof CraftWebApp || $app instanceof CraftConsoleApp)) { |
||
107 | return; |
||
108 | } |
||
109 | // Make sure we're in devMode |
||
110 | if (!Craft::$app->config->general->devMode) { |
||
111 | return; |
||
112 | } |
||
113 | |||
114 | // Register our event handlers |
||
115 | $this->registerEventHandlers(); |
||
116 | |||
117 | // Add our console controller |
||
118 | if (Craft::$app->request->isConsoleRequest) { |
||
119 | Craft::$app->controllerMap['autocomplete'] = AutocompleteController::class; |
||
120 | } |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Registers our event handlers |
||
125 | */ |
||
126 | public function registerEventHandlers() |
||
127 | { |
||
128 | Event::on(Plugins::class, Plugins::EVENT_AFTER_INSTALL_PLUGIN, [$this, 'regenerateAutocompleteClasses']); |
||
129 | Event::on(Plugins::class, Plugins::EVENT_AFTER_UNINSTALL_PLUGIN, [$this, 'deleteAutocompleteClasses']); |
||
130 | Event::on(Globals::class, Globals::EVENT_AFTER_SAVE_GLOBAL_SET, [$this, 'deleteAutocompleteClasses']); |
||
131 | Event::on(CraftWebApp::class, CraftWebApp::EVENT_INIT, [$this, 'generateAutocompleteClasses']); |
||
132 | Craft::info('Event Handlers installed', __METHOD__); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Call each of the autocomplete generator classes to tell them to generate their classes if they don't exist already |
||
137 | */ |
||
138 | public function generateAutocompleteClasses() |
||
139 | { |
||
140 | if (Craft::$app->getIsInstalled()) { |
||
141 | $autocompleteGenerators = $this->getAllAutocompleteGenerators(); |
||
142 | foreach ($autocompleteGenerators as $generatorClass) { |
||
143 | /* @var Generator $generatorClass */ |
||
144 | $generatorClass::generate(); |
||
145 | } |
||
146 | Craft::info('Autocomplete classes generated', __METHOD__); |
||
147 | } |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Call each of the autocomplete generator classes to tell them to regenerate their classes from scratch |
||
152 | */ |
||
153 | public function regenerateAutocompleteClasses() |
||
154 | { |
||
155 | $autocompleteGenerators = $this->getAllAutocompleteGenerators(); |
||
156 | foreach ($autocompleteGenerators as $generatorClass) { |
||
157 | /* @var Generator $generatorClass */ |
||
158 | $generatorClass::regenerate(); |
||
159 | } |
||
160 | Craft::info('Autocomplete classes regenerated', __METHOD__); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Call each of the autocomplete generator classes to tell them to delete their classes |
||
165 | */ |
||
166 | public function deleteAutocompleteClasses() |
||
167 | { |
||
168 | $autocompleteGenerators = $this->getAllAutocompleteGenerators(); |
||
169 | foreach ($autocompleteGenerators as $generatorClass) { |
||
170 | /* @var Generator $generatorClass */ |
||
171 | $generatorClass::delete(); |
||
172 | } |
||
173 | Craft::info('Autocomplete classes deleted', __METHOD__); |
||
174 | } |
||
175 | |||
176 | // Protected Methods |
||
177 | // ========================================================================= |
||
178 | |||
179 | /** |
||
180 | * Returns all available autocomplete generator classes. |
||
181 | * |
||
182 | * @return string[] The available autocomplete generator classes |
||
183 | */ |
||
184 | public function getAllAutocompleteGenerators(): array |
||
185 | { |
||
186 | if ($this->allAutocompleteGenerators) { |
||
0 ignored issues
–
show
|
|||
187 | return $this->allAutocompleteGenerators; |
||
188 | } |
||
189 | |||
190 | $event = new RegisterComponentTypesEvent([ |
||
191 | 'types' => self::DEFAULT_AUTOCOMPLETE_GENERATORS, |
||
192 | ]); |
||
193 | $this->trigger(self::EVENT_REGISTER_AUTOCOMPLETE_GENERATORS, $event); |
||
194 | $this->allAutocompleteGenerators = $event->types; |
||
0 ignored issues
–
show
|
|||
195 | |||
196 | return $this->allAutocompleteGenerators; |
||
197 | } |
||
198 | } |
||
199 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.