edoniti
edoniti

Reputation: 107

Update a Laravel Eloquent model twice

I get 20 rows using Laravel Eloquent Model, with the following code, I want to mark them as locked after getting them and then mark them as unlocked after finish the work with them. But the article_unlock update to 0 is not being executed.

$articles_object = Article::where('article_posted', '=', 0)->where('article_lock', '=', 0)->take(20);
$articles_object->update(array('article_lock' => 1));
$articles = $articles_object->get();
foreach($articles as $article)
{
\\ do the work
}
$articles_object->update(array('article_lock' => 0));

Upvotes: 2

Views: 1152

Answers (1)

Ben Swinburne
Ben Swinburne

Reputation: 26467

This happens because you're reusing a builder object, not a data set.

Effectively what happens is your Builder ($articles_object) creates the basis of a query.

When you run the update method on this Builder object it creates and runs the query.

UPDATE `articles`
SET `article_lock` = 1
WHERE `article_posted` = 0
    AND `article_lock` = 0
LIMIT 20

This sets the lock flag to 1 on the 20 rows (because of take())

The Builder object is still a Builder object even after you ran this query and has no concept of the rows it originally ran the update on. It's not a collection like you'd get from get().

What this means is when you execute the second call to update() the exact same query as above runs.

The difference here is that your where clause is WHERE article_lock = 0 meaning that it will never find the same rows as previously, because you've just set article_lock to 1 on them.

You'd need to keep track of the Ids you'd just locked, perhaps similarly to the below, and then run a query on those records specifically to zero your lock flag.

$lockedIds = [];

foreach($articles as $article)
{
\\ do the work

    $lockedIds[] = $article->id;
}

Articles::whereIn('id', $lockedIds)->update(['article_lock' => 0]);

Upvotes: 4

Related Questions