Як повторно зберегти сутність як інший рядок у Доктрині 2


77

Скажімо, у мене є сутність $e. Чи існує якийсь загальний спосіб зберегти його як інший рядок, який містив би ті самі дані сутності, але інший первинний ключ?

Навіщо мені це потрібно: я реалізую якусь схему тимчасової бази даних, і замість оновлення рядка мені просто потрібно створити іншу.


Щойно з верхівки моєї голови (тобто неперевіреної), ви пробували $f = clone $e? Можливо, вам доведеться застосувати __clone()метод
Філ

4
@Phil: клонована сутність має однаковий PK, таким чином просто оновлює той самий рядок. І ще більш дивно - spl_object_hash(Doctrine використовує його для ідентифікації конкретних випадків) однакові для оригіналу та клонованого об'єкта, хоча вони містять різні дані
zerkms

@Phil: __clone()теж не допомогло б - Доктрина використовує $oid = spl_object_hash($entity);та якусь внутрішню карту для отримання стану об’єкта. І для обох (оригінального та клонованого) це було б однаково -MANAGED
zerkms

1
це не правда. clone $ e повертає інший екземпляр і, отже, інше значення spl_object_hash ().
Флоріан Кляйн

1
Все одно пробував і був у цьому впевнений. Клон - це інший екземпляр, і поки ви не попросите UnitOfWork / identityMap зареєструвати його, ця сутність буде вважатися ВСТАВЛЕНОЮ.
Флоріан Кляйн

Відповіді:


161

Спробуйте клонувати та додайте наступний метод до своєї сутності

public function __clone() {
    $this->id = null;
}

Можливо, вам доведеться від'єднати сутність, перш ніж зберігати її. Зараз у мене немає зручної машини для тестування.

$f = clone $e;
$em->detach($f);
$em->persist($f);
$em->flush();

Оновлення

Просто спробував використати просту демонстрацію SQLite. Вам не потрібно нічого робити. Наступне працювало для мене, не додаючи __clone()методу і не роблячи чогось іншого незвичного

$new = clone $old;
$em->persist($new);
$em->flush();

Після очищення $newсутність мала новий ідентифікатор і була збережена як новий рядок у БД.

Я б як і раніше обнуляв властивість ID за допомогою __clone()методу, оскільки це має сенс із чистого погляду моделі.

Оновлення 2

Копаючись у коді доктрини, це пов’язано з тим, що створені проксі-класи реалізуються за __clone()допомогою цього важливого рядка

unset($this->_entityPersister, $this->_identifier);

6
Коли я спробував цей метод, будь-які зміни в початковій сутності також зберігалися в БД, а також вставлявся новий запис. Це пов’язано з тим, що менеджер сутності все ще керує нею. Навіть коли я від'єдную вихідну сутність, вона все одно зберігає зміни. Я не знаю, чому і як успішно змусити менеджера сутності припинити керувати початковою сутністю (тобто відкинути зміни). Ні, $em->refresh($old)ні, $em->detach($old)здається, не працює ...
Чадвік Мейер

2
Якщо ви збираєтеся впровадити, __clone()переконайтеся, що це зроблено безпечно, як показано в документації, інакше ви можете легко зламати речі.
Yep_It's_Me

2
Зверніть увагу, що реалізація методу __clone () працює лише у випадку, якщо у вас плоскі об'єкти без будь-яких відносин. Зокрема, будуть копіюватися лише дані, які не є посиланнями на інші об’єкти, усі посилання будуть такими ж, як і в оригінальному об’єкті.
barbieswimcrew

2
@barbieswimcrew правильно. У мене є інша відповідь, що стосується цього сценарію
Філ

2
@ Yep_It's_Me ось непорушне (банкомат) посилання на документацію доктрини про те, як впровадити клон або пробудитись
Dimitry K


-3

Ось проста стратегія, яку я використовував і не передбачає надмірної складності:

$new->fromArray( $old->toArray() );
$new->id = NULL;

2
Звідки беруться методи fromArrayта toArrayметоди?
zerkms

Ви не використовуєте Doctrine_Collectionпредмети?
повторно

1
Я використовую лише звичайні php-об'єкти, які просто містять дані та надають методи доступу / мутатора для доступу / модифікації. Це не поширює жодних класів Доктрини
zerkms
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.