From 32870eca8646df63835c2160ae8bbc1b224e2ca7 Mon Sep 17 00:00:00 2001 From: otsch Date: Wed, 1 Jun 2022 19:34:20 +0200 Subject: [PATCH] Add dirty hook For implementation in the url package we need a way to get informed when something in the query string was changed, to update the full url. --- src/Query.php | 19 +++- tests/DirtyHookTest.php | 203 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 tests/DirtyHookTest.php diff --git a/src/Query.php b/src/Query.php index bfff4c5..d12881b 100644 --- a/src/Query.php +++ b/src/Query.php @@ -25,10 +25,6 @@ final class Query implements ArrayAccess, Iterator private const TEMP_SPACE_REPLACEMENT = ''; - private ?Query $parent = null; - - private bool $isDirty = false; - private ?string $string = null; /** @@ -45,6 +41,12 @@ final class Query implements ArrayAccess, Iterator */ private bool $boolToInt = true; + private ?Query $parent = null; + + private bool $isDirty = false; + + private ?Closure $dirtyHookCallback = null; + /** * @param string|mixed[] $query */ @@ -396,6 +398,13 @@ public function map(Closure $mappingCallback): self return $this; } + public function setDirtyHook(Closure $callback): self + { + $this->dirtyHookCallback = $callback; + + return $this; + } + /** * @param int|string $offset * @throws Exception @@ -719,6 +728,8 @@ private function setDirty(): void $this->isDirty = true; $this->parent?->setDirty(); + + $this->dirtyHookCallback?->call($this); } /** diff --git a/tests/DirtyHookTest.php b/tests/DirtyHookTest.php new file mode 100644 index 0000000..1569ad5 --- /dev/null +++ b/tests/DirtyHookTest.php @@ -0,0 +1,203 @@ + 'bar']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->set('baz', 'quz'); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when appendTo() was called', function () { + $query = Query::fromArray(['foo' => 'bar']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->appendTo('foo', 'baz'); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when remove() was called', function () { + $query = Query::fromArray(['foo' => 'bar']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->remove('foo'); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when removeValueFrom() was called', function () { + $query = Query::fromArray(['foo' => ['1', '2']]); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->removeValueFrom('foo', '2'); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when filter() was called', function () { + $query = Query::fromArray(['1', '2', '3', '4', '5']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->filter(function ($value) { + return (int) $value > 2; + }); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when map() was called', function () { + $query = Query::fromArray(['1', '2', '3', '4', '5']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->map(function ($value) { + return (int) $value + 1; + }); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when boolToString() was called', function () { + $query = Query::fromArray(['foo' => true, 'bar' => false]); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->boolToString(); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when boolToInt() was called', function () { + $query = Query::fromArray(['foo' => true, 'bar' => false]); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->boolToString(); + + $query->boolToInt(); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when spaceCharacterPercentTwenty() was called', function () { + $query = Query::fromArray(['foo' => 'spa ce']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->spaceCharacterPercentTwenty(); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when spaceCharacterPlus() was called', function () { + $query = Query::fromArray(['foo' => 'spa ce']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->spaceCharacterPercentTwenty(); + + $query->spaceCharacterPlus(); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when separator() was called', function () { + $query = Query::fromArray(['foo' => '1', 'bar' => '2']); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->separator(';'); + + expect($hookWasCalled)->toBeTrue(); +}); + +it('calls the dirty hook when something in a child Query instance was changed', function () { + $query = Query::fromArray(['foo' => ['bar' => 'baz']]); + + $hookWasCalled = false; + + $query->setDirtyHook(function () use (& $hookWasCalled) { + $hookWasCalled = true; + }); + + expect($hookWasCalled)->toBeFalse(); + + $query->get('foo')->set('quz', 'test'); + + expect($hookWasCalled)->toBeTrue(); +});