Laravel seeding using a yield generator
I was needing to improve the performance of a pivot table seeder recently and decided to use a generator to do it.
Interestingly, one of the easiest to implement iterators is the yield
syntax introduced in PHP 5.5. It allows for good abstraction
between the data that is to be iterated and the source of said data. That can lead to significant performance increases
as well since it might, depending on the use case, reduce database calls or the amount of data being stored in memory among other things.
Basically what the yield
syntax does is it returns an instance of the Generator
class for that sequence in the loop.
When next()
is called on the Generator
class (which yield
is) PHP then resumes with the state from when the yield
statement was called. It continues on until there is nothing
left to yield.
could be:
protected function userIterator()
{
$maxCount = \App\User::count();
$take = 100;
for ($i = $maxCount; $i > 0; $i = ($i - $take)) {
$commentIds = \App\User::where('id', '>', $this->lastId)->take($take)->lists('id')->toArray();
$this->lastId = last($userIds);
foreach ($userIds as $userId) {
yield $userId;
}
}
}
The consuming function might look like so:
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
foreach ($this->userIterator() as $userId) {
$this->createUserPost($userId, $this->getRandomPostId());
}
}