php - Why Entity Manager flush the same date for each entities?
Get the solution ↓↓↓I am making fixtures for my entities in symfony 5.2.
One of these represent a magazine with a title, a description and a release date.
My fixture code:
class MagazineFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
$faker = Factory::create();
$intialReleaseDate = new DateTime('1913-04-01');
for ($i=0; $i < 100; $i++) {
$title = $faker->sentence($nbrwords=6, $variableNbWords=true);
$number = $i + 1;
// A magazine is release each month.
$releaseDate = $intialReleaseDate;
$intialReleaseDate->modify('first day of next month');
$magazine = new Magazine();
$magazine
->setTitle($title)
->setNumber($number)
->setReleaseDate($releaseDate)
;
$manager->persist($magazine);
}
$manager->flush();
}
}
The issue is when I run my fixture, each magazine have the same date (which is the last date), I verified all the date by printing them in the for loop and all are correct.
I tried to move the flush method in the for loop and it works! The date are correctly saved in the database.
I learned that the flush method must be called when all entities are persisted and it worked all the time until now. I don't understand why it doesn't work here.
Answer
Solution:
The reason this is happening has nothing to do with theflush
method or the Entity Manager in general. The reason this is happening is because variables holding objects don't hold the object itself, but rather an identifier (quote from the Objects and references page):
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
To demonstrate, consider a simple case:
class A
{
public $b;
}
class B
{
public $num;
}
$b = new B();
$b->num = 2;
$a = new A();
$a->b = $b;
print_r($a);
$b->num = 4;
print_r($a);
The firstprint_r
will show the following:
A Object (
[b] => B Object (
[num] => 2
)
)
The second one will show:
A Object (
[b] => B Object (
[num] => 4
)
)
Even though we didn't perform any modifications on$a
itself, by modifying (mutating)$b
, we've ensured that$a->b
holds the updated value.
So what's happening in your code is, sinceDateTime
is mutable, by modifying it in each iteration you are modifying the same instance that you assign into every entity. That means that, by the end of the loop, every entity will be referencing the modified instance, resulting in the same date being flushed.
Solutions to get around this issue, while still allowing a singleflush
call after the loop, would be either switching toDateTimeImmutable
, which creates a new instance when modified or passing a clone of theDateTime
object into your entities.
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: gd library extension not available with this php installation.
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.