Doctrine - пользовательский тип столбца не обновляется - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть сущность Dish с пользовательским типом столбца stock_collection.

<?php

declare(strict_types=1);

namespace App\Entity\Dish;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Resource\Model\ResourceInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Webmozart\Assert\Assert as WebmozartAssert;

/**
 * @ORM\Entity
 */
class Dish implements ResourceInterface
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

    /**
     * @ORM\Column(type="string", length=20, unique=true, nullable=false)
     *
     * @Assert\Length(min="3", max="20")
     * @Assert\NotBlank
     */
    private string $code;

    /**
     * @var Collection<int,Stock>
     *
     * @Assert\Valid
     *
     * @ORM\Column(type="stock_collection")
     */
    private Collection $stocks;

    public function __construct($code, $stock) 
    {
        $this->code = $code;

        $this->stocks = new ArrayCollection(
            array_map(
                fn (int $quantity, string $code): Stock => new Stock($code, $quantity),
                $stock,
                array_keys($stock)
            )
        );
    }

    public function getCode(): string
    {
        return $this->code;
    }

    public function setCode(string $code): void
    {
        $this->code = $code;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getStocks(): Collection
    {
        return $this->stocks;
    }

    public function setStocks(Collection $stocks): void
    {
        $this->stocks = $stocks;
    }

    public function decreaseStockQuantity(string $menuType, int $quantity): void
    {
        WebmozartAssert::greaterThanEq($quantity, 0, 'Can not decrease of a negative quantity');

        $this->getStock($menuType)->decreaseQuantity($quantity);
    }

    public function getStockQuantity(string $menuType): int
    {
        return $this->getStock($menuType)->getQuantity();
    }

    public function getStock(string $menuType): Stock
    {
        foreach ($this->stocks as $stock) {
            if ($stock->getMenuType() === $menuType) {
                return $stock;
            }
        }

        throw new \InvalidArgumentException(sprintf('Stock for menu type %s not found', $menuType));
    }
}
<?php

declare(strict_types=1);

namespace App\Entity\Dish;

use Symfony\Component\Validator\Constraints as Assert;
use Webmozart\Assert\Assert as WebmozartAssert;

class Stock implements \JsonSerializable
{
    /**
     * @Assert\NotBlank
     */
    private string $menuType;

    /**
     * @Assert\NotBlank
     * @Assert\PositiveOrZero
     */
    private int $quantity;

    private bool $inventory;

    public function __construct(string $menuType, int $quantity = 0, bool $inventory = true)
    {
        $this->menuType = $menuType;
        $this->quantity = $quantity;
        $this->inventory = $inventory;
    }

    public static function fromArray(array $data): self
    {
        WebmozartAssert::keyExists($data, 'menuType');
        WebmozartAssert::keyExists($data, 'quantity');
        WebmozartAssert::keyExists($data, 'inventory');

        return new self(
            $data['menuType'],
            $data['quantity'],
            $data['inventory']
        );
    }

    public function getMenuType(): string
    {
        return $this->menuType;
    }

    public function setMenuType(string $menuType): void
    {
        $this->menuType = $menuType;
    }

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

    public function setQuantity(int $quantity): void
    {
        $this->quantity = $quantity;
    }

    public function inventory(): bool
    {
        return $this->inventory;
    }

    public function setInventory(bool $inventory): void
    {
        $this->inventory = $inventory;
    }

    public function decreaseQuantity(int $quantity): void
    {
        $this->quantity -= $quantity;
    }

    public function jsonSerialize()
    {
        return [
            'menuType' => $this->menuType,
            'quantity' => $this->quantity,
            'inventory' => $this->inventory,
        ];
    }
}
<?php

declare(strict_types=1);

namespace App\Doctrine\DBAL\Types;

use App\Entity\Dish\Stock;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\JsonType;

final class StockCollectionType extends JsonType
{
    public function getName()
    {
        return 'stock_collection';
    }

    /**
     * @param $value
     *
     * @throws ConversionException
     *
     * @return array|mixed|null
     */
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        $value = parent::convertToPHPValue($value, $platform);

        $value = array_values(array_map(fn ($data): Stock => Stock::fromArray($data), $value));

        return new ArrayCollection($value);
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        return parent::convertToDatabaseValue($value->toArray(), $platform);
    }
}

Когда я вызываю метод setStocks для Dish сущности, * Метод 1010 * вызывается правильно, и значение сохраняется в базе данных, но когда я редактирую только одно свойство запаса, например, вызываю descreaseStockQuantity, метод convertToDatabaseValue не вызывается, поэтому значение не изменяется в база данных. Почему это происходит?

1 Ответ

1 голос
/ 22 апреля 2020

Это потому, что Dish (точно UnitOfWork) не знает об изменениях в Stock. Насколько я помню, самый простой способ решить эту проблему - изменить поле updated_at на Dish в методе decreaseStockQuantity. Или вы можете сделать Stock неизменным и переназначать новое значение при каждом изменении запаса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...