У меня есть форма, которая позволяет мне сохранять запись или дублировать ее. Форма сохраняет запись как объект $view
, который, случается, имеет несколько связанных объектов, например. $viewVersion
, которые управляются компоновщиком форм в formType с вложенными объектами (это, вероятно, не имеет значения).
Если я вношу изменения и передаю форму для "дублирования", код клонирует объект $view
с функцией на моей сущности, которая отключает $view->id
и другие ассоциации. Это заставляет Doctrine создавать новую запись, когда она сохраняет запись в базе данных. Это прекрасно работает. Ура!
НО, изменения, внесенные в запись, также сохраняются в исходном объекте, который был клонирован (и, следовательно, сохранен в базе данных). Таким образом, он сохраняет эти изменения в ДВА записей базы данных. Мне нравится эта функциональность, но мне нужно понять, ПОЧЕМУ она делает это, чтобы она не прерывалась позже. Вот краткие сводки кода:
// File: CmsBundle/Controller/AdminEditController.php
// Get the Entity Manager
$em = $this->getDoctrine()->getManager();
// Get the View based on the requested ID
// Is there some magic that happens here to make the entity manager track this $view entity?
$view = $em->getRepository("GutensiteCmsBundle:View\View")->find($request->query->get('id'));
// Various bits of code to do whatever I want before a save
// ...
if ($request->isMethod( 'POST' )) {
$form->handleRequest($request);
if( $form->isValid() ) {
// Duplicate the view entity if the view button is pushed
if(
$form->has('duplicate')
&& $form->get('duplicate')->isClicked()
) {
$view = clone $view;
}
// Persist the cloned view
$em->persist($view);
$em->flush();
}
}
Объект View имеет специальную функцию клонирования, которая запускается на клоне, которая сбрасывает идентификаторы клонированных версий:
// File: CmsBundle/Entity/View.php
public function __clone() {
if($this->id) {
$this->setId(null);
$this->setLockVersion(1);
$this->setPublished(null);
// Clone associated entities and reassociate with THIS version (even though there is no id yet, there will be when it persists)
// clone the current version (which also has a clone function like this)
$version = clone $this->getVersion();
// reset the viewid with a custom function
$version->resetView();
// Add this cloned verion to the version history
$this->addVersion($version);
}
Я много читал о клонировании, и мне постоянно говорят, что вам не нужно detach оригинал $view
от диспетчера объектов. Кроме того, я пробовал, и это не принесло пользы. Изменения в представлении $view, которые были отправлены формой и обработаны до $view до клонирования, по-прежнему сохраняются в исходном идентификаторе записи $view
(например, 33), а также в новой клонированной записи (например, 62), Таким образом, сохраняются два состояния, хотя один объект сохраняется только для одного объекта.
Что происходит?
Update
Мне сказали, что если вы загружаете объект с менеджером сущностей, он отслеживается менеджером сущности. Поэтому, если вы вызовете flush()
в любое время, любые изменения будут сохранены, даже если вы не вызывали persist($view)
в сущности. Поэтому, когда я клонирую сущность, менеджер сущности эффективно управляет двумя объектами: оригиналом и клоном.
Я попытался отделить представление от менеджера сущности до клонирования двумя способами:
// detach method 1
$em->detach($view);
$em->flush();
// detach method 2
$em->refresh($view);
$em->flush();
// clone the view after detaching the first entity.
$view = clone $view;
Но менеджер объектов по-прежнему сохраняет изменения в исходной записи $view
.
Я также попытался добавить unset($this->_entityPersister, $this->_identifier);
в свой пользовательский метод __clone()
. Но это также не отделяло исходный объект или клонированную версию от менеджера сущности. Изменения были сохранены как в старой записи, так и в новой записи.
Ничто не может заставить диспетчера объектов игнорировать исходный объект.