Как испраить ошибку: SQLSTATE: Duplicate alias: имя таблицы указано больше одного раза?

Есть модель корзины Cart и таблица carts, которая имеет вид:
| id | user_id |
|----|---------|
| 1  | 1       |


App/Models/Cart.php

<?php

namespace App\Models;

use App\Models\Product\ProductVariant;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\{BelongsToMany, HasOne};

class Cart extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
    ];

    public $timestamps = false;

    public function items(): BelongsToMany
    {
        return $this->belongsToMany(CartProduct::class, 'cart_products');
    }
}



Есть модель CartProduct и таблица cart_products
| id | cart_id | product_variant_id | quantity | price |
|----|---------|--------------------|----------|-------|
| 1  | 1       | 1                  | 5        | 1234  |
| 2  | 1       | 2                  | 12       | 50332 |


App/Models/CartProduct.php

class CartProduct extends Model
{
    use HasFactory;
    
    protected $table = "cart_products";

    public $timestamps = false;

    protected $fillable = [
        'product_variant_id',
        'quantity'
    ];

    public function product(): HasOne
    {
        return $this->hasOne(ProductVariant::class, 'id');
    }

    public function cart(): HasOne
    {
        return $this->hasOne(Cart::class);
    }
}



При попытке получить корзину авторизованного пользователя вместе с товарами из такого eloquent-выражения:
$cart = Cart::where('user_id', Auth::id())->with('items')->first();
получаю следующую ошибку:
SQLSTATE[42712]: Duplicate alias: 7 ОШИБКА: имя таблицы "cart_products" указано больше одного раза
select "cart_products".*, "cart_products"."cart_id" as "pivot_cart_id", "cart_products"."cart_product_id" as "pivot_cart_product_id" from "cart_products" inner join "cart_products" on "cart_products"."id" = "cart_products"."cart_product_id" where "cart_products"."cart_id" in (1)


Не понимаю почему так происходит (хотя есть подозрение что это из-за того, что при описании релейшена items() в модели Cart, я указываю явно таблицу cart_products и в самой модели CartProduct у меня эта таблица явно указывается в private $table = 'cart_products'), но я просто хочу через отношение получить набор id, cart_id, product_variant_id, quantity, price. Если в отношении items() модели Cart.php убрать явное указание таблицы, то отношение будет пытаться работать с таблицей cart_cart_products, что совсем неверно. В чем может быть причина? Скорее всего допустил какую-то мелкую ошибку, которую не могу увидеть.
  • Вопрос задан
  • 275 просмотров
Решения вопроса 2
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Пожалуйста, называйте связи так, как называется модель, которую вы хотите получить.

items() ? чего? вы хотите получить CartProduct. назовите cartProducts()

очень редко, но бывает, когда CartProduct можно получить двумя способами. Тогда cartProductsByModel1(), cartProductsByModel2()

исключение - абстрактные паттерны, деревья. там можно назвать parent/children/treeParent/treeChild

<?php

Class Cart {
    // ...

    // вот здесь написано, что CartProduct может быть одновременно в двух и более корзинах. не могу представить себе логику, где участник заказывает на сайте товар, а потом этот же товар (который ты заморозил только что) кто-то еще заказывает
    public function items(): BelongsToMany
    {
        return $this->belongsToMany(CartProduct::class, 'cart_products');
        
        // Cart.hasMany(CartProduct) + CartProduct.belongsTo(Cart) + CartProduct.belongsTo(Product)
        // и второе
        // https://github.com/illuminate/database/blob/master/Eloquent/Concerns/HasRelationships.php#L477
        // первым параметром "тип", вторым - "через что". Вы указываете, что "связь много ко многим" должна вернуть "связь много ко многим"
        // при связи Много-Ко-Многим надо Cart.belongsToMany(Product::class, 'cart_products')
    }
}


<?php

class CartProduct {
    // ...

    // здесь написано, что CartProduct старше чем Product. Это выразится в том, что вы сможете "привязать" CartProduct только из самого Product, причем один раз. Это дважды неверно.
    public function product(): HasOne
    {
        return $this->hasOne(ProductVariant::class, 'id');

        // Во первых каждый продукт с его количеством может быть куплен много раз, а вариант всего лишь показывает на его подвид
        // Во вторых модель CartProduct создается позже чем Product, а значит писать $product.addChild($cartProduct) это снова дичь
        // Product.hasMany(ProductVariant::class) + CartProduct.belongsTo(ProductVariant::class) + $cartProduct.associate($productVariant);
    }

    // то же самое. CartProduct старше чем Cart, хотя он в ней лежит. BelongsTo задает старшинство и позволяет добавлять родителя в потомок, а hasOne указывает связь, которая нужна только для select, но не годится для insert
    // Потому что hasOne() - это возможность добавить потомка, причем в Eloquent нету метода addChild() его ещё и самому писать надо типа CartProduct.cart().insert($array) и это тут же нарушает идею отложенной записи, т.к. выполняет запрос немедленно и требует транзакции прямо в модели, тогда как транзакция относится к задаче, а не к модели
    public function cart(): HasOne
    {
        return $this->hasOne(Cart::class);
    }
}
Ответ написан
Комментировать
iMedved2009
@iMedved2009
Не люблю людей
Это лажа
public function items(): BelongsToMany
    {
        return $this->belongsToMany(CartProduct::class, 'cart_products');
    }

Вы классу CartProduct прописываете отношение к самому CartProduct

Наверное должно быть так?
public function items(): BelongsToMany
    {
        return $this->belongsToMany(ProductVariant::class, 'cart_products');
    }
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы