Метод yii\db\ActiveQuery::init

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

Здравствуйте!
Появилась такая проблема с кодом, который по сути должен был выгружать пользователю сугубо его публикации, реализовано было через yii\db\ActiveQuery::init в модельке:

Код: Выделить всё

   <?php

namespace app\modules\main\models;

use Yii;

/**
 * This is the ActiveQuery class for [[Publications]].
 *
 * @see Publications
 */
class PublicationsQuery extends \yii\db\ActiveQuery
{
    /*public function active()
    {
        return $this->andWhere('[[status]]=1');
    }
    */
    
    public function init()
    {
        $modelClass = $this->modelClass;
        $tableName = $modelClass::tableName();
        $this->andWhere([$tableName.'.user_id' => Yii::$app->user->id]);
        parent::init();
    }

    /**
     * @inheritdoc
     * @return Publications[]|array
     */
    public function all($db = null)
    {
        return parent::all($db);
    }

    /**
     * @inheritdoc
     * @return Publications|array|null
     */
    public function one($db = null)
    {
        return parent::one($db);
    }
}

Но эта структура ломает валидатор уникальности и пропускает одинаковые имена публикаций:

Код: Выделить всё

 ['job_title','unique', 'targetClass' => self::className(), 'message' => Yii::t('app', 'Публикация с таким именем уже есть в базе')],
Подскажите, пожалуйста, способ как это довести до ума, чтобы выдавало только записи пользователя и не позволяло ему добавлять одинаковые, я уже голову ломаю битый час
azz
Сообщения: 197
Зарегистрирован: 2016.07.06, 17:20

Re: Метод yii\db\ActiveQuery::init

Сообщение azz »

только обсуждали
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

azz писал(а): 2018.11.14, 17:03 только обсуждали
Я это читал перед тем как создать тему - там явно не мой случай, я разными способами пробовал, проблема именно в части с ActiveQuery. Я не знаю как её переделать, без неё валидатор работает, с ней нет.
someweb
Сообщения: 552
Зарегистрирован: 2017.03.09, 10:12

Re: Метод yii\db\ActiveQuery::init

Сообщение someweb »

Фильтруйте в контроллере.
Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа. Роберт Шекли.
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

someweb писал(а): 2018.11.14, 17:27 Фильтруйте в контроллере.
Каким образом, контроллер самый элементарный, у меня нет обёртки из сценариев и тд и тп?

Код: Выделить всё

<?php

namespace app\modules\main\controllers;

use Yii;
use app\modules\main\models\Publications;
use app\modules\main\models\PublicationsSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
/**
 * DefaultController implements the CRUD actions for Publications model.
 */
class PublicationsController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['post'],
                ],
            ],
          
        ];
    }

    /**
     * Lists all Publications models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new PublicationsSearch;
        $dataProvider = $searchModel->search(Yii::$app->request->getQueryParams());

        return $this->render('index', [
            'dataProvider' => $dataProvider,
            'searchModel' => $searchModel,
        ]);
    }

    /**
     * Displays a single Publications model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('view', ['model' => $model]);
        }
    }

    /**
     * Creates a new Publications model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new Publications;

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Updates an existing Publications model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Deletes an existing Publications model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

   /**
     * Finds the Publications model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Publications the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Publications::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}

someweb
Сообщения: 552
Зарегистрирован: 2017.03.09, 10:12

Re: Метод yii\db\ActiveQuery::init

Сообщение someweb »

Код: Выделить всё

    public function actionIndex()
    {
        $searchModel = new PublicationsSearch;
        $dataProvider = $searchModel->search(Yii::$app->request->getQueryParams(), Yii::$app->user->id);

        return $this->render('index', [
            'dataProvider' => $dataProvider,
            'searchModel' => $searchModel,
        ]);
    }

Код: Выделить всё

    protected function findModel($id)
    {
        if (($model = Publications::findOne($id)) !== null && $model->user_id == Yii::$app->user->id) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}
И в PublicationsSearch::search() добавьте условие фильтрации по user_id
Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа. Роберт Шекли.
SindBad
Сообщения: 81
Зарегистрирован: 2015.06.18, 10:53

Re: Метод yii\db\ActiveQuery::init

Сообщение SindBad »

Приветствую!
Такой вопрос, почему решили условие добавлять не через find а именно через init?
Так ведь было бы логичнее, where бы пытался добавиться к SELECT'ам, а не ко всем запросам.
Возможно, такой бубен поможет по теме, а возможно и нет. В таком случае надо дебажить запрос из валидатора при помощи встроенного дебаггера или $query->createCommand()->getRawSql() и смотреть, что мешает ему найти существующую запись.
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

А точно, благодарю, я с этого пути ушел ибо сделал так только в методе protected function findModel($id), а в public function actionIndex() забыл и подумал, что этот способ не рабочий...
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

SindBad писал(а): 2018.11.14, 17:50 Приветствую!
Такой вопрос, почему решили условие добавлять не через find а именно через init?
Так ведь было бы логичнее, where бы пытался добавиться к SELECT'ам, а не ко всем запросам.
Возможно, такой бубен поможет по теме, а возможно и нет. В таком случае надо дебажить запрос из валидатора при помощи встроенного дебаггера или $query->createCommand()->getRawSql() и смотреть, что мешает ему найти существующую запись.
Решил из-за того, что я смог накопать в исходном коде и освоить для себя ибо полной подробной документации или мануалов нету и было - всё копируют с основной документации, которая на первый взгляд сравнительно и нормальная, но как покопаешься, то в итоге оказывается, что она ограниченная и не гибкая. Потому всё по кускам собираю для себя на практических задачах. Если честно, я даже не знаю того о чём вы говорили и в какой части архитектуры оно применяется и как. Если не сложно, можете объяснить?
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

chungachguk писал(а): 2018.11.14, 18:26 А это что?
https://www.yiiframework.com/doc/guide/ ... rying-data
это огрызки кода без целостной картины отображения происходящего, которые как зайцу стоп-сигнал - либо слишком элементарное либо не юзабельно из-за отсутствия целостной архитектуры для понимания.
Аватара пользователя
chungachguk
Сообщения: 435
Зарегистрирован: 2012.07.17, 11:52

Re: Метод yii\db\ActiveQuery::init

Сообщение chungachguk »

Странно. А люди целые приложения строят на этих огрызках кода.
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

chungachguk писал(а): 2018.11.14, 18:33 Странно. А люди целые приложения строят на этих огрызках кода.
ну видимо им больше повезло с озарением либо они методом тыка нашли, как и где применить эти куски кода, чтобы решить свою задачу. Я, например, понятия не имею к чему это и в какой части архитектуры приложения применять в своём случае - мне нужно осознание всей картины, а не просто копипаст.
SindBad
Сообщения: 81
Зарегистрирован: 2015.06.18, 10:53

Re: Метод yii\db\ActiveQuery::init

Сообщение SindBad »

zhe17065564 писал(а): 2018.11.14, 18:01
Решил из-за того, что я смог накопать в исходном коде и освоить для себя ибо полной подробной документации или мануалов нету и было - всё копируют с основной документации, которая на первый взгляд сравнительно и нормальная, но как покопаешься, то в итоге оказывается, что она ограниченная и не гибкая. Потому всё по кускам собираю для себя на практических задачах. Если честно, я даже не знаю того о чём вы говорили и в какой части архитектуры оно применяется и как. Если не сложно, можете объяснить?
Малость ошибся, find - это метод ActiveRecord.
Можно переопределить его вот так:

Код: Выделить всё

    public static function find()
    {
        $query = Yii::createObject(ActiveQuery::className(), [get_called_class()]);
        return $query->where([static::tableName() . '.user_id' => Yii::$app->user->id]);
    }
так как именно метод find используется при выборке, это более правильно.
Но опять же, если где-то в другом месте кода снова использовать where, то это условие будет "перебито".

А вот с методом search, как выше подсказали, возможно, будет даже более правильно. Все зависит от того, нужна ли привязка к пользователю в момент проверки уникальности.
Аватара пользователя
zhe17065564
Сообщения: 63
Зарегистрирован: 2016.06.09, 10:46
Откуда: Украина
Контактная информация:

Re: Метод yii\db\ActiveQuery::init

Сообщение zhe17065564 »

SindBad писал(а): 2018.11.14, 19:33
А вот с методом search, как выше подсказали, возможно, будет даже более правильно. Все зависит от того, нужна ли привязка к пользователю в момент проверки уникальности.
Спасибо большое. С search почему-то не сработало, я перепроверял и пробовал задавать заранее как подготовленный параметр, но это надо уже завтра на свежую голову смотреть - за 9 часов голова не варит уже, могу знатно косячить.
Ну как сказать, на уникальность проверяется только имя публикации - пользователь там не при чем, у него только права проверяются и доступ он имеет только к своим публикациям, так что нет - не нужна
SindBad
Сообщения: 81
Зарегистрирован: 2015.06.18, 10:53

Re: Метод yii\db\ActiveQuery::init

Сообщение SindBad »

В этом случае действительно правильнее добавлять условие в search.
Ответить