Как поправить костыль с реляцией и where в yii2?

Есть 3 таблицы:
- Статьи
- Теги
- Связи (Тег-Статья)

У меня была задача показать все записи конкретного тега. Я написал реляцию и наткнулся на проблему.
Таблицы Статьи и Теги содержат после URL, поэтому при написании:

$query->innerJoinWith(['tagsAll'])->andWhere(['url'=>$tag]);


Возникает ошибка:
Integrity constraint violation: 1052 Column 'url' in where clause is ambiguous

Поэтому я подключил модель тегов и сделал как-то так:
$query->innerJoinWith(['tagsAll'])->andWhere([Tags::tableName().'.url'=>$tag]);


При таком варианте все работает. Но я просто жопой чую, что это слоупочный костыль. Подскажите, пожалуйста, можно ли решить проблему более оптимальным вариантом?
  • Вопрос задан
  • 7257 просмотров
Решения вопроса 1
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
проблема решается алиасами таблиц.

В yii1 по дефолту таблице, которая идет в from присваивался алиас t, для таблиц, которые вы прописываете джойном можно явно указать алиас. И тогда в where можно будет писать
andWhere('t.url=:url')

Но в Yii1 были проблемы с этим. Если к таблице ничего не джойнится, то и алиас не назначается, а значит запросы, где проставлены элиасы падают. Это решалось так же кастылями (как и любая проблема Yii). Решили ли они эту проблему во второй ветке я не знаю, но помниться мне реализация AR второй версии не сильно далеко ушла от реализации первой версии. Это была одна из причин по которой я ушел с Yii - изменения были анонсированы больше двух лет назад, зарелижены только сейчас.

p.s. используйте биндинг параметров.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
NekitoSP
@NekitoSP
Для связей подобного рода (все записи тега, или все теги записи с использованием промежуточных таблиц) вам наверное лучше будет использовать viaTable.
для модели Article получение тегов будет выглядеть так:
public function getTags()
{
	return $this->hasMany(Tags::className(), ['id' => 'tag_id'])
		->viaTable('{{%article_tag}}', ['article_id' => 'id']);
}


Ну и для тега (в модели Tags) получение статей, использующих этот тег:
public function getArticles()
{
	return $this->hasMany(Article::className(), ['id' => 'article_id'])
		->viaTable('{{%article_tag}}', ['tag_id' => 'id']);
}


Использовать можно будет так:
$tag->articles;//результат - массив моделей статей
где $tag - например $tag = Tags::findOne(['url' => $tag), естественно после findOne не забываем проверить $tag, чтобы при случае его отсутствия не получить UnknownPropertyException
Ответ написан
Прошу прощения, может я не понял. А нельзя сначала вытащить в контроллере теги из урла, а потом передать их в модель, в которой будет уже поиск делаться?
$tags = self::find()->where(['like', 'name', $keyword])->all();,
Ну и так далее. Или я не о том?
Ответ написан
Ваш ответ на вопрос

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

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