Completed
Push — master ( 174f7e...d11969 )
by Basil
03:45
created

Module::fileToName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
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
 * @author Basil Suter <[email protected]>
20
 * @since 1.0.0
21
 */
22
abstract class Module extends \yii\base\Module
23
{
24
    /**
25
     * @var array Contains the apis for each module to provided them in the admin module. They represents
26
     * the name of the api and the value represents the class. Example value:
27
     *
28
     * ```php
29
     * [
30
     *     'api-admin-user' => 'admin\apis\UserController',
31
     *     'api-cms-navcontainer' => 'admin\apis\NavContainerController'
32
     * ]
33
     * ```
34
     */
35
    public $apis = [];
36
37
    /**
38
     * @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:
39
     *
40
     * ```php
41
     * [
42
     *     'link' => 'luya\cms\tags\LinkTag',
43
     *     'file' => ['class' => 'luya\admin\tags\FileTag'],
44
     * ]
45
     * ```
46
     *
47
     * As by default the yii2 configurable object you can also pass properties to your tag object in order to configure them.
48
     */
49
    public $tags = [];
50
    
51
    /**
52
     * @var array Contains all urlRules for this module. You can either provide a full {{luya\web\UrlRule}}
53
     * object configuration as array like this:
54
     *
55
     * ```php
56
     * 'urlRules' => [
57
     *     ['pattern' => 'mymodule/detail/<id:\d+>', 'route' => 'mymodule/detail/user'],
58
     * ],
59
     * ```
60
     *
61
     * Or you can provide a key value pairing where key is the pattern and the value is the route:
62
     *
63
     * ```php
64
     * 'urlRules' => [
65
     *     'mymodule/detail/<id:\d+>' => 'mymodule/detail/user',
66
     * ],
67
     * ```
68
     */
69
    public $urlRules = [];
70
71
    /**
72
     * @var array An array containing all components which should be registered for the current module. If
73
     * the component does not exists an Exception will be thrown.
74
     */
75
    public $requiredComponents = [];
76
77
    /**
78
     * @var bool Defines the location of the layout file whether in the @app namespace or a module:
79
     *
80
     * - true = looking for layout file in `@app/views/<ID>/layouts`.
81
     * - false = looking for layout file in `@module/views/layouts/`.
82
     *
83
     * This variable is only available if your not in a context call. A context call would be if the cms renders the module.
84
     */
85
    public $useAppLayoutPath = true;
86
    
87
    /**
88
     * @var bool Define the location of the view files inside the controller actions
89
     *
90
     * - true = the view path of the @app/views
91
     * - false = the view path of the @modulename/views
92
     *
93
     */
94
    public $useAppViewPath = false;
95
    
96
    /**
97
     * @var string if this/the module is included via another module (parent module), the parent module will write its
98
     * name inside the child modules $context variable. For example the cms includes the news module, the context variable
99
     * of news would have the value "cms".
100
     */
101
    public $context;
102
103
    /**
104
     * @var string The default name of the moduleLayout
105
     */
106
    public $moduleLayout = 'layout';
107
108
    /**
109
     * @inheritdoc
110
     */
111
    public function init()
112
    {
113
        parent::init();
114
        // verify all the components
115
        foreach ($this->requiredComponents as $component) {
116
            if (!Yii::$app->has($component)) {
117
                throw new InvalidConfigException(sprintf('The required component "%s" is not registered in the configuration file', $component));
118
            }
119
        }
120
        
121
        static::onLoad();
122
    }
123
124
    /**
125
     * Override the default implementation of Yii's getLayoutPath(). If the property `$useAppLayoutPath` is true,.
126
     *
127
     * the *@app* namespace views will be looked up for view files
128
     *
129
     * @return string
130
     * @see \yii\base\Module::getLayoutPath()
131
     */
132
    public function getLayoutPath()
133
    {
134
        if ($this->useAppLayoutPath) {
135
            $this->setLayoutPath('@app/views/'.$this->id.'/layouts');
136
        }
137
138
        return parent::getLayoutPath();
139
    }
140
141
    /**
142
     * Extract the current module from the route and return the new resolved route.
143
     *
144
     * @param string $route Route to resolve, e.g. `admin/default/index`
145
     * @return string The resolved route without the module id `default/index` when input was `admin/default/index`
146
     * and the current module id is `admin`.
147
     */
148
    public function resolveRoute($route)
149
    {
150
        $routeParts = explode('/', $route);
151
        foreach ($routeParts as $k => $v) {
152
            if (($k == 0 && $v == $this->id) || (empty($v))) {
153
                unset($routeParts[$k]);
154
            }
155
        }
156
        if (count($routeParts) == 0) {
157
            return $this->defaultRoute;
158
        }
159
160
        return implode('/', $routeParts);
161
    }
162
163
    /**
164
     * register a component to the application. id => definition. All components will be registered during bootstrap process.
165
     *
166
     * @return array
167
     */
168
    public function registerComponents()
169
    {
170
        return [];
171
    }
172
173
    /**
174
     * Define a last of importer class with an array or run code directily with the import() method.
175
     *
176
     * Can be either an array with classes:
177
     *
178
     * ```php
179
     * public function import(ImportControllerInterface $importer)
180
     * {
181
     *     return [
182
     *         'path\to\class\Import',
183
     *         MyImporterClass::className(),
184
     *     ];
185
     * }
186
     * ```
187
     *
188
     * Or a direct functional call which executes importer things:
189
     *
190
     * ```php
191
     * public function import(ImportControllerInterface $importer)
192
     * {
193
     *     foreach ($importer->getDirectoryFiles('blocks') as $block) {
194
     *         // do something with block file.
195
     *     }
196
     * }
197
     * ```
198
     *
199
     * @param \luya\console\interfaces\ImportControllerInterface $importer The importer controller class which will be invoke to the import method.
200
     * @return boolean|array If an array is returned it must contain object class to created extending from {{luya\console\Command}}.
201
     */
202
    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...
203
    {
204
        return false;
205
    }
206
    
207
    /**
208
     * returns "luya\base" for example.
209
     *
210
     * @return string
211
     */
212
    public function getNamespace()
213
    {
214
        return implode('\\', array_slice(explode('\\', get_class($this)), 0, -1));
215
    }
216
    
217
    /**
218
     * Returns all controller files of this module from the `getControllerPath()` folder, where the key is the reusable
219
     * id of this controller and value the file on the server.
220
     *
221
     * @return array Returns an array where the key is the controller id and value the original file.
222
     */
223
    public function getControllerFiles()
224
    {
225
        $files = [];
226
        try { // https://github.com/yiisoft/yii2/blob/master/framework/base/Module.php#L253
227
            foreach (FileHelper::findFiles($this->controllerPath) as $file) {
228
                $files[$this->fileToName($this->controllerPath, $file)] = $file;
229
            }
230
        } catch (InvalidParamException $e) {
231
            try {
232
                $staticPath = static::staticBasePath() . DIRECTORY_SEPARATOR . 'controllers';
233
                foreach (FileHelper::findFiles($staticPath) as $file) {
234
                    $files[$this->fileToName($staticPath, $file)] = $file;
235
                }
236
            } catch (InvalidParamException $e) {
237
                 // catch if folder not found.
238
            }
239
        };
240
        
241
        return $files;
242
    }
243
    
244
    private function fileToName($prefix, $file)
245
    {
246
        $value = ltrim(str_replace([$prefix, 'Controller.php'], '', $file), DIRECTORY_SEPARATOR);
247
        return Inflector::camel2id($value);
248
    }
249
    
250
    /**
251
     * Overrides the yii2 default behavior by not throwing an exception if no alias has been defined
252
     * for the controller namespace. Otherwise each module requires an alias for its first namepsace entry
253
     * which results into exception for external modules without an alias.
254
     * exception.
255
     *
256
     * @inheritdoc
257
     */
258
    public function getControllerPath()
259
    {
260
        return Yii::getAlias('@' . str_replace('\\', '/', $this->controllerNamespace), false);
261
    }
262
263
    // STATIC METHODS
264
265
    /**
266
     * Internal used to register the translations from the translation array or set alias paths.
267
     *
268
     * This is a static behavior, so we can call this call without the object context, for example when
269
     * the composer plugin registers blocks but the module is not registered with translations.
270
     *
271
     * @return void
272
     */
273
    public static function onLoad()
274
    {
275
    }
276
    
277
    /**
278
     * Register a Translation to the i18n component.
279
     *
280
     * In order to register Translations you can register them inside the {{luya\base\Module::onLoad()}} method.
281
     *
282
     * ```php
283
     * public static function onLoad()
284
     * {
285
     *     $this->registerTranslation('mymodule*', static::staticBasePath() . '/messages', [
286
     *         'mymodule' => 'mymodule.php',
287
     *         'mymodule/sub' => 'sub.php',
288
     *     ]);
289
     * }
290
     * ```
291
     *
292
     * @param string $prefix The prefix of which the messages are indicated
293
     * @param string $basePath The path to the messages folder where the messages are located.
294
     * @param array $fileMap The files mapping inside the messages folder.
295
     */
296
    public static function registerTranslation($prefix, $basePath, array $fileMap)
297
    {
298
        Yii::$app->i18n->translations[$prefix] = [
299
            'class' => 'yii\i18n\PhpMessageSource',
300
            'basePath' => $basePath,
301
            'fileMap' => $fileMap,
302
        ];
303
    }
304
    
305
    /**
306
     * Get base path from static view port.
307
     *
308
     * @return string
309
     */
310
    public static function staticBasePath()
311
    {
312
        $class = new \ReflectionClass(get_called_class());
313
        
314
        return dirname($class->getFileName());
315
    }
316
317
    /**
318
     * Base translation method which invokes the onLoad function.
319
     * 
320
     * This makes it possible to register module translations without adding the module
321
     * to the components list. This is very important for luya extensions.
322
     * 
323
     * @param string $category the message category.
324
     * @param string $message the message to be translated.
325
     * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
326
     * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
327
     * [[\yii\base\Application::language|application language]] will be used.
328
     * @return string the translated message.
329
     */
330
    public static function baseT($category, $message, array $params = [], $language = null)
331
    {
332
        static::onLoad();
333
        return Yii::t($category, $message, $params, $language);
334
    }
335
}
336