Я занялся разработкой плагина для Yii3 под PHPStorm некоторое время назад.
Помимо плагина время от времени заглядываю в сам Yii3, на работе использую Yii2, различные библиотеки и вовсе на чистом PHP сделаны.
Переключаться между инструментами проблем не вызывает, но некоторые вещи имеют несколько бонусных DX (Developer Experience) очков, а некоторые в минусе.
Логично ведь, что если ты пишешь функцию, которая должна принимать значение из набора, то нужно показать этот набор. А может еще и свалидировать ошибку. А еще и провалиться внутрь по CTRL+Click. А еще и обратный референс найти. Ну и рефакторинг общий сделать, раз уж разошлись.
Давайте разберем пример:
$this->render('index', $params);
Вы сотню раз видели такой код и скорее всего точно можно угадать, что эта функция принимает имя вью файла и параметры в качестве аргументов.
Может ли 'index'
быть любым? Скорее всего нет. Может ли 'index'
быть заменен на 'view'
? Скорее всего да, если есть такой файл. Как понять есть ли такой файл? Сходить и посмотреть в директорию. В директории есть следующие файлы: 'index.php', 'view.php', 'create.php', 'update.php'
Ну и отлично? Нужно их и показать в автокомплите. Стоп, метод render()
принимает имя файла без его расширения .php
. Ну тогда и отрежем? Отрежем.
Раз уж знаем файл, то предоставим на него reference, чтобы PHPStorm предоставил переход к файлу и автоматический рефакторинг.
Таким образом мы можем сделать подсказки и для какого-нибудь FileHelper::read('/path/to/file.txt')
:
Знаем что будет файл
Знаем откуда будем отталкиваться если это relative path Значит можем сделать lookup в директорию и достать подсказки?
Помимо подсказок «в файл» скорее всего вы часто сталкиваетесь еще и с подсказками «в свойство»:
$activeRecord->getAttribute('<property>')
$activeRecord->getLabel('<property>')
Helper::getColumn($object, '<property>')
Helper::index($objects, '<property>')
$queryBuilder->where(['<property>' => '<value>])
И куча других примеров. Если функция принимает аргументом значение одного из свойств из нужного объекта, то скорее всего, при нарушении этого ограничения, вы получите исключение?
Такие фишки обычно закладывают в ABCD Plugin. Но этот плагин может не обновляться, отказаться от поддержки легаси, не существовать под вашу версию IDE, не поддерживать новые фичи и точно не будет поддерживать thrid-party libraries. В такие плагины закладывают немного иной функционал, но зачастую докидывают и всякие автокомплиты с референсингом.
Теперь не нужно искать плагин под вашу любимую библиотеку или собственный метод:
Добавляем конфиг
Комитим в репу
Повышаем DX вашего кода на 499 бонусных поинтов
В README описан пример и на мой взгляд он довольно понятен. Если нет, дайте мне знать.
Разберем несколько вариантов конфига, но для начала вводная:
Нулевое. Пишите сколько угодно файлов, храните их где хотите, главное чтобы файл имел окончание .meta-storm.xml
Первое. Всё должно лежать внутри:
<?xml version="1.0" encoding="UTF-8" ?>
<meta-storm xmlns="meta-storm">
<definitions>
----- тут все определения -----
</definitions>
</meta-storm>
Второе. На данный момент есть 2 варианта референсинга: файлы и свойства.
Третье. Есть текстовые процессоры: regexp
и append
для файлов.
Подсказка метода render()
в Yii2 фреймворке:
<files
className="\yii\base\Controller"
methodName="render"
argumentIndex="0"
fileExt="php"
relatedTo="file"
>
<directoryProcessors>
<regexp from="Controller\.php" to=""/>
<regexp from="([a-z])([A-Z])" to="$1-$2"/>
<regexp from="/controllers/" to="/views/"/>
<regexp from="/modules/([^\\/]+)/views/" to="/themes/default/modules/$1/views/"/>
</directoryProcessors>
</files>
Подсказка метода render()
в файле представления:
<files
className="\yii\base\View"
methodName="render"
argumentIndex="0"
fileExt="php"
relatedTo="directory"
/>
Одинаково для
renderFile
,renderAjax
Подсказка мейлера:
<files
className="\yii\swiftmailer\Mailer"
methodName="compose"
argumentIndex="0"
fileExt="php"
relatedTo="project"
>
<directoryProcessors>
<append value="common/mail/" />
</directoryProcessors>
</files>
Подсказка Active Form
:
<properties
className="\yii\widgets\ActiveForm"
methodName="field"
argumentIndex="1"
relatedTo="argument"
relatedArgumentIndex="0"
/>
Подсказка ArrayHelper
:
<properties
className="\yii\helpers\ArrayHelper"
methodName="getColumn"
argumentIndex="1"
relatedTo="argument"
relatedArgumentIndex="0"
/>
Описывать значения className
и methodName
думаю смысла нет.
argumentIndex
– это позиция аргумента, которому вы будете добавлять интерактив.
relatedTo
– та самая вещь, которая побудила меня написать этот плагин, значения могут быть следующие: file
, directory
, project
, argument
, variable
, все они описаны в документации. Основная мысль заложенная здесь – это base, от которой нужно отталкиваться:
Искать файлы в текущей директории
Искать файлы по статическому пути
Искать файлы по имени текущего файла, предварительно преобразовав его
Искать данные в переменной
$var->
Искать в аргументе:
property($obj, 'prop1')
Первая версия содержит описанный выше функционал, но уже есть некоторые планы на будущее. Буду рад фидбеку и желаемым фичам.
Как появится время, буду раскидывать Pull Request в используемые проекты. Вы уже сейчас можете установить себе плагин и попробовать покрыть любые из используемых кейсов.
Обсуждение доработок, фичей и багов можно вести в Issue на гитхабе.
Полезные ссылки
Обсуждение можно продолжить у меня в телеграмм канале