Doctrine入門、トラッキングでエンティティの変更を知る

前回の続きです。
今回は変更についてです。

use App\Entities\Item;
use Doctrine\ORM\EntityManager;

/** @var EntityManager $manager */
$manager = require 'createManager.php';

$work = $manager->getUnitOfWork();

/** @var array<Item> $items */
$items = $manager->getRepository(Item::class)->findAll();

// IDが1と4のエンティティを変更
$items[0]->setPower(123);
$items[3]->setPower(456);
$items[3]->setName('QQQ');

// id = 2 を削除
$manager->remove($items[1]);

// id = 5 を外す
$manager->detach($items[4]);

// Add(StateはManagedになるがIdentiferMapには登録されない)
$addItem = new Item('XXX', 123);
$manager->persist($addItem);

// New(インスタンスを作っただけ)
$newItem = new Item('YYY', 456);

// 管理エンティティから変更を算出(このメソッドはflush()時にも呼び出さえれる)
$work->computeChangeSets();

foreach([...$items, $addItem, $newItem] as $item)
{
    $set = $work->getEntityChangeSet($item);
    if($set)
    {
        print_r($item);
        print_r($set);
        echo "------------------------------------\n";
    }
}
App\Entities\Item Object
(
    [id:App\Entities\Item:private] => 1
    [name:App\Entities\Item:private] => F
    [power:App\Entities\Item:private] => 123
)
Array
(
    [power] => Array
        (
            [0] => 8
            [1] => 123
        )

)
------------------------------------
App\Entities\Item Object
(
    [id:App\Entities\Item:private] => 4
    [name:App\Entities\Item:private] => QQQ
    [power:App\Entities\Item:private] => 456
)
Array
(
    [name] => Array
        (
            [0] => D
            [1] => QQQ
        )

    [power] => Array
        (
            [0] => 5
            [1] => 456
        )

)
------------------------------------
App\Entities\Item Object
(
    [name:App\Entities\Item:private] => XXX
    [power:App\Entities\Item:private] => 123
)
Array
(
    [name] => Array
        (
            [0] => 
            [1] => XXX
        )

    [power] => Array
        (
            [0] => 
            [1] => 123
        )

)
------------------------------------

まずIDが1と4のItemに変更を加えます。

$items[0]->setPower(123);
$items[3]->setPower(456);
$items[3]->setName('QQQ');

次にcomputeChangeSets()で変更を算出し取得できるようにします。
このメソッドはflush()時に内部で呼び出されるようですが、今回は変更を知るためこのタイミングで呼び出します。

$work->computeChangeSets();

エンティティごとに変更を算出するcomputeChangeSet()もありますがここには触れません。

idが1のエンティティはpower8から123へ変更されていることが確認できます。

[power] => Array(
    [0] => 8
    [1] => 123
)

idが4のエンティティはpower5から456へ、nameDからQQQへの変更が確認できます。
追加したエンティティはそれぞれpowernullから123へ、namenullからXXXへ変更されてます。

変更算出

computeChangeSets()を実行しないと変更が反映されてないことが分ります

use App\Entities\Item;
use Doctrine\ORM\EntityManager;

/** @var EntityManager $manager */
$manager = require 'createManager.php';

$work = $manager->getUnitOfWork();

/** @var Item $item */
$item = $manager->find(Item::class, 1);

print_r($item);

// 1
$item->setName('QQQ');
print_r($work->getEntityChangeSet($item));

// 2
$work->computeChangeSets();
print_r($work->getEntityChangeSet($item));

// 3
$item->setName('WWWWWWWWW');
print_r($work->getEntityChangeSet($item));

// 4
$item->setName('XXXXXXXXXXXXXX');

// 5
$work->computeChangeSets();
print_r($work->getEntityChangeSet($item));
App\Entities\Item Object
(
    [id:App\Entities\Item:private] => 1
    [name:App\Entities\Item:private] => F
    [power:App\Entities\Item:private] => 8
)
Array
(
)
Array
(
    [name] => Array
        (
            [0] => F
            [1] => QQQ
        )

)
Array
(
    [name] => Array
        (
            [0] => F
            [1] => QQQ
        )

)
Array
(
    [name] => Array
        (
            [0] => QQQ
            [1] => XXXXXXXXXXXXXX
        )

)

この例ではWWWWWWWWWの変更を拾えませんでした。
得られる変更はcomputeChangeSets()を呼び出した時点のものでした。

状態の取得

use App\Entities\Item;
use Doctrine\ORM\EntityManager;

/** @var EntityManager $manager */
$manager = require 'createManager.php';

$work = $manager->getUnitOfWork();

/** @var array<Item> $items */
$items = $manager->getRepository(Item::class)->findAll();

// IDが1と4のエンティティを変更
$items[0]->setPower(123);
$items[3]->setPower(456);
$items[3]->setName('QQQ');

// id = 2 を削除
$manager->remove($items[1]);

// id = 5 を外す
$manager->detach($items[4]);

// Add(StateはManagedになるがIdentiferMapには登録されない)
$addItem = new Item('XXX', 123);
$manager->persist($addItem);

// New(インスタンスを作っただけ)
$newItem = new Item('YYY', 456);

// 管理エンティティから変更を算出(このメソッドはflush()時にも呼び出さえれる)
$work->computeChangeSets();

echo " ==== [Insertions] \n";
print_r($work->getScheduledEntityInsertions());

echo " ==== [Deletions] \n";
print_r($work->getScheduledEntityDeletions());

echo " ==== [Updates] \n";
print_r($work->getScheduledEntityUpdates());
 ==== [Insertions] 
Array
(
    [86] => App\Entities\Item Object
        (
            [name:App\Entities\Item:private] => XXX
            [power:App\Entities\Item:private] => 123
        )

)
 ==== [Deletions] 
Array
(
    [90] => App\Entities\Item Object
        (
            [id:App\Entities\Item:private] => 2
            [name:App\Entities\Item:private] => A
            [power:App\Entities\Item:private] => 3
        )

)
 ==== [Updates] 
Array
(
    [88] => App\Entities\Item Object
        (
            [id:App\Entities\Item:private] => 1
            [name:App\Entities\Item:private] => F
            [power:App\Entities\Item:private] => 123
        )

    [92] => App\Entities\Item Object
        (
            [id:App\Entities\Item:private] => 4
            [name:App\Entities\Item:private] => QQQ
            [power:App\Entities\Item:private] => 456
        )

)

それぞれgetScheduledEntityInsertions()は追加されたエンティティ、getScheduledEntityDeletions()は削除されたエンティティ、getScheduledEntityUpdates()は変更されたエンティティを取得できました。

$work->computeChangeSets();

ただしcomputeChangeSets()よ呼び出してなかったら、追加または削除されたエンティティは取得出来ますが、変更されたエンティティは取得出来ません。

certificate Docker Gutenberg Hyper-V openssl PHP React ReduxToolkit REST ubuntu WordPress オレオレ認証局 フレームワーク