steevanb / doctrine-read-only-hydrator

Add SimpleObject and ReadOnly hydrators do Doctrine.
GNU General Public License v3.0
57 stars 14 forks source link

Read only entity is tracked in the unit of work, can be persisted #10

Closed HeathNaylor closed 3 years ago

HeathNaylor commented 6 years ago

I set up a basic prototype to see if this package would help solve a problem I am working on.

The code I have is very basic:

bootstrap.php

<?php

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use steevanb\DoctrineReadOnlyHydrator\Hydrator\ReadOnlyHydrator;

require_once "vendor/autoload.php";

$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode);
$config->addCustomHydrationMode(ReadOnlyHydrator::HYDRATOR_NAME, ReadOnlyHydrator::class);

$conn = array(
    'driver' => 'pdo_sqlite',
    'path' => __DIR__ . '/db.sqlite',
);

// obtaining the entity manager
$entityManager = EntityManager::create($conn, $config);

index.php

<?php

use steevanb\DoctrineReadOnlyHydrator\Hydrator\ReadOnlyHydrator;

require_once "bootstrap.php";

$queryBuilder = $entityManager->createQueryBuilder('user');

/** @var User $object */
$object = $queryBuilder
    ->select('user')
    ->from('user', 'user')
    ->where('user.id = ?1')
    ->setParameter(1, 1)
    ->getQuery()->setHydrationMode(ReadOnlyHydrator::HYDRATOR_NAME)->getResult()[0];

$entityManager->clear();

$object->setName('ASDF');
$entityManager->merge($object);
$entityManager->flush();

echo 'done';

After I run getResult() through the query, my entity manager unit of work is in this state: image

To test my theory, I clear the entity manager, mutate the read only entity, merge it back into the entity manager to flush it.

The result is an updated record with ASDF as a user name in the database. image

composer.json

{
    "require": {
        "doctrine/orm": "2.5.6",
        "steevanb/doctrine-read-only-hydrator": "^2.2"
    },
    "autoload": {
        "psr-0": {"": "src/"}
    }
}
steevanb commented 6 years ago

That's normal : when you use QueryBuilder, UnitOfWork register all you show in your screen. But it doens't register the hydrated object, as it's the hydrator who do that.

If you don't want to insert / update read only hydrated entities, you need to manualy register steevanb\DoctrineReadOnlyHydrator\EventSubscriber\ReadOnlySubscriber in Doctrine EventManager, and you don't do that in your snippet.

That's automaticaly done with you use Symfony Bundle.

HeathNaylor commented 6 years ago

I guess I am confused, on the readme it says

So, in case you don't need to modify your entity, you want to be really faster, or just retrieve data stored in your database, you can use SimpleObjectHydrator or ReadOnlyHydrator.

This hydrated entities can't be persisted / flushed, because they are not registered in UnitOfwork to be faster.

I ended up going a different route that did not use these hydrators, but my overall goal was to get a quickly hydrated entity out of the database without it being registered to the unit of work.