A
A
Alexander Stepanov2019-11-14 18:15:27
Yii
Alexander Stepanov, 2019-11-14 18:15:27

By what magic can adding to the cart happen "in one"?

There is a shop on yii2 advanced. Created about six months ago and all clicks were processed as intended.
A couple of months ago they sent edits - made, checked, everything is gut.
Then there were more edits...
And 2 days ago, after making more edits, I tried to add an item to the cart to check the checkout, but the cart stubbornly showed 0 items. Although everything went well in the controller and a flash message appeared on the page stating that the product was successfully added.
After long attempts to understand "what I did wrong" and another click on the "add to cart" button, the product was added and I almost relaxed, but ... by clicking on "add to cart" on another product, the message successfully appeared, but the product was in cart has not been added.
What is very remarkable is that only some products are added to the cart, and after adding one product, no other product is added i.e. the product is added only to an empty cart and no more than one item.
All products are active, with pictures, descriptions and meta tags are filled. are identical.
I went through the chain of actions performed by the site code with var_dump and everything is also output in the same way to the line of saving in the model, which, in theory, should guarantee the same behavior, but ...
The logs are empty, the success flash message, and somewhere somehow something it doesn’t grow together and I can’t understand why and even what to cling to.
Below is the code, maybe you will find something that I don’t see point blank:
Add action:

/**
     * @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,
        ]);
    }

Add Service:
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 makes a record of the number of units for each item added:
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);
    }

The essence of the basket:
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);
    }

Cart storage:
use shop\cart\CartItem;

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

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

Please help me figure it out.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Maxim, 2019-11-14
@Exebeche

You lay out the entire code of the project))
In general, why lay out if this project is already in the public domain . At the same time, check out the license . Trying to make money on what a person has done for free for educational purposes. This won't help you...
Use tests. Look for errors through the debugger.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question