From 2af18cedb393467f10517903f12d6ec6a96bf27a Mon Sep 17 00:00:00 2001 From: Arif Hoque Date: Fri, 9 Jan 2026 11:16:40 +0600 Subject: [PATCH 1/2] New Entity ORM repair() method --- src/Phaseolies/Database/Entity/Builder.php | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Phaseolies/Database/Entity/Builder.php b/src/Phaseolies/Database/Entity/Builder.php index 621fd48..bd59359 100644 --- a/src/Phaseolies/Database/Entity/Builder.php +++ b/src/Phaseolies/Database/Entity/Builder.php @@ -21,7 +21,6 @@ use Phaseolies\Support\Facades\URL; use Phaseolies\Support\Contracts\Encryptable; use Phaseolies\Support\Collection; - use Phaseolies\Database\Entity\Model; class Builder @@ -2964,6 +2963,29 @@ public function search(array $attributes, ?string $searchTerm = null): self return $this->where($searchQuery); } + /** + * Get records and fix/normalize data + * + * @param callable $fixer + * @param bool $saveChanges + * @return Collection + */ + public function repair(callable $fixer, bool $saveChanges = false): Collection + { + $results = $this->get(); + + foreach ($results as $item) { + $original = $item->getAttributes(); + $fixer($item); + + if ($saveChanges && $item->getAttributes() !== $original) { + $item->save(); + } + } + + return $results; + } + /** * Convert camelCase to snake_case for column names * From 94f874d9d09435ecbb0ba5dfa527206ad85eb5a7 Mon Sep 17 00:00:00 2001 From: Arif Hoque Date: Fri, 9 Jan 2026 12:30:36 +0600 Subject: [PATCH 2/2] Unit test for repair() method --- tests/Model/Query/EntityModelQueryTest.php | 56 ++++++++++++++++++++++ tests/Support/Model/MockProduct.php | 18 +++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/Support/Model/MockProduct.php diff --git a/tests/Model/Query/EntityModelQueryTest.php b/tests/Model/Query/EntityModelQueryTest.php index c22d3f5..d0cde5d 100644 --- a/tests/Model/Query/EntityModelQueryTest.php +++ b/tests/Model/Query/EntityModelQueryTest.php @@ -15,6 +15,7 @@ use Phaseolies\DI\Container; use PHPUnit\Framework\TestCase; use PDO; +use Tests\Support\Model\MockProduct; class EntityModelQueryTest extends TestCase { @@ -97,7 +98,20 @@ private function createTestTables(): void ) "); + $this->pdo->exec(" + CREATE TABLE product ( + price INTEGER + ) + "); + // Insert test data + $this->pdo->exec(" + INSERT INTO product (price) VALUES + (875), + (435), + (999) + "); + $this->pdo->exec(" INSERT INTO users (name, email, age, status, created_at) VALUES ('John Doe', 'john@example.com', 30, 'active', '2024-01-01 10:00:00'), @@ -2605,4 +2619,46 @@ public function testPostTagRelateMethod() $this->assertEquals([2], array_keys($changes['detached'])); $this->assertEquals([], $changes['updated']); } + + public function testRepairMethodFetchingRecords() + { + $products = MockProduct::repair(function ($product) { + $product->price = preg_replace('/[^0-9]/', '', $product->price); + }, false); + + $this->assertEquals(3, count($products)); + } + + public function testRepairPreviewsPriceCleanupWithoutPersistingChanges() + { + $products = MockProduct::repair(function ($product) { + $product->price = preg_replace('/[^0-5]/', '', $product->price); + }, false); + + foreach ($products[0] as $product) { + $this->assertTrue(str_contains($product->price, 5)); + } + + // Cause product 3 id price is = 999 + foreach ($products[2] as $product) { + $this->assertNull($product->price); + } + } + + public function testRepairMethodSaveChanges() + { + $products = MockProduct::query() + ->repair(function ($product) { + $product->price = preg_replace('/[^0-9]/', '', $product->price); + }, true); + + foreach ($products[0] as $product) { + $this->assertTrue(str_contains($product->price, 5)); + } + + // Cause product 3 id price is = 999 + foreach ($products[2] as $product) { + $this->assertNull($product->price); + } + } } diff --git a/tests/Support/Model/MockProduct.php b/tests/Support/Model/MockProduct.php new file mode 100644 index 0000000..5f25371 --- /dev/null +++ b/tests/Support/Model/MockProduct.php @@ -0,0 +1,18 @@ +