Отже ... що робити, коли ми хочемо знайти набір змін поза життєвим циклом Доктрини? Як згадувалось у моєму коментарі до публікації @Ocramius вище, можливо, можливо створити метод "лише для читання", який не змішуватиметься з фактичною стійкістю Доктрини, але дає користувачеві уявлення про те, що змінилося.
Ось приклад того, про що я думаю ...
public static function diffDoctrineObject(EntityManager $em, $entity) {
$uow = $em->getUnitOfWork();
$class = $em->getClassMetadata(get_class($entity));
$oid = spl_object_hash($entity);
$entityChangeSets = array();
if ($uow->isReadOnly($entity)) {
return null;
}
if ( ! $class->isInheritanceTypeNone()) {
$class = $em->getClassMetadata(get_class($entity));
}
$actualData = array();
foreach ($class->reflFields as $name => $refProp) {
$value = $refProp->getValue($entity);
if ($class->isCollectionValuedAssociation($name) && $value !== null) {
if ($value instanceof PersistentCollection) {
if ($value->getOwner() === $entity) {
continue;
}
$value = new ArrayCollection($value->getValues());
}
if ( ! $value instanceof Collection) {
$value = new ArrayCollection($value);
}
$assoc = $class->associationMappings[$name];
$value = new PersistentCollection(
$em, $em->getClassMetadata($assoc['targetEntity']), $value
);
$value->setOwner($entity, $assoc);
$value->setDirty( ! $value->isEmpty());
$class->reflFields[$name]->setValue($entity, $value);
$actualData[$name] = $value;
continue;
}
if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) {
$actualData[$name] = $value;
}
}
$originalEntityData = $uow->getOriginalEntityData($entity);
if (empty($originalEntityData)) {
$originalEntityData = $actualData;
$changeSet = array();
foreach ($actualData as $propName => $actualValue) {
if ( ! isset($class->associationMappings[$propName])) {
$changeSet[$propName] = array(null, $actualValue);
continue;
}
$assoc = $class->associationMappings[$propName];
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
$changeSet[$propName] = array(null, $actualValue);
}
}
$entityChangeSets[$oid] = $changeSet;
} else {
$originalData = $originalEntityData;
$isChangeTrackingNotify = $class->isChangeTrackingNotify();
$changeSet = $isChangeTrackingNotify ? $uow->getEntityChangeSet($entity) : array();
foreach ($actualData as $propName => $actualValue) {
if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) {
continue;
}
$orgValue = $originalData[$propName];
if ($orgValue === $actualValue) {
continue;
}
if ( ! isset($class->associationMappings[$propName])) {
if ($isChangeTrackingNotify) {
continue;
}
$changeSet[$propName] = array($orgValue, $actualValue);
continue;
}
$assoc = $class->associationMappings[$propName];
if ($actualValue instanceof PersistentCollection) {
$owner = $actualValue->getOwner();
if ($owner === null) {
$actualValue->setOwner($entity, $assoc);
} else if ($owner !== $entity) {
if (!$actualValue->isInitialized()) {
$actualValue->initialize();
}
$newValue = clone $actualValue;
$newValue->setOwner($entity, $assoc);
$class->reflFields[$propName]->setValue($entity, $newValue);
}
}
if ($orgValue instanceof PersistentCollection) {
$changeSet[$propName] = $orgValue;
continue;
}
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($assoc['isOwningSide']) {
$changeSet[$propName] = array($orgValue, $actualValue);
}
}
}
if ($changeSet) {
$entityChangeSets[$oid] = $changeSet;
}
}
return $entityChangeSets[$oid];
}
Тут це сформульовано як статичний метод, але може стати методом усередині UnitOfWork ...?
Я не в курсі всіх внутрішніх аспектів Доктрини, тому міг пропустити щось, що має побічний ефект або неправильно зрозуміти частину того, що робить цей метод, але (дуже) швидкий тест, здається, дає мені результати, яких я очікую бачити.
Сподіваюся, це комусь допоможе!