I have a doctrine entity which is being persisted to the database without me ever calling persist or flush.
I’ve managed to reproduce the problem quite simply below. As you will see, this script loads a row from a database table called MyEntity and obtains a php object with the row’s fields as attributes. The script then changes one of the attributes, but does not call persist or flush. Then the script create an empty transaction which does nothing. Oddly, this makes the object persist in the sense that the changes made to the php object are also made in the database. I wouldn’t have expected this script to make any changes to the database.
What is happening here?
Note that if I remove the empty transaction, the problem dissapears and no change is made to the database.
Here is the code (test.php):
<?php
use Doctrine\ORM\Tools\Setup;
require_once("Doctrine/ORM/Tools/Setup.php");
Setup::registerAutoloadPEAR();
$classloader = new Doctrine\Common\ClassLoader('testEntities', __DIR__);
$classloader->register();
$paths = array();
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$dbParams = array("driver" => "pdo_mysql",
"host" => "localhost",
"user" => "username",
"password" => "password",
"dbname" => "databaseName",
"charset" => "utf8");
$em = \Doctrine\ORM\EntityManager::create($dbParams, $config);
$em->getConnection()->exec("SET NAMES UTF8");
$matches = $em->getRepository('testEntities\\MyEntity')->findBy(array('ID' => 1));
echo("<pre>");
if (!empty($matches)) {
$object = $matches[0];
print_r($object);
$object->Content = "WILL IT BLEND?";
print_r($object);
}
$em->transactional(function($em) {
// Nothing happens here, but if I comment out the call to transactional, the behaviour of the script changes.
});
echo("</pre>Done!");
?>
Create and fill MyEntity table in the database:
CREATE TABLE `MyEntity` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Content` varchar(500) COLLATE utf8_swedish_ci NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;
INSERT INTO MyEntity (ID, Content) VALUES (NULL, "Hello World");
Create MyEntity doctrine Entity (testEntities\MyEntity.php):
<?php
namespace testEntities;
/** @Entity @Table(name="MyEntity")*/
class MyEntity
{
/**
* @Id @GeneratedValue(strategy="AUTO") @Column(type="integer")
*/
public $ID;
/**
* @Column(type="string", length=500)
*/
public $Content;
}
?>
Doctrine manual: 9. Transactions and Concurrency -> 9.1.2. Approach 2: Explicitly (at section bottom):
So:
EntityManager#transactional($func)flushes the EntityManager prior to transaction commit (if$funccall was successful – your case).