Completed
Push — master ( ddc5b5...caec31 )
by Basil
03:16
created

Module::setUrlRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace luya\base;
4
5
use Yii;
6
use yii\helpers\Inflector;
7
use yii\base\InvalidParamException;
8
use yii\base\InvalidConfigException;
9
use luya\helpers\FileHelper;
10
use luya\console\interfaces\ImportControllerInterface;
11
12
/**
13
 * LUYA Module base class.
14
 *
15
 * The module class provides url rule defintions and other helper methods.
16
 *
17
 * In order to use a module within the CMS context it must extend from this base module class.
18
 *
19
 * @property array $urlRules Contains all urlRules for this module. You can either provide a full {{luya\web\UrlRule}} object configuration as array like this:
20
 * ```php
21
 * 'urlRules' => [
22
 *     ['pattern' => 'mymodule/detail/<id:\d+>', 'route' => 'mymodule/detail/user'],
23
 * ],
24
 * ```
25
 *
26
 * Or you can provide a key value pairing where key is the pattern and the value is the route:
27
 *
28
 * ```php
29
 * 'urlRules' => [
30
 *     'mymodule/detail/<id:\d+>' => 'mymodule/detail/user',
31
 * ],
32
 * ```
33
 *
34
 * @author Basil Suter <[email protected]>
35
 * @since 1.0.0
36
 */
37
abstract class Module extends \yii\base\Module
38
{
39
    /**
40
     * @var array Contains the apis for each module to provided them in the admin module. They represents
41
     * the name of the api and the value represents the class. Example value:
42
     *
43
     * ```php
44
     * [
45
     *     'api-admin-user' => 'admin\apis\UserController',
46
     *     'api-cms-navcontainer' => 'admin\apis\NavContainerController'
47
     * ]
48
     * ```
49
     */
50
    public $apis = [];
51
52
    /**
53
     * @var array An array with Tag class names to inject into the tag parser on luya boot, where key is the identifier and value the create object conifg:
54
     *
55
     * ```php
56
     * [
57
     *     'link' => 'luya\cms\tags\LinkTag',
58
     *     'file' => ['class' => 'luya\admin\tags\FileTag'],
59
     * ]
60
     * ```
61
     *
62
     * As by default the yii2 configurable object you can also pass properties to your tag object in order to configure them.
63
     */
64
    public $tags = [];
65
    
66
    private $_urlRules = [];
67
    
68
    /**
69
     * UrlRules for this module. You can either provide a full {{luya\web\UrlRule}}
70
     * object configuration as array like this:
71
     *
72
     * ```php
73
     * 'urlRules' => [
74
     *     ['pattern' => 'mymodule/detail/<id:\d+>', 'route' => 'mymodule/detail/user'],
75
     * ],
76
     * ```
77
     *
78
     * Or you can provide a key value pairing where key is the pattern and the value is the route:
79
     *
80
     * ```php
81
     * 'urlRules' => [
82
     *     'mymodule/detail/<id:\d+>' => 'mymodule/detail/user',
83
     * ],
84
     * ```
85
     *
86
     * @var array $rules Contains all urlRules for this module. You can either provide a full {{luya\web\UrlRule}}
87
     * object configuration as array
88
     * @since 1.0.1
89
     */
90
    public function setUrlRules(array $rules)
91
    {
92
        $this->_urlRules = $rules;
93
    }
94
95
    /**
96
     * Getter method for urlRules.
97
     *
98
     * > Never use the getter method, use the $urlRules virtual property as it provides backwards compatibility.
99
     *
100
     * @return array
101
     * @since 1.0.1
102
     */
103
    public function getUrlRules()
104
    {
105
        return $this->_urlRules;
106
    }
107
108
    /**
109
     * @var array An array containing all components which should be registered for the current module. If
110
     * the component does not exists an Exception will be thrown.
111
     */
112
    public $requiredComponents = [];
113
114
    /**
115
     * @var bool Defines the location of the layout file whether in the @app namespace or a module:
116
     *
117
     * - true = looking for layout file in `@app/views/<ID>/layouts`.
118
     * - false = looking for layout file in `@module/views/layouts/`.
119
     *
120
     * This variable is only available if your not in a context call. A context call would be if the cms renders the module.
121
     */
122
    public $useAppLayoutPath = true;
123
    
124
    /**
125
     * @var bool Define the location of the view files inside the controller actions
126
     *
127
     * - true = the view path of the @app/views
128
     * - false = the view path of the @modulename/views
129
     *
130
     */
131
    public $useAppViewPath = false;
132
    
133
    /**
134
     * @var string if this/the module is included via another module (parent module), the parent module will write its
135
     * name inside the child modules $context variable. For example the cms includes the news module, the context variable
136
     * of news would have the value "cms".
137
     */
138
    public $context;
139
140
    /**
141
     * @var string The default name of the moduleLayout
142
     */
143
    public $moduleLayout = 'layout';
144
145
    /**
146
     * @inheritdoc
147
     */
148
    public function init()
149
    {
150
        parent::init();
151
        // verify all the components
152
        foreach ($this->requiredComponents as $component) {
153
            if (!Yii::$app->has($component)) {
154
                throw new InvalidConfigException(sprintf('The required component "%s" is not registered in the configuration file', $component));
155
            }
156
        }
157
        
158
        static::onLoad();
159
    }
160
161
    /**
162
     * Override the default implementation of Yii's getLayoutPath(). If the property `$useAppLayoutPath` is true,.
163
     *
164
     * the *@app* namespace views will be looked up for view files
165
     *
166
     * @return string
167
     * @see \yii\base\Module::getLayoutPath()
168
     */
169
    public function getLayoutPath()
170
    {
171
        if ($this->useAppLayoutPath) {
172
            $this->setLayoutPath('@app/views/'.$this->id.'/layouts');
173
        }
174
175
        return parent::getLayoutPath();
176
    }
177
178
    /**
179
     * Extract the current module from the route and return the new resolved route.
180
     *
181
     * @param string $route Route to resolve, e.g. `admin/default/index`
182
     * @return string The resolved route without the module id `default/index` when input was `admin/default/index`
183
     * and the current module id is `admin`.
184
     */
185
    public function resolveRoute($route)
186
    {
187
        $routeParts = explode('/', $route);
188
        foreach ($routeParts as $k => $v) {
189
            if (($k == 0 && $v == $this->id) || (empty($v))) {
190
                unset($routeParts[$k]);
191
            }
192
        }
193
        if (count($routeParts) == 0) {
194
            return $this->defaultRoute;
195
        }
196
197
        return implode('/', $routeParts);
198
    }
199
200
    /**
201
     * register a component to the application. id => definition. All components will be registered during bootstrap process.
202
     *
203
     * @return array
204
     */
205
    public function registerComponents()
206
    {
207
        return [];
208
    }
209
210
    /**
211
     * Define a last of importer class with an array or run code directily with the import() method.
212
     *
213
     * Can be either an array with classes:
214
     *
215
     * ```php
216
     * public function import(ImportControllerInterface $importer)
217
     * {
218
     *     return [
219
     *         'path\to\class\Import',
220
     *         MyImporterClass::className(),
221
     *     ];
222
     * }
223
     * ```
224
     *
225
     * Or a direct functional call which executes importer things:
226
     *
227
     * ```php
228
     * public function import(ImportControllerInterface $importer)
229
     * {
230
     *     foreach ($importer->getDirectoryFiles('blocks') as $block) {
231
     *         // do something with block file.
232
     *     }
233
     * }
234
     * ```
235
     *
236
     * @param \luya\console\interfaces\ImportControllerInterface $importer The importer controller class which will be invoke to the import method.
237
     * @return boolean|array If an array is returned it must contain object class to created extending from {{luya\console\Command}}.
238
     */
239
    public function import(ImportControllerInterface $importer)
0 ignored issues
show
Unused Code introduced by
The parameter $importer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
        return false;
242
    }
243
    
244
    /**
245
     * returns "luya\base" for example.
246
     *
247
     * @return string
248
     */
249
    public function getNamespace()
250
    {
251
        return implode('\\', array_slice(explode('\\', get_class($this)), 0, -1));
252
    }
253
    
254
    /**
255
     * Returns all controller files of this module from the `getControllerPath()` folder, where the key is the reusable
256
     * id of this controller and value the file on the server.
257
     *
258
     * @return array Returns an array where the key is the controller id and value the original file.
259
     */
260
    public function getControllerFiles()
261
    {
262
        $files = [];
263
        try { // https://github.com/yiisoft/yii2/blob/master/framework/base/Module.php#L253
264
            foreach (FileHelper::findFiles($this->controllerPath) as $file) {
265
                $files[$this->fileToName($this->controllerPath, $file)] = $file;
266
            }
267
        } catch (InvalidParamException $e) {
268
            try {
269
                $staticPath = static::staticBasePath() . DIRECTORY_SEPARATOR . 'controllers';
270
                foreach (FileHelper::findFiles($staticPath) as $file) {
271
                    $files[$this->fileToName($staticPath, $file)] = $file;
272
                }
273
            } catch (InvalidParamException $e) {
274
                // catch if folder not found.
275
            }
276
        };
277
        
278
        return $files;
279
    }
280
    
281
    private function fileToName($prefix, $file)
282
    {
283
        $value = ltrim(str_replace([$prefix, 'Controller.php'], '', $file), DIRECTORY_SEPARATOR);
284
        return Inflector::camel2id($value);
285
    }
286
    
287
    /**
288
     * Overrides the yii2 default behavior by not throwing an exception if no alias has been defined
289
     * for the controller namespace. Otherwise each module requires an alias for its first namepsace entry
290
     * which results into exception for external modules without an alias.
291
     * exception.
292
     *
293
     * @inheritdoc
294
     */
295
    public function getControllerPath()
296
    {
297
        return Yii::getAlias('@' . str_replace('\\', '/', $this->controllerNamespace), false);
298
    }
299
300
    // STATIC METHODS
301
302
    /**
303
     * Internal used to register the translations from the translation array or set alias paths.
304
     *
305
     * This is a static behavior, so we can call this call without the object context, for example when
306
     * the composer plugin registers blocks but the module is not registered with translations.
307
     *
308
     * @return void
309
     */
310
    public static function onLoad()
311
    {
312
    }
313
    
314
    /**
315
     * Register a Translation to the i18n component.
316
     *
317
     * In order to register Translations you can register them inside the {{luya\base\Module::onLoad()}} method.
318
     *
319
     * ```php
320
     * public static function onLoad()
321
     * {
322
     *     $this->registerTranslation('mymodule*', static::staticBasePath() . '/messages', [
323
     *         'mymodule' => 'mymodule.php',
324
     *         'mymodule/sub' => 'sub.php',
325
     *     ]);
326
     * }
327
     * ```
328
     *
329
     * @param string $prefix The prefix of which the messages are indicated
330
     * @param string $basePath The path to the messages folder where the messages are located.
331
     * @param array $fileMap The files mapping inside the messages folder.
332
     */
333
    public static function registerTranslation($prefix, $basePath, array $fileMap)
334
    {
335
        Yii::$app->i18n->translations[$prefix] = [
336
            'class' => 'yii\i18n\PhpMessageSource',
337
            'basePath' => $basePath,
338
            'fileMap' => $fileMap,
339
        ];
340
    }
341
    
342
    /**
343
     * Get base path from static view port.
344
     *
345
     * @return string
346
     */
347
    public static function staticBasePath()
348
    {
349
        $class = new \ReflectionClass(get_called_class());
350
        
351
        return dirname($class->getFileName());
352
    }
353
354
    /**
355
     * Base translation method which invokes the onLoad function.
356
     *
357
     * This makes it possible to register module translations without adding the module
358
     * to the components list. This is very important for luya extensions.
359
     *
360
     * @param string $category the message category.
361
     * @param string $message the message to be translated.
362
     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
363
     * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
364
     * [[\yii\base\Application::language|application language]] will be used.
365
     * @return string the translated message.
366
     */
367
    public static function baseT($category, $message, array $params = [], $language = null)
368
    {
369
        static::onLoad();
370
        return Yii::t($category, $message, $params, $language);
371
    }
372
}
373