Skip to content

feat: add lazyEach to EntityControlTrait - #271

Merged
DenTray merged 32 commits into
masterfrom
add-lazy-each
Jun 8, 2026
Merged

feat: add lazyEach to EntityControlTrait#271
DenTray merged 32 commits into
masterfrom
add-lazy-each

Conversation

@neellii

@neellii neellii commented Mar 27, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a lazyEach() helper to EntityControlTrait to iterate through models lazily (by ID) while preserving the trait’s state-reset behavior after query execution.

Changes:

  • Added EntityControlTrait::lazyEach() built on Eloquent lazyById(), returning the number of iterated records.
  • Extended SQL mocking helpers with a dedicated mock for the lazy-by-id query shape.
  • Added PHPUnit coverage for lazyEach() with both non-empty and empty result sets.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Traits/EntityControlTrait.php Introduces lazyEach() using lazyById() and resets settable properties afterward.
tests/support/Traits/SqlMockTrait.php Adds SQL mock helper for the expected lazyById select + eager-load query.
tests/EntityControlTraitTest.php Adds tests validating return count and settable-property reset for lazyEach().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Traits/EntityControlTrait.php Outdated
Comment on lines +369 to +378
$this
->getQuery($where)
->lazyById($chunkSize)
->tapEach(function () use (&$count) {
$count++;
})
->each($callback);

$this->postQueryHook();

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lazyEach() calls postQueryHook() only after iterating successfully. If the provided callback throws an exception during iteration, the hook will never run and the repository can leak state (withTrashed/onlyTrashed/force/with/withCount) into subsequent calls. Consider wrapping the iteration in a try { ... } finally { $this->postQueryHook(); } to guarantee reset even on failure.

Suggested change
$this
->getQuery($where)
->lazyById($chunkSize)
->tapEach(function () use (&$count) {
$count++;
})
->each($callback);
$this->postQueryHook();
try {
$this
->getQuery($where)
->lazyById($chunkSize)
->tapEach(function () use (&$count) {
$count++;
})
->each($callback);
} finally {
$this->postQueryHook();
}

Copilot uses AI. Check for mistakes.
Comment thread src/Traits/EntityControlTrait.php Outdated
$this->postQueryHook();
}

public function lazyEach(Closure $callback, array $where = [], int $chunkSize = 500): int

Copilot AI Mar 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new lazyEach() method’s parameter order (callback, where, chunkSize) is inconsistent with chunk() (limit, callback, where) and with most other methods in this trait that take $where as the last optional argument. This inconsistency makes the public API harder to remember/use (especially without named args). Consider aligning the signature/argument order with existing methods (or adding a PHPDoc showing intended usage).

Suggested change
public function lazyEach(Closure $callback, array $where = [], int $chunkSize = 500): int
public function lazyEach(int $chunkSize, Closure $callback, array $where = []): int

Copilot uses AI. Check for mistakes.
Comment thread src/Traits/EntityControlTrait.php Outdated
$this->postQueryHook();
}

public function lazyEach(Closure $callback, array $where = [], int $chunkSize = 500): int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function lazyEach(Closure $callback, array $where = [], int $chunkSize = 500): int
public function lazyEach(Closure $callback, array $where = [], int $chunkSize = 500): void

Comment thread src/Traits/EntityControlTrait.php Outdated
Comment on lines +367 to +379
$count = 0;

$this
->getQuery($where)
->lazyById($chunkSize)
->tapEach(function () use (&$count) {
$count++;
})
->each($callback);

$this->postQueryHook();

return $count;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tapEach is required?

Suggested change
$count = 0;
$this
->getQuery($where)
->lazyById($chunkSize)
->tapEach(function () use (&$count) {
$count++;
})
->each($callback);
$this->postQueryHook();
return $count;
$this
->getQuery($where)
->lazyById($chunkSize)
->each($callback);
$this->postQueryHook();

using

$count = 0;

->lazyEach(function ($item) use (&$count) {
    $count++;
});

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i think we can skip "counting" since its a helper package and "counting" can be implemented in a $callback

@pirs1337 pirs1337 assigned neellii and unassigned pirs1337 Mar 29, 2026
@neellii neellii assigned pirs1337 and unassigned neellii Mar 31, 2026
Comment thread tests/support/Traits/SqlMockTrait.php Outdated
Comment thread tests/EntityControlTraitTest.php Outdated
@pirs1337 pirs1337 assigned DenTray and unassigned pirs1337 Mar 31, 2026
@astorozhevsky

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/EntityControlTraitTest.php Outdated
Comment thread tests/EntityControlTraitTest.php Outdated
Comment thread tests/EntityControlTraitTest.php
@DenTray

DenTray commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

@neellii could you please fix tests for the new tests

@DenTray DenTray assigned neellii and unassigned DenTray Apr 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9bb90e1fce

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tests/EntityControlTraitTest.php Outdated
public function testLazyEachEmptyResult()
{
$this->mockSelect(
'select "test_models".* from "test_models" where "test_models"."deleted_at" is not null order by "id" asc limit 500',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Align lazyEach empty-result SQL mock with repository state

testLazyEachEmptyResult mocks a query with "deleted_at" is not null, but the test calls self::$testRepositoryClass->lazyEach(...) without setting onlyTrashed(). In EntityControlTrait::getQuery(), that predicate is only applied when the onlyTrashed flag is enabled, so this expectation does not match the actual query path and makes the new empty-result test fail/misrepresent behavior.

Useful? React with 👍 / 👎.

@neellii neellii assigned neellii and unassigned DenTray May 25, 2026
@neellii neellii assigned DenTray and unassigned neellii May 25, 2026
DenTray and others added 3 commits June 8, 2026 07:30
…nk coverage and fixture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread tests/EntityControlTraitTest.php Outdated
DenTray and others added 9 commits June 8, 2026 10:09
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…of version check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… ordering issues

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…it < 10.5.30

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread tests/MockTraitTest.php Outdated
DenTray and others added 2 commits June 8, 2026 11:47
…3 compatibility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ravel version

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@DenTray
DenTray merged commit 83cb996 into master Jun 8, 2026
11 checks passed
@DenTray
DenTray deleted the add-lazy-each branch June 8, 2026 05:55

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3b757eaad

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tests/MockTraitTest.php
$assertionFailureProp->setValue($handler, null);
foreach ($class->getProperty('mockObjects')->getValue($this) as $entry) {
if ($isNewPhpunit) {
$handler = $entry['mockObject']->__phpunit_getInvocationHandler();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat PHPUnit 11 mock entries as objects

When the suite runs with PHPUnit 11 or newer, this branch tries to index each mockObjects entry as an array, but PHPUnit's TestCase::registerMockObject() still appends the mock object itself in 11/12; with the unconstrained phpunit/phpunit >=10.5.30 dev requirement, installing a current PHPUnit makes any test that calls clearMockAssertionFailures() fail with an object-as-array error before it can clear the handler state.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants