Code

< 40 %
40-60 %
> 60 %
1
<?php
2
3
namespace Nwidart\Modules;
4
5
use Illuminate\Cache\CacheManager;
6
use Illuminate\Container\Container;
7
use Illuminate\Contracts\Translation\Translator;
8
use Illuminate\Filesystem\Filesystem;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Str;
11
use Illuminate\Support\Traits\Macroable;
12
use Nwidart\Modules\Constants\ModuleEvent;
13
use Nwidart\Modules\Contracts\ActivatorInterface;
14
15
abstract class Module
16
{
17
    use Macroable;
18
19
    /**
20
     * The laravel|lumen application instance.
21
     *
22
     * @var \Illuminate\Contracts\Foundation\Application|\Laravel\Lumen\Application
23
     */
24
    protected $app;
25
26
    /**
27
     * The module name.
28
     */
29
    protected string $name;
30
31
    /**
32
     * The module path.
33
     */
34
    protected string $path;
35
36
    /**
37
     * Array of cached Json objects, keyed by filename
38
     */
39
    protected array $moduleJson = [];
40
41
    /**
42
     * Cache Manager
43
     */
44
    private CacheManager $cache;
45
46
    /**
47
     * Filesystem
48
     */
49
    private Filesystem $files;
50
51
    /**
52
     * Translator
53
     */
54
    private Translator $translator;
55
56
    /**
57
     * ActivatorInterface
58
     */
59
    private ActivatorInterface $activator;
60
61
    /**
62
     * The constructor.
63
     */
64
    public function __construct(Container $app, string $name, string $path)
65
    {
66 190
        $this->name = $name;
67
        $this->path = $path;
68 190
        $this->cache = $app['cache'];
69 190
        $this->files = $app['files'];
70 190
        $this->translator = $app['translator'];
71 190
        $this->activator = $app[ActivatorInterface::class];
72 190
        $this->app = $app;
73 190
    }
74 190
75 190
    /**
76
     * Returns an array of assets
77
     */
78
    public static function getAssets(): array
79
    {
80
        $paths = [];
81
82 132
        if (file_exists(public_path('build/manifest.json'))) {
83
            $files = json_decode(file_get_contents(public_path('build/manifest.json')), true);
84 132
85
            if (is_array($files)) {
86
                foreach ($files as $file) {
87
                    // Ignore files which aren't entrypoints.
88
                    if (empty($file['isEntry'])) {
89
                        continue;
90
                    }
91
92 146
                    if (isset($file['src'])) {
93
                        $paths[] = $file['src'];
94 146
                    }
95
                }
96
            }
97
        }
98
99
        return $paths;
100
    }
101
102 131
    /**
103
     * Get name.
104 131
     */
105
    public function getName(): string
106
    {
107
        return $this->name;
108
    }
109
110
    /**
111
     * Get name in lower case.
112 6
     */
113
    public function getLowerName(): string
114 6
    {
115
        return strtolower($this->name);
116
    }
117
118
    /**
119
     * Get name in studly case.
120
     */
121
    public function getStudlyName(): string
122 2
    {
123
        return Str::studly($this->name);
124 2
    }
125
126
    /**
127
     * Get name in studly case.
128
     */
129
    public function getKebabName(): string
130
    {
131
        return Str::kebab($this->name);
132 4
    }
133
134 4
    /**
135
     * Get name in snake case.
136
     */
137
    public function getSnakeName(): string
138
    {
139
        return Str::snake($this->name);
140
    }
141
142
    /**
143
     * Get description.
144
     */
145
    public function getDescription(): string
146
    {
147
        return $this->get('description');
148
    }
149
150
    /**
151
     * Get priority.
152 3
     */
153
    public function getPriority(): string
154 3
    {
155
        return $this->get('priority');
156
    }
157
158
    /**
159
     * Get path.
160
     */
161
    public function getPath(): string
162 152
    {
163
        return $this->path;
164 152
    }
165
166
    /**
167
     * Get app path.
168
     */
169
    public function getAppPath(): string
170
    {
171
        $app_path = rtrim($this->getExtraPath(config('modules.paths.app_folder', '')), '/');
172
173
        return is_dir($app_path) ? $app_path : $this->getPath();
174
    }
175
176
    /**
177
     * Set path.
178
     */
179
    public function setPath(string $path): self
180
    {
181
        $this->path = $path;
182
183
        return $this;
184 2
    }
185
186 2
    /**
187 2
     * Bootstrap the application events.
188
     */
189
    public function boot(): void
190 2
    {
191
        if (config('modules.register.translations', true) === true) {
192
            $this->registerTranslation();
193
        }
194 2
195 2
        if ($this->isLoadFilesOnBoot()) {
196
            $this->registerFiles();
197
        }
198
199
        $this->fireEvent(ModuleEvent::BOOT);
200
    }
201
202 2
    /**
203
     * Register module's translation.
204 2
     */
205
    protected function registerTranslation(): void
206 2
    {
207
        $lowerName = $this->getLowerName();
208 2
209 2
        $langPath = $this->getPath().'/Resources/lang';
210
211 2
        if (is_dir($langPath)) {
212
            $this->loadTranslationsFrom($langPath, $lowerName);
213
        }
214
    }
215
216
    /**
217
     * Get json contents from the cache, setting as needed.
218
     */
219
    public function json(?string $file = null): Json
220 124
    {
221
        if ($file === null) {
222 124
            $file = 'module.json';
223 122
        }
224
225
        return Arr::get($this->moduleJson, $file, function () use ($file) {
226
            return $this->moduleJson[$file] = new Json($this->getPath().'/'.$file, $this->files);
227 124
        });
228 124
    }
229
230
    /**
231
     * Get a specific data from json file by given the key.
232
     */
233
    public function get(string $key, $default = null)
234
    {
235
        return $this->json()->get($key, $default);
236
    }
237
238
    /**
239 14
     * Get a specific data from composer.json file by given the key.
240
     */
241 14
    public function getComposerAttr(string $key, $default = null)
242
    {
243
        return $this->json('composer.json')->get($key, $default);
244
    }
245
246
    /**
247
     * Register the module.
248
     */
249
    public function register(): void
250
    {
251
        $this->registerAliases();
252 2
253
        $this->registerProviders();
254 2
255
        if ($this->isLoadFilesOnBoot() === false) {
256
            $this->registerFiles();
257
        }
258
259
        $this->fireEvent(ModuleEvent::REGISTER);
260
    }
261
262
    /**
263
     * fire the module event.
264
     */
265
    public function fireEvent(string $event): void
266
    {
267
        $this->app['events']->dispatch(sprintf('modules.%s.%s', $this->getLowerName(), $event), [$this]);
268
    }
269
270
    /**
271
     * Register the aliases from this module.
272
     */
273
    abstract public function registerAliases(): void;
274
275
    /**
276
     * Register the service providers from this module.
277
     */
278 11
    abstract public function registerProviders(): void;
279
280 11
    /**
281 11
     * Get the path to the cached *_module.php file.
282
     */
283
    abstract public function getCachedServicesPath(): string;
284
285
    /**
286
     * Register the files from this module.
287
     */
288
    protected function registerFiles(): void
289
    {
290
        foreach ($this->get('files', []) as $file) {
291
            include $this->path.'/'.$file;
292
        }
293
    }
294
295
    /**
296
     * Handle call __toString.
297
     */
298
    public function __toString(): string
299
    {
300
        return $this->getStudlyName();
301
    }
302
303
    /**
304
     * Determine whether the given status same with the current module status.
305
     */
306
    public function isStatus(bool $status): bool
307
    {
308
        return $this->activator->hasStatus($this, $status);
309
    }
310
311
    /**
312
     * Determine whether the current module activated.
313
     */
314 5
    public function isEnabled(): bool
315
    {
316 5
        return $this->activator->hasStatus($this, true);
317
    }
318
319
    /**
320
     *  Determine whether the current module not disabled.
321
     */
322
    public function isDisabled(): bool
323
    {
324
        return ! $this->isEnabled();
325
    }
326 5
327
    /**
328 5
     * Set active state for current module.
329
     */
330
    public function setActive(bool $active): void
331
    {
332
        $this->activator->setActive($this, $active);
333
    }
334
335
    /**
336 12
     * Disable the current module.
337
     */
338 12
    public function disable(): void
339
    {
340
        $this->fireEvent(ModuleEvent::DISABLING);
341
342
        $this->activator->disable($this);
343
344
        $this->fireEvent(ModuleEvent::DISABLED);
345
    }
346 4
347
    /**
348 4
     * Enable the current module.
349
     */
350
    public function enable(): void
351
    {
352
        $this->fireEvent(ModuleEvent::ENABLING);
353
354
        $this->activator->enable($this);
355
356
        $this->fireEvent(ModuleEvent::ENABLED);
357
    }
358 1
359
    /**
360 1
     * Delete the current module.
361 1
     */
362
    public function delete(): bool
363
    {
364
        $this->fireEvent(ModuleEvent::DELETING);
365
366 5
        $this->activator->delete($this);
367
368 5
        $result = $this->json()->getFilesystem()->deleteDirectory($this->getPath());
369
370 5
        $this->fireEvent(ModuleEvent::DELETED);
371 5
372
        return $result;
373 5
    }
374 5
375
    /**
376
     * Get extra path.
377
     */
378
    public function getExtraPath(?string $path): string
379 6
    {
380
        return $this->getPath().($path ? '/'.$path : '');
381 6
    }
382
383 6
    /**
384 6
     * Check can load files of module on boot method.
385
     */
386 6
    protected function isLoadFilesOnBoot(): bool
387 6
    {
388
        return config('modules.register.files', 'register') === 'boot' &&
389
            // force register method if option == boot && app is AsgardCms
390
            ! class_exists('\Modules\Core\Foundation\AsgardCms');
391
    }
392
393
    /**
394 107
     * Register a translation file namespace.
395
     */
396 107
    private function loadTranslationsFrom(string $path, string $namespace): void
397
    {
398 107
        $this->translator->addNamespace($namespace, $path);
399
    }
400
}
401