From 6dfff1c75ad2afc56d7821d4e2c005fbbe72e10e Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Mon, 1 Jul 2024 12:45:55 -0300 Subject: [PATCH 01/25] add size method --- src/DataStructure/Map.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/DataStructure/Map.php b/src/DataStructure/Map.php index cf2866e..987daed 100644 --- a/src/DataStructure/Map.php +++ b/src/DataStructure/Map.php @@ -43,4 +43,10 @@ public function get(mixed $key): mixed; * @return bool true if the key-value pair was removed, false otherwise */ public function remove(mixed $key): bool; + /** + * Returns the number of key-value mappings in the map. + * + * @return int the number of key-value mappings + */ + public function size(): int; } From 18284e01a688f1b63d4f04a147d5b2c945651bf7 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Mon, 1 Jul 2024 18:34:00 -0300 Subject: [PATCH 02/25] feat: Normalize Interfaces - Refined and standardized interface definitions across the project - Applied Single Responsibility Principle (SRP) to ensure each interface has a clear, singular purpose - Consistent naming conventions were implemented for better readability and maintainability - Added thorough documentation for each interface, including method descriptions and expected behaviors - Organized interfaces within appropriate namespaces to prevent naming collisions and maintain a logical structure - Ensured parameter names in interface methods are consistent with implementing classes - Avoided including constructors in interfaces to maintain flexibility These changes enhance the overall clarity, maintainability, and professional quality of the codebase. --- src/DataStructure/Behavioral/Countable.php | 2 +- src/DataStructure/Behavioral/Indexable.php | 26 ++-------- .../Behavioral/IterableCollection.php | 3 +- src/DataStructure/Behavioral/Modifiable.php | 41 ++++++++++++++++ src/DataStructure/Behavioral/Searchable.php | 38 +++++++++++++++ src/DataStructure/Map.php | 47 +++++++++++++----- src/DataStructure/Queue.php | 4 +- src/DataStructure/Set.php | 48 +++++++------------ src/DataStructure/Structural/Collection.php | 48 ++----------------- src/DataStructure/Tree.php | 39 ++------------- .../Behavioral/CountableTest.php | 6 +-- .../Behavioral/IndexableTest.php | 16 ------- {src => tests}/DataStructure/DequeTest.php | 16 ------- tests/DataStructure/MapTest.php | 30 ++++++++++++ .../Structural/CollectionTest.php | 16 ------- 15 files changed, 181 insertions(+), 199 deletions(-) create mode 100644 src/DataStructure/Behavioral/Modifiable.php create mode 100644 src/DataStructure/Behavioral/Searchable.php rename {src => tests}/DataStructure/DequeTest.php (79%) diff --git a/src/DataStructure/Behavioral/Countable.php b/src/DataStructure/Behavioral/Countable.php index 918453d..1f5c41d 100644 --- a/src/DataStructure/Behavioral/Countable.php +++ b/src/DataStructure/Behavioral/Countable.php @@ -23,5 +23,5 @@ interface Countable * * @return int The number of elements */ - public function count(): int; + public function size(): int; } diff --git a/src/DataStructure/Behavioral/Indexable.php b/src/DataStructure/Behavioral/Indexable.php index f12f0e5..73c7950 100644 --- a/src/DataStructure/Behavioral/Indexable.php +++ b/src/DataStructure/Behavioral/Indexable.php @@ -19,37 +19,19 @@ interface Indexable { /** - * Checks if an element exists at the given index. + * Retrieves an element at the specified index. * - * @param int $index The index to check - * - * @return bool True if the index exists, false otherwise - */ - public function contains(int $index): bool; - - /** - * Gets the element at the specified index. - * - * @param int $index The index of the element + * @param int $index The index of the element to retrieve * * @return mixed The element at the specified index */ public function get(int $index): mixed; /** - * Sets the element at the specified index. + * Sets an element at the specified index. * - * @param int $index The index at which to set the element + * @param int $index The index where the element should be set * @param mixed $element The element to set */ public function set(int $index, mixed $element): void; - - /** - * Removes the element at the specified index. - * - * @param int $index The index of the element to remove - * - * @return bool True if the element was removed, false otherwise - */ - public function remove(int $index): bool; } diff --git a/src/DataStructure/Behavioral/IterableCollection.php b/src/DataStructure/Behavioral/IterableCollection.php index 558cfe5..a490e8f 100644 --- a/src/DataStructure/Behavioral/IterableCollection.php +++ b/src/DataStructure/Behavioral/IterableCollection.php @@ -9,7 +9,8 @@ * * Provides the ability to iterate over a collection. * - * @author Walmir Silva + * @category Interfaces + * * @author Walmir Silva * @license MIT * diff --git a/src/DataStructure/Behavioral/Modifiable.php b/src/DataStructure/Behavioral/Modifiable.php new file mode 100644 index 0000000..94fd577 --- /dev/null +++ b/src/DataStructure/Behavioral/Modifiable.php @@ -0,0 +1,41 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Modifiable +{ + /** + * Adds an element to the collection. + * + * @param mixed $element The element to add + */ + public function add(mixed $element): void; + + /** + * Removes an element from the collection. + * + * @param mixed $element The element to remove + * + * @return bool True if the element was removed, false otherwise + */ + public function remove(mixed $element): bool; + + /** + * Clears all elements from the collection. + */ + public function clear(): void; +} diff --git a/src/DataStructure/Behavioral/Searchable.php b/src/DataStructure/Behavioral/Searchable.php new file mode 100644 index 0000000..1e301d4 --- /dev/null +++ b/src/DataStructure/Behavioral/Searchable.php @@ -0,0 +1,38 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Searchable +{ + /** + * Checks if the collection contains a specific element. + * + * @param mixed $element The element to check for + * + * @return bool True if the element is present, false otherwise + */ + public function contains(mixed $element): bool; + + /** + * Finds the index of a specific element in the collection. + * + * @param mixed $element The element to find + * + * @return int The index of the element + */ + public function find(mixed $element): mixed; +} diff --git a/src/DataStructure/Map.php b/src/DataStructure/Map.php index 987daed..2a203b5 100644 --- a/src/DataStructure/Map.php +++ b/src/DataStructure/Map.php @@ -4,6 +4,9 @@ namespace KaririCode\Contract\DataStructure; +use KaririCode\Contract\DataStructure\Behavioral\Countable; +use KaririCode\Contract\DataStructure\Behavioral\IterableCollection; + /** * Interface Map. * @@ -16,37 +19,59 @@ * * @see https://kariricode.org/ */ -interface Map +interface Map extends Countable, IterableCollection { /** - * Puts a key-value pair into the map. + * Adds a key-value pair to the map. * - * @param mixed $key the key - * @param mixed $value the value + * @param mixed $key The key to add + * @param mixed $value The value to add */ public function put(mixed $key, mixed $value): void; /** - * Gets a value by its key. + * Retrieves a value by its key. * - * @param mixed $key the key + * @param mixed $key The key to retrieve the value for * - * @return mixed the value associated with the key + * @return mixed The value associated with the key */ public function get(mixed $key): mixed; /** * Removes a key-value pair from the map. * - * @param mixed $key the key + * @param mixed $key The key to remove * * @return bool true if the key-value pair was removed, false otherwise */ public function remove(mixed $key): bool; + + /** + * Checks if the map contains a specific key. + * + * @param mixed $key The key to check for + * + * @return bool true if the key is present, false otherwise + */ + public function containsKey(mixed $key): bool; + /** - * Returns the number of key-value mappings in the map. + * Returns all keys in the map. * - * @return int the number of key-value mappings + * @return array The keys in the map + */ + public function keys(): array; + + /** + * Returns all values in the map. + * + * @return array The values in the map + */ + public function values(): array; + + /** + * Clears all key-value pairs from the map. */ - public function size(): int; + public function clear(): void; } diff --git a/src/DataStructure/Queue.php b/src/DataStructure/Queue.php index d16c10c..47fd3d7 100644 --- a/src/DataStructure/Queue.php +++ b/src/DataStructure/Queue.php @@ -4,6 +4,8 @@ namespace KaririCode\Contract\DataStructure; +use KaririCode\Contract\DataStructure\Behavioral\Modifiable; + /** * Interface Queue. * @@ -16,7 +18,7 @@ * * @see https://kariricode.org/ */ -interface Queue +interface Queue extends Modifiable { /** * Enqueues an element into the queue. diff --git a/src/DataStructure/Set.php b/src/DataStructure/Set.php index 0427b19..ec9af06 100644 --- a/src/DataStructure/Set.php +++ b/src/DataStructure/Set.php @@ -4,6 +4,9 @@ namespace KaririCode\Contract\DataStructure; +use KaririCode\Contract\DataStructure\Behavioral\Modifiable; +use KaririCode\Contract\DataStructure\Behavioral\Searchable; + /** * Interface Set. * @@ -16,51 +19,32 @@ * * @see https://kariricode.org/ */ -interface Set +interface Set extends Modifiable, Searchable { /** - * Adds an element to the set. - * - * @param mixed $element The element to add - * - * @return bool True if the element was added, false if it was already present - */ - public function add(mixed $element): bool; - - /** - * Removes an element from the set. + * Performs a union of this set with another set. * - * @param mixed $element The element to remove + * @param Set $other The other set to union with * - * @return bool True if the element was removed, false if it was not present + * @return Set The resulting set after the union */ - public function remove(mixed $element): bool; + public function union(Set $other): Set; /** - * Checks if the set contains a specific element. + * Performs an intersection of this set with another set. * - * @param mixed $element The element to check for + * @param Set $other The other set to intersect with * - * @return bool True if the element is present, false otherwise + * @return Set The resulting set after the intersection */ - public function contains(mixed $element): bool; + public function intersection(Set $other): Set; /** - * Removes all elements from the set. - */ - public function clear(): void; - - /** - * Returns the number of elements in the set. + * Performs a difference of this set with another set. * - * @return int The number of elements in the set - */ - public function size(): int; - - /** - * Checks if the set is empty. + * @param Set $other The other set to differentiate with * - * @return bool True if the set is empty, false otherwise + * @return Set The resulting set after the difference */ - public function isEmpty(): bool; + public function difference(Set $other): Set; } diff --git a/src/DataStructure/Structural/Collection.php b/src/DataStructure/Structural/Collection.php index 7d13890..cfda28a 100644 --- a/src/DataStructure/Structural/Collection.php +++ b/src/DataStructure/Structural/Collection.php @@ -6,6 +6,8 @@ use KaririCode\Contract\DataStructure\Behavioral\Countable; use KaririCode\Contract\DataStructure\Behavioral\Indexable; +use KaririCode\Contract\DataStructure\Behavioral\Modifiable; +use KaririCode\Contract\DataStructure\Behavioral\Searchable; /** * Interface Collection. @@ -19,56 +21,12 @@ * * @see https://kariricode.org/ */ -interface Collection extends Countable, Indexable +interface Collection extends Countable, Indexable, Modifiable, Searchable { - /** - * Adds an element to the collection. - * - * @param mixed $element The element to add - */ - public function add(mixed $element): void; - /** * Adds all elements from another collection to this collection. * * @param Collection $collection The collection whose elements are to be added */ public function addAll(Collection $collection): void; - - /** - * Removes the first occurrence of a specific element from the collection. - * - * @param mixed $element The element to remove - * - * @return bool True if the element was removed, false otherwise - */ - public function remove(mixed $element): bool; - - /** - * Checks if the collection contains a specific element. - * - * @param mixed $element The element to check for - * - * @return bool True if the element is present, false otherwise - */ - public function contains(mixed $element): bool; - - /** - * Removes all elements from the collection. - */ - public function clear(): void; - - /** - * Checks if the collection is empty. - * - * @return bool True if the collection is empty, false otherwise - */ - public function isEmpty(): bool; - - /** - * Returns all elements of the collection as an array. - * - * @return array The elements of the collection - */ - public function getItems(): array; } diff --git a/src/DataStructure/Tree.php b/src/DataStructure/Tree.php index a4fa395..0460840 100644 --- a/src/DataStructure/Tree.php +++ b/src/DataStructure/Tree.php @@ -4,6 +4,9 @@ namespace KaririCode\Contract\DataStructure; +use KaririCode\Contract\DataStructure\Behavioral\Modifiable; +use KaririCode\Contract\DataStructure\Behavioral\Searchable; + /** * Interface Tree. * @@ -16,15 +19,8 @@ * * @see https://kariricode.org/ */ -interface Tree +interface Tree extends Modifiable, Searchable { - /** - * Adds a value to the tree. - * - * @param mixed $value the value to add - */ - public function add(mixed $value): void; - /** * Inserts a value into the tree at the specified position. * @@ -32,31 +28,4 @@ public function add(mixed $value): void; * @param mixed $value the value to insert */ public function insert(int $index, mixed $value): void; - - /** - * Removes a value from the tree. - * - * @param mixed $value the value to remove - * - * @return bool true if the value was removed, false otherwise - */ - public function remove(mixed $value): bool; - - /** - * Finds a value in the tree. - * - * @param mixed $value the value to find - * - * @return mixed|null the found value or null if not found - */ - public function find(mixed $value): mixed; - - /** - * Checks if the tree contains a specific value. - * - * @param mixed $value the value to check - * - * @return bool true if the value is found, false otherwise - */ - public function contains(mixed $value): bool; } diff --git a/tests/DataStructure/Behavioral/CountableTest.php b/tests/DataStructure/Behavioral/CountableTest.php index 367d507..fb07418 100644 --- a/tests/DataStructure/Behavioral/CountableTest.php +++ b/tests/DataStructure/Behavioral/CountableTest.php @@ -9,11 +9,11 @@ final class CountableTest extends TestCase { - public function testCount(): void + public function testSize(): void { $mock = $this->createMock(Countable::class); - $mock->method('count')->willReturn(5); + $mock->method('size')->willReturn(5); - $this->assertSame(5, $mock->count()); + $this->assertSame(5, $mock->size()); } } diff --git a/tests/DataStructure/Behavioral/IndexableTest.php b/tests/DataStructure/Behavioral/IndexableTest.php index 12c7450..7cf62be 100644 --- a/tests/DataStructure/Behavioral/IndexableTest.php +++ b/tests/DataStructure/Behavioral/IndexableTest.php @@ -9,14 +9,6 @@ final class IndexableTest extends TestCase { - public function testContains(): void - { - $mock = $this->createMock(Indexable::class); - $mock->method('contains')->with(1)->willReturn(true); - - $this->assertTrue($mock->contains(1)); - } - public function testGet(): void { $mock = $this->createMock(Indexable::class); @@ -32,12 +24,4 @@ public function testSet(): void $mock->set(1, 'value'); } - - public function testRemove(): void - { - $mock = $this->createMock(Indexable::class); - $mock->method('remove')->with(1)->willReturn(true); - - $this->assertTrue($mock->remove(1)); - } } diff --git a/src/DataStructure/DequeTest.php b/tests/DataStructure/DequeTest.php similarity index 79% rename from src/DataStructure/DequeTest.php rename to tests/DataStructure/DequeTest.php index ce12778..5662fb3 100644 --- a/src/DataStructure/DequeTest.php +++ b/tests/DataStructure/DequeTest.php @@ -56,20 +56,4 @@ public function testPeekLast(): void $this->assertSame('element', $mock->peekLast()); } - - public function testIsEmpty(): void - { - $mock = $this->createMock(Deque::class); - $mock->method('isEmpty')->willReturn(true); - - $this->assertTrue($mock->isEmpty()); - } - - public function testSize(): void - { - $mock = $this->createMock(Deque::class); - $mock->method('size')->willReturn(0); - - $this->assertSame(0, $mock->size()); - } } diff --git a/tests/DataStructure/MapTest.php b/tests/DataStructure/MapTest.php index 973dbc8..326bcb8 100644 --- a/tests/DataStructure/MapTest.php +++ b/tests/DataStructure/MapTest.php @@ -9,6 +9,7 @@ final class MapTest extends TestCase { + // Test putting a key-value pair into the map public function testPut(): void { $mock = $this->createMock(Map::class); @@ -17,6 +18,7 @@ public function testPut(): void $mock->put('key', 'value'); } + // Test getting a value by its key public function testGet(): void { $mock = $this->createMock(Map::class); @@ -25,6 +27,7 @@ public function testGet(): void $this->assertSame('value', $mock->get('key')); } + // Test removing a key-value pair from the map public function testRemove(): void { $mock = $this->createMock(Map::class); @@ -32,4 +35,31 @@ public function testRemove(): void $this->assertTrue($mock->remove('key')); } + + // Test checking if a key exists in the map + public function testContainsKey(): void + { + $mock = $this->createMock(Map::class); + $mock->method('containsKey')->with('key')->willReturn(true); + + $this->assertTrue($mock->containsKey('key')); + } + + // Test getting all keys in the map + public function testKeys(): void + { + $mock = $this->createMock(Map::class); + $mock->method('keys')->willReturn(['key1', 'key2']); + + $this->assertSame(['key1', 'key2'], $mock->keys()); + } + + // Test getting all values in the map + public function testValues(): void + { + $mock = $this->createMock(Map::class); + $mock->method('values')->willReturn(['value1', 'value2']); + + $this->assertSame(['value1', 'value2'], $mock->values()); + } } diff --git a/tests/DataStructure/Structural/CollectionTest.php b/tests/DataStructure/Structural/CollectionTest.php index 05d9c75..c0f01ff 100644 --- a/tests/DataStructure/Structural/CollectionTest.php +++ b/tests/DataStructure/Structural/CollectionTest.php @@ -49,20 +49,4 @@ public function testClear(): void $mock->clear(); } - - public function testIsEmpty(): void - { - $mock = $this->createMock(Collection::class); - $mock->method('isEmpty')->willReturn(true); - - $this->assertTrue($mock->isEmpty()); - } - - public function testGetItems(): void - { - $mock = $this->createMock(Collection::class); - $mock->method('getItems')->willReturn(['element1', 'element2']); - - $this->assertSame(['element1', 'element2'], $mock->getItems()); - } } From 132e0ee90fd1b40635a28f5578741db248e06ac5 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Mon, 1 Jul 2024 18:49:38 -0300 Subject: [PATCH 03/25] Refactor and Normalize Collection Interface and Implementation - Refactored `Collection` interface for consistency and adherence to best practices. - Ensured all tests are comprehensive and validate the expected behavior. --- src/DataStructure/Structural/Collection.php | 7 +++ .../Structural/CollectionTest.php | 57 +++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/DataStructure/Structural/Collection.php b/src/DataStructure/Structural/Collection.php index cfda28a..949a711 100644 --- a/src/DataStructure/Structural/Collection.php +++ b/src/DataStructure/Structural/Collection.php @@ -29,4 +29,11 @@ interface Collection extends Countable, Indexable, Modifiable, Searchable * @param Collection $collection The collection whose elements are to be added */ public function addAll(Collection $collection): void; + + /** + * Returns an array containing all elements in the collection. + * + * @return array The elements in the collection + */ + public function getItems(): array; } diff --git a/tests/DataStructure/Structural/CollectionTest.php b/tests/DataStructure/Structural/CollectionTest.php index c0f01ff..707f9d2 100644 --- a/tests/DataStructure/Structural/CollectionTest.php +++ b/tests/DataStructure/Structural/CollectionTest.php @@ -12,7 +12,9 @@ final class CollectionTest extends TestCase public function testAdd(): void { $mock = $this->createMock(Collection::class); - $mock->expects($this->once())->method('add')->with('element'); + $mock->expects($this->once()) + ->method('add') + ->with('element'); $mock->add('element'); } @@ -21,7 +23,9 @@ public function testAddAll(): void { $collectionMock = $this->createMock(Collection::class); $mock = $this->createMock(Collection::class); - $mock->expects($this->once())->method('addAll')->with($collectionMock); + $mock->expects($this->once()) + ->method('addAll') + ->with($collectionMock); $mock->addAll($collectionMock); } @@ -29,7 +33,9 @@ public function testAddAll(): void public function testRemove(): void { $mock = $this->createMock(Collection::class); - $mock->method('remove')->with('element')->willReturn(true); + $mock->method('remove') + ->with('element') + ->willReturn(true); $this->assertTrue($mock->remove('element')); } @@ -37,7 +43,9 @@ public function testRemove(): void public function testContains(): void { $mock = $this->createMock(Collection::class); - $mock->method('contains')->with('element')->willReturn(true); + $mock->method('contains') + ->with('element') + ->willReturn(true); $this->assertTrue($mock->contains('element')); } @@ -45,8 +53,47 @@ public function testContains(): void public function testClear(): void { $mock = $this->createMock(Collection::class); - $mock->expects($this->once())->method('clear'); + $mock->expects($this->once()) + ->method('clear'); $mock->clear(); } + + public function testSize(): void + { + $mock = $this->createMock(Collection::class); + $mock->method('size') + ->willReturn(3); + + $this->assertSame(3, $mock->size()); + } + + public function testGetItems(): void + { + $mock = $this->createMock(Collection::class); + $mock->method('getItems') + ->willReturn(['item1', 'item2']); + + $this->assertSame(['item1', 'item2'], $mock->getItems()); + } + + public function testGet(): void + { + $mock = $this->createMock(Collection::class); + $mock->method('get') + ->with(0) + ->willReturn('element'); + + $this->assertSame('element', $mock->get(0)); + } + + public function testSet(): void + { + $mock = $this->createMock(Collection::class); + $mock->expects($this->once()) + ->method('set') + ->with(0, 'element'); + + $mock->set(0, 'element'); + } } From f40b0c3fe5a9c97b0e6da467d77ce6f331cc62a2 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 2 Jul 2024 10:08:37 -0300 Subject: [PATCH 04/25] feat: Add BinaryHeap implementation and comprehensive tests - Implemented BinaryHeap class with support for both min-heap and max-heap operations. - Methods include: add, poll, peek, size, isEmpty, heapifyUp, heapifyDown, swap, and compare. - Created unit tests for BinaryHeap class ensuring 100% coverage. - Tested all key operations: add, poll, peek, heapifyUp, heapifyDown, swap, and compare. - Included edge case tests for min-heap and max-heap scenarios. - Ensured compliance with type safety and PHP 8.0+ features. - Added comprehensive documentation and examples for BinaryHeap usage. This commit enhances the KaririCode Framework by providing a robust, type-safe, and efficient BinaryHeap data structure with extensive unit tests. --- .../Structural/BPlusTreeCollection.php | 59 ++++++++ .../Structural/BPlusTreeCollectionTest.php | 134 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/DataStructure/Structural/BPlusTreeCollection.php create mode 100644 tests/DataStructure/Structural/BPlusTreeCollectionTest.php diff --git a/src/DataStructure/Structural/BPlusTreeCollection.php b/src/DataStructure/Structural/BPlusTreeCollection.php new file mode 100644 index 0000000..af11b6b --- /dev/null +++ b/src/DataStructure/Structural/BPlusTreeCollection.php @@ -0,0 +1,59 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface BPlusTreeCollection extends Collection, Tree, Sortable +{ + /** + * Retrieves the order (maximum number of children) of the B+ Tree. + * + * @return int The order of the B+ Tree + */ + public function getOrder(): int; + + /** + * Performs a range search in the B+ Tree. + * + * @param mixed $start The start of the range (inclusive) + * @param mixed $end The end of the range (inclusive) + * + * @return array An array of values within the specified range + */ + public function rangeSearch(mixed $start, mixed $end): array; + + /** + * Retrieves the minimum value in the B+ Tree. + * + * @return mixed The minimum value + */ + public function getMinimum(): mixed; + + /** + * Retrieves the maximum value in the B+ Tree. + * + * @return mixed The maximum value + */ + public function getMaximum(): mixed; + + /** + * Balances the B+ Tree to maintain its properties. + */ + public function balance(): void; +} diff --git a/tests/DataStructure/Structural/BPlusTreeCollectionTest.php b/tests/DataStructure/Structural/BPlusTreeCollectionTest.php new file mode 100644 index 0000000..fbe0325 --- /dev/null +++ b/tests/DataStructure/Structural/BPlusTreeCollectionTest.php @@ -0,0 +1,134 @@ +createMock(BPlusTreeCollection::class); + $mock->expects($this->once()) + ->method('add') + ->with('element'); + + $mock->add('element'); + } + + public function testAddAll(): void + { + $collectionMock = $this->createMock(BPlusTreeCollection::class); + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->expects($this->once()) + ->method('addAll') + ->with($collectionMock); + + $mock->addAll($collectionMock); + } + + public function testRemove(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('remove') + ->with('element') + ->willReturn(true); + + $this->assertTrue($mock->remove('element')); + } + + public function testContains(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('contains') + ->with('element') + ->willReturn(true); + + $this->assertTrue($mock->contains('element')); + } + + public function testClear(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->expects($this->once()) + ->method('clear'); + + $mock->clear(); + } + + public function testSize(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('size') + ->willReturn(3); + + $this->assertSame(3, $mock->size()); + } + + public function testGetItems(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('getItems') + ->willReturn(['item1', 'item2']); + + $this->assertSame(['item1', 'item2'], $mock->getItems()); + } + + public function testGetOrder(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('getOrder') + ->willReturn(4); + + $this->assertSame(4, $mock->getOrder()); + } + + public function testRangeSearch(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('rangeSearch') + ->with(10, 20) + ->willReturn([10, 15, 20]); + + $this->assertSame([10, 15, 20], $mock->rangeSearch(10, 20)); + } + + public function testGetMinimum(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('getMinimum') + ->willReturn(1); + + $this->assertSame(1, $mock->getMinimum()); + } + + public function testGetMaximum(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->method('getMaximum') + ->willReturn(100); + + $this->assertSame(100, $mock->getMaximum()); + } + + public function testBalance(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->expects($this->once()) + ->method('balance'); + + $mock->balance(); + } + + public function testSort(): void + { + $mock = $this->createMock(BPlusTreeCollection::class); + $mock->expects($this->once()) + ->method('sort'); + + $mock->sort(); + } +} From aaeb8d971ee57b53afb50a66c32a60fe16a5bde4 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 2 Jul 2024 10:25:30 -0300 Subject: [PATCH 05/25] docs: Update README files in English and Portuguese - Enhanced the overview and key features sections for clarity and completeness. - Added detailed descriptions for all implemented data structures: - TreeSet - ArrayDeque - ArrayQueue - TreeMap - LinkedList - BinaryHeap - HashMap - Included complexity analysis and key methods for each data structure. - Provided usage examples for each data structure to demonstrate functionality. - Updated installation instructions and requirements. - Updated acknowledgments and roadmap sections. --- README.md | 254 +++++++++++++++++++++++++---------------------- README.pt-br.md | 256 ++++++++++++++++++++++++++---------------------- 2 files changed, 277 insertions(+), 233 deletions(-) diff --git a/README.md b/README.md index e82ee1e..187db81 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# KaririCode Contract +# KaririCode Framework: Contract Component [![en](https://img.shields.io/badge/lang-en-red.svg)](README.md) [![pt-br](https://img.shields.io/badge/lang-pt--br-green.svg)](README.pt-br.md) @@ -10,162 +10,184 @@ ## Overview -The `kariricode/contract` package provides a set of standardized interfaces for common data structures and patterns within the KaririCode Framework. This library ensures consistency and interoperability across various components of the KaririCode ecosystem, following PSR standards and utilizing modern PHP practices. +The Contract component is a fundamental part of the KaririCode Framework, providing a comprehensive set of interfaces that define contracts for various data structures and behaviors. These interfaces serve as the foundation for implementing robust, consistent, and interoperable data structure components within and beyond the KaririCode ecosystem. -## Features +## Key Features -- **🗂️ PSR Standards**: Adheres to PHP-FIG PSR standards for interoperability. -- **📚 Comprehensive Interfaces**: Includes interfaces for common data structures such as Collection, Heap, Map, Queue, Stack, and Tree. -- **🚀 Modern PHP**: Utilizes PHP 8.3 features to ensure type safety and modern coding practices. -- **🔍 High Quality**: Ensures code quality and security through rigorous testing and analysis tools. +- **Comprehensive Set of Interfaces**: Covers a wide range of data structures and behaviors. +- **Type Safety**: Leverages PHP 8.3+ features for better type checking and higher code reliability. +- **Flexibility**: Allows multiple implementations of the same interface, promoting code reuse and modularity. +- **Standardization**: Provides a consistent API across different implementations. -## Installation +## Available Interfaces and Their Applications -You can install the package via Composer: +### Structural Interfaces -```bash -composer require kariricode/contract -``` +#### Collection -## Usage +Defines the contract for a collection of elements. Ideal for implementing lists, sets, and other custom collections. -Implement the provided interfaces in your classes to ensure consistent and reliable functionality across different components of the KaririCode Framework. +**Suggested Applications:** -Example of implementing the `CollectionList` interface: +- Implementing a product catalog in an e-commerce site. +- Managing a task list in a productivity app. -```php -items[] = $item; - } - - public function remove(mixed $item): bool - { - $index = array_search($item, $this->items, true); - if ($index === false) { - return false; - } - unset($this->items[$index]); - return true; - } - - public function get(int $index): mixed - { - return $this->items[$index] ?? null; - } - - public function clear(): void - { - $this->items = []; - } - - public function getIterator(): \Traversable - { - return new \ArrayIterator($this->items); - } - - public function count(): int - { - return count($this->items); - } - - public function offsetExists(mixed $offset): bool - { - return isset($this->items[$offset]); - } - - public function offsetGet(mixed $offset): mixed - { - return $this->items[$offset] ?? null; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if ($offset === null) { - $this->items[] = $value; - } else { - $this->items[$offset] = $value; - } - } - - public function offsetUnset(mixed $offset): void - { - unset($this->items[$offset]); - } -} -``` +#### Set -## Development Environment +Defines the contract for set data structures, which do not allow duplicate elements. -### Docker +**Suggested Applications:** -To maintain consistency and ensure the environment's integrity, we provide a Docker setup: +- Maintaining a unique list of tags in a blog system. +- Implementing a spam filter based on IP addresses. -- **🐳 Docker Compose**: Used to manage multi-container Docker applications. -- **📦 Dockerfile**: Defines the Docker image for the PHP environment. +#### Queue -To start the environment: +Defines the contract for queue data structures, which follow the FIFO (First-In-First-Out) principle. -```bash -make up -``` +**Suggested Applications:** -### Makefile +- Order processing system in a restaurant. +- Task management in a print system. -We include a `Makefile` to streamline common development tasks: +#### Stack -- **Start services**: `make up` -- **Stop services**: `make down` -- **Run tests**: `make test` -- **Install dependencies**: `make composer-install` -- **Run code style checks**: `make cs-check` -- **Fix code style issues**: `make cs-fix` -- **Security checks**: `make security-check` +Defines the contract for stack data structures, which follow the LIFO (Last-In-First-Out) principle. -For a complete list of commands, run: +**Suggested Applications:** -```bash -make help -``` +- Implementing a browser history in a web browser. +- Managing function calls in a programming language interpreter. + +#### Tree + +Defines the contract for tree data structures. + +**Suggested Applications:** + +- Representing hierarchical structures such as product categories. +- Implementing a virtual file system. + +#### Heap + +Defines the contract for heap data structures. + +**Suggested Applications:** + +- Implementing a priority queue in a customer service system. +- Optimizing sorting and search algorithms. + +#### Deque + +Extends the Queue interface to define the contract for double-ended queue structures. + +**Suggested Applications:** + +- Implementing a circular buffer for stream processing. +- Developing a card game where cards can be added or removed from both ends. + +### Behavioral Interfaces + +#### Countable, Indexable, Modifiable, Searchable + +These interfaces define common behaviors that can be applied to various data structures. + +**Suggested Applications:** -## Testing +- Implementing custom collections with specific functionalities. +- Developing wrappers for existing data structures to add new features. -To run the tests, you can use the following command: +#### Sortable, Comparable + +Define contracts for objects that can be sorted and compared. + +**Suggested Applications:** + +- Implementing custom sorting algorithms. +- Developing ordered data structures, such as binary search trees. + +#### IterableCollection, Iterator + +Provide the ability to iterate over a collection. + +**Suggested Applications:** + +- Implementing custom collections that can be used in foreach loops. +- Developing specialized iterators to traverse complex data structures. + +### Specialized Interfaces + +#### BPlusTreeCollection + +Defines the contract for B+ tree data structures. + +**Suggested Applications:** + +- Implementing database indexes for fast queries. +- Optimizing file systems for quick access to large volumes of data. + +#### Serializable + +Defines the contract for serializing and deserializing data. + +**Suggested Applications:** + +- Implementing a cache system that can store complex objects. +- Developing a custom data persistence mechanism. + +## Installation + +### Requirements + +- PHP 8.3 or higher +- Composer + +### Via Composer ```bash -make test +composer require kariricode/contract ``` -## Contributing +## Usage -Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) for details on the process for submitting pull requests. +To use these interfaces in your project, simply implement them in your classes. For example: -## Support +```php +use KaririCode\Contract\DataStructure\Collection; -For any issues, please visit our [issue tracker](https://github.com/Kariri-PHP-Framework/kariri-contract/issues). +class MyCollection implements Collection +{ + // Implement the methods defined in the Collection interface +} +``` ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. -## About KaririCode +## Support and Community + +- **Documentation**: [https://kariricode.org](https://kariricode.org) +- **Issue Tracker**: [GitHub Issues](https://github.com/KaririCode-Framework/kariricode-contract/issues) +- **Community**: [KaririCode Club Community](https://kariricode.club) +- **Professional Support**: For enterprise-level support, contact us at support@kariricode.org -The KaririCode Framework is a modern, robust, and scalable PHP framework designed to streamline web development by providing a comprehensive set of tools and components. For more information, visit the [KaririCode website](https://kariricode.org/). +## Acknowledgments -Join the KaririCode Club for access to exclusive content, community support, and advanced tutorials on PHP and the KaririCode Framework. Learn more at [KaririCode Club](https://kariricode.org/club). +- The KaririCode Framework team and contributors. +- The PHP community for their continuous support and inspiration. --- +Built with ❤️ by the KaririCode team. Empowering developers to build more robust and flexible PHP applications. + Maintained by Walmir Silva - [walmir.silva@kariricode.org](mailto:walmir.silva@kariricode.org) diff --git a/README.pt-br.md b/README.pt-br.md index a519b12..a209334 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -1,4 +1,4 @@ -# KaririCode Contract +# KaririCode Framework: Contract Component [![en](https://img.shields.io/badge/lang-en-red.svg)](README.md) [![pt-br](https://img.shields.io/badge/lang-pt--br-green.svg)](README.pt-br.md) @@ -10,162 +10,184 @@ ## Visão Geral -O pacote `kariricode/contract` fornece um conjunto de interfaces padronizadas para estruturas de dados e padrões comuns dentro do KaririCode Framework. Esta biblioteca garante consistência e interoperabilidade entre vários componentes do ecossistema KaririCode, seguindo os padrões PSR e utilizando práticas modernas de PHP. +O componente Contract é uma parte fundamental do KaririCode Framework, fornecendo um conjunto abrangente de interfaces que definem os contratos para várias estruturas de dados e comportamentos. Essas interfaces servem como base para implementar componentes de estrutura de dados robustos, consistentes e interoperáveis dentro do ecossistema KaririCode e além. -## Funcionalidades +## Características Principais -- **🗂️ Padrões PSR**: Adere aos padrões PSR do PHP-FIG para interoperabilidade. -- **📚 Interfaces Abrangentes**: Inclui interfaces para estruturas de dados comuns, como Collection, Heap, Map, Queue, Stack e Tree. -- **🚀 PHP Moderno**: Utiliza recursos do PHP 8.3 para garantir segurança de tipos e práticas de codificação modernas. -- **🔍 Alta Qualidade**: Garante qualidade e segurança do código através de rigorosos testes e ferramentas de análise. +- **Conjunto Abrangente de Interfaces**: Cobre uma ampla gama de estruturas de dados e comportamentos. +- **Segurança de Tipos**: Aproveita os recursos do PHP 8.3+ para melhor verificação de tipos e maior confiabilidade do código. +- **Flexibilidade**: Permite múltiplas implementações da mesma interface, promovendo reutilização de código e modularidade. +- **Padronização**: Fornece uma API consistente em diferentes implementações. -## Instalação +## Interfaces Disponíveis e Suas Aplicações -Você pode instalar o pacote via Composer: +### Interfaces Estruturais -```bash -composer require kariricode/contract -``` +#### Collection -## Uso +Define o contrato para uma coleção de elementos. Ideal para implementar listas, conjuntos e outras coleções personalizadas. -Implemente as interfaces fornecidas em suas classes para garantir funcionalidade consistente e confiável entre diferentes componentes do KaririCode Framework. +**Aplicações Sugeridas:** -Exemplo de implementação da interface `CollectionList`: +- Implementação de um catálogo de produtos em um e-commerce. +- Gerenciamento de uma lista de tarefas em um aplicativo de produtividade. -```php -items[] = $item; - } - - public function remove(mixed $item): bool - { - $index = array_search($item, $this->items, true); - if ($index === false) { - return false; - } - unset($this->items[$index]); - return true; - } - - public function get(int $index): mixed - { - return $this->items[$index] ?? null; - } - - public function clear(): void - { - $this->items = []; - } - - public function getIterator(): \Traversable - { - return new \ArrayIterator($this->items); - } - - public function count(): int - { - return count($this->items); - } - - public function offsetExists(mixed $offset): bool - { - return isset($this->items[$offset]); - } - - public function offsetGet(mixed $offset): mixed - { - return $this->items[$offset] ?? null; - } - - public function offsetSet(mixed $offset, mixed $value): void - { - if ($offset === null) { - $this->items[] = $value; - } else { - $this->items[$offset] = $value; - } - } - - public function offsetUnset(mixed $offset): void - { - unset($this->items[$offset]); - } -} -``` +#### Set -## Ambiente de Desenvolvimento +Define o contrato para estruturas de dados de conjunto, que não permitem elementos duplicados. -### Docker +**Aplicações Sugeridas:** -Para manter a consistência e garantir a integridade do ambiente, fornecemos uma configuração Docker: +- Manutenção de uma lista única de tags em um sistema de blog. +- Implementação de um filtro de spam baseado em endereços IP. -- **🐳 Docker Compose**: Usado para gerenciar aplicações Docker de múltiplos contêineres. -- **📦 Dockerfile**: Define a imagem Docker para o ambiente PHP. +#### Queue -Para iniciar o ambiente: +Define o contrato para estruturas de dados de fila, que seguem o princípio FIFO (First-In-First-Out). -```bash -make up -``` +**Aplicações Sugeridas:** -### Makefile +- Sistema de processamento de pedidos em um restaurante. +- Gerenciamento de tarefas em um sistema de impressão. -Incluímos um `Makefile` para simplificar tarefas comuns de desenvolvimento: +#### Stack -- **Iniciar serviços**: `make up` -- **Parar serviços**: `make down` -- **Executar testes**: `make test` -- **Instalar dependências**: `make composer-install` -- **Verificar estilo de código**: `make cs-check` -- **Corrigir problemas de estilo de código**: `make cs-fix` -- **Verificações de segurança**: `make security-check` +Define o contrato para estruturas de dados de pilha, que seguem o princípio LIFO (Last-In-First-Out). -Para uma lista completa de comandos, execute: +**Aplicações Sugeridas:** -```bash -make help -``` +- Implementação de um histórico de navegação em um navegador web. +- Gerenciamento de chamadas de função em um interpretador de linguagem de programação. + +#### Tree + +Define o contrato para estruturas de dados em árvore. + +**Aplicações Sugeridas:** + +- Representação de estruturas hierárquicas, como categorias de produtos. +- Implementação de um sistema de arquivos virtual. + +#### Heap + +Define o contrato para estruturas de dados de heap. + +**Aplicações Sugeridas:** + +- Implementação de uma fila de prioridade em um sistema de atendimento ao cliente. +- Otimização de algoritmos de ordenação e busca. + +#### Deque + +Estende a interface Queue para definir o contrato para estruturas de fila de duas pontas. + +**Aplicações Sugeridas:** + +- Implementação de um buffer circular para processamento de streams de dados. +- Desenvolvimento de um jogo de cartas onde as cartas podem ser adicionadas ou removidas de ambas as extremidades. + +### Interfaces Comportamentais + +#### Countable, Indexable, Modifiable, Searchable + +Estas interfaces definem comportamentos comuns que podem ser aplicados a várias estruturas de dados. + +**Aplicações Sugeridas:** -## Testes +- Implementação de coleções personalizadas com funcionalidades específicas. +- Desenvolvimento de wrappers para estruturas de dados existentes para adicionar novas funcionalidades. -Para executar os testes, você pode usar o seguinte comando: +#### Sortable, Comparable + +Definem contratos para objetos que podem ser ordenados e comparados. + +**Aplicações Sugeridas:** + +- Implementação de algoritmos de ordenação personalizados. +- Desenvolvimento de estruturas de dados ordenadas, como árvores de busca binária. + +#### IterableCollection, Iterator + +Fornecem a capacidade de iterar sobre uma coleção. + +**Aplicações Sugeridas:** + +- Implementação de coleções personalizadas que podem ser usadas em loops foreach. +- Desenvolvimento de iteradores especializados para percorrer estruturas de dados complexas. + +### Interfaces Especializadas + +#### BPlusTreeCollection + +Define o contrato para estruturas de dados de árvore B+. + +**Aplicações Sugeridas:** + +- Implementação de índices de banco de dados para consultas rápidas. +- Otimização de sistemas de arquivos para acesso rápido a grandes volumes de dados. + +#### Serializable + +Define o contrato para serializar e desserializar dados. + +**Aplicações Sugeridas:** + +- Implementação de um sistema de cache que pode armazenar objetos complexos. +- Desenvolvimento de um mecanismo de persistência de dados personalizado. + +## Instalação + +### Requisitos + +- PHP 8.3 ou superior +- Composer + +### Via Composer ```bash -make test +composer require kariricode/contract ``` -## Contribuindo +## Uso -Contribuições são bem-vindas! Por favor, leia nossas [diretrizes de contribuição](CONTRIBUTING.md) para detalhes sobre o processo de envio de pull requests. +Para usar essas interfaces em seu projeto, simplesmente implemente-as em suas classes. Por exemplo: -## Suporte +```php +use KaririCode\Contract\DataStructure\Collection; -Para qualquer problema, por favor, visite nosso [rastreador de problemas](https://github.com/Kariri-PHP-Framework/kariri-contract/issues). +class MinhaColecao implements Collection +{ + // Implemente os métodos definidos na interface Collection +} +``` ## Licença -Este projeto é licenciado sob a licença MIT - veja o arquivo [LICENSE](LICENSE) para mais detalhes. +Este projeto está licenciado sob a Licença MIT - veja o arquivo [LICENSE](LICENSE) para detalhes. + +## Suporte e Comunidade -## Sobre o KaririCode +- **Documentação**: [https://kariricode.org](https://kariricode.org) +- **Rastreador de Problemas**: [GitHub Issues](https://github.com/KaririCode-Framework/kariricode-contract/issues) +- **Comunidade**: [Comunidade KaririCode Club](https://kariricode.club) +- **Suporte Profissional**: Para suporte de nível empresarial, entre em contato conosco em support@kariricode.org -O KaririCode Framework é um framework PHP moderno, robusto e escalável, projetado para simplificar o desenvolvimento web, fornecendo um conjunto abrangente de ferramentas e componentes. Para mais informações, visite o [site do KaririCode](https://kariricode.org/). +## Agradecimentos -Junte-se ao Clube KaririCode para ter acesso a conteúdos exclusivos, suporte da comunidade e tutoriais avançados sobre PHP e o KaririCode Framework. Saiba mais em [Clube KaririCode](https://kariricode.org/club). +- A equipe do KaririCode Framework e contribuidores. +- A comunidade PHP por seu contínuo apoio e inspiração. --- +Construído com ❤️ pela equipe KaririCode. Capacitando desenvolvedores a construir aplicações PHP mais robustas e flexíveis. + Mantido por Walmir Silva - [walmir.silva@kariricode.org](mailto:walmir.silva@kariricode.org) From b1d76627827275fd0c5b9a540b73fc58ff8cea61 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 2 Jul 2024 10:36:39 -0300 Subject: [PATCH 06/25] style: Normalize code formatting and style --- src/DataStructure/Structural/BPlusTreeCollection.php | 4 ++-- tests/DataStructure/Structural/BPlusTreeCollectionTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DataStructure/Structural/BPlusTreeCollection.php b/src/DataStructure/Structural/BPlusTreeCollection.php index af11b6b..1ff2706 100644 --- a/src/DataStructure/Structural/BPlusTreeCollection.php +++ b/src/DataStructure/Structural/BPlusTreeCollection.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace KaririCode\Contract\DataStructure; +namespace KaririCode\Contract\DataStructure\Structural; use KaririCode\Contract\DataStructure\Behavioral\Sortable; -use KaririCode\Contract\DataStructure\Structural\Collection; +use KaririCode\Contract\DataStructure\Tree; /** * Interface BPlusTreeCollection. diff --git a/tests/DataStructure/Structural/BPlusTreeCollectionTest.php b/tests/DataStructure/Structural/BPlusTreeCollectionTest.php index fbe0325..ea1ff36 100644 --- a/tests/DataStructure/Structural/BPlusTreeCollectionTest.php +++ b/tests/DataStructure/Structural/BPlusTreeCollectionTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace KaririCode\Tests\Contract\DataStructure; +namespace KaririCode\Tests\Contract\DataStructure\Structural; -use KaririCode\Contract\DataStructure\BPlusTreeCollection; +use KaririCode\Contract\DataStructure\Structural\BPlusTreeCollection; use PHPUnit\Framework\TestCase; final class BPlusTreeCollectionTest extends TestCase From ff2922fa0408c939c3238a4b2412728a4e7e567b Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 5 Jul 2024 10:58:14 -0300 Subject: [PATCH 07/25] feat: Create Container interface and add unit tests - Define the Container interface with methods: `set`, `get`, and `has`. - Implement unit tests for `set` method to ensure services are registered correctly. - Add unit tests for `get` method to verify correct retrieval of services by identifier. - Include unit tests for `has` method to check existence of services in the container. - Normalize the `@category` comments in the interface documentation for consistency. These changes establish a foundational contract for dependency injection within the KaririCode project and ensure robust and reliable functionality through comprehensive testing --- src/DataStructure/Behavioral/Comparable.php | 2 +- src/DataStructure/Behavioral/Countable.php | 2 +- src/DataStructure/Behavioral/Indexable.php | 2 +- .../Behavioral/IterableCollection.php | 2 +- src/DataStructure/Behavioral/Iterator.php | 2 +- src/DataStructure/Behavioral/Modifiable.php | 2 +- src/DataStructure/Behavioral/Searchable.php | 2 +- src/DataStructure/Behavioral/Sortable.php | 2 +- src/DataStructure/Deque.php | 2 +- src/DataStructure/Heap.php | 2 +- src/DataStructure/Map.php | 2 +- src/DataStructure/Queue.php | 2 +- src/DataStructure/Set.php | 2 +- src/DataStructure/Stack.php | 2 +- .../Structural/BPlusTreeCollection.php | 2 +- src/DataStructure/Structural/Collection.php | 2 +- src/DataStructure/Tree.php | 2 +- src/DependencyInjection/Container.php | 46 +++++++++++++++++++ tests/DependencyInjection/ContainerTest.php | 43 +++++++++++++++++ 19 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 src/DependencyInjection/Container.php create mode 100644 tests/DependencyInjection/ContainerTest.php diff --git a/src/DataStructure/Behavioral/Comparable.php b/src/DataStructure/Behavioral/Comparable.php index b20ff44..7e856ba 100644 --- a/src/DataStructure/Behavioral/Comparable.php +++ b/src/DataStructure/Behavioral/Comparable.php @@ -9,7 +9,7 @@ * * Defines the contract for objects that can be compared. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Countable.php b/src/DataStructure/Behavioral/Countable.php index 1f5c41d..84c7060 100644 --- a/src/DataStructure/Behavioral/Countable.php +++ b/src/DataStructure/Behavioral/Countable.php @@ -9,7 +9,7 @@ * * Defines the contract for counting elements. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Indexable.php b/src/DataStructure/Behavioral/Indexable.php index 73c7950..d09e7bd 100644 --- a/src/DataStructure/Behavioral/Indexable.php +++ b/src/DataStructure/Behavioral/Indexable.php @@ -9,7 +9,7 @@ * * Defines the contract for indexed access to elements. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/IterableCollection.php b/src/DataStructure/Behavioral/IterableCollection.php index a490e8f..841c980 100644 --- a/src/DataStructure/Behavioral/IterableCollection.php +++ b/src/DataStructure/Behavioral/IterableCollection.php @@ -9,7 +9,7 @@ * * Provides the ability to iterate over a collection. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Iterator.php b/src/DataStructure/Behavioral/Iterator.php index f74691c..3f6bd57 100644 --- a/src/DataStructure/Behavioral/Iterator.php +++ b/src/DataStructure/Behavioral/Iterator.php @@ -9,7 +9,7 @@ * * Defines the contract for iterating over a collection of elements. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Modifiable.php b/src/DataStructure/Behavioral/Modifiable.php index 94fd577..069265e 100644 --- a/src/DataStructure/Behavioral/Modifiable.php +++ b/src/DataStructure/Behavioral/Modifiable.php @@ -9,7 +9,7 @@ * * Defines the contract for modifying elements in a collection. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Searchable.php b/src/DataStructure/Behavioral/Searchable.php index 1e301d4..72c6f54 100644 --- a/src/DataStructure/Behavioral/Searchable.php +++ b/src/DataStructure/Behavioral/Searchable.php @@ -9,7 +9,7 @@ * * Defines the contract for searching elements in a collection. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Behavioral/Sortable.php b/src/DataStructure/Behavioral/Sortable.php index 70533f7..a3dae4d 100644 --- a/src/DataStructure/Behavioral/Sortable.php +++ b/src/DataStructure/Behavioral/Sortable.php @@ -11,7 +11,7 @@ * Classes implementing this interface should provide an implementation * for the sort method to allow sorting of their elements. * - * @category Interfaces + * @category DataStructure\Behavioral * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Deque.php b/src/DataStructure/Deque.php index cc767fd..9f40999 100644 --- a/src/DataStructure/Deque.php +++ b/src/DataStructure/Deque.php @@ -10,7 +10,7 @@ * Extends the Queue interface to define the contract for double-ended queue data structures, * which allow elements to be added and removed from both ends. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Heap.php b/src/DataStructure/Heap.php index 6464ccd..58f91d9 100644 --- a/src/DataStructure/Heap.php +++ b/src/DataStructure/Heap.php @@ -10,7 +10,7 @@ * Defines the contract for heap data structures. * A heap is a specialized tree-based data structure that satisfies the heap property. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Map.php b/src/DataStructure/Map.php index 2a203b5..a5d621f 100644 --- a/src/DataStructure/Map.php +++ b/src/DataStructure/Map.php @@ -12,7 +12,7 @@ * * Defines the contract for map data structures, which store key-value pairs. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Queue.php b/src/DataStructure/Queue.php index 47fd3d7..340bcad 100644 --- a/src/DataStructure/Queue.php +++ b/src/DataStructure/Queue.php @@ -11,7 +11,7 @@ * * Defines the contract for queue data structures, which follow the FIFO (First-In-First-Out) principle. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Set.php b/src/DataStructure/Set.php index ec9af06..dfaefda 100644 --- a/src/DataStructure/Set.php +++ b/src/DataStructure/Set.php @@ -12,7 +12,7 @@ * * Defines the contract for set data structures, which do not allow duplicate elements. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Stack.php b/src/DataStructure/Stack.php index 7292271..282d574 100644 --- a/src/DataStructure/Stack.php +++ b/src/DataStructure/Stack.php @@ -9,7 +9,7 @@ * * Defines the contract for stack data structures, which follow the LIFO (Last-In-First-Out) principle. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Structural/BPlusTreeCollection.php b/src/DataStructure/Structural/BPlusTreeCollection.php index 1ff2706..d3c1415 100644 --- a/src/DataStructure/Structural/BPlusTreeCollection.php +++ b/src/DataStructure/Structural/BPlusTreeCollection.php @@ -12,7 +12,7 @@ * * Defines the contract for B+ Tree data structures. * - * @category Interfaces + * @category DataStructure\Structural * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Structural/Collection.php b/src/DataStructure/Structural/Collection.php index 949a711..ff20d66 100644 --- a/src/DataStructure/Structural/Collection.php +++ b/src/DataStructure/Structural/Collection.php @@ -14,7 +14,7 @@ * * Defines the contract for a collection of elements. * - * @category Interfaces + * @category DataStructure\Structural * * @author Walmir Silva * @license MIT diff --git a/src/DataStructure/Tree.php b/src/DataStructure/Tree.php index 0460840..a9df7ec 100644 --- a/src/DataStructure/Tree.php +++ b/src/DataStructure/Tree.php @@ -12,7 +12,7 @@ * * Defines the contract for tree data structures. * - * @category Interfaces + * @category DataStructure * * @author Walmir Silva * @license MIT diff --git a/src/DependencyInjection/Container.php b/src/DependencyInjection/Container.php new file mode 100644 index 0000000..b520644 --- /dev/null +++ b/src/DependencyInjection/Container.php @@ -0,0 +1,46 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Container +{ + /** + * Registers a service with the container. + * + * @param string $id identifier of the service to register + * @param callable $service a callable that returns the service instance + */ + public function set(string $id, callable $service): void; + + /** + * Retrieves a service by its identifier. + * + * @param string $id identifier of the service to retrieve + * + * @return mixed the service instance + */ + public function get(string $id): mixed; + + /** + * Checks if the container can return a service for the given identifier. + * + * @param string $id identifier of the service to check + * + * @return bool true if the service is found, false otherwise + */ + public function has(string $id): bool; +} diff --git a/tests/DependencyInjection/ContainerTest.php b/tests/DependencyInjection/ContainerTest.php new file mode 100644 index 0000000..1b936e8 --- /dev/null +++ b/tests/DependencyInjection/ContainerTest.php @@ -0,0 +1,43 @@ +createMock(Container::class); + $mock->expects($this->once()) + ->method('set') + ->with($this->equalTo('service.id'), $this->isType('callable')); + + $mock->set('service.id', function () { + return new \stdClass(); + }); + } + + public function testGet(): void + { + $mock = $this->createMock(Container::class); + $mock->method('get') + ->with('service.id') + ->willReturn(new \stdClass()); + + $this->assertInstanceOf(\stdClass::class, $mock->get('service.id')); + } + + public function testHas(): void + { + $mock = $this->createMock(Container::class); + $mock->method('has') + ->with('service.id') + ->willReturn(true); + + $this->assertTrue($mock->has('service.id')); + } +} From 8316540f2f757446ff35dff85b0529a55c6ea46a Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 5 Jul 2024 16:40:32 -0300 Subject: [PATCH 08/25] feat: Add logging interfaces and corresponding tests - Created Configurable interface for managing configuration settings. - Created Loggable interface to define logging methods for various log levels. - Created ContextAware interface for managing context information in logs. - Created FormatterAware interface for handling log formatter settings. - Created HandlerAware interface for managing log handlers. - Created ProcessorAware interface for managing log processors. - Created LoggingManager interface that combines various logging functionalities. - Created LogFormatter interface for defining log formatters. - Created LogHandler interface for handling log records. - Created LogLevel interface for defining log levels. - Created LogProcessor interface for processing log records before handling. - Created LogRotator interface for managing log file rotation. - Added unit tests for each interface to ensure correct functionality: - ConfigurableTest: Tests for setConfig and getConfig methods. - LoggableTest: Tests for various logging level methods. - ContextAwareTest: Tests for withContext and getContext methods. - FormatterAwareTest: Tests for setFormatter and getFormatter methods. - HandlerAwareTest: Tests for addHandler, pushHandler, popHandler, and getHandlers methods. - ProcessorAwareTest: Tests for addProcessor and getProcessors methods. - LoggingManagerTest: Comprehensive tests for all LoggingManager methods. - LogFormatterTest: Test for the format method. - LogHandlerTest: Test for the handle method. - LogLevelTest: Test for the getLevel method. - LogProcessorTest: Test for the process method. - LogRotatorTest: Test for the rotate method. --- src/ImmutableValue.php | 22 ++ src/Logging/Behavioral/Configurable.php | 46 +++++ src/Logging/Behavioral/Loggable.php | 96 +++++++++ src/Logging/LogFormatter.php | 34 +++ src/Logging/LogHandler.php | 37 ++++ src/Logging/LogLevel.php | 28 +++ src/Logging/LogProcessor.php | 36 ++++ src/Logging/LogRotator.php | 32 +++ src/Logging/LoggingManager.php | 42 ++++ src/Logging/Structural/ContextAware.php | 37 ++++ src/Logging/Structural/FormatterAware.php | 46 +++++ src/Logging/Structural/HandlerAware.php | 57 +++++ src/Logging/Structural/ProcessorAware.php | 39 ++++ tests/Logging/Behavioral/ConfigurableTest.php | 37 ++++ tests/Logging/Behavioral/LoggableTest.php | 130 ++++++++++++ tests/Logging/LogFormatterTest.php | 26 +++ tests/Logging/LogHandlerTest.php | 24 +++ tests/Logging/LogLevelTest.php | 23 +++ tests/Logging/LogProcessorTest.php | 25 +++ tests/Logging/LogRotatorTest.php | 23 +++ tests/Logging/LoggingManagerTest.php | 194 ++++++++++++++++++ tests/Logging/Structural/ContextAwareTest.php | 36 ++++ .../Logging/Structural/FormatterAwareTest.php | 37 ++++ tests/Logging/Structural/HandlerAwareTest.php | 64 ++++++ .../Logging/Structural/ProcessorAwareTest.php | 37 ++++ 25 files changed, 1208 insertions(+) create mode 100644 src/ImmutableValue.php create mode 100644 src/Logging/Behavioral/Configurable.php create mode 100644 src/Logging/Behavioral/Loggable.php create mode 100644 src/Logging/LogFormatter.php create mode 100644 src/Logging/LogHandler.php create mode 100644 src/Logging/LogLevel.php create mode 100644 src/Logging/LogProcessor.php create mode 100644 src/Logging/LogRotator.php create mode 100644 src/Logging/LoggingManager.php create mode 100644 src/Logging/Structural/ContextAware.php create mode 100644 src/Logging/Structural/FormatterAware.php create mode 100644 src/Logging/Structural/HandlerAware.php create mode 100644 src/Logging/Structural/ProcessorAware.php create mode 100644 tests/Logging/Behavioral/ConfigurableTest.php create mode 100644 tests/Logging/Behavioral/LoggableTest.php create mode 100644 tests/Logging/LogFormatterTest.php create mode 100644 tests/Logging/LogHandlerTest.php create mode 100644 tests/Logging/LogLevelTest.php create mode 100644 tests/Logging/LogProcessorTest.php create mode 100644 tests/Logging/LogRotatorTest.php create mode 100644 tests/Logging/LoggingManagerTest.php create mode 100644 tests/Logging/Structural/ContextAwareTest.php create mode 100644 tests/Logging/Structural/FormatterAwareTest.php create mode 100644 tests/Logging/Structural/HandlerAwareTest.php create mode 100644 tests/Logging/Structural/ProcessorAwareTest.php diff --git a/src/ImmutableValue.php b/src/ImmutableValue.php new file mode 100644 index 0000000..8cf2edd --- /dev/null +++ b/src/ImmutableValue.php @@ -0,0 +1,22 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ImmutableValue +{ + // No methods needed; this interface serves as a marker. +} diff --git a/src/Logging/Behavioral/Configurable.php b/src/Logging/Behavioral/Configurable.php new file mode 100644 index 0000000..1c2874d --- /dev/null +++ b/src/Logging/Behavioral/Configurable.php @@ -0,0 +1,46 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Configurable +{ + /** + * Retrieves the current configuration. + * + * @return ImmutableValue the current configuration object + */ + public function getConfig(): ImmutableValue; + + /** + * Sets a new configuration. + * + * @param ImmutableValue $config the new configuration object + * + * @return Configurable the current instance for method chaining + */ + public function setConfig(ImmutableValue $config): Configurable; +} diff --git a/src/Logging/Behavioral/Loggable.php b/src/Logging/Behavioral/Loggable.php new file mode 100644 index 0000000..e8b3144 --- /dev/null +++ b/src/Logging/Behavioral/Loggable.php @@ -0,0 +1,96 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Loggable +{ + /** + * Logs with an arbitrary level. + * + * @param LogLevel $level the log level + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function log(LogLevel $level, string|\Stringable $message, array $context = []): void; + + /** + * Logs a debug message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function debug(string|\Stringable $message, array $context = []): void; + + /** + * Logs an info message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function info(string|\Stringable $message, array $context = []): void; + + /** + * Logs a notice message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function notice(string|\Stringable $message, array $context = []): void; + + /** + * Logs a warning message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function warning(string|\Stringable $message, array $context = []): void; + + /** + * Logs an error message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function error(string|\Stringable $message, array $context = []): void; + + /** + * Logs a critical message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function critical(string|\Stringable $message, array $context = []): void; + + /** + * Logs an alert message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function alert(string|\Stringable $message, array $context = []): void; + + /** + * Logs an emergency message. + * + * @param string|\Stringable $message the log message + * @param array $context additional context for the log message + */ + public function emergency(string|\Stringable $message, array $context = []): void; +} diff --git a/src/Logging/LogFormatter.php b/src/Logging/LogFormatter.php new file mode 100644 index 0000000..ad166f9 --- /dev/null +++ b/src/Logging/LogFormatter.php @@ -0,0 +1,34 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LogFormatter +{ + /** + * Formats a log record. + * + * This method is responsible for formatting the log record into a specific string format. + * + * @param ImmutableValue $record the log record to be formatted + * + * @return string the formatted log record as a string + */ + public function format(ImmutableValue $record): string; +} diff --git a/src/Logging/LogHandler.php b/src/Logging/LogHandler.php new file mode 100644 index 0000000..d0b831d --- /dev/null +++ b/src/Logging/LogHandler.php @@ -0,0 +1,37 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LogLevel +{ + /** + * Gets the log level as a string. + * + * @return string the log level + */ + public function getLevel(): string; +} diff --git a/src/Logging/LogProcessor.php b/src/Logging/LogProcessor.php new file mode 100644 index 0000000..cfcda5a --- /dev/null +++ b/src/Logging/LogProcessor.php @@ -0,0 +1,36 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LogProcessor +{ + /** + * Processes a log record. + * + * This method is responsible for processing the log record, performing tasks such as + * adding additional information, modifying existing information, or filtering out + * certain log records. + * + * @param array $record the log record to be processed, represented as an associative array + * + * @return array the processed log record + */ + public function process(array $record): array; +} diff --git a/src/Logging/LogRotator.php b/src/Logging/LogRotator.php new file mode 100644 index 0000000..2755134 --- /dev/null +++ b/src/Logging/LogRotator.php @@ -0,0 +1,32 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LogRotator +{ + /** + * Rotates a log file. + * + * This method is responsible for rotating the specified log file, such as renaming + * it and creating a new file for future log entries. + * + * @param string $filename the name of the log file to be rotated + */ + public function rotate(string $filename): void; +} diff --git a/src/Logging/LoggingManager.php b/src/Logging/LoggingManager.php new file mode 100644 index 0000000..5e1d2af --- /dev/null +++ b/src/Logging/LoggingManager.php @@ -0,0 +1,42 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LoggingManager extends + Loggable, + HandlerAware, + ProcessorAware, + FormatterAware, + ContextAware, + Configurable +{ + /** + * Gets the name of the logger. + * + * @return string the name of the logger + */ + public function getName(): string; +} diff --git a/src/Logging/Structural/ContextAware.php b/src/Logging/Structural/ContextAware.php new file mode 100644 index 0000000..aeee1c4 --- /dev/null +++ b/src/Logging/Structural/ContextAware.php @@ -0,0 +1,37 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ContextAware +{ + /** + * Sets the context for the current instance. + * + * @param array $context the context data to set + * + * @return self returns the current instance to allow method chaining + */ + public function withContext(array $context): self; + + /** + * Retrieves the current context. + * + * @return array the current context data + */ + public function getContext(): array; +} diff --git a/src/Logging/Structural/FormatterAware.php b/src/Logging/Structural/FormatterAware.php new file mode 100644 index 0000000..bbdbb10 --- /dev/null +++ b/src/Logging/Structural/FormatterAware.php @@ -0,0 +1,46 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface FormatterAware +{ + /** + * Sets the formatter for the current instance. + * + * @param ImmutableValue $formatter the formatter to set + * + * @return FormatterAware returns the current instance to allow method chaining + */ + public function setFormatter(ImmutableValue $formatter): FormatterAware; + + /** + * Retrieves the current formatter. + * + * @return ImmutableValue the current formatter + */ + public function getFormatter(): ImmutableValue; +} diff --git a/src/Logging/Structural/HandlerAware.php b/src/Logging/Structural/HandlerAware.php new file mode 100644 index 0000000..17fa76b --- /dev/null +++ b/src/Logging/Structural/HandlerAware.php @@ -0,0 +1,57 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface HandlerAware +{ + /** + * Adds a log handler to the logger. + * + * @param LogHandler $handler the log handler instance + * @param LogLevel|null $level the logging level for the handler (optional) + * + * @return self returns the instance for method chaining + */ + public function addHandler(LogHandler $handler, ?LogLevel $level = null): HandlerAware; + + /** + * Pushes a log handler onto the stack. + * + * @param LogHandler $handler the log handler instance + * + * @return self returns the instance for method chaining + */ + public function pushHandler(LogHandler $handler): HandlerAware; + + /** + * Pops a log handler from the stack. + * + * @return LogHandler|null the log handler instance or null if the stack is empty + */ + public function popHandler(): ?LogHandler; + + /** + * Retrieves all log handlers. + * + * @return LogHandler[] an array of log handler instances + */ + public function getHandlers(): array; +} diff --git a/src/Logging/Structural/ProcessorAware.php b/src/Logging/Structural/ProcessorAware.php new file mode 100644 index 0000000..1a64970 --- /dev/null +++ b/src/Logging/Structural/ProcessorAware.php @@ -0,0 +1,39 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessorAware +{ + /** + * Adds a log processor to the logger. + * + * @param LogProcessor $processor the log processor instance + * + * @return ProcessorAware returns the current instance to allow method chaining + */ + public function addProcessor(LogProcessor $processor): ProcessorAware; + + /** + * Retrieves all log processors. + * + * @return LogProcessor[] an array of log processor instances + */ + public function getProcessors(): array; +} diff --git a/tests/Logging/Behavioral/ConfigurableTest.php b/tests/Logging/Behavioral/ConfigurableTest.php new file mode 100644 index 0000000..214cde5 --- /dev/null +++ b/tests/Logging/Behavioral/ConfigurableTest.php @@ -0,0 +1,37 @@ +createMock(ImmutableValue::class); + $configurableMock = $this->createMock(Configurable::class); + + $configurableMock->expects($this->once()) + ->method('setConfig') + ->with($this->equalTo($configMock)) + ->willReturnSelf(); + + $this->assertSame($configurableMock, $configurableMock->setConfig($configMock)); + } + + public function testGetConfig(): void + { + $configMock = $this->createMock(ImmutableValue::class); + $configurableMock = $this->createMock(Configurable::class); + + $configurableMock->expects($this->once()) + ->method('getConfig') + ->willReturn($configMock); + + $this->assertSame($configMock, $configurableMock->getConfig()); + } +} diff --git a/tests/Logging/Behavioral/LoggableTest.php b/tests/Logging/Behavioral/LoggableTest.php new file mode 100644 index 0000000..797f922 --- /dev/null +++ b/tests/Logging/Behavioral/LoggableTest.php @@ -0,0 +1,130 @@ +createMock(LogLevel::class); + $message = 'Test message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('log') + ->with($this->equalTo($levelMock), $this->equalTo($message), $this->equalTo($context)); + + $loggableMock->log($levelMock, $message, $context); + } + + public function testDebug(): void + { + $message = 'Test debug message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('debug') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->debug($message, $context); + } + + public function testInfo(): void + { + $message = 'Test info message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('info') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->info($message, $context); + } + + public function testNotice(): void + { + $message = 'Test notice message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('notice') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->notice($message, $context); + } + + public function testWarning(): void + { + $message = 'Test warning message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('warning') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->warning($message, $context); + } + + public function testError(): void + { + $message = 'Test error message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('error') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->error($message, $context); + } + + public function testCritical(): void + { + $message = 'Test critical message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('critical') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->critical($message, $context); + } + + public function testAlert(): void + { + $message = 'Test alert message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('alert') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->alert($message, $context); + } + + public function testEmergency(): void + { + $message = 'Test emergency message'; + $context = ['key' => 'value']; + $loggableMock = $this->createMock(Loggable::class); + + $loggableMock->expects($this->once()) + ->method('emergency') + ->with($this->equalTo($message), $this->equalTo($context)); + + $loggableMock->emergency($message, $context); + } +} diff --git a/tests/Logging/LogFormatterTest.php b/tests/Logging/LogFormatterTest.php new file mode 100644 index 0000000..8c3d881 --- /dev/null +++ b/tests/Logging/LogFormatterTest.php @@ -0,0 +1,26 @@ +createMock(ImmutableValue::class); + $formatterMock = $this->createMock(LogFormatter::class); + $formattedRecord = 'Formatted log record'; + + $formatterMock->expects($this->once()) + ->method('format') + ->with($this->equalTo($recordMock)) + ->willReturn($formattedRecord); + + $this->assertSame($formattedRecord, $formatterMock->format($recordMock)); + } +} diff --git a/tests/Logging/LogHandlerTest.php b/tests/Logging/LogHandlerTest.php new file mode 100644 index 0000000..5abff5b --- /dev/null +++ b/tests/Logging/LogHandlerTest.php @@ -0,0 +1,24 @@ +createMock(ImmutableValue::class); + $logHandlerMock = $this->createMock(LogHandler::class); + + $logHandlerMock->expects($this->once()) + ->method('handle') + ->with($this->equalTo($recordMock)); + + $logHandlerMock->handle($recordMock); + } +} diff --git a/tests/Logging/LogLevelTest.php b/tests/Logging/LogLevelTest.php new file mode 100644 index 0000000..795618b --- /dev/null +++ b/tests/Logging/LogLevelTest.php @@ -0,0 +1,23 @@ +createMock(LogLevel::class); + + $logLevelMock->expects($this->once()) + ->method('getLevel') + ->willReturn($level); + + $this->assertSame($level, $logLevelMock->getLevel()); + } +} diff --git a/tests/Logging/LogProcessorTest.php b/tests/Logging/LogProcessorTest.php new file mode 100644 index 0000000..596bcb9 --- /dev/null +++ b/tests/Logging/LogProcessorTest.php @@ -0,0 +1,25 @@ + 'Test log message']; + $processedRecord = ['message' => 'Test log message', 'processed' => true]; + $logProcessorMock = $this->createMock(LogProcessor::class); + + $logProcessorMock->expects($this->once()) + ->method('process') + ->with($this->equalTo($record)) + ->willReturn($processedRecord); + + $this->assertSame($processedRecord, $logProcessorMock->process($record)); + } +} diff --git a/tests/Logging/LogRotatorTest.php b/tests/Logging/LogRotatorTest.php new file mode 100644 index 0000000..56637ad --- /dev/null +++ b/tests/Logging/LogRotatorTest.php @@ -0,0 +1,23 @@ +createMock(LogRotator::class); + + $rotatorMock->expects($this->once()) + ->method('rotate') + ->with($this->equalTo($filename)); + + $rotatorMock->rotate($filename); + } +} diff --git a/tests/Logging/LoggingManagerTest.php b/tests/Logging/LoggingManagerTest.php new file mode 100644 index 0000000..7353b57 --- /dev/null +++ b/tests/Logging/LoggingManagerTest.php @@ -0,0 +1,194 @@ +createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getName') + ->willReturn($name); + + $this->assertSame($name, $loggingManagerMock->getName()); + } + + public function testAddHandler(): void + { + $handlerMock = $this->createMock(LogHandler::class); + $levelMock = $this->createMock(LogLevel::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('addHandler') + ->with($this->equalTo($handlerMock), $this->equalTo($levelMock)) + ->willReturnSelf(); + + $this->assertSame($loggingManagerMock, $loggingManagerMock->addHandler($handlerMock, $levelMock)); + } + + public function testPushHandler(): void + { + $handlerMock = $this->createMock(LogHandler::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('pushHandler') + ->with($this->equalTo($handlerMock)) + ->willReturnSelf(); + + $this->assertSame($loggingManagerMock, $loggingManagerMock->pushHandler($handlerMock)); + } + + public function testPopHandler(): void + { + $handlerMock = $this->createMock(LogHandler::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('popHandler') + ->willReturn($handlerMock); + + $this->assertSame($handlerMock, $loggingManagerMock->popHandler()); + } + + public function testGetHandlers(): void + { + $handlers = [$this->createMock(LogHandler::class)]; + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getHandlers') + ->willReturn($handlers); + + $this->assertSame($handlers, $loggingManagerMock->getHandlers()); + } + + public function testAddProcessor(): void + { + $processorMock = $this->createMock(LogProcessor::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('addProcessor') + ->with($this->equalTo($processorMock)) + ->willReturnSelf(); + + $this->assertSame($loggingManagerMock, $loggingManagerMock->addProcessor($processorMock)); + } + + public function testGetProcessors(): void + { + $processors = [$this->createMock(LogProcessor::class)]; + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getProcessors') + ->willReturn($processors); + + $this->assertSame($processors, $loggingManagerMock->getProcessors()); + } + + public function testSetFormatter(): void + { + $formatterMock = new class() implements LogFormatter, ImmutableValue { + public function format(ImmutableValue $record): string + { + return 'formatted'; + } + }; + + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('setFormatter') + ->with($this->equalTo($formatterMock)) + ->willReturnSelf(); + + $this->assertSame( + $loggingManagerMock, + $loggingManagerMock->setFormatter($formatterMock) + ); + } + + public function testGetFormatter(): void + { + $formatterMock = new class() implements LogFormatter, ImmutableValue { + public function format(ImmutableValue $record): string + { + return 'formatted'; + } + }; + + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getFormatter') + ->willReturn($formatterMock); + + $this->assertSame($formatterMock, $loggingManagerMock->getFormatter()); + } + + public function testWithContext(): void + { + $context = ['key' => 'value']; + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('withContext') + ->with($this->equalTo($context)) + ->willReturnSelf(); + + $this->assertSame($loggingManagerMock, $loggingManagerMock->withContext($context)); + } + + public function testGetContext(): void + { + $context = ['key' => 'value']; + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getContext') + ->willReturn($context); + + $this->assertSame($context, $loggingManagerMock->getContext()); + } + + public function testSetConfig(): void + { + $configMock = $this->createMock(ImmutableValue::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('setConfig') + ->with($this->equalTo($configMock)) + ->willReturnSelf(); + + $this->assertSame($loggingManagerMock, $loggingManagerMock->setConfig($configMock)); + } + + public function testGetConfig(): void + { + $configMock = $this->createMock(ImmutableValue::class); + $loggingManagerMock = $this->createMock(LoggingManager::class); + + $loggingManagerMock->expects($this->once()) + ->method('getConfig') + ->willReturn($configMock); + + $this->assertSame($configMock, $loggingManagerMock->getConfig()); + } +} diff --git a/tests/Logging/Structural/ContextAwareTest.php b/tests/Logging/Structural/ContextAwareTest.php new file mode 100644 index 0000000..932344d --- /dev/null +++ b/tests/Logging/Structural/ContextAwareTest.php @@ -0,0 +1,36 @@ + 'value']; + $contextAwareMock = $this->createMock(ContextAware::class); + + $contextAwareMock->expects($this->once()) + ->method('withContext') + ->with($this->equalTo($context)) + ->willReturnSelf(); + + $this->assertSame($contextAwareMock, $contextAwareMock->withContext($context)); + } + + public function testGetContext(): void + { + $context = ['key' => 'value']; + $contextAwareMock = $this->createMock(ContextAware::class); + + $contextAwareMock->expects($this->once()) + ->method('getContext') + ->willReturn($context); + + $this->assertSame($context, $contextAwareMock->getContext()); + } +} diff --git a/tests/Logging/Structural/FormatterAwareTest.php b/tests/Logging/Structural/FormatterAwareTest.php new file mode 100644 index 0000000..dd89f95 --- /dev/null +++ b/tests/Logging/Structural/FormatterAwareTest.php @@ -0,0 +1,37 @@ +createMock(ImmutableValue::class); + $formatterAwareMock = $this->createMock(FormatterAware::class); + + $formatterAwareMock->expects($this->once()) + ->method('setFormatter') + ->with($this->equalTo($formatterMock)) + ->willReturnSelf(); + + $this->assertSame($formatterAwareMock, $formatterAwareMock->setFormatter($formatterMock)); + } + + public function testGetFormatter(): void + { + $formatterMock = $this->createMock(ImmutableValue::class); + $formatterAwareMock = $this->createMock(FormatterAware::class); + + $formatterAwareMock->expects($this->once()) + ->method('getFormatter') + ->willReturn($formatterMock); + + $this->assertSame($formatterMock, $formatterAwareMock->getFormatter()); + } +} diff --git a/tests/Logging/Structural/HandlerAwareTest.php b/tests/Logging/Structural/HandlerAwareTest.php new file mode 100644 index 0000000..21ce57f --- /dev/null +++ b/tests/Logging/Structural/HandlerAwareTest.php @@ -0,0 +1,64 @@ +createMock(LogHandler::class); + $levelMock = $this->createMock(LogLevel::class); + $handlerAwareMock = $this->createMock(HandlerAware::class); + + $handlerAwareMock->expects($this->once()) + ->method('addHandler') + ->with($this->equalTo($handlerMock), $this->equalTo($levelMock)) + ->willReturnSelf(); + + $this->assertSame($handlerAwareMock, $handlerAwareMock->addHandler($handlerMock, $levelMock)); + } + + public function testPushHandler(): void + { + $handlerMock = $this->createMock(LogHandler::class); + $handlerAwareMock = $this->createMock(HandlerAware::class); + + $handlerAwareMock->expects($this->once()) + ->method('pushHandler') + ->with($this->equalTo($handlerMock)) + ->willReturnSelf(); + + $this->assertSame($handlerAwareMock, $handlerAwareMock->pushHandler($handlerMock)); + } + + public function testPopHandler(): void + { + $handlerMock = $this->createMock(LogHandler::class); + $handlerAwareMock = $this->createMock(HandlerAware::class); + + $handlerAwareMock->expects($this->once()) + ->method('popHandler') + ->willReturn($handlerMock); + + $this->assertSame($handlerMock, $handlerAwareMock->popHandler()); + } + + public function testGetHandlers(): void + { + $handlers = [$this->createMock(LogHandler::class)]; + $handlerAwareMock = $this->createMock(HandlerAware::class); + + $handlerAwareMock->expects($this->once()) + ->method('getHandlers') + ->willReturn($handlers); + + $this->assertSame($handlers, $handlerAwareMock->getHandlers()); + } +} diff --git a/tests/Logging/Structural/ProcessorAwareTest.php b/tests/Logging/Structural/ProcessorAwareTest.php new file mode 100644 index 0000000..b9300df --- /dev/null +++ b/tests/Logging/Structural/ProcessorAwareTest.php @@ -0,0 +1,37 @@ +createMock(LogProcessor::class); + $processorAwareMock = $this->createMock(ProcessorAware::class); + + $processorAwareMock->expects($this->once()) + ->method('addProcessor') + ->with($this->equalTo($processorMock)) + ->willReturnSelf(); + + $this->assertSame($processorAwareMock, $processorAwareMock->addProcessor($processorMock)); + } + + public function testGetProcessors(): void + { + $processors = [$this->createMock(LogProcessor::class)]; + $processorAwareMock = $this->createMock(ProcessorAware::class); + + $processorAwareMock->expects($this->once()) + ->method('getProcessors') + ->willReturn($processors); + + $this->assertSame($processors, $processorAwareMock->getProcessors()); + } +} From fd0cb1cb799bf165dc2807ff76bddc43f16ce03f Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Wed, 10 Jul 2024 14:04:42 -0300 Subject: [PATCH 09/25] feat: Update logging interfaces Add tests for LoggerAware and LoggerConfigurable interfaces - Revised and enhanced logging interfaces for better consistency and flexibility. - Implemented new methods to support asynchronous logging. - Improved documentation of the interfaces to facilitate integration. - Added unit tests to ensure the robustness of the new implementations. - Added unit test for LoggerAware interface to verify setLogger method. - Added unit test for LoggerConfigurable interface to verify configure method. - Ensured proper mock setup and expectations in tests. --- .gitignore | 1 + src/Logging/Behavioral/LoggerConfigurable.php | 26 ++++++++++++ src/Logging/LogFormatter.php | 9 ++++ src/Logging/LogHandler.php | 5 +++ src/Logging/LogProcessor.php | 4 +- src/Logging/Logger.php | 21 ++++++++++ src/Logging/LoggerExtended.php | 42 +++++++++++++++++++ src/Logging/Structural/LoggerAware.php | 25 +++++++++++ .../Behavioral/LoggerConfigurableTest.php | 23 ++++++++++ tests/Logging/LogFormatterTest.php | 17 ++++++++ tests/Logging/LogProcessorTest.php | 5 ++- tests/Logging/LoggingManagerTest.php | 10 +++++ tests/Logging/Structural/LoggerAwareTest.php | 24 +++++++++++ 13 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 src/Logging/Behavioral/LoggerConfigurable.php create mode 100644 src/Logging/Logger.php create mode 100644 src/Logging/LoggerExtended.php create mode 100644 src/Logging/Structural/LoggerAware.php create mode 100644 tests/Logging/Behavioral/LoggerConfigurableTest.php create mode 100644 tests/Logging/Structural/LoggerAwareTest.php diff --git a/.gitignore b/.gitignore index 36acca2..2abd83c 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ temp/ tmp/ .vscode/launch.json .vscode/extensions.json +tests/lista_de_arquivos.php \ No newline at end of file diff --git a/src/Logging/Behavioral/LoggerConfigurable.php b/src/Logging/Behavioral/LoggerConfigurable.php new file mode 100644 index 0000000..31c9d16 --- /dev/null +++ b/src/Logging/Behavioral/LoggerConfigurable.php @@ -0,0 +1,26 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LoggerConfigurable +{ + /** + * Configures the logger. + */ + public function configure(array $config): void; +} diff --git a/src/Logging/LogFormatter.php b/src/Logging/LogFormatter.php index ad166f9..ef5962d 100644 --- a/src/Logging/LogFormatter.php +++ b/src/Logging/LogFormatter.php @@ -31,4 +31,13 @@ interface LogFormatter * @return string the formatted log record as a string */ public function format(ImmutableValue $record): string; + + /** + * Formats a set of log records. + * + * @param ImmutableValue[] $records + * + * @return string The formatted log records + */ + public function formatBatch(array $records): string; } diff --git a/src/Logging/LogHandler.php b/src/Logging/LogHandler.php index d0b831d..8b48a9c 100644 --- a/src/Logging/LogHandler.php +++ b/src/Logging/LogHandler.php @@ -34,4 +34,9 @@ interface LogHandler * @param array $record the log record to be processed, represented as an associative array */ public function handle(ImmutableValue $record): void; + + /** + * Checks whether the handler is handling the given log level. + */ + public function isHandling(ImmutableValue $record): bool; } diff --git a/src/Logging/LogProcessor.php b/src/Logging/LogProcessor.php index cfcda5a..c726c9b 100644 --- a/src/Logging/LogProcessor.php +++ b/src/Logging/LogProcessor.php @@ -4,6 +4,8 @@ namespace KaririCode\Contract\Logging; +use KaririCode\Contract\ImmutableValue; + /** * Interface LogProcessor. * @@ -32,5 +34,5 @@ interface LogProcessor * * @return array the processed log record */ - public function process(array $record): array; + public function process(ImmutableValue $record): ImmutableValue; } diff --git a/src/Logging/Logger.php b/src/Logging/Logger.php new file mode 100644 index 0000000..1eac483 --- /dev/null +++ b/src/Logging/Logger.php @@ -0,0 +1,21 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Logger extends Loggable +{ +} diff --git a/src/Logging/LoggerExtended.php b/src/Logging/LoggerExtended.php new file mode 100644 index 0000000..a266f37 --- /dev/null +++ b/src/Logging/LoggerExtended.php @@ -0,0 +1,42 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LoggerExtendedInterface extends Logger +{ + /** + * Adds a new handler to the logger. + */ + public function addHandler(HandlerAware $handler): self; + + /** + * Adds a new processor to the logger. + */ + public function addProcessor(ProcessorAware $processor): self; + + /** + * Sets a formatter for the logger. + */ + public function setFormatter(FormatterAware $formatter): self; + + /** + * Gets the name of the logger. + */ + public function getName(): string; +} diff --git a/src/Logging/Structural/LoggerAware.php b/src/Logging/Structural/LoggerAware.php new file mode 100644 index 0000000..82b6b13 --- /dev/null +++ b/src/Logging/Structural/LoggerAware.php @@ -0,0 +1,25 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface LoggerAware +{ + /** + * Sets a logger instance on the object. + */ + public function setLogger(Logger $logger): void; +} diff --git a/tests/Logging/Behavioral/LoggerConfigurableTest.php b/tests/Logging/Behavioral/LoggerConfigurableTest.php new file mode 100644 index 0000000..4322d39 --- /dev/null +++ b/tests/Logging/Behavioral/LoggerConfigurableTest.php @@ -0,0 +1,23 @@ + 'debug', 'format' => 'json']; + $loggerConfigurableMock = $this->createMock(LoggerConfigurable::class); + + $loggerConfigurableMock->expects($this->once()) + ->method('configure') + ->with($this->equalTo($config)); + + $loggerConfigurableMock->configure($config); + } +} diff --git a/tests/Logging/LogFormatterTest.php b/tests/Logging/LogFormatterTest.php index 8c3d881..e4e296c 100644 --- a/tests/Logging/LogFormatterTest.php +++ b/tests/Logging/LogFormatterTest.php @@ -23,4 +23,21 @@ public function testFormat(): void $this->assertSame($formattedRecord, $formatterMock->format($recordMock)); } + + public function testFormatBatch(): void + { + $recordMock1 = $this->createMock(ImmutableValue::class); + $recordMock2 = $this->createMock(ImmutableValue::class); + $records = [$recordMock1, $recordMock2]; + $formattedRecords = 'Formatted log records'; + + $formatterMock = $this->createMock(LogFormatter::class); + + $formatterMock->expects($this->once()) + ->method('formatBatch') + ->with($this->equalTo($records)) + ->willReturn($formattedRecords); + + $this->assertSame($formattedRecords, $formatterMock->formatBatch($records)); + } } diff --git a/tests/Logging/LogProcessorTest.php b/tests/Logging/LogProcessorTest.php index 596bcb9..daa6e31 100644 --- a/tests/Logging/LogProcessorTest.php +++ b/tests/Logging/LogProcessorTest.php @@ -4,6 +4,7 @@ namespace KaririCode\Contract\Tests\Logging; +use KaririCode\Contract\ImmutableValue; use KaririCode\Contract\Logging\LogProcessor; use PHPUnit\Framework\TestCase; @@ -11,8 +12,8 @@ final class LogProcessorTest extends TestCase { public function testProcess(): void { - $record = ['message' => 'Test log message']; - $processedRecord = ['message' => 'Test log message', 'processed' => true]; + $record = $this->createMock(ImmutableValue::class); + $processedRecord = $this->createMock(ImmutableValue::class); $logProcessorMock = $this->createMock(LogProcessor::class); $logProcessorMock->expects($this->once()) diff --git a/tests/Logging/LoggingManagerTest.php b/tests/Logging/LoggingManagerTest.php index 7353b57..5df0381 100644 --- a/tests/Logging/LoggingManagerTest.php +++ b/tests/Logging/LoggingManagerTest.php @@ -109,6 +109,11 @@ public function format(ImmutableValue $record): string { return 'formatted'; } + + public function formatBatch(array $records): string + { + return 'formatted batch'; + } }; $loggingManagerMock = $this->createMock(LoggingManager::class); @@ -131,6 +136,11 @@ public function format(ImmutableValue $record): string { return 'formatted'; } + + public function formatBatch(array $records): string + { + return 'formatted batch'; + } }; $loggingManagerMock = $this->createMock(LoggingManager::class); diff --git a/tests/Logging/Structural/LoggerAwareTest.php b/tests/Logging/Structural/LoggerAwareTest.php new file mode 100644 index 0000000..98c4e78 --- /dev/null +++ b/tests/Logging/Structural/LoggerAwareTest.php @@ -0,0 +1,24 @@ +createMock(Logger::class); + $loggerAwareMock = $this->createMock(LoggerAware::class); + + $loggerAwareMock->expects($this->once()) + ->method('setLogger') + ->with($this->equalTo($loggerMock)); + + $loggerAwareMock->setLogger($loggerMock); + } +} From 30dd4623cc3c01ce5855a80599d34853b2fca4fc Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Thu, 18 Jul 2024 10:44:47 -0300 Subject: [PATCH 10/25] feat(logging): improve log rotation and update log handler - Removed .phpcs-cache for cleaner repository - Updated src/Logging/LogHandler.php to enhance log handling capabilities - Modified src/Logging/LogLevel.php for better log level management - Enhanced src/Logging/LogRotator.php with improved file rotation logic - Updated src/Logging/Logger.php to integrate changes in log handling and rotation --- .phpcs-cache | 1 - src/Logging/LogHandler.php | 3 ++- src/Logging/LogLevel.php | 7 +++++++ src/Logging/LogRotator.php | 2 ++ src/Logging/Logger.php | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) delete mode 100644 .phpcs-cache diff --git a/.phpcs-cache b/.phpcs-cache deleted file mode 100644 index cc71453..0000000 --- a/.phpcs-cache +++ /dev/null @@ -1 +0,0 @@ -{"config":{"phpVersion":80308,"phpExtensions":"8fab9f49dd9f972e8c3521e490e96b80","tabWidth":4,"encoding":"utf-8","recordErrors":true,"annotations":true,"configData":{"installed_paths":"..\/..\/slevomat\/coding-standard"},"codeHash":"2262759546115f5ddab5ae60f21cd773","rulesetHash":"a1799b49768b6828a638979ad9e38f0a"},"\/app\/src\/DataStructure\/Tree.php":{"hash":"75dfe8b3d5b2cca6e3c29a9ce425073033188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":44}},"Line indent":{"values":{"spaces":28}},"PHP keyword case":{"values":{"lower":11}},"Multiple statements on same line":{"values":{"no":6}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":6}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":244},"\/app\/src\/DataStructure\/CollectionList.php":{"hash":"e8a434907640b1489c3f41535c4dadc233188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":42,"81-120":1}},"Line indent":{"values":{"spaces":26}},"PHP keyword case":{"values":{"lower":12}},"Multiple statements on same line":{"values":{"no":6}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":7}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":249},"\/app\/src\/DataStructure\/IterableCollection.php":{"hash":"07a17928757efe31293039b8b75e90f233188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":22}},"Line indent":{"values":{"spaces":6}},"PHP keyword case":{"values":{"lower":6}},"Multiple statements on same line":{"values":{"no":3}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":114},"\/app\/src\/DataStructure\/Queue.php":{"hash":"632541089da9ae51f2be435278ebc52233188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":40}},"Line indent":{"values":{"spaces":24}},"PHP keyword case":{"values":{"lower":12}},"Multiple statements on same line":{"values":{"no":6}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":5}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":221},"\/app\/src\/DataStructure\/Stack.php":{"hash":"f91712d0ed562b4d49da13ee607a537833188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":40}},"Line indent":{"values":{"spaces":24}},"PHP keyword case":{"values":{"lower":12}},"Multiple statements on same line":{"values":{"no":6}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":5}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":221},"\/app\/src\/DataStructure\/Map.php":{"hash":"6796eba673f24279a7d29287f04e123733188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":59}},"Line indent":{"values":{"spaces":43}},"PHP keyword case":{"values":{"lower":16}},"Multiple statements on same line":{"values":{"no":8}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":6}},"PHP type case":{"values":{"lower":11}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":346},"\/app\/src\/DataStructure\/Heap.php":{"hash":"50a1eb336d6ed6a9cf8873fc0288314333188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":40}},"Line indent":{"values":{"spaces":24}},"PHP keyword case":{"values":{"lower":12}},"Multiple statements on same line":{"values":{"no":6}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":5}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":221},"\/app\/tests\/DataStructure\/TreeTest.php":{"hash":"cad6ad886a919553d50313506f26920833188","errors":{"28":{"21":[{"message":"Expected 1 space after class keyword; 0 found","source":"PSR12.Classes.AnonClassDeclaration.SpaceAfterKeyword","listener":"PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\Classes\\AnonClassDeclarationSniff","severity":5,"fixable":true}]}},"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":58}},"Line indent":{"values":{"spaces":50}},"PHP keyword case":{"values":{"lower":24}},"Multiple statements on same line":{"values":{"no":26}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":5}},"PHP type case":{"values":{"lower":5}},"Function opening brace placement":{"values":{"new line":5}},"PHP constant case":{"values":{"lower":1}},"Spaces after control structure open parenthesis":{"values":[1]},"Spaces before control structure close parenthesis":{"values":[1]},"Blank lines at start of control structure":{"values":[1]},"Blank lines at end of control structure":{"values":[1]},"Control structure defined inline":{"values":{"no":1}}},"errorCount":1,"warningCount":0,"fixableCount":1,"numTokens":518},"\/app\/tests\/DataStructure\/HeapTest.php":{"hash":"05a750810e94204a98caa9a83250a10433188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":43}},"Line indent":{"values":{"spaces":35}},"PHP keyword case":{"values":{"lower":15}},"Multiple statements on same line":{"values":{"no":19}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":4}},"Function opening brace placement":{"values":{"new line":4}},"PHP constant case":{"values":{"lower":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":387},"\/app\/tests\/DataStructure\/CollectionListTest.php":{"hash":"7d3e48545ac6fb0f73dd05882f018e6133188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":45}},"Line indent":{"values":{"spaces":37}},"PHP keyword case":{"values":{"lower":15}},"Multiple statements on same line":{"values":{"no":20}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":4}},"Function opening brace placement":{"values":{"new line":4}},"PHP constant case":{"values":{"lower":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":396},"\/app\/tests\/DataStructure\/MapTest.php":{"hash":"0195c30d6c0184fb43ab17dbd20abe5833188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":67}},"Line indent":{"values":{"spaces":59}},"PHP keyword case":{"values":{"lower":19}},"Multiple statements on same line":{"values":{"no":30}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":6}},"PHP type case":{"values":{"lower":6}},"Function opening brace placement":{"values":{"new line":6}},"PHP constant case":{"values":{"lower":2}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":622},"\/app\/tests\/DataStructure\/StackTest.php":{"hash":"9eca664ad4ea1298d9e064993f51364933188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":43}},"Line indent":{"values":{"spaces":35}},"PHP keyword case":{"values":{"lower":15}},"Multiple statements on same line":{"values":{"no":19}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":4}},"Function opening brace placement":{"values":{"new line":4}},"PHP constant case":{"values":{"lower":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":387},"\/app\/tests\/DataStructure\/QueueTest.php":{"hash":"cac83d07be0dee6cc597f402f6e4e50c33188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":43}},"Line indent":{"values":{"spaces":35}},"PHP keyword case":{"values":{"lower":15}},"Multiple statements on same line":{"values":{"no":19}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":4}},"PHP type case":{"values":{"lower":4}},"Function opening brace placement":{"values":{"new line":4}},"PHP constant case":{"values":{"lower":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":387},"\/app\/tests\/DataStructure\/IterableCollectionTest.php":{"hash":"1d027ebf9aa76d8d98869fc1659ecea333188","errors":[],"warnings":[],"metrics":{"Declarations and side effects mixed":{"values":{"no":1}},"PHP short open tag used":{"values":{"no":1}},"EOL char":{"values":{"\\n":1}},"Number of newlines at EOF":{"values":{"1":1}},"PHP closing tag at end of PHP-only file":{"values":{"no":1}},"Line length":{"values":{"80 or less":17}},"Line indent":{"values":{"spaces":9}},"PHP keyword case":{"values":{"lower":9}},"Multiple statements on same line":{"values":{"no":8}},"One class per file":{"values":{"yes":1}},"Class defined in namespace":{"values":{"yes":1}},"PascalCase class name":{"values":{"yes":1}},"Class opening brace placement":{"values":{"new line":1}},"CamelCase method name":{"values":{"yes":1}},"PHP type case":{"values":{"lower":1}},"Function opening brace placement":{"values":{"new line":1}}},"errorCount":0,"warningCount":0,"fixableCount":0,"numTokens":152}} \ No newline at end of file diff --git a/src/Logging/LogHandler.php b/src/Logging/LogHandler.php index 8b48a9c..20797d0 100644 --- a/src/Logging/LogHandler.php +++ b/src/Logging/LogHandler.php @@ -31,12 +31,13 @@ interface LogHandler * This method is responsible for handling the log record, performing tasks such as * writing it to a file, sending it over the network, or any other logging behavior. * - * @param array $record the log record to be processed, represented as an associative array + * @param ImmutableValue $record the log record to be processed, represented as an associative array */ public function handle(ImmutableValue $record): void; /** * Checks whether the handler is handling the given log level. + * @param ImmutableValue $record the log record to be processed, represented as an associative array */ public function isHandling(ImmutableValue $record): bool; } diff --git a/src/Logging/LogLevel.php b/src/Logging/LogLevel.php index 613833a..ec7d050 100644 --- a/src/Logging/LogLevel.php +++ b/src/Logging/LogLevel.php @@ -25,4 +25,11 @@ interface LogLevel * @return string the log level */ public function getLevel(): string; + + /** + * Gets the log level as a int level + * + * @return int the log level + */ + public function getValue(): int; } diff --git a/src/Logging/LogRotator.php b/src/Logging/LogRotator.php index 2755134..16a0f8e 100644 --- a/src/Logging/LogRotator.php +++ b/src/Logging/LogRotator.php @@ -20,6 +20,7 @@ */ interface LogRotator { + public function shouldRotate(string $filePath): bool; /** * Rotates a log file. * @@ -29,4 +30,5 @@ interface LogRotator * @param string $filename the name of the log file to be rotated */ public function rotate(string $filename): void; + } diff --git a/src/Logging/Logger.php b/src/Logging/Logger.php index 1eac483..c1a11f9 100644 --- a/src/Logging/Logger.php +++ b/src/Logging/Logger.php @@ -18,4 +18,5 @@ */ interface Logger extends Loggable { + public function getName(): string; } From fc2bbe37e7232abde88a81c86e4f08f642da32ae Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Thu, 10 Oct 2024 18:01:04 -0300 Subject: [PATCH 11/25] Refactor:Indexable interface and LogLevel class - Modified the Indexable.php interface to enhance functionality. - Updated the LogLevel.php class to add new log levels. - Made lint adjustments in LogRotator class. --- src/DataStructure/Behavioral/Indexable.php | 6 +++--- src/Logging/LogHandler.php | 1 + src/Logging/LogLevel.php | 9 ++++++++- src/Logging/LogRotator.php | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/DataStructure/Behavioral/Indexable.php b/src/DataStructure/Behavioral/Indexable.php index d09e7bd..e291d02 100644 --- a/src/DataStructure/Behavioral/Indexable.php +++ b/src/DataStructure/Behavioral/Indexable.php @@ -21,11 +21,11 @@ interface Indexable /** * Retrieves an element at the specified index. * - * @param int $index The index of the element to retrieve + * @param mixed $index The index of the element to retrieve * * @return mixed The element at the specified index */ - public function get(int $index): mixed; + public function get(mixed $index): mixed; /** * Sets an element at the specified index. @@ -33,5 +33,5 @@ public function get(int $index): mixed; * @param int $index The index where the element should be set * @param mixed $element The element to set */ - public function set(int $index, mixed $element): void; + public function set(mixed $index, mixed $element): void; } diff --git a/src/Logging/LogHandler.php b/src/Logging/LogHandler.php index 20797d0..66dc6e8 100644 --- a/src/Logging/LogHandler.php +++ b/src/Logging/LogHandler.php @@ -37,6 +37,7 @@ public function handle(ImmutableValue $record): void; /** * Checks whether the handler is handling the given log level. + * * @param ImmutableValue $record the log record to be processed, represented as an associative array */ public function isHandling(ImmutableValue $record): bool; diff --git a/src/Logging/LogLevel.php b/src/Logging/LogLevel.php index ec7d050..dfff525 100644 --- a/src/Logging/LogLevel.php +++ b/src/Logging/LogLevel.php @@ -27,7 +27,14 @@ interface LogLevel public function getLevel(): string; /** - * Gets the log level as a int level + * Gets the color level as a string. + * + * @return string the color level + */ + public function getColor(): string; + + /** + * Gets the log level as a int level. * * @return int the log level */ diff --git a/src/Logging/LogRotator.php b/src/Logging/LogRotator.php index 16a0f8e..c128edd 100644 --- a/src/Logging/LogRotator.php +++ b/src/Logging/LogRotator.php @@ -21,6 +21,7 @@ interface LogRotator { public function shouldRotate(string $filePath): bool; + /** * Rotates a log file. * @@ -30,5 +31,4 @@ public function shouldRotate(string $filePath): bool; * @param string $filename the name of the log file to be rotated */ public function rotate(string $filename): void; - } From 788e7732b70aa081f0d1b093bdaa889cdc702964 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Sun, 13 Oct 2024 17:25:43 -0300 Subject: [PATCH 12/25] feat(contract): Add Processor interfaces and tests - Introduce new interfaces: Processor, ConfigurableProcessor, Pipeline - Add comprehensive PHPUnit tests for each interface - Enhance code documentation with detailed PHP DocBlocks - Ensure consistency with existing KaririCode coding standards --- src/Logging/LogHandler.php | 1 + src/Logging/LogRotator.php | 2 +- src/Processor/ConfigurableProcessor.php | 27 ++++++++++++++ src/Processor/Pipeline.php | 36 +++++++++++++++++++ src/Processor/Processor.php | 29 +++++++++++++++ tests/Processor/ConfigurableProcessorTest.php | 32 +++++++++++++++++ tests/Processor/PipelineTest.php | 36 +++++++++++++++++++ tests/Processor/ProcessorTest.php | 22 ++++++++++++ 8 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/Processor/ConfigurableProcessor.php create mode 100644 src/Processor/Pipeline.php create mode 100644 src/Processor/Processor.php create mode 100644 tests/Processor/ConfigurableProcessorTest.php create mode 100644 tests/Processor/PipelineTest.php create mode 100644 tests/Processor/ProcessorTest.php diff --git a/src/Logging/LogHandler.php b/src/Logging/LogHandler.php index 20797d0..66dc6e8 100644 --- a/src/Logging/LogHandler.php +++ b/src/Logging/LogHandler.php @@ -37,6 +37,7 @@ public function handle(ImmutableValue $record): void; /** * Checks whether the handler is handling the given log level. + * * @param ImmutableValue $record the log record to be processed, represented as an associative array */ public function isHandling(ImmutableValue $record): bool; diff --git a/src/Logging/LogRotator.php b/src/Logging/LogRotator.php index 16a0f8e..c128edd 100644 --- a/src/Logging/LogRotator.php +++ b/src/Logging/LogRotator.php @@ -21,6 +21,7 @@ interface LogRotator { public function shouldRotate(string $filePath): bool; + /** * Rotates a log file. * @@ -30,5 +31,4 @@ public function shouldRotate(string $filePath): bool; * @param string $filename the name of the log file to be rotated */ public function rotate(string $filename): void; - } diff --git a/src/Processor/ConfigurableProcessor.php b/src/Processor/ConfigurableProcessor.php new file mode 100644 index 0000000..84b3b37 --- /dev/null +++ b/src/Processor/ConfigurableProcessor.php @@ -0,0 +1,27 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ConfigurableProcessor extends Processor +{ + /** + * Configures the processor with the provided options. + * + * @param array $options The configuration options + */ + public function configure(array $options): void; +} diff --git a/src/Processor/Pipeline.php b/src/Processor/Pipeline.php new file mode 100644 index 0000000..57b6034 --- /dev/null +++ b/src/Processor/Pipeline.php @@ -0,0 +1,36 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Pipeline +{ + /** + * Adds a processor to the pipeline. + * + * @param Processor $processor The processor to be added + */ + public function addProcessor(Processor $processor): self; + + /** + * Executes the processing pipeline on the provided input. + * + * @param mixed $input The value to be processed by the pipeline + * + * @return mixed The final result after passing through all processors + */ + public function process(mixed $input): mixed; +} diff --git a/src/Processor/Processor.php b/src/Processor/Processor.php new file mode 100644 index 0000000..c1d865e --- /dev/null +++ b/src/Processor/Processor.php @@ -0,0 +1,29 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Processor +{ + /** + * Processes the provided input and returns the result. + * + * @param mixed $input The value to be processed + * + * @return mixed The result of the processing + */ + public function process(mixed $input): mixed; +} diff --git a/tests/Processor/ConfigurableProcessorTest.php b/tests/Processor/ConfigurableProcessorTest.php new file mode 100644 index 0000000..8c0b479 --- /dev/null +++ b/tests/Processor/ConfigurableProcessorTest.php @@ -0,0 +1,32 @@ +createMock(ConfigurableProcessor::class); + $mock->expects($this->once()) + ->method('configure') + ->with(['option' => 'value']); + + $mock->configure(['option' => 'value']); + } + + public function testProcess(): void + { + $mock = $this->createMock(ConfigurableProcessor::class); + $mock->expects($this->once()) + ->method('process') + ->with('input') + ->willReturn('output'); + + $this->assertSame('output', $mock->process('input')); + } +} diff --git a/tests/Processor/PipelineTest.php b/tests/Processor/PipelineTest.php new file mode 100644 index 0000000..0fa0e1c --- /dev/null +++ b/tests/Processor/PipelineTest.php @@ -0,0 +1,36 @@ +createMock(Pipeline::class); + $processor = $this->createMock(Processor::class); + + $mock->expects($this->once()) + ->method('addProcessor') + ->with($processor) + ->willReturnSelf(); + + $this->assertSame($mock, $mock->addProcessor($processor)); + } + + public function testProcess(): void + { + $mock = $this->createMock(Pipeline::class); + $mock->expects($this->once()) + ->method('process') + ->with('input') + ->willReturn('output'); + + $this->assertSame('output', $mock->process('input')); + } +} diff --git a/tests/Processor/ProcessorTest.php b/tests/Processor/ProcessorTest.php new file mode 100644 index 0000000..dcdb94a --- /dev/null +++ b/tests/Processor/ProcessorTest.php @@ -0,0 +1,22 @@ +createMock(Processor::class); + $mock->expects($this->once()) + ->method('process') + ->with('input') + ->willReturn('output'); + + $this->assertSame('output', $mock->process('input')); + } +} From b40023f5fe2f60c81caa713f3494ab9df503f28a Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Sun, 13 Oct 2024 19:16:48 -0300 Subject: [PATCH 13/25] feat: add ProcessorRegistry interface and unit tests - Introduced `ProcessorRegistry` interface to standardize processor registration and retrieval across contexts. - Added `ProcessorRegistryTest` class to ensure correctness of the new interface, covering scenarios like processor registration, retrieval, and error handling. --- composer.lock | 479 +++++++++++----------- src/Processor/ProcessorRegistry.php | 65 +++ tests/Logging/LoggingManagerTest.php | 4 +- tests/Processor/ProcessorRegistryTest.php | 81 ++++ tests/Processor/ProcessorTest.php | 1 + 5 files changed, 390 insertions(+), 240 deletions(-) create mode 100644 src/Processor/ProcessorRegistry.php create mode 100644 tests/Processor/ProcessorRegistryTest.php diff --git a/composer.lock b/composer.lock index 8268973..dba8718 100644 --- a/composer.lock +++ b/composer.lock @@ -138,30 +138,38 @@ }, { "name": "composer/pcre", - "version": "3.1.4", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "04229f163664973f68f38f6f73d917799168ef24" + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", - "reference": "04229f163664973f68f38f6f73d917799168ef24", + "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.x-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { @@ -189,7 +197,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.4" + "source": "https://github.com/composer/pcre/tree/3.3.1" }, "funding": [ { @@ -205,28 +213,28 @@ "type": "tidelift" } ], - "time": "2024-05-27T13:40:54+00:00" + "time": "2024-08-27T18:44:43+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -270,7 +278,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -286,7 +294,7 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/xdebug-handler", @@ -547,16 +555,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -596,7 +604,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -604,20 +612,20 @@ "type": "github" } ], - "time": "2024-02-07T09:43:46+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.59.3", + "version": "v3.64.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29" + "reference": "58dd9c931c785a79739310aef5178928305ffa67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/30ba9ecc2b0e5205e578fe29973c15653d9bfd29", - "reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/58dd9c931c785a79739310aef5178928305ffa67", + "reference": "58dd9c931c785a79739310aef5178928305ffa67", "shasum": "" }, "require": { @@ -699,7 +707,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.59.3" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.64.0" }, "funding": [ { @@ -707,26 +715,26 @@ "type": "github" } ], - "time": "2024-06-16T14:17:03+00:00" + "time": "2024-08-30T23:09:38+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.8.1", + "version": "7.9.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.1", - "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -737,9 +745,9 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -817,7 +825,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" }, "funding": [ { @@ -833,20 +841,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:35:24+00:00" + "time": "2024-07-24T11:22:20+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", "shasum": "" }, "require": { @@ -854,7 +862,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -900,7 +908,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.2" + "source": "https://github.com/guzzle/promises/tree/2.0.3" }, "funding": [ { @@ -916,20 +924,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:19:20+00:00" + "time": "2024-07-18T10:29:17+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", "shasum": "" }, "require": { @@ -944,8 +952,8 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1016,7 +1024,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.2" + "source": "https://github.com/guzzle/psr7/tree/2.7.0" }, "funding": [ { @@ -1032,7 +1040,7 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:05:35+00:00" + "time": "2024-07-18T11:15:46+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -1087,20 +1095,20 @@ }, { "name": "justinrainbow/json-schema", - "version": "v5.2.13", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", @@ -1111,11 +1119,6 @@ "bin/validate-json" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, "autoload": { "psr-4": { "JsonSchema\\": "src/JsonSchema/" @@ -1151,9 +1154,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/v5.2.13" + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" }, - "time": "2023-09-26T02:20:38+00:00" + "time": "2024-07-06T21:00:26+00:00" }, { "name": "league/container", @@ -1382,16 +1385,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.2", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -1402,7 +1405,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -1434,9 +1437,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-03-05T20:51:40+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "nunomaduro/phpinsights", @@ -1725,16 +1728,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.29.1", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", - "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", "shasum": "" }, "require": { @@ -1766,38 +1769,38 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" }, - "time": "2024-05-31T08:52:43+00:00" + "time": "2024-10-13T11:25:22+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.14", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { "phpunit/phpunit": "^10.1" @@ -1809,7 +1812,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -1838,7 +1841,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -1846,7 +1849,7 @@ "type": "github" } ], - "time": "2024-03-12T15:33:41+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2093,16 +2096,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.24", + "version": "10.5.36", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015" + "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f124e3e3e561006047b532fd0431bf5bb6b9015", - "reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", + "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", "shasum": "" }, "require": { @@ -2112,26 +2115,26 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.5", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-invoker": "^4.0", - "phpunit/php-text-template": "^3.0", - "phpunit/php-timer": "^6.0", - "sebastian/cli-parser": "^2.0", - "sebastian/code-unit": "^2.0", - "sebastian/comparator": "^5.0", - "sebastian/diff": "^5.0", - "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.1", - "sebastian/global-state": "^6.0.1", - "sebastian/object-enumerator": "^5.0", - "sebastian/recursion-context": "^5.0", - "sebastian/type": "^4.0", - "sebastian/version": "^4.0" + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.2", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -2174,7 +2177,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.24" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.36" }, "funding": [ { @@ -2190,7 +2193,7 @@ "type": "tidelift" } ], - "time": "2024-06-20T13:09:54+00:00" + "time": "2024-10-08T15:36:51+00:00" }, { "name": "psr/cache", @@ -2506,16 +2509,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -2550,9 +2553,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "psr/simple-cache", @@ -3023,31 +3026,31 @@ }, { "name": "react/socket", - "version": "v1.15.0", + "version": "v1.16.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038" + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038", - "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", - "react/dns": "^1.11", + "react/dns": "^1.13", "react/event-loop": "^1.2", - "react/promise": "^3 || ^2.6 || ^1.2.1", - "react/stream": "^1.2" + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" }, "require-dev": { "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", + "react/async": "^4.3 || ^3.3 || ^2", "react/promise-stream": "^1.4", - "react/promise-timer": "^1.10" + "react/promise-timer": "^1.11" }, "type": "library", "autoload": { @@ -3091,7 +3094,7 @@ ], "support": { "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.15.0" + "source": "https://github.com/reactphp/socket/tree/v1.16.0" }, "funding": [ { @@ -3099,7 +3102,7 @@ "type": "open_collective" } ], - "time": "2023-12-15T11:02:10+00:00" + "time": "2024-07-26T10:38:09+00:00" }, { "name": "react/stream", @@ -3349,16 +3352,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", + "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", "shasum": "" }, "require": { @@ -3369,7 +3372,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^10.4" }, "type": "library", "extra": { @@ -3414,7 +3417,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.2" }, "funding": [ { @@ -3422,7 +3425,7 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-08-12T06:03:08+00:00" }, { "name": "sebastian/complexity", @@ -4162,16 +4165,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.1", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877" + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/8f90f7a53ce271935282967f53d0894f8f1ff877", - "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c", + "reference": "62d32998e820bddc40f99f8251958aed187a5c9c", "shasum": "" }, "require": { @@ -4238,20 +4241,20 @@ "type": "open_collective" } ], - "time": "2024-05-22T21:24:41+00:00" + "time": "2024-09-18T10:38:58+00:00" }, { "name": "symfony/cache", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "e933e1d947ffb88efcdd34a2bd51561cab7deaae" + "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e933e1d947ffb88efcdd34a2bd51561cab7deaae", - "reference": "e933e1d947ffb88efcdd34a2bd51561cab7deaae", + "url": "https://api.github.com/repos/symfony/cache/zipball/86e5296b10e4dec8c8441056ca606aedb8a3be0a", + "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a", "shasum": "" }, "require": { @@ -4319,7 +4322,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.1.2" + "source": "https://github.com/symfony/cache/tree/v7.1.5" }, "funding": [ { @@ -4335,7 +4338,7 @@ "type": "tidelift" } ], - "time": "2024-06-11T13:32:38+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/cache-contracts", @@ -4415,16 +4418,16 @@ }, { "name": "symfony/console", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0aa29ca177f432ab68533432db0de059f39c92ae" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0aa29ca177f432ab68533432db0de059f39c92ae", - "reference": "0aa29ca177f432ab68533432db0de059f39c92ae", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { @@ -4488,7 +4491,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.2" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -4504,7 +4507,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4731,16 +4734,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", "shasum": "" }, "require": { @@ -4777,7 +4780,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + "source": "https://github.com/symfony/filesystem/tree/v7.1.5" }, "funding": [ { @@ -4793,20 +4796,20 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/finder", - "version": "v7.1.1", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6" + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/fbb0ba67688b780efbc886c1a0a0948dcf7205d6", - "reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6", + "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", "shasum": "" }, "require": { @@ -4841,7 +4844,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.1" + "source": "https://github.com/symfony/finder/tree/v7.1.4" }, "funding": [ { @@ -4857,20 +4860,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-08-13T14:28:19+00:00" }, { "name": "symfony/http-client", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "90ace27d17ccc9afc6f7ec0081e8529fb0e29425" + "reference": "abca35865118edf35a23f2f24978a1784c831cb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/90ace27d17ccc9afc6f7ec0081e8529fb0e29425", - "reference": "90ace27d17ccc9afc6f7ec0081e8529fb0e29425", + "url": "https://api.github.com/repos/symfony/http-client/zipball/abca35865118edf35a23f2f24978a1784c831cb4", + "reference": "abca35865118edf35a23f2f24978a1784c831cb4", "shasum": "" }, "require": { @@ -4935,7 +4938,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.1.2" + "source": "https://github.com/symfony/http-client/tree/v7.1.5" }, "funding": [ { @@ -4951,7 +4954,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T08:00:31+00:00" + "time": "2024-09-20T13:35:23+00:00" }, { "name": "symfony/http-client-contracts", @@ -5100,20 +5103,20 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -5159,7 +5162,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -5175,24 +5178,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -5237,7 +5240,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -5253,24 +5256,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -5318,7 +5321,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -5334,24 +5337,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -5398,7 +5401,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -5414,24 +5417,24 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5478,7 +5481,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -5494,24 +5497,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", - "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5554,7 +5557,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" }, "funding": [ { @@ -5570,20 +5573,20 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v7.1.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "febf90124323a093c7ee06fdb30e765ca3c20028" + "reference": "5c03ee6369281177f07f7c68252a280beccba847" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028", - "reference": "febf90124323a093c7ee06fdb30e765ca3c20028", + "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", + "reference": "5c03ee6369281177f07f7c68252a280beccba847", "shasum": "" }, "require": { @@ -5615,7 +5618,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.1" + "source": "https://github.com/symfony/process/tree/v7.1.5" }, "funding": [ { @@ -5631,7 +5634,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-19T21:48:23+00:00" }, { "name": "symfony/service-contracts", @@ -5780,16 +5783,16 @@ }, { "name": "symfony/string", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8", - "reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { @@ -5847,7 +5850,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.2" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -5863,7 +5866,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:27:18+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/var-exporter", @@ -5943,16 +5946,16 @@ }, { "name": "symfony/yaml", - "version": "v7.1.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2" + "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/fa34c77015aa6720469db7003567b9f772492bf2", - "reference": "fa34c77015aa6720469db7003567b9f772492bf2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4e561c316e135e053bd758bf3b3eb291d9919de4", + "reference": "4e561c316e135e053bd758bf3b3eb291d9919de4", "shasum": "" }, "require": { @@ -5994,7 +5997,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.1.1" + "source": "https://github.com/symfony/yaml/tree/v7.1.5" }, "funding": [ { @@ -6010,7 +6013,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:57:53+00:00" + "time": "2024-09-17T12:49:58+00:00" }, { "name": "theseer/tokenizer", diff --git a/src/Processor/ProcessorRegistry.php b/src/Processor/ProcessorRegistry.php new file mode 100644 index 0000000..44d3c2e --- /dev/null +++ b/src/Processor/ProcessorRegistry.php @@ -0,0 +1,65 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessorRegistry +{ + /** + * Registers a processor within a specific context. + * + * This method allows for the addition of a processor to the registry, + * associating it with a given context and name for later retrieval. + * + * @param string $context The context under which the processor is registered + * @param string $name The unique name of the processor within the context + * @param Processor $processor The processor instance to be registered + */ + public function register(string $context, string $name, Processor $processor): void; + + /** + * Retrieves a processor by its context and name. + * + * This method fetches a previously registered processor based on its + * associated context and name. + * + * @param string $context The context of the processor to retrieve + * @param string $name The name of the processor to retrieve + * + * @throws \RuntimeException If the processor is not found in the specified context + * + * @return Processor The requested processor instance + */ + public function get(string $context, string $name): Processor; + + /** + * Retrieves all processors registered under a specific context. + * + * This method returns a HashMap containing all processors associated + * with the given context. + * + * @param string $context The context for which to retrieve processors + * + * @throws \RuntimeException If the specified context is not found in the registry + * + * @return HashMap A HashMap containing all processors in the specified context + */ + public function getContextProcessors(string $context): Map; +} diff --git a/tests/Logging/LoggingManagerTest.php b/tests/Logging/LoggingManagerTest.php index 5df0381..21074a1 100644 --- a/tests/Logging/LoggingManagerTest.php +++ b/tests/Logging/LoggingManagerTest.php @@ -104,7 +104,7 @@ public function testGetProcessors(): void public function testSetFormatter(): void { - $formatterMock = new class() implements LogFormatter, ImmutableValue { + $formatterMock = new class implements LogFormatter, ImmutableValue { public function format(ImmutableValue $record): string { return 'formatted'; @@ -131,7 +131,7 @@ public function formatBatch(array $records): string public function testGetFormatter(): void { - $formatterMock = new class() implements LogFormatter, ImmutableValue { + $formatterMock = new class implements LogFormatter, ImmutableValue { public function format(ImmutableValue $record): string { return 'formatted'; diff --git a/tests/Processor/ProcessorRegistryTest.php b/tests/Processor/ProcessorRegistryTest.php new file mode 100644 index 0000000..c82dc7f --- /dev/null +++ b/tests/Processor/ProcessorRegistryTest.php @@ -0,0 +1,81 @@ +processorRegistryMock = $this->createMock(ProcessorRegistry::class); + $this->processorMock = $this->createMock(Processor::class); + } + + public function testRegister(): void + { + $this->processorRegistryMock->expects($this->once()) + ->method('register') + ->with('context', 'name', $this->processorMock); + + $this->processorRegistryMock->register('context', 'name', $this->processorMock); + } + + public function testGet(): void + { + $this->processorRegistryMock->expects($this->once()) + ->method('get') + ->with('context', 'name') + ->willReturn($this->processorMock); + + $this->assertSame($this->processorMock, $this->processorRegistryMock->get('context', 'name')); + } + + public function testGetContextProcessors(): void + { + $contextProcessorsMock = $this->createMock(Map::class); + + $this->processorRegistryMock->expects($this->once()) + ->method('getContextProcessors') + ->with('context') + ->willReturn($contextProcessorsMock); + + $this->assertSame($contextProcessorsMock, $this->processorRegistryMock->getContextProcessors('context')); + } + + public function testGetThrowsException(): void + { + $this->processorRegistryMock->expects($this->once()) + ->method('get') + ->with('nonexistent', 'name') + ->willThrowException(new \RuntimeException('Processor not found')); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Processor not found'); + + $this->processorRegistryMock->get('nonexistent', 'name'); + } + + public function testGetContextProcessorsThrowsException(): void + { + $this->processorRegistryMock->expects($this->once()) + ->method('getContextProcessors') + ->with('nonexistent') + ->willThrowException(new \RuntimeException('Context not found')); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Context not found'); + + $this->processorRegistryMock->getContextProcessors('nonexistent'); + } +} diff --git a/tests/Processor/ProcessorTest.php b/tests/Processor/ProcessorTest.php index dcdb94a..7965ba6 100644 --- a/tests/Processor/ProcessorTest.php +++ b/tests/Processor/ProcessorTest.php @@ -11,6 +11,7 @@ final class ProcessorTest extends TestCase { public function testProcess(): void { + /** @var Processor|MockObject */ $mock = $this->createMock(Processor::class); $mock->expects($this->once()) ->method('process') From 9e223a4f6c7f699fce67e5e1d72f056961fa3314 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Mon, 14 Oct 2024 17:32:03 -0300 Subject: [PATCH 14/25] feat(processor): add ProcessorBuilder interface and test suite - Add ProcessorBuilder interface in KaririCode\Contract\Processor namespace - Define build() method for constructing individual processors - Define buildPipeline() method for assembling processor pipelines - Create ProcessorBuilderTest class in KaririCode\Contract\Tests\Processor namespace - Implement tests for build() and buildPipeline() methods - Cover success scenarios and exception handling - Ensure proper interaction with ProcessorRegistry --- src/Processor/ProcessorBuilder.php | 53 ++++++++++++++ tests/Processor/ProcessorBuilderTest.php | 89 ++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 src/Processor/ProcessorBuilder.php create mode 100644 tests/Processor/ProcessorBuilderTest.php diff --git a/src/Processor/ProcessorBuilder.php b/src/Processor/ProcessorBuilder.php new file mode 100644 index 0000000..bc786f3 --- /dev/null +++ b/src/Processor/ProcessorBuilder.php @@ -0,0 +1,53 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessorBuilder +{ + /** + * Builds a single processor. + * + * This method constructs and configures a processor based on the provided + * context, name, and configuration options. + * + * @param string $context The context in which the processor is being built + * @param string $name The name of the processor to build + * @param array $processorConfig Configuration options for the processor + * + * @throws \RuntimeException If the processor cannot be built or configured + * + * @return Processor The constructed processor instance + */ + public function build(string $context, string $name, array $processorConfig = []): Processor; + + /** + * Builds a pipeline of processors. + * + * This method constructs a pipeline by building and assembling multiple + * processors based on the provided specifications and context. + * + * @param string $context The context in which the pipeline is being built + * @param array $processorSpecs An array of processor specifications + * + * @throws \RuntimeException If the pipeline cannot be built or if any processor fails to construct + * + * @return Pipeline The constructed pipeline instance containing the specified processors + */ + public function buildPipeline(string $context, array $processorSpecs): Pipeline; +} diff --git a/tests/Processor/ProcessorBuilderTest.php b/tests/Processor/ProcessorBuilderTest.php new file mode 100644 index 0000000..959bf89 --- /dev/null +++ b/tests/Processor/ProcessorBuilderTest.php @@ -0,0 +1,89 @@ +processorBuilderMock = $this->createMock(ProcessorBuilder::class); + $this->processorMock = $this->createMock(Processor::class); + $this->pipelineMock = $this->createMock(Pipeline::class); + $this->processorRegistryMock = $this->createMock(ProcessorRegistry::class); + } + + public function testBuild(): void + { + $this->processorBuilderMock->expects($this->once()) + ->method('build') + ->with('context', 'name', []) + ->willReturn($this->processorMock); + + $this->assertSame($this->processorMock, $this->processorBuilderMock->build('context', 'name')); + } + + public function testBuildWithConfig(): void + { + $config = ['option' => 'value']; + $this->processorBuilderMock->expects($this->once()) + ->method('build') + ->with('context', 'name', $config) + ->willReturn($this->processorMock); + + $this->assertSame($this->processorMock, $this->processorBuilderMock->build('context', 'name', $config)); + } + + public function testBuildPipeline(): void + { + $processorSpecs = [ + 'processor1' => [], + 'processor2' => ['option' => 'value'], + ]; + + $this->processorBuilderMock->expects($this->once()) + ->method('buildPipeline') + ->with('context', $processorSpecs) + ->willReturn($this->pipelineMock); + + $this->assertSame($this->pipelineMock, $this->processorBuilderMock->buildPipeline('context', $processorSpecs)); + } + + public function testBuildThrowsException(): void + { + $this->processorBuilderMock->expects($this->once()) + ->method('build') + ->with('nonexistent', 'name') + ->willThrowException(new \RuntimeException('Processor not found')); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Processor not found'); + $this->processorBuilderMock->build('nonexistent', 'name'); + } + + public function testBuildPipelineThrowsException(): void + { + $this->processorBuilderMock->expects($this->once()) + ->method('buildPipeline') + ->with('nonexistent', []) + ->willThrowException(new \RuntimeException('Failed to build pipeline')); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Failed to build pipeline'); + $this->processorBuilderMock->buildPipeline('nonexistent', []); + } +} From 611e84ffbbe22f4d6377887fcc2b1d18bd8321d2 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 15 Oct 2024 11:10:56 -0300 Subject: [PATCH 15/25] feat(contract): add PHPDoc for ProcessableAttribute interface and create unit tests - Add PHPDoc comments for ProcessableAttribute interface, including method descriptions and author/license information - Create unit tests for ProcessableAttribute interface, testing `getProcessors` and `getFallbackValue` methods --- src/Processor/ProcessableAttribute.php | 34 ++++++++++++++++++ tests/Processor/ProcessableAttributeTest.php | 38 ++++++++++++++++++++ tests/Processor/ProcessorTest.php | 7 ++-- 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/Processor/ProcessableAttribute.php create mode 100644 tests/Processor/ProcessableAttributeTest.php diff --git a/src/Processor/ProcessableAttribute.php b/src/Processor/ProcessableAttribute.php new file mode 100644 index 0000000..95d7b61 --- /dev/null +++ b/src/Processor/ProcessableAttribute.php @@ -0,0 +1,34 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessableAttribute +{ + /** + * Retrieves the processors associated with the attribute. + * + * @return array The list of processors + */ + public function getProcessors(): array; + + /** + * Provides a fallback value for the attribute if processing fails or is not available. + * + * @return mixed The fallback value + */ + public function getFallbackValue(): mixed; +} diff --git a/tests/Processor/ProcessableAttributeTest.php b/tests/Processor/ProcessableAttributeTest.php new file mode 100644 index 0000000..9551ae8 --- /dev/null +++ b/tests/Processor/ProcessableAttributeTest.php @@ -0,0 +1,38 @@ +createMock(ProcessableAttribute::class); + $processors = ['processor1', 'processor2']; + + $processableAttribute->expects($this->once()) + ->method('getProcessors') + ->willReturn($processors); + + $this->assertSame($processors, $processableAttribute->getProcessors()); + } + + public function testGetFallbackValue(): void + { + /** @var ProcessableAttribute|MockObject */ + $processableAttribute = $this->createMock(ProcessableAttribute::class); + $fallbackValue = 'default value'; + + $processableAttribute->expects($this->once()) + ->method('getFallbackValue') + ->willReturn($fallbackValue); + + $this->assertSame($fallbackValue, $processableAttribute->getFallbackValue()); + } +} diff --git a/tests/Processor/ProcessorTest.php b/tests/Processor/ProcessorTest.php index 7965ba6..e58928f 100644 --- a/tests/Processor/ProcessorTest.php +++ b/tests/Processor/ProcessorTest.php @@ -5,6 +5,7 @@ namespace KaririCode\Contract\Tests\Processor; use KaririCode\Contract\Processor\Processor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; final class ProcessorTest extends TestCase @@ -12,12 +13,12 @@ final class ProcessorTest extends TestCase public function testProcess(): void { /** @var Processor|MockObject */ - $mock = $this->createMock(Processor::class); - $mock->expects($this->once()) + $processor = $this->createMock(Processor::class); + $processor->expects($this->once()) ->method('process') ->with('input') ->willReturn('output'); - $this->assertSame('output', $mock->process('input')); + $this->assertSame('output', $processor->process('input')); } } From bf99f58e451435efe9d9a2a912d181191c97d66c Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 15 Oct 2024 13:31:32 -0300 Subject: [PATCH 16/25] feat(contract): add Sanitizer, Serializer, and Validator interfaces with unit tests - Add `Sanitizer` interface for sanitizing input data in `src/Sanitizer/` - Add `Validator` interface for validating input data in `src/Validator/` - Add `Serializer` interface for serializing and deserializing data in `src/Serializer/` - Create unit tests for each interface to ensure expected behavior --- src/Sanitizer/Sanitizer.php | 29 ++++++++++++++++++++++ src/Serializer/Serializer.php | 38 +++++++++++++++++++++++++++++ src/Validator/Validator.php | 29 ++++++++++++++++++++++ tests/Sanitizer/SanitizerTest.php | 24 ++++++++++++++++++ tests/Serializer/SerializerTest.php | 36 +++++++++++++++++++++++++++ tests/Validator/ValidatorTest.php | 24 ++++++++++++++++++ 6 files changed, 180 insertions(+) create mode 100644 src/Sanitizer/Sanitizer.php create mode 100644 src/Serializer/Serializer.php create mode 100644 src/Validator/Validator.php create mode 100644 tests/Sanitizer/SanitizerTest.php create mode 100644 tests/Serializer/SerializerTest.php create mode 100644 tests/Validator/ValidatorTest.php diff --git a/src/Sanitizer/Sanitizer.php b/src/Sanitizer/Sanitizer.php new file mode 100644 index 0000000..c452f43 --- /dev/null +++ b/src/Sanitizer/Sanitizer.php @@ -0,0 +1,29 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Sanitizer +{ + /** + * Sanitizes the provided input and returns the cleaned result. + * + * @param mixed $input The value to be sanitized + * + * @return mixed The sanitized result + */ + public function sanitize(mixed $input): mixed; +} diff --git a/src/Serializer/Serializer.php b/src/Serializer/Serializer.php new file mode 100644 index 0000000..43a7f1b --- /dev/null +++ b/src/Serializer/Serializer.php @@ -0,0 +1,38 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Serializer +{ + /** + * Serializes the provided input into a specific format. + * + * @param mixed $input The value to be serialized + * + * @return string The serialized data + */ + public function serialize(mixed $input): string; + + /** + * Deserializes the provided data from a specific format. + * + * @param string $data The serialized data + * + * @return mixed The deserialized value + */ + public function deserialize(string $data): mixed; +} diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php new file mode 100644 index 0000000..ff8e0f2 --- /dev/null +++ b/src/Validator/Validator.php @@ -0,0 +1,29 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface Validator +{ + /** + * Validates the provided input and returns a boolean indicating if the input is valid. + * + * @param mixed $input The value to be validated + * + * @return bool True if the input is valid, false otherwise + */ + public function validate(mixed $input): bool; +} diff --git a/tests/Sanitizer/SanitizerTest.php b/tests/Sanitizer/SanitizerTest.php new file mode 100644 index 0000000..02e4e64 --- /dev/null +++ b/tests/Sanitizer/SanitizerTest.php @@ -0,0 +1,24 @@ +createMock(Sanitizer::class); + $sanitizer->expects($this->once()) + ->method('sanitize') + ->with('dirtyInput') + ->willReturn('cleanInput'); + + $this->assertSame('cleanInput', $sanitizer->sanitize('dirtyInput')); + } +} diff --git a/tests/Serializer/SerializerTest.php b/tests/Serializer/SerializerTest.php new file mode 100644 index 0000000..493627a --- /dev/null +++ b/tests/Serializer/SerializerTest.php @@ -0,0 +1,36 @@ +createMock(Serializer::class); + $serializer->expects($this->once()) + ->method('serialize') + ->with('inputData') + ->willReturn('serializedData'); + + $this->assertSame('serializedData', $serializer->serialize('inputData')); + } + + public function testDeserialize(): void + { + /** @var Serializer|MockObject */ + $serializer = $this->createMock(Serializer::class); + $serializer->expects($this->once()) + ->method('deserialize') + ->with('serializedData') + ->willReturn('inputData'); + + $this->assertSame('inputData', $serializer->deserialize('serializedData')); + } +} diff --git a/tests/Validator/ValidatorTest.php b/tests/Validator/ValidatorTest.php new file mode 100644 index 0000000..bde2e3f --- /dev/null +++ b/tests/Validator/ValidatorTest.php @@ -0,0 +1,24 @@ +createMock(Validator::class); + $validator->expects($this->once()) + ->method('validate') + ->with('validInput') + ->willReturn(true); + + $this->assertTrue($validator->validate('validInput')); + } +} From b1a95215cbdcf41f938f7259412c45f93391d275 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Tue, 15 Oct 2024 19:31:10 -0300 Subject: [PATCH 17/25] fix(validator): correct return type of Validator interface --- src/Validator/Validator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index ff8e0f2..8d94c33 100644 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -19,11 +19,11 @@ interface Validator { /** - * Validates the provided input and returns a boolean indicating if the input is valid. + * Validates the provided input and returns the validated result. * * @param mixed $input The value to be validated * - * @return bool True if the input is valid, false otherwise + * @return mixed The validated result */ - public function validate(mixed $input): bool; + public function validate(mixed $input): mixed; } From 2fcec445bf5b5bfc56b2a385f48078e78ff79d95 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 18 Oct 2024 09:58:21 -0300 Subject: [PATCH 18/25] feat(contract): add CustomizableMessageAttribute interface - Introduce CustomizableMessageAttribute interface in KaririCode\Contract\Processor\Attribute namespace - Add method getMessage(string $validatorName): ?string to the interface - Create unit tests for CustomizableMessageAttribute in CustomizableMessageAttributeTest - Update existing ProcessableAttribute interface documentation for consistency --- .../CustomizableMessageAttribute.php | 29 +++++++++++++ .../{ => Attribute}/ProcessableAttribute.php | 9 +--- .../CustomizableMessageAttributeTest.php | 43 +++++++++++++++++++ .../ProcessableAttributeTest.php | 17 +------- 4 files changed, 75 insertions(+), 23 deletions(-) create mode 100644 src/Processor/Attribute/CustomizableMessageAttribute.php rename src/Processor/{ => Attribute}/ProcessableAttribute.php (69%) create mode 100644 tests/Processor/Attribute/CustomizableMessageAttributeTest.php rename tests/Processor/{ => Attribute}/ProcessableAttributeTest.php (52%) diff --git a/src/Processor/Attribute/CustomizableMessageAttribute.php b/src/Processor/Attribute/CustomizableMessageAttribute.php new file mode 100644 index 0000000..1e24c74 --- /dev/null +++ b/src/Processor/Attribute/CustomizableMessageAttribute.php @@ -0,0 +1,29 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface CustomizableMessageAttribute +{ + /** + * Retrieves a custom message for a specific validator. + * + * @param string $validatorName The name of the validator + * + * @return string|null The custom message if set, null otherwise + */ + public function getMessage(string $validatorName): ?string; +} diff --git a/src/Processor/ProcessableAttribute.php b/src/Processor/Attribute/ProcessableAttribute.php similarity index 69% rename from src/Processor/ProcessableAttribute.php rename to src/Processor/Attribute/ProcessableAttribute.php index 95d7b61..b0c8a51 100644 --- a/src/Processor/ProcessableAttribute.php +++ b/src/Processor/Attribute/ProcessableAttribute.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace KaririCode\Contract\Processor; +namespace KaririCode\Contract\Processor\Attribute; /** * Interface ProcessableAttribute. @@ -24,11 +24,4 @@ interface ProcessableAttribute * @return array The list of processors */ public function getProcessors(): array; - - /** - * Provides a fallback value for the attribute if processing fails or is not available. - * - * @return mixed The fallback value - */ - public function getFallbackValue(): mixed; } diff --git a/tests/Processor/Attribute/CustomizableMessageAttributeTest.php b/tests/Processor/Attribute/CustomizableMessageAttributeTest.php new file mode 100644 index 0000000..69acad3 --- /dev/null +++ b/tests/Processor/Attribute/CustomizableMessageAttributeTest.php @@ -0,0 +1,43 @@ +createMock(CustomizableMessageAttribute::class); + + $validatorName = 'requiredValidator'; + $expectedMessage = 'This field is required.'; + + $customizableMessageAttribute->expects($this->once()) + ->method('getMessage') + ->with($validatorName) + ->willReturn($expectedMessage); + + $this->assertSame($expectedMessage, $customizableMessageAttribute->getMessage($validatorName)); + } + + public function testGetMessageReturnsNull(): void + { + /** @var CustomizableMessageAttribute|MockObject */ + $customizableMessageAttribute = $this->createMock(CustomizableMessageAttribute::class); + + $validatorName = 'nonExistentValidator'; + + $customizableMessageAttribute->expects($this->once()) + ->method('getMessage') + ->with($validatorName) + ->willReturn(null); + + $this->assertNull($customizableMessageAttribute->getMessage($validatorName)); + } +} diff --git a/tests/Processor/ProcessableAttributeTest.php b/tests/Processor/Attribute/ProcessableAttributeTest.php similarity index 52% rename from tests/Processor/ProcessableAttributeTest.php rename to tests/Processor/Attribute/ProcessableAttributeTest.php index 9551ae8..a919dda 100644 --- a/tests/Processor/ProcessableAttributeTest.php +++ b/tests/Processor/Attribute/ProcessableAttributeTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace KaririCode\Contract\Tests\Processor; +namespace KaririCode\Contract\Tests\Processor\Attribute; -use KaririCode\Contract\Processor\ProcessableAttribute; +use KaririCode\Contract\Processor\Attribute\ProcessableAttribute; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -22,17 +22,4 @@ public function testGetProcessors(): void $this->assertSame($processors, $processableAttribute->getProcessors()); } - - public function testGetFallbackValue(): void - { - /** @var ProcessableAttribute|MockObject */ - $processableAttribute = $this->createMock(ProcessableAttribute::class); - $fallbackValue = 'default value'; - - $processableAttribute->expects($this->once()) - ->method('getFallbackValue') - ->willReturn($fallbackValue); - - $this->assertSame($fallbackValue, $processableAttribute->getFallbackValue()); - } } From 1cbe3ca9553e46a5bc87d11ab60e6f06d0bb4582 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 18 Oct 2024 13:59:09 -0300 Subject: [PATCH 19/25] feat: add BaseProcessorAttribute abstract class --- .../Attribute/BaseProcessorAttribute.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/Processor/Attribute/BaseProcessorAttribute.php diff --git a/src/Processor/Attribute/BaseProcessorAttribute.php b/src/Processor/Attribute/BaseProcessorAttribute.php new file mode 100644 index 0000000..d98e682 --- /dev/null +++ b/src/Processor/Attribute/BaseProcessorAttribute.php @@ -0,0 +1,43 @@ +processors = $this->normalizeProcessors($processors); + $this->messages = $messages ?? []; + } + + public function getProcessors(): array + { + return $this->processors; + } + + public function getMessage(string $processorName): ?string + { + return $this->messages[$processorName] ?? null; + } + + protected function normalizeProcessors(array $processors): array + { + $normalized = []; + foreach ($processors as $key => $value) { + if (is_int($key)) { + $normalized[$value] = []; + } elseif (is_string($value)) { + $normalized[$key] = []; + } else { + $normalized[$key] = $value; + } + } + + return $normalized; + } +} From 756ea9f5b240f085dc5b7aac81f6408d92a37c13 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 18 Oct 2024 18:07:48 -0300 Subject: [PATCH 20/25] refactor: adjusty filterValidProcessors in BaseProcessorAttribute --- composer.lock | 26 +++++++++---------- .../Attribute/BaseProcessorAttribute.php | 21 ++++----------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/composer.lock b/composer.lock index dba8718..37f757f 100644 --- a/composer.lock +++ b/composer.lock @@ -845,16 +845,16 @@ }, { "name": "guzzlehttp/promises", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8" + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", - "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", "shasum": "" }, "require": { @@ -908,7 +908,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.3" + "source": "https://github.com/guzzle/promises/tree/2.0.4" }, "funding": [ { @@ -924,7 +924,7 @@ "type": "tidelift" } ], - "time": "2024-07-18T10:29:17+00:00" + "time": "2024-10-17T10:06:22+00:00" }, { "name": "guzzlehttp/psr7", @@ -3352,16 +3352,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", - "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { @@ -3372,7 +3372,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.4" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -3417,7 +3417,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -3425,7 +3425,7 @@ "type": "github" } ], - "time": "2024-08-12T06:03:08+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", diff --git a/src/Processor/Attribute/BaseProcessorAttribute.php b/src/Processor/Attribute/BaseProcessorAttribute.php index d98e682..542b8b3 100644 --- a/src/Processor/Attribute/BaseProcessorAttribute.php +++ b/src/Processor/Attribute/BaseProcessorAttribute.php @@ -6,12 +6,12 @@ abstract class BaseProcessorAttribute implements ProcessableAttribute, CustomizableMessageAttribute { - protected array $processors; - protected array $messages; + private readonly array $processors; + private readonly array $messages; public function __construct(array $processors, ?array $messages = null) { - $this->processors = $this->normalizeProcessors($processors); + $this->processors = self::filterValidProcessors($processors); $this->messages = $messages ?? []; } @@ -25,19 +25,8 @@ public function getMessage(string $processorName): ?string return $this->messages[$processorName] ?? null; } - protected function normalizeProcessors(array $processors): array + private static function filterValidProcessors(array $processors): array { - $normalized = []; - foreach ($processors as $key => $value) { - if (is_int($key)) { - $normalized[$value] = []; - } elseif (is_string($value)) { - $normalized[$key] = []; - } else { - $normalized[$key] = $value; - } - } - - return $normalized; + return array_filter($processors, static fn ($v) => null !== $v && false !== $v); } } From 9de21b2697c882828376514c70c583c7a0e62abf Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Mon, 21 Oct 2024 15:31:19 -0300 Subject: [PATCH 21/25] feat(processor): add ProcessorValidator and ValidatableProcessor interfaces with unit tests - Added ProcessorValidator interface to define contract for validating processors in a pipeline. - Added ValidatableProcessor interface to define contract for processors with validation capabilities. - Created unit tests for ProcessorValidator and ValidatableProcessor to ensure proper validation behavior. --- docker-compose.yml | 2 - src/Processor/ProcessorValidator.php | 41 +++++++++++++ src/Processor/ValidatableProcessor.php | 48 +++++++++++++++ tests/Processor/ProcessorValidatorTest.php | 45 ++++++++++++++ tests/Processor/ValidatableProcessorTest.php | 62 ++++++++++++++++++++ 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/Processor/ProcessorValidator.php create mode 100644 src/Processor/ValidatableProcessor.php create mode 100644 tests/Processor/ProcessorValidatorTest.php create mode 100644 tests/Processor/ValidatableProcessorTest.php diff --git a/docker-compose.yml b/docker-compose.yml index 0c1b8de..e27bea1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: php: container_name: kariricode-contract diff --git a/src/Processor/ProcessorValidator.php b/src/Processor/ProcessorValidator.php new file mode 100644 index 0000000..77e8ff2 --- /dev/null +++ b/src/Processor/ProcessorValidator.php @@ -0,0 +1,41 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessorValidator +{ + /** + * Validates a processor and returns any validation errors. + * + * This method checks whether the given processor meets the required validation + * criteria. If the processor is invalid, it returns an array containing the error + * details, including a custom error message if provided. Otherwise, it returns null. + * + * @param Processor $processor the processor to be validated + * @param string $processorName the unique name of the processor, used to identify it in the context of validation + * @param array $messages an array of custom messages for validation errors, keyed by processor name + * + * @return array|null the validation error details, or null if validation passes + */ + public function validate(Processor $processor, string $processorName, array $messages): ?array; +} diff --git a/src/Processor/ValidatableProcessor.php b/src/Processor/ValidatableProcessor.php new file mode 100644 index 0000000..5375041 --- /dev/null +++ b/src/Processor/ValidatableProcessor.php @@ -0,0 +1,48 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ValidatableProcessor extends Processor +{ + /** + * Checks if the processor is in a valid state. + * + * This method determines whether the processor has met all required + * conditions and can continue processing. A processor that fails validation + * may halt the processing pipeline or trigger corrective actions. + * + * @return bool true if the processor is valid, false otherwise + */ + public function isValid(): bool; + + /** + * Retrieves the error key if the processor fails validation. + * + * When a processor is deemed invalid by the isValid method, this method + * returns a key that uniquely identifies the validation error. This key + * can be used for logging, error messages, or further handling within the + * processing pipeline. + * + * @return string|null the error key, or null if no validation error occurred + */ + public function getErrorKey(): ?string; +} diff --git a/tests/Processor/ProcessorValidatorTest.php b/tests/Processor/ProcessorValidatorTest.php new file mode 100644 index 0000000..22b8f87 --- /dev/null +++ b/tests/Processor/ProcessorValidatorTest.php @@ -0,0 +1,45 @@ +createMock(Processor::class); + /** @var ProcessorValidator|MockObject */ + $validator = $this->createMock(ProcessorValidator::class); + + $validator->expects($this->once()) + ->method('validate') + ->with($processor, 'testProcessor', []) + ->willReturn(null); + + $this->assertNull($validator->validate($processor, 'testProcessor', [])); + } + + public function testValidateReturnsErrorDetailsOnInvalidProcessor(): void + { + /** @var Processor|MockObject */ + $processor = $this->createMock(Processor::class); + /** @var ProcessorValidator|MockObject */ + $validator = $this->createMock(ProcessorValidator::class); + + $errorDetails = ['error' => 'Invalid processor']; + + $validator->expects($this->once()) + ->method('validate') + ->with($processor, 'testProcessor', []) + ->willReturn($errorDetails); + + $this->assertSame($errorDetails, $validator->validate($processor, 'testProcessor', [])); + } +} diff --git a/tests/Processor/ValidatableProcessorTest.php b/tests/Processor/ValidatableProcessorTest.php new file mode 100644 index 0000000..ee02a7c --- /dev/null +++ b/tests/Processor/ValidatableProcessorTest.php @@ -0,0 +1,62 @@ +createMock(ValidatableProcessor::class); + + $processor->expects($this->once()) + ->method('isValid') + ->willReturn(true); + + $this->assertTrue($processor->isValid()); + } + + public function testIsValidReturnsFalseForInvalidProcessor(): void + { + /** @var ValidatableProcessor|MockObject */ + $processor = $this->createMock(ValidatableProcessor::class); + + $processor->expects($this->once()) + ->method('isValid') + ->willReturn(false); + + $this->assertFalse($processor->isValid()); + } + + public function testGetErrorKeyReturnsNullForValidProcessor(): void + { + /** @var ValidatableProcessor|MockObject */ + $processor = $this->createMock(ValidatableProcessor::class); + + $processor->expects($this->once()) + ->method('getErrorKey') + ->willReturn(null); + + $this->assertNull($processor->getErrorKey()); + } + + public function testGetErrorKeyReturnsErrorKeyForInvalidProcessor(): void + { + /** @var ValidatableProcessor|MockObject */ + $processor = $this->createMock(ValidatableProcessor::class); + + $errorKey = 'error_key_123'; + + $processor->expects($this->once()) + ->method('getErrorKey') + ->willReturn($errorKey); + + $this->assertSame($errorKey, $processor->getErrorKey()); + } +} From 8b7d45b4ac819d24c7d2702c1f3a74a63fab197c Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Thu, 24 Oct 2024 15:47:08 -0300 Subject: [PATCH 22/25] feat(validator): Add reset method to ValidatableProcessor interface The reset method is added to ensure proper state reset between validations. This change helps prevent state leakage between multiple validation cycles by allowing processors to clear their validation state before reuse. - Add reset() method with proper PHPDoc - Maintain consistent documentation style - Keep backward compatibility with existing implementations --- src/Processor/ValidatableProcessor.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Processor/ValidatableProcessor.php b/src/Processor/ValidatableProcessor.php index 5375041..538c6a0 100644 --- a/src/Processor/ValidatableProcessor.php +++ b/src/Processor/ValidatableProcessor.php @@ -23,6 +23,16 @@ */ interface ValidatableProcessor extends Processor { + /** + * Resets the processor's state to its initial values. + * + * This method should be called before reusing the processor instance to ensure + * that any previous validation state is cleared and the processor is ready for + * new validation. This is particularly important when processors are reused + * across multiple validation cycles. + */ + public function reset(): void; + /** * Checks if the processor is in a valid state. * From 50f6c513b92ed5102bbe570912911259ec0cb285 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Thu, 24 Oct 2024 15:47:08 -0300 Subject: [PATCH 23/25] feat(validator): Add reset method to ValidatableProcessor interface The reset method is added to ensure proper state reset between validations. This change helps prevent state leakage between multiple validation cycles by allowing processors to clear their validation state before reuse. - Add reset() method with proper PHPDoc - Maintain consistent documentation style - Keep backward compatibility with existing implementations --- composer.lock | 26 +++++++++++++------------- src/Processor/ValidatableProcessor.php | 10 ++++++++++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 37f757f..2a2bb53 100644 --- a/composer.lock +++ b/composer.lock @@ -1160,16 +1160,16 @@ }, { "name": "league/container", - "version": "4.2.2", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/thephpleague/container.git", - "reference": "ff346319ca1ff0e78277dc2311a42107cc1aab88" + "reference": "72f9bebe7bd623007782a40f5ec305661ab706d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/ff346319ca1ff0e78277dc2311a42107cc1aab88", - "reference": "ff346319ca1ff0e78277dc2311a42107cc1aab88", + "url": "https://api.github.com/repos/thephpleague/container/zipball/72f9bebe7bd623007782a40f5ec305661ab706d8", + "reference": "72f9bebe7bd623007782a40f5ec305661ab706d8", "shasum": "" }, "require": { @@ -1230,7 +1230,7 @@ ], "support": { "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/4.2.2" + "source": "https://github.com/thephpleague/container/tree/4.2.3" }, "funding": [ { @@ -1238,7 +1238,7 @@ "type": "github" } ], - "time": "2024-03-13T13:12:53+00:00" + "time": "2024-10-23T12:06:58+00:00" }, { "name": "mockery/mockery", @@ -2096,16 +2096,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.36", + "version": "10.5.37", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870" + "reference": "c7cffa0efa2b70c22366523e6d804c9419eb2400" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", - "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c7cffa0efa2b70c22366523e6d804c9419eb2400", + "reference": "c7cffa0efa2b70c22366523e6d804c9419eb2400", "shasum": "" }, "require": { @@ -2126,7 +2126,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.2", + "sebastian/comparator": "^5.0.3", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", @@ -2177,7 +2177,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.36" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.37" }, "funding": [ { @@ -2193,7 +2193,7 @@ "type": "tidelift" } ], - "time": "2024-10-08T15:36:51+00:00" + "time": "2024-10-19T13:03:41+00:00" }, { "name": "psr/cache", diff --git a/src/Processor/ValidatableProcessor.php b/src/Processor/ValidatableProcessor.php index 5375041..538c6a0 100644 --- a/src/Processor/ValidatableProcessor.php +++ b/src/Processor/ValidatableProcessor.php @@ -23,6 +23,16 @@ */ interface ValidatableProcessor extends Processor { + /** + * Resets the processor's state to its initial values. + * + * This method should be called before reusing the processor instance to ensure + * that any previous validation state is cleared and the processor is ready for + * new validation. This is particularly important when processors are reused + * across multiple validation cycles. + */ + public function reset(): void; + /** * Checks if the processor is in a valid state. * From 260fd8326d921e275f0d8797d79cb3cf1376d00f Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 25 Oct 2024 14:43:56 -0300 Subject: [PATCH 24/25] test(processor): add unit tests for ProcessingResult interface - Add test cases for all ProcessingResult interface methods - Include setUp with mock creation - Validate error handling and data processing - Ensure proper type declarations --- src/Processor/ProcessingResult.php | 75 ++++++++++++++++ tests/Processor/ProcessingResultTest.php | 110 +++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 src/Processor/ProcessingResult.php create mode 100644 tests/Processor/ProcessingResultTest.php diff --git a/src/Processor/ProcessingResult.php b/src/Processor/ProcessingResult.php new file mode 100644 index 0000000..8e0feaf --- /dev/null +++ b/src/Processor/ProcessingResult.php @@ -0,0 +1,75 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +interface ProcessingResult +{ + /** + * Adds an error associated with a specific property. + * + * @param string $property The property where the error occurred + * @param string $errorKey A unique identifier for the type of error + * @param string $message A human-readable error message + */ + public function addError(string $property, string $errorKey, string $message): void; + + /** + * Stores processed data for a specific property. + * + * @param string $property The property associated with the processed data + * @param mixed $value The processed value to be stored + */ + public function setProcessedData(string $property, mixed $value): void; + + /** + * Checks if there are any errors in the processing result. + * + * @return bool True if there are errors, false otherwise + */ + public function hasErrors(): bool; + + /** + * Retrieves all errors that occurred during processing. + * + * @return array> + * A map of property names to their associated errors + */ + public function getErrors(): array; + + /** + * Retrieves all processed data. + * + * @return array A map of property names to their processed values + */ + public function getProcessedData(): array; + + /** + * Converts the processing result into an array representation. + * + * @return array{ + * isValid: bool, + * errors: array>, + * processedData: array + * } + */ + public function toArray(): array; + + /** + * Clears all stored errors and processed data. + */ + public function clear(): void; +} diff --git a/tests/Processor/ProcessingResultTest.php b/tests/Processor/ProcessingResultTest.php new file mode 100644 index 0000000..b3fda46 --- /dev/null +++ b/tests/Processor/ProcessingResultTest.php @@ -0,0 +1,110 @@ +processingResultMock = $this->createMock(ProcessingResult::class); + } + + public function testAddError(): void + { + $this->processingResultMock->expects($this->once()) + ->method('addError') + ->with('property', 'error_key', 'error message'); + + $this->processingResultMock->addError('property', 'error_key', 'error message'); + } + + public function testSetProcessedData(): void + { + $this->processingResultMock->expects($this->once()) + ->method('setProcessedData') + ->with('property', 'value'); + + $this->processingResultMock->setProcessedData('property', 'value'); + } + + public function testHasErrors(): void + { + $this->processingResultMock->expects($this->once()) + ->method('hasErrors') + ->willReturn(true); + + $this->assertTrue($this->processingResultMock->hasErrors()); + } + + public function testGetErrors(): void + { + $expectedErrors = [ + 'property' => [ + [ + 'errorKey' => 'error_key', + 'message' => 'error message', + ], + ], + ]; + + $this->processingResultMock->expects($this->once()) + ->method('getErrors') + ->willReturn($expectedErrors); + + $this->assertSame($expectedErrors, $this->processingResultMock->getErrors()); + } + + public function testGetProcessedData(): void + { + $expectedData = [ + 'property' => 'processed value', + ]; + + $this->processingResultMock->expects($this->once()) + ->method('getProcessedData') + ->willReturn($expectedData); + + $this->assertSame($expectedData, $this->processingResultMock->getProcessedData()); + } + + public function testToArray(): void + { + $expectedArray = [ + 'isValid' => false, + 'errors' => [ + 'property' => [ + [ + 'errorKey' => 'error_key', + 'message' => 'error message', + ], + ], + ], + 'processedData' => [ + 'property' => 'processed value', + ], + ]; + + $this->processingResultMock->expects($this->once()) + ->method('toArray') + ->willReturn($expectedArray); + + $this->assertSame($expectedArray, $this->processingResultMock->toArray()); + } + + public function testClear(): void + { + $this->processingResultMock->expects($this->once()) + ->method('clear'); + + $this->processingResultMock->clear(); + } +} From 9034f37645afc4151a6d2b453447d815b1462855 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Sat, 26 Oct 2024 16:14:38 -0300 Subject: [PATCH 25/25] refactor: add professional comments to BaseProcessorAttribute and update register return in ProcessorRegistry - Change `register` method in `ProcessorRegistry` interface to return `self` instead of `void` for fluent interface support - Add professional comments to `BaseProcessorAttribute` abstract class, clarifying property roles and method responsibilities - Document `filterValidProcessors` and other methods for clearer functionality understanding --- .gitignore | 3 +- .../Attribute/BaseProcessorAttribute.php | 52 +++++++++++++++++++ src/Processor/ProcessorRegistry.php | 6 ++- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2abd83c..3c57061 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,5 @@ temp/ tmp/ .vscode/launch.json .vscode/extensions.json -tests/lista_de_arquivos.php \ No newline at end of file +tests/lista_de_arquivos.php +/composer.lock \ No newline at end of file diff --git a/src/Processor/Attribute/BaseProcessorAttribute.php b/src/Processor/Attribute/BaseProcessorAttribute.php index 542b8b3..2dd4fb0 100644 --- a/src/Processor/Attribute/BaseProcessorAttribute.php +++ b/src/Processor/Attribute/BaseProcessorAttribute.php @@ -4,27 +4,79 @@ namespace KaririCode\Contract\Processor\Attribute; +/** + * Classe BaseProcessorAttribute. + * + * Classe abstrata que implementa atributos de processamento, fornecendo funcionalidades + * para registrar processadores e mensagens customizadas associadas a cada um. Esta classe + * é projetada para servir como base para a criação de atributos de processamento que + * suportam personalização de mensagens. + * + * @category Processor + * + * @license MIT + */ abstract class BaseProcessorAttribute implements ProcessableAttribute, CustomizableMessageAttribute { + /** + * @var array Lista de processadores associados ao atributo. + * Somente processadores válidos são armazenados nesta lista. + */ private readonly array $processors; + + /** + * @var array Lista de mensagens customizadas para os processadores. + * As mensagens são associadas ao nome do processador e são opcionais. + */ private readonly array $messages; + /** + * Construtor da classe BaseProcessorAttribute. + * + * Inicializa a lista de processadores e, opcionalmente, as mensagens customizadas. + * Os processadores inválidos (nulos ou false) são automaticamente filtrados. + * + * @param array $processors Lista de processadores a serem associados ao atributo + * @param array|null $messages (Opcional) Lista de mensagens customizadas associadas aos processadores + */ public function __construct(array $processors, ?array $messages = null) { $this->processors = self::filterValidProcessors($processors); $this->messages = $messages ?? []; } + /** + * Retorna a lista de processadores associados ao atributo. + * + * @return array A lista de processadores válidos + */ public function getProcessors(): array { return $this->processors; } + /** + * Obtém uma mensagem customizada para um processador específico, caso esteja definida. + * + * @param string $processorName O nome do processador para o qual a mensagem é requisitada + * + * @return string|null A mensagem customizada associada ao processador, ou null se não existir + */ public function getMessage(string $processorName): ?string { return $this->messages[$processorName] ?? null; } + /** + * Filtra e retorna somente os processadores válidos. + * + * Este método estático remove processadores nulos ou definidos como false, + * garantindo que apenas processadores utilizáveis sejam armazenados. + * + * @param array $processors Lista de processadores a serem filtrados + * + * @return array A lista de processadores válidos + */ private static function filterValidProcessors(array $processors): array { return array_filter($processors, static fn ($v) => null !== $v && false !== $v); diff --git a/src/Processor/ProcessorRegistry.php b/src/Processor/ProcessorRegistry.php index 44d3c2e..05ac723 100644 --- a/src/Processor/ProcessorRegistry.php +++ b/src/Processor/ProcessorRegistry.php @@ -15,8 +15,8 @@ * * @category ProcessorPipeline * - * @author Walmir Silva * @license MIT + * @author Walmir Silva * * @see https://kariricode.org/ */ @@ -31,8 +31,10 @@ interface ProcessorRegistry * @param string $context The context under which the processor is registered * @param string $name The unique name of the processor within the context * @param Processor $processor The processor instance to be registered + * + * @return self Returns the current instance to enable a fluent interface */ - public function register(string $context, string $name, Processor $processor): void; + public function register(string $context, string $name, Processor $processor): self; /** * Retrieves a processor by its context and name.