Как сохранить клон сущности как обновление с Doctrine2 - PullRequest
0 голосов
/ 06 июня 2018

Мне не нравится использовать сеттеры, так как я не люблю мутировать объекты после их создания, поэтому вместо этого я использую стиль withFoo(Foo $foo), который возвращает клон:

public function withFoo(Foo $foo): self
{
    $clone = clone $this;
    $clone->foo = $foo;
    return $clone;
}

Это очень долго служило мне, но теперь я должен работать с Doctrine2, и он не работает:

$foo = $fooRepository->getByBar($bar);
$foo = $foo->withBaz($baz);
$emi->flush();

Это приводит к ошибке в моих журналах примерно так:

app.ERROR: An exception occurred while executing 'INSERT INTO foo (id, bar, baz) VALUES (?, ?, ?)' with params ["51f74f6e-8e20-42ec-ba21-ac3ae62658ef", "Bar", "Baz"]:  SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '51f74f6e-8e20-42ec-ba21-ac3ae62658ef' for key 'PRIMARY' [] []

Если я изменю свой код на следующий, он не будет обновляться без проблем:

public function withFoo(Foo $foo): self
{
    $this->foo = $foo;
    return $this;
}

На данный момент мне пришлось прибегнуть к использованию обычного установщика, но я неэто не нравитсяЕсть ли способ сделать это?

Я хочу сказать, чтобы сохранить обновление, но использовать идентификатор, чтобы определить, какую запись для обновления.Например, REPLACE INTO в MySQL.

Любая помощь?

1 Ответ

0 голосов
/ 07 июня 2018

ОК, так что спасибо @Cerad, который сделал предложение в комментариях к моему вопросу.Мне действительно нужна была функция detach and merge .Таким образом, у сущности есть метод withBar(Bar $bar):

<?php
namespace App\Entity

use Doctrine\ORM\Mapping as ORM;

/**
 * Foo
 *
 * @ORM\Table(name="foo", ...)
 * @ORM\Entity
 */
class Foo
{
    /**
     * @var string
     *
     * @ORM\Column(name="id", type="string", length=36, nullable=false)
     * @ORM\Id
     */
    private $id;

    /**
     * @var Bar
     * 
     * @ORM\Column(name="bar", type="object" ...)
     */
    private $bar;

    public function __construct(string $id, Bar $bar)
    {
        $this->id = $id;
        $this->bar = $bar;
    }

    public function withBar(Bar $bar): self
    {
        $clone = clone $this;
        $clone->bar = $bar;
        return $clone;
    }
}

, который работает так же, как и в проектах, в которых не использовался Doctrine, возвращая измененный COPY оригинала, а немутируя это.Доволен этим.

Далее, метод обновления FooRepository становится примерно таким:

<?php
namespace App\Repository;

use App\Entity\Foo;
use Doctrine\ORM\EntityManagerInterface;

class FooRepository
{
    private $emi, $repository;

    public function __construct(EntityManagerInterface $emi)
    {
        $this->emi = $emi;
        $this->repository = $emi->getRepository(Foo::class);
    }

    public function updateBar(string $id, Bar $bar): Foo
    {
        // Get the `Foo` and update the `Bar`
        $foo = $this->repository->findOneBy(['id'=>$id]);
        $foo = $foo->withBar($bar);

        // Detach and merge the entity
        // You can do the detach before the `withBar()` but it makes no difference
        // as the modified entity is actually an entirely new object, so Doctrine
        // can't see it until it's merged anyway
        $this->emi->detach($foo);
        $this->emi->merge($foo);
        $this->emi->flush();

        return $foo;
    }
}

Обработка ошибок намеренно опущена, так как примеры все равно придуманы

Спасибо за указатель.Если бы вы написали это как ответ, я бы с радостью принял это и дал бы вам ответ

...