Verification: a143cc29221c9be0

Php artisan ide helper models не работает

Disclaimer

Код представленный ниже это обусифицированный боевой код, я его не отлаживал, может потребоваться доработка напильником. Я делюсь с вами только идеями.

Описание проблемы

Есть у нас ветка драфт, что бы пушить в драфт не надо делать МР, эта ветка нужна для того что бы программист мог по быстрому показать свои наработки бизнес аналитику, что бы фронт-энд мог интегрироваться с изменениями на бэк-энде. Драфт регулярно ресетиться.

То есть ты что то сделал с функционалом, решил показать другим разработчикам - выкатываешь всё на драфт, на БД драфта раскатывается твоя миграция, ты показал, понял что был не прав и переделываешь миграцию, в это время кто то ресетит драфт вместе с твоей миграцией, и что мы имеем ? мы имеем миграцию которая были применена и которую ни кто не откатил, как думаете получиться ещё раз её применить ?

Другая проблема в том что миграции локально применяются по мере разработки кода, а накатываются на БД, по мере тестирования кода. Фича которую ты разработал может на пару недель застрять в тестировании, а фича которую ты делал на этой неделе уже будет раскатана сегодня, и когда завтра из тестирования выйдет первая фича и будет накатываться на прод, могут возникнуть проблемы. Это не смертельно, но очень неприятно.

То есть порядок применения миграций иногда бывает хаотичным.

Правило первое: "накатывать можно бесконечно"

Правило первое, пишем миграцию так что бы её можно было бесконечное количество раз накатывать на саму себя. То есть накатываем миграцию, удаляем запись этой миграции в таблице migrations, и если мы ещё раз накатим эту же миграцию, то не должно быть эксепшена, миграция не должна вызвать сбой.

Миграцию можно как бесконечное количество раз накатить на саму себя, так и откатить с самой себя.

Для работы миграциями по штучно я использую такое команды:

# накатить конкретную миграцию
php artisan migrate --path="services/best-team-servise/database/migrations/2021_02_04_240000_alter_data_model_table_add_unique_index.php" --pretend
# ключ --pretend позволит нам посмотреть SQL до того как будет применена миграция, иногда полезно

# откатить ровно одну миграцию
php artisan migrate:rollback --step=1
# можно откатить и десять, при случае раберётесь

После того как миграция применена, можно сгенерировать описание модели

php artisan ide-helper:models "Project\Models\DataModel"

и сделать посев данных:

php artisan db:seed --class=DataModelSeeder

Как сделать так что бы миграцию можно было бесконечно применять ? в методах up() и down() миграции, мы должны делать проверку того, что действие со схемой БД можно выполнить.

Если мы добавляем колонку, то проверяем что колонка не существует, если мы дропаем индекс, то проверяем что индекс существует.

Получаем Builder :

        $conn = (new DataModel())->connection;
        $builder = Schema::connection($conn);

проверяем что миграция не была применена (проверяем что миграция может быть выполнена):

        $isExists = $builder->hasColumn(
            'data_model',
            'deleted_at'
        );

Если миграция может быть выполнена, то выполняем:

        if (!$isExists) {
            $builder->table(
                'data_model',
                function (Blueprint $table) {
                    $table->softDeletesTz();
                }
            );
        }

Аналогично с таблицами - проверяем что таблица не существует, с индексами - проверяем что индекс не существует, с индексами посложней, но можно, поможет такой код:

        $alias = (new DataModel())->connection;
        $builder = Schema
            ::connection($alias)
            ->getConnection()
            ->getDoctrineSchemaManager();

$existingIndexes = $builder->listTableIndexes('data_model');

С индексами в Laravel есть заморочка, если мы создали индекс как:

Blueprint::unique('index_name');

То и удалять надо как:

Blueprint::dropUnique('index_name');

С таблицами и колонками у Laravel ок, с индексами похуже, с триггерами совсем плохо, приходиться писать на чистом SQL, наверное я чего то не знаю о Laravel ? Адепты, подскажите !

Накатываем чистым SQL, пишем так:

DROP TRIGGER IF EXISTS trigger_name
    ON public.data_model;
CREATE TRIGGER trigger_name
    BEFORE INSERT
    ON public.data_model
    FOR EACH ROW
    EXECUTE PROCEDURE public.function_name();

Когда откатываем, пишем так же:

DROP TRIGGER IF EXISTS trigger_name
    ON public.data_model;

Правило второе: "шаблонные имена"

Миграций в проекте сотни, за полгода было написано 1000+ миграций. Конечно вся 1000 не лежит в одной директории, они раскиданы по директориям модулей.

Но тем нем нее, когда открываешь директорию в которой 50+ миграций, тебе сложно ориентироваться в них без "хороших" имён.

Соглашения об именах

Если создаём таблицу, то имя миграции начинается с create, если меняем таблицу то alter, если удаляем таблицу, то drop.

Следующая часть имени миграции это имя колонки или индекса над которым будет произведены изменения.

alter_data_model_add_property_column
alter_data_model_alter_property_column_to_text
alter_data_model_alter_property_column_set_default_value
alter_data_model_create_index_on_code_type_columns
alter_data_model_create_unique_index_on_code_column

Дропать таблицы, конечно, можно только на этапе MVP.

Команды для создания миграций:

# делаем миграцию для создания таблицы
php artisan make:migration create_profile_table --create=profile

# делаем миграцию для изменения таблицы
php artisan make:migration add_confirmed_to_profile --table=profile

Файл миграции будет помещён в директорию database/migrations собственно приложения, у нас каждый сервис это отдельный пакет и после создания файла миграции его надо переложить в директорию своего пакета.

Правило третье: таблицы и колонки дропать нельзя, все колонки nullable()

Поскольку миграции применяются хаотично, и в одной версии колонка может быть создана и если колонка будет NOT NULL, то версия кода, которая ни чего не знает об этой колонке, не сможет работать, пока мы не откатим миграцию в которой эта колонка создаётся.

Откатывать миграции вместе с репозиторием, эта так себе занятие.

Поэтому все колонки должны быть только nullable(), проверку того что обязательные колонки имеют значение, надо делать на уровне кода бизнес логики или с помощью обсерверов.

Соответственно при посеве данных, что бы не подменять файлы данных для посева, не прописывать какие конкретно колонки мы пишем - мы должны делать запись только в те колонки которые существуют:

            $columns = Schema
            ::connection((new DataModel())->connection)
            ->getConnection()
            ->getDoctrineSchemaManager()
            ->listTableColumns($(new DataModel())->getTable());

            $data = [];
            foreach ($columns as $column) {
                $name = $column->getName();
/* @var array[] $record строка данных для посева*/
                $exists = key_exists($name, $record);
                if ($exists) {
                    $data[$name] = $record[$name];
                }
            }

            $isSuccess = DataModel
                ::withTrashed()
                ->updateOrCreate(
                    ['uniqe_index_column' => $data['uniqe_index_column'],],
                    $data
                )->exists;

Правило четвёртое: значения по умолчанию, там где null недопустим

Булевые колонки должны иметь значение по умолчанию, колонки статусов и тому подобное, тоже должны иметь значения по умолчанию, что бы записи добавленные кодом который ни чего не знает об этих колонках, не ломал работу кода, для которого эти колонки необходимы.

Либо можно в коде использовать какое то значение по умолчанию, но я такой способ не люблю, потому что это хард код, и это убивает гибкость нашего приложения. Работа приложения должна настраиваться или через переменные окружения, или файлы конфигов, или записи БД.

Подсказки

Ctrl+P
Показать подсказку по параметрам метода или функции. (Parameter Info)
Ctrl+Shift+Enter
Дополнение языковых конструкций (if, switch, for, foreach)
Ctrl+Shift+I
Показать реализацию метода/функции, применяемые стили HTML класса, etc.. (Quick Definition)

Форматирование

Ctrl+D
Дублировать строку под курсором.
Ctrl+Shift+D       Ctrl+Y
Удалить строку под курсором.
Ctrl+Shift+J
Объединить выделенные строки в одну (multiline to single line). Это упрощает форматирование массивов и HTML тегов.
Ctrl+Alt+R
Отформатировать код.
Ctrl+Shift+↑↓
Меняет строки местами, перемещает текущую строку вверх/вниз.
Ctrl+Alt+J
Обернуть HTML тегом выделенный текст или текущую строку.
Ctrl+Shift+J может не работать, если итоговая строка будет длиннее допустимых 80-160 символов.
Настроить допустимую ширину экрана/колонок, Settings » Editor » Code Style, Hard wrap at: 120.

Навигация

Ctrl+B
Открыть файл реализации класса по выделенному имени класса. То же, что и Ctrl+Click.
Ctrl+J
Окно Live Template шаблонов.
Alt+      Alt+
Перемещение между методами класса - предыдущий метод, следующий метод
Ctrl+F12
Окно со списком методов класса (сигнатура класса)
Ctrl+E
Окно с последними измененными файлами
Ctrl+Shift+N
Быстрый поиск и открытие файла (выделите часть имени файла или класса и нажмите сочетание клавиш).
Ctrl+Alt+Shift+N
Быстрый поиск и переход к символу (классу, методу, переменной, константе).  Поиск также работает по первым символам CamelCase  имени. Например по caca будет найдено CamelCase.
Ctrl+-/+
Свернуть/развернуть (collapse/expand) блок под курсором
Ctrl+Shift+-/+
Свернуть/развернуть (collapse/expand) все
Ctrl+Alt+-/+
Свернуть/развернуть (collapse/expand) все комментарии (это кастомный хоткей)
Alt+Enter
Это универсальный контекстный помощник. Отображает контекстное меню с доступными действиями, в зависимости от того где находится курсор. Тут и:
  • Импорт класса под курсором в секцию use;
  • Обновление блока комментариев по сигнатуре метода;
  • Добавление методов интерфейса, которые необходимо реализовать;
  • Замена кавычек для строк;
Ctrl+W   или  Alt+Shift+
Последовательное выделение области под кареткой. (Select Word at Caret). Я добавил еще и хоткей Alt+A - он сподручней.
Alt+1
Показать/скрыть панель дерева файлов проекта (Project Tool Window)
Alt+2
Я переопределил этот хоткей на панель структуры класса (Structure Tool Window)
Alt+3
Показать/скрыть панель с результатами последнего поиска (Find Tool Window)
Alt+4
Я заремапил этот хоткей на панель консоли (Terminal Tool Window). По умолчанию на этой клавише находится Run Tool Window, а панель терминала вызывалась по Alt+-.
Ctrl+Shift+X
Панель Command Tools Console. Консоль командных инструментов как-то Composer, Symfony 2 (app/console), Laravel (artisan), etc.. Есть поддержка дополнения кода.
Shift+Escape
Скрыть текущую активную панель (Hide Active Tool Window). Я добавил на этот экшн просто клавишу Escape.
Ctrl+Tab
Переключение между 2-мя последними вкладками редактора.

Закладки (Bookmark)

Ctrl+F11 или F11
Поставить закладку.
Ctrl+Shift+F11
Поставить закладку с указанием мнемоники (идентификатора, номера закладки)
Shift+F11
Показать закладки

Кодинг и рефакторинг

Shift+F6
Переименовать переменную (или теги HTML элемента) везде, где она используется.
Ctrl+Alt+V
Извлечь (вынести) выделенный код в переменную.
Ctrl+Alt+M
Извлечь (вынести) выделенный код в метод
F6
Перенести static методы в другой класс вместе с обновлением всех участков кода, в которых эти методы вызываются.
Alt+F7
Найти в проекте все (явные) места, в которых используется класс, метод, свойство, ф-ция (под курсором).
Ctrl+Shift+O-M
Список magic или родительских методов для переопределения (Override Methods). Переопределил с Ctrl+O.

Форматирование

Ctrl+D
Дублировать строку под курсором.
Ctrl+Shift+D       Ctrl+Y
Удалить строку под курсором.
Ctrl+Shift+J
Объединить выделенные строки в одну (multiline to single line). Это упрощает форматирование массивов и HTML тегов.
Ctrl+Alt+R
Отформатировать код.
Ctrl+Shift+↑↓
Меняет строки местами, перемещает текущую строку вверх/вниз.
Ctrl+Alt+J
Обернуть HTML тегом выделенный текст или текущую строку.
Ctrl+Shift+J может не работать, если итоговая строка будет длиннее допустимых 80-160 символов.
Настроить допустимую ширину экрана/колонок, Settings » Editor » Code Style, Hard wrap at: 120.

Навигация

Ctrl+B
Открыть файл реализации класса по выделенному имени класса. То же, что и Ctrl+Click.
Ctrl+J
Окно Live Template шаблонов.
Alt+      Alt+
Перемещение между методами класса - предыдущий метод, следующий метод
Ctrl+F12
Окно со списком методов класса (сигнатура класса)
Ctrl+E
Окно с последними измененными файлами
Ctrl+Shift+N
Быстрый поиск и открытие файла (выделите часть имени файла или класса и нажмите сочетание клавиш).
Ctrl+Alt+Shift+N
Быстрый поиск и переход к символу (классу, методу, переменной, константе).  Поиск также работает по первым символам CamelCase  имени. Например по caca будет найдено CamelCase.
Ctrl+-/+
Свернуть/развернуть (collapse/expand) блок под курсором
Ctrl+Shift+-/+
Свернуть/развернуть (collapse/expand) все
Ctrl+Alt+-/+
Свернуть/развернуть (collapse/expand) все комментарии (это кастомный хоткей)
Alt+Enter
Это универсальный контекстный помощник. Отображает контекстное меню с доступными действиями, в зависимости от того где находится курсор. Тут и:
  • Импорт класса под курсором в секцию use;
  • Обновление блока комментариев по сигнатуре метода;
  • Добавление методов интерфейса, которые необходимо реализовать;
  • Замена кавычек для строк;
Ctrl+W   или  Alt+Shift+
Последовательное выделение области под кареткой. (Select Word at Caret). Я добавил еще и хоткей Alt+A - он сподручней.
Alt+1
Показать/скрыть панель дерева файлов проекта (Project Tool Window)
Alt+2
Я переопределил этот хоткей на панель структуры класса (Structure Tool Window)
Alt+3
Показать/скрыть панель с результатами последнего поиска (Find Tool Window)
Alt+4
Я заремапил этот хоткей на панель консоли (Terminal Tool Window). По умолчанию на этой клавише находится Run Tool Window, а панель терминала вызывалась по Alt+-.
Ctrl+Shift+X
Панель Command Tools Console. Консоль командных инструментов как-то Composer, Symfony 2 (app/console), Laravel (artisan), etc.. Есть поддержка дополнения кода.
Shift+Escape
Скрыть текущую активную панель (Hide Active Tool Window). Я добавил на этот экшн просто клавишу Escape.
Ctrl+Tab
Переключение между 2-мя последними вкладками редактора.

Закладки (Bookmark)

Ctrl+F11 или F11
Поставить закладку.
Ctrl+Shift+F11
Поставить закладку с указанием мнемоники (идентификатора, номера закладки)
Shift+F11
Показать закладки

Кодинг и рефакторинг

Shift+F6
Переименовать переменную (или теги HTML элемента) везде, где она используется.
Ctrl+Alt+V
Извлечь (вынести) выделенный код в переменную.
Ctrl+Alt+M
Извлечь (вынести) выделенный код в метод
F6
Перенести static методы в другой класс вместе с обновлением всех участков кода, в которых эти методы вызываются.
Alt+F7
Найти в проекте все (явные) места, в которых используется класс, метод, свойство, ф-ция (под курсором).
Ctrl+Shift+O-M
Список magic или родительских методов для переопределения (Override Methods). Переопределил с Ctrl+O.

Отладка

Shift+F7
Выбрать функцию/метод для следующего "Step into" (см. видео фрагмент)

Установка и настройка laravel-ide-helper

Установка для Laravel 4.x

Подключение пакета barryvdh/laravel-ide-helper:

composer require --dev "barryvdh/laravel-ide-helper: 1.*"

Регистрация пакета в файле app/config/app.php в секции providers:

'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',

Для автоматического обновление документации при обновлении зависимостей проекта - пропишите команду генерации в секцию post-update-cmd файла composer.json:

"post-update-cmd": [
  "php artisan clear-compiled",
  "php artisan ide-helper:generate -M",
  "php artisan optimize"
],

Установка для Laravel 5.x

Подключение пакета barryvdh/laravel-ide-helper:

composer require --dev barryvdh/laravel-ide-helper

Регистрация пакета в файле  config/app.php в секции providers:

Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,

Для автоматического обновление документации при обновлении зависимостей проекта - пропишите команду генерации в секцию post-update-cmd файла composer.json:

"post-update-cmd": [
  "Illuminate\\Foundation\\ComposerScripts::postUpdate",
  "php artisan ide-helper:generate",
  "php artisan ide-helper:meta",
  "php artisan optimize"
]
Примечание

Если вы не используете БД и вас достала ошибка: Could not determine driver/connection for DB... SQLSTATE[28000] [1045] Access denied for user... - запустите генерацию документации с опцией -M. Этим параметром мы указываем использовать SQLite Memory, а для него не нужны ни какие настройки доступа:

php artisan ide-helper:generate -M

Уберите опцию -M, если у вас настроено соединение с БД.

Для генерации документации в файл _ide_helper.php вручную - выполните:

php artisan clear-compiled && php artisan ide-helper:generate -M

Или запустите скрипт композера:

composer run-script post-update-cmd

Использование laravel-ide-helper

Документирование свойств моделей

Требуется установить пакет:

composer require --dev doctrine/dbal

Для файла документации моделей _ide_helper_models.php с описанием свойств модели и дополнительных методов фильтрации выполните:

php artisan ide-helper:models --nowrite
Примечание

При генерации файла _ide_helper_models.php документация из блока комментариев класса модели будет добавлена к сгенерированной документации. Но, использую отдельный файл документации, вы столкнетесь с проблемой инспекции кода своей IDE и ошибкой: "Multiple definitions exist for class YourModel" или "Other declaration of class Model exist at _ide_helper_models".

Решения этой проблемы все еще нет.. Голосуемhttps://youtrack.jetbrains.com/issue/WI-17646

Вы можете лишь подавить эту ошибку: Settings » Inspections » PHP » Undefined » Undefined class » Don't report multiple class declaration potential problems.

Или указать IDE не инспектировать отдельный класс:

/** @noinspection PhpUndefinedClassInspection */

Для этого можно поставить курсор внутри класса модели или на ее имени, жмем Alt+Enter → Inspection options → Supress for statement. Хотя, для моделей сторонних библиотек такой способ не особо хорош.

Для генерации блока комментариев непосредственно в классах моделей выполните:

php artisan ide-helper:models --write
Примечание

При генерации PhpDoc комментариев в класс модели существующая документация будет сохранена. Также останутся незатронутыми описания свойств.

Вы можете указать определенные модели для которых нужно сгенерировать документацию:

php artisan ide-helper:models User "Api\Post" --nowrite

Также вы можете документировать необходимые свойства и методы моделей вручную. Пример:

/**
 * @property  string  $title  Описание свойства
 * @property  \Illuminate\Database\Eloquent\Collection|\Roles[]  $roles
 * @property  \Carbon\Carbon  $created_at
 * @property  \Carbon\Carbon  $updated_at
 *
 * @method static \User firstOrFail(array $columns=[])
 * @method static \Illuminate\Support\Collection|\User findOrFail(mixed $id, array $columns=['*'])
 * @method static \User whereName(string $username)
 */
class User extends Eloquent {}

Расширенная конфигурация

Для расширенной конфигурации генератора документации _ide_helper необходимо опубликовать конфиг пакета:

php artisan config:publish barryvdh/laravel-ide-helper

Опции конфигурации

include_helpers
Генерировать ли документацию для функций-хелперов в файл _ide_helper.php. По умолчанию false, т.к. PhpStorm и так предоставляет возможность использовать дополнения кода для helper'ов (http://laravel.com/docs/4.2/helpers).
extra
Указать дополнительные классы, методы которых будут добавлены к зарегистрированным фасадам (aliases из файла app/config/app.php).
magic
Этот параметр используется для подмены методов фасада собственными. Применимо только к фасадам описанным в секции aliases файла app/config/app.php.

Проектирование/подготовка

Разработку бота предлагаю, как и все нормальные разработчики, начать с проектирования, постановки задачи и объяснения как работает laravel. Перед этим скажу, что я пишу код в phpStrom. Можно писать в любом другом IDE, но я пользуюсь именно им.

В laravel реализован паттерн MVC(Model View Controller). Это не значит, что нужно писать только под mvc, можно и говнокодить, но лучше пользоваться теми преимуществами, которые предоставляет фреймворк. Если вы знакомы с mvc, но не применяли его, как я, то разработка с помощью laravel’a это лучший способ закрепить знания.

Что должен делать наш бот:


  • Спрашивать у пользователя его имя
  • Поинтересоваться, нравится пользователю погода или нет
  • Также записать ответ в БД
  • Попрощаться и отправить картинку

Немного о MVC. При обращение к нашему ПО, посредством команд(url адреса), мы должны принять эти команды и обработать, понять, что требуется пользователю. Для этого есть пути, так называемые routes. Routes определяет какой Controller нужно использовать, в свою очередь controller, если это требуется, обращается к БД через model. Model связывается с базой данных и возвращает нужный нам результат. В боте view не нужен, т.к. вся работа идет через интерфейс мессенджера. Тем самым, после получения данных от model’и, controller отдает эти данные view, в нашем случае это blade шаблон (именно его использует laravel). Данные можно отдать и обычной php странице, но лучше это делать через blade шаблоны. Мы используем интерфейс мессенджера, то отправлять данные будем сразу в него.