Сортировка через junction table

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
andreyrud
Сообщения: 265
Зарегистрирован: 2011.09.26, 14:59

Сортировка через junction table

Сообщение andreyrud »

Имеется 3 таблицы Products, Images и ProductImages. ProductImages таблица связей между продуктами и картинками с полем сортировки sort. Имеется метод выборки картинок из продукта.

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

    public function getImages()
    {
        $imgs = $this->hasMany(Images::className(), ['id' => 'images_id'])
          ->viaTable(ProductImages::tableName(), ['product_id' => 'id']);
        return $imgs;
    }
 
Как добавить сортировку результата по полю ProductImages::sort?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Сортировка через junction table

Сообщение ElisDN »

Попробуйте:

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

public function getImages()
{
    return $this->hasMany(Images::className(), ['id' => 'images_id'])
        ->viaTable(ProductImages::tableName(), ['product_id' => 'id'])
        ->orderBy(['sort' => SORT_ASC]);
} 
pavlm
Сообщения: 84
Зарегистрирован: 2013.09.02, 16:33

Re: Сортировка через junction table

Сообщение pavlm »

так не получится, надо делать join:

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

public function getImages()
{
    return $this->hasMany(Images::className(), ['id' => 'images_id'])
        ->viaTable(ProductImages::tableName(), ['product_id' => 'id'])
        ->join('INNER JOIN', 'product_images', 'product_images.id = image.id')
        ->orderBy(['product_images.sort' => SORT_ASC]);
} 
или через joinWith, если есть подходящяя реляция.
andreyrud
Сообщения: 265
Зарегистрирован: 2011.09.26, 14:59

Re: Сортировка через junction table

Сообщение andreyrud »

Пример с ->orderBy(['sort' => SORT_ASC]); не работает и выдает ошибку:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sort' in 'order clause'
The SQL being executed was: SELECT * FROM `images` WHERE `id` IN ('76', '83', '91', '98') ORDER BY `sort`
Второй примет работает в виде:

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

public function getImages()
{
    $imgs = $this->hasMany(Images::className(), ['id' => 'images_id'])

    // Таблица соответствия
    ->viaTable(ProductImages::tableName(), ['product_id' => 'id'])

     // Сортировка
     ->join('INNER JOIN', 'product_images', 'product_images.images_id = images.id')
     ->orderBy(['product_images.sort' => SORT_ASC]);

     return $imgs;
} 
Вид первого примера как-то красивше и приятнее... Жаль не работает. В Yii1 работало.
andreyrud
Сообщения: 265
Зарегистрирован: 2011.09.26, 14:59

Re: Сортировка через junction table

Сообщение andreyrud »

Поторопилсо...

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

public function getImages()
{
    $imgs = $this->hasMany(Images::className(), ['id' => 'images_id'])

    // Таблица соответствия
    ->viaTable(ProductImages::tableName(), ['product_id' => 'id'])

     // Сортировка
     ->join('INNER JOIN', 'product_images', 'product_images.images_id = images.id')
     ->orderBy(['product_images.sort' => SORT_ASC]);

     return $imgs;
}
строит запрос:

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

SELECT full,title FROM images
INNER JOIN product_images ON product_images.images_id = images.id
WHERE images.id IN (9,841,842,843)
ORDER BY product_images.sort
и выбирает все записи с images.id. То есть если одно и тоже изображение используется для нескольких продуктов, то и их тоже.
Таким образом условие WHERE images.id IN (9,841,842,843) не срабатывает и вместо 4 записей я получаю больше.

pavlm, какую именно реляцию вы имели ввиду, упоминая joinWith?
pavlm
Сообщения: 84
Зарегистрирован: 2013.09.02, 16:33

Re: Сортировка через junction table

Сообщение pavlm »

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

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

$imgs->andWhere(["product_images.product_id" => $this->id]) 
pavlm
Сообщения: 84
Зарегистрирован: 2013.09.02, 16:33

Re: Сортировка через junction table

Сообщение pavlm »

pavlm писал(а):те реляции которые генерируются при создании модели скорее всего не подойдут для этой задачи.
соврал, наоборот подойдут, вот вариант с joinWith:

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

public function getImages()
{
    $imgs = $this->hasMany(Images::className(), ['id' => 'images_id'])
     ->via('productImages') // реляция для моделей ProductImage
     ->joinWith('productImages')
     ->orderBy(['product_images.sort' => SORT_ASC]);
     ->andWhere(["product_images.product_id" => $this->id]);

     return $imgs;
}
Аватара пользователя
mat.twg
Сообщения: 222
Зарегистрирован: 2012.02.22, 20:44
Откуда: Санкт-Петербург

Re: Сортировка через junction table

Сообщение mat.twg »

AR испортили в плане join, строй запросы через билдер и проблем не будет:

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

        
$query = (new \yii\db\Query())
    ->select([
                'item.id AS id', 
                'item.alias AS alias',
                'item.parent_id AS parent_id',
                'item.template_id AS template_id',
                'template.name AS template_name'
            ])
            ->from('catalog_items item')
            ->leftJoin('catalog_items_template template', '`template`.`id` = `item`.`template_id`')
            ->where('category_id=:category_id AND disabled=0 AND alias=:alias',[':category_id'=>$_category['id'], ':alias'=>$item]);        
        
        $command = $query->createCommand();
        $_item   = $command->queryAll();
        
или через представления, тоже хороший вариант.
andreyrud
Сообщения: 265
Зарегистрирован: 2011.09.26, 14:59

Re: Сортировка через junction table

Сообщение andreyrud »

Какое имеется ввиду представление? Уж очень не хочется делать через DAO...
Последний раз редактировалось andreyrud 2015.04.10, 00:25, всего редактировалось 1 раз.
andreyrud
Сообщения: 265
Зарегистрирован: 2011.09.26, 14:59

Re: Сортировка через junction table

Сообщение andreyrud »

pavlm писал(а):
pavlm писал(а):те реляции которые генерируются при создании модели скорее всего не подойдут для этой задачи.
соврал, наоборот подойдут, вот вариант с joinWith:

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

public function getImages()
{
    $imgs = $this->hasMany(Images::className(), ['id' => 'images_id'])
     ->via('productImages') // реляция для моделей ProductImage
     ->joinWith('productImages')
     ->orderBy(['product_images.sort' => SORT_ASC]);
     ->andWhere(["product_images.product_id" => $this->id]);

     return $imgs;
}
Выдает "common\models\Product has no relation named "product_images". Calling unknown method: common\models\Product::getproduct_images()". Причем не понятно что должно быть в этом методе Product::getproduct_images()?
pavlm
Сообщения: 84
Зарегистрирован: 2013.09.02, 16:33

Re: Сортировка через junction table

Сообщение pavlm »

andreyrud писал(а): Выдает "common\models\Product has no relation named "product_images". Calling unknown method: common\models\Product::getproduct_images()". Причем не понятно что должно быть в этом методе Product::getproduct_images()?
Должна быть реляция от product к product_images, и модель ProductImages тоже необходима, если у вас прописаны в БД все внешние ключи, то при генерации модели эта реляция должна была сама получиться.
PS: предложенный выше способ работает только для одного продукта.
Ответить