diff --git a/README.md b/README.md index f95d550..c4d2d1e 100644 --- a/README.md +++ b/README.md @@ -1,207 +1,208 @@ -# Versatile Collections -[![Build Status](https://img.shields.io/travis/rotexsoft/versatile-collections/master.png?style=flat-square)](https://travis-ci.org/rotexsoft/versatile-collections)   -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/39472c4a7ad5402aaf19a38e72ed651c)](https://www.codacy.com/app/rotexdegba/versatile-collections?utm_source=github.com&utm_medium=referral&utm_content=rotexsoft/versatile-collections&utm_campaign=Badge_Grade)   -[![Release](https://img.shields.io/github/release/rotexsoft/versatile-collections.png?style=flat-square)](https://github.com/rotexsoft/versatile-collections/releases/latest)   -[![License](https://img.shields.io/badge/license-BSD-brightgreen.png?style=flat-square)](https://github.com/rotexsoft/versatile-collections/blob/master/LICENSE)   - -A collection package that can be extended to implement things such as a Dependency Injection Container, -RecordSet objects for housing database records, a bag of http cookies, or technically any collection of -items that can be looped over and whose items can each be accessed using array-access syntax or object -property syntax. - -This package provides optional strict-typing of collection items and strives for 100 % unit-test coverage. - -![Collection Classes](versatile-collections.svg) - -## Installation - -**Via composer:** (Requires PHP 5.6+) - - - composer require rotexsoft/versatile-collections - - -## Basics - -If you are simply looking to store items of the same or differing types in a collection you can use simply use the **GenericCollection** class like so: - -```php -some_key = $item4; // object property assignment syntax with specified property - // `some_key`. This will update $collection['some_key'] - // changing its value from $item3 to $item4 - -$collection->appendItem($item3) // same effect as: - ->appendItem($item5); // $collection[] = $item3; - // $collection[] = $item5; - // Adds an item to the end of the collection - // You can chain the method calls - -$collection->prependItem($item6, 'new_key'); // adds an item with the optional - // specified key to the front of - // collection. - // You can chain the method calls - -$collection->push($item7); // same effect as: - // $collection[] = $item7; - // Adds an item to the end of the collection - // You can chain the method calls - -$collection->put('eight_item', $item8) // same effect as: - ->put('ninth_item', $item9); // $collection['eight_item'] = $item8; - // $collection['ninth_item'] = $item9; - // Adds an item with the specified key to - // the collection. If the specified key - // already exists in the collection the - // item previously associated with the - // key is overwritten with the new item. - // You can chain the method calls - -``` - -You can also make any class in your application behave exactly like **\VersatileCollections\GenericCollection** -by implementing **\VersatileCollections\CollectionInterface** and using -**\VersatileCollections\CollectionInterfaceImplementationTrait** in such classes. - -If you want to enforce strict-typing, the following Collection classes are provided -in this package: - -* **ArraysCollection :** a collection that only stores items that are arrays (i.e. items for which is_array is true) -* **CallablesCollection :** a collection that only stores items that are callables (i.e. items for which is_callable is true) -* **FloatsCollection :** a collection that only stores items that are floats (i.e. items for which is_float is true) -* **IntsCollection :** a collection that only stores items that are integers (i.e. items for which is_int is true) -* **NumericsCollection :** a collection that only stores items that are either floats or integers (i.e. items for which is_int or is_float is true) -* **ObjectsCollection :** a collection that only stores items that are objects (i.e. items for which is_object is true) -* **ResourcesCollection :** a collection that only stores items that are resources (i.e. items for which is_resource is true) -* **ScalarsCollection :** a collection that only stores items that are scalars (i.e. items for which is_scalar is true) -* **StringsCollection :** a collection that only stores items that are strings (i.e. items for which is_string is true) - -To implement a custom collection that only contains objects that are instances of -a specific class (for example **\PDO**), your custom collection class must adhere to -the following requirements: - -* Your custom collection class must implement **\VersatileCollections\StrictlyTypedCollectionInterface** which currently contains the methods below: - - * **public function checkType($item)** : it must return true if `$item` is of the expected type or false otherwise - * **public function getType()** : it must return a string or an array of strings representing the name(s) of the expected type(s) - -* Your custom collection class should use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** (which contains implementation of the methods in **\VersatileCollections\StrictlyTypedCollectionInterface**). If you choose not to use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait**, then you will have to implement all the methods specified in **\VersatileCollections\StrictlyTypedCollectionInterface** and make sure you call the **checkType($item)** method in every method where you add items to or modify items in the collection such as **offsetSet($key, $val)** and throw an **VersatileCollections\Exceptions\InvalidItemException** exception whenever **checkType($item)** returns false. If you use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** in your custom collection class but add new methods that also add items to or modify items in the collection you can use the helper method **isRightTypeOrThrowInvalidTypeException($item, $calling_functions_name)** provided in **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** to validate items (it will automatically throw an exception for you if the item you are validating is of the wrong type; see **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait::offsetSet($key, $val)** for an example of how this helper method should be used). - -* You can optionally override **StrictlyTypedCollectionInterfaceImplementationTrait::__construct(...$arr_objs)** with a constructor -with the same signature but with the specific type. For example, **__construct(\PDO ...$pdo_objs)** ensures that only instances of -**\PDO** can be injected into the constructor via argument unpacking. - -The code example below shows how a custom collection class called **PdoCollection**, -that only stores items that are instances of **\PDO**, can be implemented: - -```php -versatile_collections_items = $pdo_objs; - } - - /** - * - * @return bool true if $item is of the expected type, else false - * - */ - public function checkType($item) { //4. implement interface methods not implemented in trait above - - return ($item instanceof \PDO); - } - - /** - * - * @return string|array a string or array of strings of type name(s) - * for items acceptable in instances of this - * collection class - * - */ - public function getType() { //4. implement interface methods not implemented in trait above - - return \PDO::class; - } -} -``` - -You can declare your custom typed collection classes as **final** so that users of your -classes will not be able to extend them and thereby circumvent the type-checking -being enforced at construct time and item addition time. - -## Documentation - -* [Methods Glossary by Category](docs/MethodsByCategory.md) -* [Methods Descriptions with Examples](docs/MethodDescriptions.md) -* [Generic Collections](docs/GenericCollections.md) -* Strictly Typed Collections - * [Arrays Collections](docs/ArraysCollection.md): a collection that can only contain [arrays](http://php.net/manual/en/language.types.array.php) - * [Callables Collections](docs/CallablesCollections.md): a collection that can only contain [callables](http://php.net/manual/en/language.types.callable.php) - * [Objects Collections](docs/ObjectsCollections.md): a collection that can only contain [objects](http://php.net/manual/en/language.types.object.php) (any kind of object) - * [Resources Collections](docs/ResourcesCollections.md): a collection that can only contain [resources](http://php.net/manual/en/language.types.resource.php) - * [Scalars Collections](docs/ScalarsCollections.md): a collection that can only scalar values. I.e. any of [booleans](http://php.net/manual/en/language.types.boolean.php), [floats](http://php.net/manual/en/language.types.float.php), [integers](http://php.net/manual/en/language.types.integer.php) or [strings](http://php.net/manual/en/language.types.string.php). It accepts any mix of scalars, e.g. ints, booleans, floats and strings can all be present in an instance of this type of collection. - * [Numerics Collections](docs/NumericsCollections.md): a collection that can only contain [floats](http://php.net/manual/en/language.types.float.php) and/or [integers](http://php.net/manual/en/language.types.integer.php) - * [Floats Collections](docs/FloatsCollections.md): a collection that can only contain [floats](http://php.net/manual/en/language.types.float.php) - * [Ints Collections](docs/IntsCollections.md): a collection that can only contain [integers](http://php.net/manual/en/language.types.integer.php) - * [Strings Collections](docs/StringsCollections.md): a collection that can only contain [strings](http://php.net/manual/en/language.types.string.php) - -* Please submit an issue or a pull request if you find any issues with the documentation. - -## Issues - -* Please submit an issue or a pull request if you find any bugs or better and -more efficient way(s) things could be implemented in this package. +# Versatile Collections +[![Build Status](https://img.shields.io/travis/rotexsoft/versatile-collections/master.png?style=flat-square)](https://travis-ci.org/rotexsoft/versatile-collections)   +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/39472c4a7ad5402aaf19a38e72ed651c)](https://www.codacy.com/app/rotexdegba/versatile-collections?utm_source=github.com&utm_medium=referral&utm_content=rotexsoft/versatile-collections&utm_campaign=Badge_Grade)   +[![Release](https://img.shields.io/github/release/rotexsoft/versatile-collections.png?style=flat-square)](https://github.com/rotexsoft/versatile-collections/releases/latest)   +[![License](https://img.shields.io/badge/license-BSD-brightgreen.png?style=flat-square)](https://github.com/rotexsoft/versatile-collections/blob/master/LICENSE)   + +A collection package that can be extended to implement things such as a Dependency Injection Container, +RecordSet objects for housing database records, a bag of http cookies, or technically any collection of +items that can be looped over and whose items can each be accessed using array-access syntax or object +property syntax. + +This package provides optional strict-typing of collection items and strives for 100 % unit-test coverage. + +![Collection Classes](versatile-collections.svg) + +## Installation + +**Via composer:** (Requires PHP 5.6+) + + + composer require rotexsoft/versatile-collections + + +## Basics + +If you are simply looking to store items of the same or differing types in a collection you can use simply use the **GenericCollection** class like so: + +```php +some_key = $item4; // object property assignment syntax with specified property + // `some_key`. This will update $collection['some_key'] + // changing its value from $item3 to $item4 + +$collection->appendItem($item3) // same effect as: + ->appendItem($item5); // $collection[] = $item3; + // $collection[] = $item5; + // Adds an item to the end of the collection + // You can chain the method calls + +$collection->prependItem($item6, 'new_key'); // adds an item with the optional + // specified key to the front of + // collection. + // You can chain the method calls + +$collection->push($item7); // same effect as: + // $collection[] = $item7; + // Adds an item to the end of the collection + // You can chain the method calls + +$collection->put('eight_item', $item8) // same effect as: + ->put('ninth_item', $item9); // $collection['eight_item'] = $item8; + // $collection['ninth_item'] = $item9; + // Adds an item with the specified key to + // the collection. If the specified key + // already exists in the collection the + // item previously associated with the + // key is overwritten with the new item. + // You can chain the method calls + +``` + +You can also make any class in your application behave exactly like **\VersatileCollections\GenericCollection** +by implementing **\VersatileCollections\CollectionInterface** and using +**\VersatileCollections\CollectionInterfaceImplementationTrait** in such classes. + +If you want to enforce strict-typing, the following Collection classes are provided +in this package: + +* **ArraysCollection :** a collection that only stores items that are arrays (i.e. items for which is_array is true) +* **CallablesCollection :** a collection that only stores items that are callables (i.e. items for which is_callable is true) +* **FloatsCollection :** a collection that only stores items that are floats (i.e. items for which is_float is true) +* **IntsCollection :** a collection that only stores items that are integers (i.e. items for which is_int is true) +* **NumericsCollection :** a collection that only stores items that are either floats or integers (i.e. items for which is_int or is_float is true) +* **ObjectsCollection :** a collection that only stores items that are objects (i.e. items for which is_object is true) +* **ResourcesCollection :** a collection that only stores items that are resources (i.e. items for which is_resource is true) +* **ScalarsCollection :** a collection that only stores items that are scalars (i.e. items for which is_scalar is true) +* **StringsCollection :** a collection that only stores items that are strings (i.e. items for which is_string is true) + +To implement a custom collection that only contains objects that are instances of +a specific class (for example **\PDO**), your custom collection class must adhere to +the following requirements: + +* Your custom collection class must implement **\VersatileCollections\StrictlyTypedCollectionInterface** which currently contains the methods below: + + * **public function checkType($item)** : it must return true if `$item` is of the expected type or false otherwise + * **public function getType()** : it must return a string or an array of strings representing the name(s) of the expected type(s) + +* Your custom collection class should use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** (which contains implementation of the methods in **\VersatileCollections\StrictlyTypedCollectionInterface**). If you choose not to use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait**, then you will have to implement all the methods specified in **\VersatileCollections\StrictlyTypedCollectionInterface** and make sure you call the **checkType($item)** method in every method where you add items to or modify items in the collection such as **offsetSet($key, $val)** and throw an **VersatileCollections\Exceptions\InvalidItemException** exception whenever **checkType($item)** returns false. If you use **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** in your custom collection class but add new methods that also add items to or modify items in the collection you can use the helper method **isRightTypeOrThrowInvalidTypeException($item, $calling_functions_name)** provided in **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait** to validate items (it will automatically throw an exception for you if the item you are validating is of the wrong type; see **\VersatileCollections\StrictlyTypedCollectionInterfaceImplementationTrait::offsetSet($key, $val)** for an example of how this helper method should be used). + +* You can optionally override **StrictlyTypedCollectionInterfaceImplementationTrait::__construct(...$arr_objs)** with a constructor +with the same signature but with the specific type. For example, **__construct(\PDO ...$pdo_objs)** ensures that only instances of +**\PDO** can be injected into the constructor via argument unpacking. + +The code example below shows how a custom collection class called **PdoCollection**, +that only stores items that are instances of **\PDO**, can be implemented: + +```php +versatile_collections_items = $pdo_objs; + } + + /** + * + * @return bool true if $item is of the expected type, else false + * + */ + public function checkType($item) { //4. implement interface methods not implemented in trait above + + return ($item instanceof \PDO); + } + + /** + * + * @return string|array a string or array of strings of type name(s) + * for items acceptable in instances of this + * collection class + * + */ + public function getType() { //4. implement interface methods not implemented in trait above + + return \PDO::class; + } +} +``` + +You can declare your custom typed collection classes as **final** so that users of your +classes will not be able to extend them and thereby circumvent the type-checking +being enforced at construct time and item addition time. + +## Documentation + +* [Methods Glossary by Category](docs/MethodsByCategory.md) +* [Methods Descriptions with Examples](docs/MethodDescriptions.md) +* [Generic Collections](docs/GenericCollections.md) +* Strictly Typed Collections + * [Arrays Collections](docs/ArraysCollection.md): a collection that can only contain [arrays](http://php.net/manual/en/language.types.array.php) + * [Callables Collections](docs/CallablesCollections.md): a collection that can only contain [callables](http://php.net/manual/en/language.types.callable.php) + * [Objects Collections](docs/ObjectsCollections.md): a collection that can only contain [objects](http://php.net/manual/en/language.types.object.php) (any kind of object) + * [Resources Collections](docs/ResourcesCollections.md): a collection that can only contain [resources](http://php.net/manual/en/language.types.resource.php) + * [Scalars Collections](docs/ScalarsCollections.md): a collection that can only scalar values. I.e. any of [booleans](http://php.net/manual/en/language.types.boolean.php), [floats](http://php.net/manual/en/language.types.float.php), [integers](http://php.net/manual/en/language.types.integer.php) or [strings](http://php.net/manual/en/language.types.string.php). It accepts any mix of scalars, e.g. ints, booleans, floats and strings can all be present in an instance of this type of collection. + * [Numerics Collections](docs/NumericsCollections.md): a collection that can only contain [floats](http://php.net/manual/en/language.types.float.php) and/or [integers](http://php.net/manual/en/language.types.integer.php) + * [Floats Collections](docs/FloatsCollections.md): a collection that can only contain [floats](http://php.net/manual/en/language.types.float.php) + * [Ints Collections](docs/IntsCollections.md): a collection that can only contain [integers](http://php.net/manual/en/language.types.integer.php) + * [Strings Collections](docs/StringsCollections.md): a collection that can only contain [strings](http://php.net/manual/en/language.types.string.php) +* [Laravel Collection Methods Equivalence](docs/LaravelMethodsEquivalence.md) + +* Please submit an issue or a pull request if you find any issues with the documentation. + +## Issues + +* Please submit an issue or a pull request if you find any bugs or better and +more efficient way(s) things could be implemented in this package. diff --git a/docs/LaravelMethodsEquivalence.md b/docs/LaravelMethodsEquivalence.md index c1f784b..4fc22d1 100644 --- a/docs/LaravelMethodsEquivalence.md +++ b/docs/LaravelMethodsEquivalence.md @@ -1,12 +1,14 @@ -|Laravel 5.7 Collection Methods |Versatile Collection Equivalent(s) +# Laravel Collection Methods Equivalence + +|Laravel Collection Methods |Versatile Collection Equivalent(s) |--- |--- |all |toArray |average |NumericsCollection::average, `$coll->getAsNewType(\VersatileCollections\NumericsCollection::class)->average();` where `$coll` is an instance of CollectionInterface containing integers and / or floats. |avg |See NumericsCollection::average above |chunk |getCollectionsOfSizeN, or iterator_to_array( yieldCollectionsOfSizeN ) -|collapse |Not implemented, see spreadsheet for alternative snippet -|combine |Not implemented, see spreadsheet for alternative snippet -|concat |appendCollection() or appendItem() depending on the use case, see spreadsheet for snippet +|collapse |Not implemented, see [below](#laravel-collection-method-collapse) for alternative snippet +|combine |Not implemented, see [below](#laravel-collection-method-combine) for alternative snippet +|concat |appendCollection() or appendItem() depending on the use case, see [below](#laravel-collection-method-concat) for snippet |contains |no non-strict version for now |containsStrict |containsItem, containsItems, containsKey, containsKeys & containsItemWithKey |count |count @@ -25,7 +27,7 @@ |firstWhere |filterFirstN |flatMap |Not implemented, maybe in a later version |flatten |Not implemented, maybe in a later version -|flip |Not implemented, see spreadsheet for alternative snippet +|flip |Not implemented, see [below](#laravel-collection-method-flip) for alternative snippet |forget |removeAll |forPage |paginate |get |getIfExists @@ -39,8 +41,8 @@ |keyBy |Not Implemented, Does not make sense for ScalarCollection and its sub-classes. |keys |getKeys |last |lastItem. Can do $coll->reverse()->filterFirstN() to emulate last() with callback -|macro |addMethod, addMethodForAllInstances & addStaticMethod -|make |makeNew +|static macro |addMethod, static addMethodForAllInstances & static addStaticMethod +|static make |static makeNew |map |map |mapInto |Not Implemented, may implement if there is enough demand or if a pull request is submitted |mapSpread |Not Implemented, may implement if there is enough demand or if a pull request is submitted @@ -79,7 +81,7 @@ |sum |NumericsCollection::sum, `$coll->getAsNewType(\VersatileCollections\NumericsCollection::class)->sum();` where `$coll` is an instance of CollectionInterface containing integers and / or floats. |take |take |tap |tap -|times |Not Implemented, may implement if there is enough demand or if a pull request is submitted +|static times |Not Implemented, may implement if there is enough demand or if a pull request is submitted |toArray |toArray. Just returns underlying array, no traversal of items to process them before returning. |toJson |Not Implemented, may implement if there is enough demand or if a pull request is submitted |transform |transform @@ -87,7 +89,7 @@ |unique |ScalarsCollection::uniqueNonStrict |uniqueStrict |unique |unless |whenFalse -|unwrap |Same as toArray() on an instance +|static unwrap |Same as toArray() on an instance |values |getItems |when |whenTrue |where |Not implemented, will be implemented in a later version @@ -97,5 +99,100 @@ |whereInstanceOf |Not implemented, will be implemented in a later version |whereNotIn |Not implemented, will be implemented in a later version |whereNotInStrict |Not implemented, will be implemented in a later version -|wrap |Not Implemented, may implement if there is enough demand or if a pull request is submitted -|zip |Not Implemented, may implement if there is enough demand or if a pull request is submitted \ No newline at end of file +|static wrap |Not Implemented, may implement if there is enough demand or if a pull request is submitted +|zip |Not Implemented, may implement if there is enough demand or if a pull request is submitted + +------------------------------------------------------------------------------------------------ +
+ +## Collapse Alternative: + +```php +collapse(); + + // equivalent to + + \VersatileCollections\GenericCollection::makeNew([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + ->reduce( + function($carry , $item) { + + foreach($item as $val) { + + $carry[] = $val; + } + return $carry; + }, + \VersatileCollections\GenericCollection::makeNew() + ); +``` + +------------------------------------------------------------------------------------------------ +
+ +## Combine Alternative: + +```php +combine(['George', 29]); + + // equivalent to + + $vals = ['George', 29]; + \VersatileCollections\GenericCollection::makeNew(['name', 'age']) + ->reduce( + function($carry , $item) use (&$vals) { + + $carry[$item] = array_shift($vals); + + return $carry; + }, + \VersatileCollections\GenericCollection::makeNew() + ); +``` + +------------------------------------------------------------------------------------------------ +
+ +## Concat Alternative: + +```php +concat(['Jane Doe']) + ->concat(['name' => 'Johnny Doe']) + ->all(); + + // equivalent to + + \VersatileCollections\GenericCollection::makeNew(['John Doe']) + ->appendCollection( + \VersatileCollections\GenericCollection::makeNew(['Jane Doe']) + ) + ->appendCollection( + \VersatileCollections\GenericCollection::makeNew(['name' => 'Johnny Doe']) + ) + ->toArray(); +``` + +------------------------------------------------------------------------------------------------ +
+ +## Flip Alternative: + +```php + 'taylor', 'framework' => 'laravel']); + + $flipped = $collection->flip(); + + // equivalent to + + $collection = \VersatileCollections\GenericCollection::makeNew( + ['name' => 'taylor', 'framework' => 'laravel'] + ); + + $flipped = \VersatileCollections\GenericCollection::makeNew( + array_flip($collection->toArray()) + ); +```