Isolution666
@Isolution666
Full-Stack Developer

Как правильно и безопасно пользоваться ORM в Yii2?

Здравствуйте.
Предыстория

Кто знает, что такое ORM, и особенно, кто пользовался, знают и понимают, что эта штука очень удобная.
Я искал, есть ли ORM в Yii2 - и нашёл там Doctrine - ( устанавливается вместе с Yii ) и класс Migration
Вы скажете, открой консоль и введи yii migrate - и будет тебе счастье.
Да! Когда ты разработчик и делаешь проект у себя на компе, можно и через консоль. НО! Если это заказчик и его сайт уже в сети интернет, и он не умеет пользоваться консолью???
Получается, что, если я хочу очистить таблицу, то я вызываю функцию, которая выполняет это действие.


Например:
в модели

<?php
use yii\db\Migration;
 
class Action extends Migration
{
    public function up($table, $params = [])
    {
        $this->createTable($table, [
            'id' => $this->primaryKey(),
            $params // передаём массив того, какие столбцы надо добавить
        ]);
    }
 
    public function down($table)
    {
        $this->dropTable($table); // передаём, какую таблицу будем удалять
    }

    public function clear($table)
    {
        $this->truncateTable($table); // передаём, какую таблицу будем очищать
    }

    public function getColumn($table, $column, $type = 'string')
    {
        $this->addColumn($table, $column, $type); // добавление столбца в таблицу
    }
// и так далее ...
}
?>



В контроллере:
пример

<?php
...
class SiteController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'clear' => ['post'], // post ?? - чтобы выполнить ?
                ],
            ],
        ];
    }
...

    public function actionClear() 
    { 
        Action::clear('post');
        return $this->redirect(['index']);
    } 
...
}
?>



В представлении:
пример

...
<?=Html::a('Truncate table', ['site/clear'], ['title' => 'очистить таблицу?', 'class' => 'btn', 'data-method' => 'post', 'data-pjax' => '',]);?>
...



Кто уже сталкивался с этим? Можно ли так выводить функционал по ссылке, безопасно ли это ?
Как обнулять индексы после очистки таблицы, чтобы автоинкримент опять начался с 1. ?

Так же хочу заметить, что подобного рода функционал доступен только одному человеку - администратору, в панели управления, которая не доступна обычным пользователям. Если к ссылке привязать post запрос, то другие запросы эта ссылка выполнить не сможет, будет запрещено, даже если кто-то угадает эту ссылку, она не выполнится, потому что не передаст request. Какие будут рекомендации?
  • Вопрос задан
  • 172 просмотра
Решения вопроса 1
myks92
@myks92 Куратор тега Yii
Нашёл решение — пометь вопрос ответом!
Даже если вы или кто-то другой «примонтировал» доктрину к проекту Yii2 (такое в принципе возможно), то это не означает, что не нужно понимать смысл миграций. Как уже сказал, Максим Федоров, миграции нужны для версионирования базы данных. Использовать версионирование (миграции) БД как команду - глупая затея.

Кроме того, миграции не должны работать с данными, они версионируют только схему. На рабочем проекте, с данными, вы работаете: через скрипты, SQL запросами и т.д.

К примеру. Вы скачали проект из репозитория. Создали пустую базу данных. Подключили к проекту. Применяете миграции, а они выдают ошибку, связанную с миграцией данных которых у вас нет. Это понятно?

Дак как же вам организовать работу заказчика не через консоль, а через веб интерфейс? Пойти можно двумя способами:

  1. С помощью Web скрипта. Создать методы в контроллере, которые будут удалять данные, изменять автоикремент напрямую, как при работе с обычными данными. У вас получится некая обертка над базой. Работайте хоть через простой SQL запрос или используя Доктрину, но это не должно быть с помощью миграций!
  2. С помощью консольного скрипта и очереди. Сделать тоже самое что и в первом варианте, только при вызове метода в контроллере вы не удаляете данные, а закидываете задачу в очередь: "Удали мне все данные из таблицы". Очередь запускается по крону, например, каждые 5 минут. Заказчик видит статус очередей по своим командам: в очереди, в работе, выполнено. Можно пойти и без очередей, но так будет лучше и у заказчика будет обратная связь.

Когда использовать второй вариант? Тогда, когда у вас могут возникнуть ошибки по лимиту памяти. Как правило, это работа с большими данными.

Например, если в вашей таблице 10 записей, то такой процесс легко можно запустить через обычный Web-овский скрипт. Но если у вас в БД 10 000 000 млн. записей, то у вас возникнет ошибка по лимиту памяти. Про 10 млн. написал преувеличено. Ошибка может возникать и с меньшим количеством данных. Всё зависит от вашего лимита памяти и самой операции.

Пример запуска скрипта из приложения без очередей используя exec:
class AdminController extends \yii\web\Controller
{
    public function actionIndex()
    {
        return $this->render('index');
    }

    public function actionComposerUpdate()
    {
        return $this->commandExec('composer update');
    }

    public function actionComposerInstall()
    {
        return $this->commandExec('composer install');
    }

    public function actionComposerSelfUpdate()
    {
        return $this->commandExec('composer self-update');
    }

    private function commandExec($command)
    {
        $projectPath = \Yii::getAlias('@app');
        $exec = "cd {$projectPath} && {$command}";

        exec($exec, $resultArray);

        if ($resultArray){
            \Yii::$app->getSession()->setFlash('info', implode("<br>", $resultArray));
        }

        return $this->redirect('index');
    }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы