Exebeche
@Exebeche
Осваиваю программирование

По какому волшебству добавление в корзину может происходить «через один»?

Имеется магазин на yii2 advanced. Создан с полгода назад и все нажатия обрабатывались как и было задумано.
Пару месяцев назад прислали правки - сделал, проверил, все гут.
Потом еще были правки...
А 2 дня назад я, внеся еще правок, попробовал добавить товар в корзину, чтобы проверить работу оформления заказа, но корзина упорно показывала 0 товаров. Хотя в контроллере все прошло успешно и на странице появилось флеш-сообщение о том, что товар успешно добавлен.
После долгих попыток понять "что я сделал не так" и очередного нажатия на кнопку "добавить в корзину" товар добавился и я почти расслабился, но... нажав на "добавить в корзину" на другом товаре сообщение с успехом появилось, но товар в корзину не добавился.
Что очень примечательно, так это то, что в корзину добавляются, только некоторые товары, а после добавления одного товара не добавляется другой товар т.е. товар добаваляется только в пустую корзину и не больше одного наименования.
Все товары активны, с картинками, заполнены описания и мета-теги т.е. идентичны.
По цепочке действий выполняемых кодом сайта прошелся с var_dump и тоже все одинаково выводится до строчки сохранения в модели, что по идее должно гарантировать и одинаковое поведение, но...
Логи пусты, флеш-сообщение success, а где-то как-то что-то не срастается и не могу понять из-за чего и даже за что зацепиться.
Ниже привожу код, может быть вы найдете то, чего я в упор не вижу:
Экшен добавления:
/**
     * @param $id
     * @return mixed
     * @throws NotFoundHttpException
     */
    public function actionAdd($id)
    {
        if (!$product = $this->products->find($id)) {
            throw new NotFoundHttpException('Запрашиваемая страница не существует.');
        }

        if (!$product->modifications) {
            try {
                $q = Yii::$app->request->post('AddToCartForm');
                $this->service->add($product->id, null, $q['quantity']);
                Yii::$app->session->setFlash('success', 'Товар успешно добавлен в корзину!');
                return $this->redirect(Yii::$app->request->referrer);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
                Yii::$app->session->setFlash('error', $e->getMessage());
            }
        }

        $this->layout = 'blank';

        $form = new AddToCartForm($product);

        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            try {
                $this->service->add($product->id, $form->modification, $form->quantity);
                return $this->redirect(['index']);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
                Yii::$app->session->setFlash('error', $e->getMessage());
            }
        }

        return $this->render('add', [
            'product' => $product,
            'model' => $form,
        ]);
    }


Сервис добавления:
public function add($productId, $modificationId, $quantity): void
    {
        $product = $this->products->get($productId);
        $modId = $modificationId ? $product->getModification($modificationId)->id : null;
        $this->cart->add(new CartItem($product, $modId, $quantity));
    }


CartItem делает для каждого добавленного товара запись о количестве единиц:
use shop\entities\Shop\Product\Modification;
use shop\entities\Shop\Product\Product;

class CartItem
{
    private $product;
    private $modificationId;
    private $quantity;

    public function __construct(Product $product, $modificationId, $quantity)
    {
//        if (!$product->canBeCheckout($modificationId, $quantity)) {
//            throw new \RuntimeException('Вы выбрали большее количество, чем есть в наличии. может быть в другом месте эту ошибку вызывать чтобы не убивался сайт7 shop\cart\CartItem');
//        }
        $this->product = $product;
        $this->modificationId = $modificationId;
        $this->quantity = $quantity;
    }

    public function getId(): string
    {
        return md5(serialize([$this->product->id, $this->modificationId]));
    }

    public function getProduct(): Product
    {
        return $this->product;
    }

    public function getModificationId(): ?Modification
    {
        return $this->modificationId;
    }

    public function getModification(): ?Modification
    {
        if ($this->modificationId) {
            return $this->product->getModification($this->modificationId);
        }
        return null;
    }

    public function getQuantity(): int
    {
        return $this->quantity ? $this->quantity : 1;
    }

    public function getPrice(): int
    {
        if ($this->modificationId) {
            return $this->product->getModificationPrice($this->modificationId);
        }
        // Крупный опт
        if ($this->product->price_roll && $this->product->roll_long && $this->quantity >= $this->product->roll_long) {
            return $this->product->price_roll;
        }
        // Мелкий опт
        if ($this->product->price_min && $this->product->min_long && $this->quantity >= $this->product->min_long) {
            return $this->product->price_min;
        }
        return $this->product->price_new;
    }

    public function getCost(): int
    {
        return $this->getPrice() * $this->quantity;
    }

    public function plus($quantity)
    {
        return new static($this->product, $this->modificationId, $this->quantity + $quantity);
    }

    public function changeQuantity($quantity)
    {
        return new static($this->product, $this->modificationId, $quantity);
    }


Сущность корзны:
use shop\cart\cost\calculator\CalculatorInterface;
use shop\cart\cost\Cost;
use shop\cart\storage\StorageInterface;

class Cart
{
    private $storage;
    private $calculator;
    /**
     * @var CartItem[]
     * */
    private $items;

    public function __construct(StorageInterface $storage, CalculatorInterface $calculator)
    {
        $this->storage = $storage;
        $this->calculator = $calculator;
    }

    /**
     * @return CartItem[]
     */
    public function getItems(): array
    {
        $this->loadItems();
        return $this->items;
    }

    public function getAmount(): int
    {
        $this->loadItems();
        return count($this->items);
    }

    public function add(CartItem $item): void
    {
        $this->loadItems();
        foreach ($this->items as $i => $current) {
            if ($current->getId() == $item->getId()) {
                $this->items[$i] = $current->plus($item->getQuantity());
                $this->saveItems();
                return;
            }
        }
        $this->items[] = $item;
        $this->saveItems();
    }

    public function set($id, $quantity): void
    {
        $this->loadItems();
        foreach ($this->items as $i => $current) {
            if ($current->getId() == $id) {
                $this->items[$i] = $current->changeQuantity($quantity);
                $this->saveItems();
                return;
            }
        }
        throw new \DomainException('Item is not found.');
    }

    public function remove($id): void
    {
        $this->loadItems();
        foreach ($this->items as $i => $current) {
            if ($current->getId() == $id) {
                unset($this->items[$i]);
                $this->saveItems();
                return;
            }
        }
        throw new \DomainException('Item is not found.');
    }

    public function clear(): void
    {
        $this->items = [];
        $this->saveItems();
    }

    public function getCost(): Cost
    {
        $this->loadItems();
        return $this->calculator->getCost($this->items);
    }

    private function loadItems(): void
    {
        if ($this->items === null) {
            $this->items = $this->storage->load();
        }
    }

    private function saveItems(): void
    {
        $this->storage->save($this->items);
    }


Хранилище корзины:
use shop\cart\CartItem;

interface StorageInterface
{
    /**
     * @return CartItem[]
     */
    public function load(): array;

    /**
     * @param CartItem[] $items
     */
    public function save(array $items): void;
}


Пожалуйста помогите разобраться.
  • Вопрос задан
  • 119 просмотров
Решения вопроса 1
myks92
@myks92 Куратор тега Yii
Нашёл решение — пометь вопрос ответом!
Вы весь код проекта выложите))

А вообще зачем выкладывать если это проект уже в общем доступе. Заодно ознакомьтесь с лицензией. Пытаетесь заработать на том, что человек сделал бесплатно в обучающих целях. В этом вам не помогут...

Используйте тесты. Ищите ошибки через дебаггер.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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