Closed rugabarbo closed 3 years ago
Can't we add same set of annotations to Module
class to solve it? https://github.com/yiisoft/yii2/blob/master/framework/web/Application.php#L19
@samdark how can it help?
The module would autocomplete standard set of components.
The module would autocomplete standard set of components
I can not understand how this is related to auto-completion of module methods that are called by syntax
\Yii::$app->getModule('...')->
.
Directly. getModule()
returns an instance of Module
so it will autocomplete methods of the module. If the module has annotations for components, they will be autocompleted.
@samdark, I'm sorry, but I still do not understand...
Suppose I have this method:
class EmailModule extends Module
{
public function queue($to, $subject, $body, $params)
{
}
}
Suppose I configured the module like this:
'modules' => [
'email' => [
'class' => \namespace\for\EmailModule::class,
],
],
What annotations and where should I put in order to get an auto-completion of EmailModule::queue()
method?
Right. That's custom module so it isn't possible on the framework level. Your solution is fine but at application level. Won't be part of the framework. Check https://github.com/samdark/yii2-cookbook/blob/master/book/ide-autocompletion.md as well.
@samdark, I'm talking about the way of access to the methods of modules at the framework level. Syntax \Yii::$app->getModule('...')->
does not allow to use annotations for autocompletion. See my first post, please.
I see nothing in your first post that could be done in the framework itself. In order to have IDE completion for custom modules you have to make custom property annotations so you need to edit the file making it pointless to have it in the framework distribution.
😞
Don't know how to explain in other way that method \Yii::$app->getModule('..')
doesn't allow write annotations for concrete modules...
Will try later.
@samdark
Александр, попробую ещё раз объяснить на русском. Может быть получится лучше, чем на английском.
Синтаксис доступа к компонентам у фреймворка такой:
\Yii::$app->componentName
Это позволяет нам писать в файле autocompletion.php для автокомплита такие аннотации:
/**
* @property namespace\componentClass $componentName
*/
abstract class BaseApplication extends yii\base\Application
{
}
После этого мы можем без дополнительных PhpStorm-плагинов воспользоваться автодополнением для компонентов в IDE. Мы начинаем набирать \Yii::$app->componentName->
, а IDE предлагает нам список методов, которые реализованы в компоненте componentName.
Здесь всё ОК.
Синтаксис доступа к модулям у фреймворка такой:
\Yii::$app->getModule('moduleName')
И это НЕ позволяет нам реализовать автокомплит конкретных модулей с помощью файла autocompletion.php. В этом и проблема.
В качестве хака можно сделать так:
/**
* @method ModuleClass1|ModuleClass2|ModuleClass3|...|ModuleClassN getModule()
*/
abstract class BaseApplication extends yii\base\Application
{
}
Но проблема такого подхода в том, что IDE будет предлагать в качестве автодополнения методы всех указанных модулей одновременно – в моём примере это ModuleClass1, ModuleClass2, ModuleClass3 и т.д. Возникает путаница, это неудобно.
Предлагаю ввести дополнительный компонент по типу моего ModuleAccessor на уровне фреймворка, который обеспечит доступ к модулям с помощью синтаксиса:
\Yii::$app->mod->moduleName
Ключевое слово mod обсуждаемо. Его я выбрал для своих проектов, но на уровне фреймворка его можно заменить на что-то другое.
В общем, суть в том, что метод getModule('...') не позволяет использовать аннотации для автокомплита, и хочется решить эту проблему именно на уровне фреймворка.
Что думаешь?
Думаю, если так делать, придётся переделать много чего... Пока не вижу нормального способа. Твой — дублирование конфига, по сути. Не очень нравится.
Но если мы не видим нормального способа, то это ведь не значит, что его нет. Нужно просто подумать. Я видел, что авторы модулей решают эту проблему разными кривыми способами. Или создают трейты с методом getModule()
и соответствующим PhpDoc (примеры есть в issue #14421), или создают дополнительную локальную переменную:
/** @var moduleClass $module */
$module = \Yii::$app->getModule('name');
$module->...
Всё это хаки, которые не очень удобны.
@rugabarbo why MyModuleClass::getInstance()
can't be used instead of \yii::$app->getModule('MyModule')
?
@rugabarbo why
MyModuleClass::getInstance()
can't be used instead of\yii::$app->getModule('MyModule')
?
Because it forces you to refer to a specific class. Modules can be interchangeable. As a result, you bind to a specific class, not a module.
@rugabarbo I'd agree with you regarding components, but not modules
Calling modules using Module::getInstance()
is bad practice. The framework has a method \Yii::$app->getModule('MyModule')
for this.
Method Module::getInstance()
is intended for internal use within a module. But not for calling a module from an application. Please read the docs: https://www.yiiframework.com/doc/guide/2.0/en/structure-modules
If you want to bind to specific classes of modules in your application, then you can. But the modules were designed differently.
For example, in my projects some modules are interchangeable and I cannot use specific classes of modules in application. Moreover, there are applications that require checking whether the concrete module is installed or not. And in this case, using the class name of a module is also cannot be used...
Theoretically could be solved via PhpStorm meta files but overall, that's not a framework job since it involves actually mapping these annotations to real classes. Won't implement it.
The easiest and universal (cross-IDE) way is to create a helper class, kinda facades in Laravel:
<?php
class ModuleFacade
{
public static function integrationFacebook(): \frontend\modules\integration\modules\facebook\Module
{
return \yii::$app->getModule('integration-facebook');
}
public static function integrationTelegram(): \frontend\modules\integration\modules\telegram\Module
{
return \yii::$app->getModule('integration-telegram');
}
}
You'll need a separate helper for each of your applications - frontend, backend, console, etc.
For me the easiest way is workaround which I suggested at the beginning of the thread. I still use this method.
What I'm using now
Why?
Need IDE autocompletion for module methods. Using of the syntax
\Yii::$app->getModule('...')->
does not give such an opportunity.What I suggest
Implement something similar to my ModuleAccessor at the kernel level ☺️