Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce collections interfaces #34

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@ composer test-coverage

## Usage

The library provide three traits that you can add to your custom class extending `ArrayIterator`.
The library defines interfaces to deal with collections and also boilerplate code with default implementations.

It defines interfaces to convert collection items to `array`, `string` and `int` and to compare items.
You can either use the provided traits to your custom class extending `ArrayIterator` or simply expand the abstract collection classes using them.

It has a default implementation for a "basic" collection and also one to filter and group data on your collections (a "filterable" collection).

It also provides some interfaces to filter and group data on your collections and base classes with default implementations.
It defines interfaces to convert collection items to `array`, `string` and `int` and to compare items.

More details:

- [Collection Interfaces](docs/collection-interfaces.md)
- [Collection Trait](docs/collection-trait.md)
- [Filterable Collection Trait](docs/filterable-collection-trait.md)
- [Auto Sortable OffsetSet Trait](docs/autosortable-offsetset-trait.md)
Expand Down
4 changes: 2 additions & 2 deletions docs/abstract-collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## AbstractCollection

This is an abstract base class that you can use for your collections. It extends `ArrayIterator` (and already uses the `CollectionTrait`) so you just need to extend it to have a proper collection class.
This is an abstract base class that you can use for your collections. It extends `ArrayIterator` and implements the `Collection` interface (and already uses the `CollectionTrait`) so you just need to extend it to have a proper collection class.

```php
<?php
Expand All @@ -19,7 +19,7 @@ $collection = MyCollection::fromIterable($myData);

## AbstractFilterableCollection

Using the same concept as `AbstractCollection` this class extends `ArrayIterator` and add the `FilterableCollectionTrait` to it.
Using the same concept as `AbstractCollection` this class extends `ArrayIterator` and implements the `FilterableCollection` (and already uses the `FilterableCollectionTrait`).

```php
<?php
Expand Down
194 changes: 194 additions & 0 deletions docs/collection-interfaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Collection Interfaces

The library defines two interfaces for collections.

The first one ([`Collection`](../src/Collection.php)) is a basic "bare-bones" collection.

The second one ([`FilterableCollection`](../src/FilterableCollection.php)) is a "filterable" collection, which allows you to filter and group elements on your collection.

`FilterableCollection` extends `Collection`, so all methods should also be implemented in a `FilterableCollection` (plus the specific methods).

Every collection interface is also extending from `FromIterable` and `ToArray` interfaces.

So they should also implement the following methods:

## fromIterable

```php
public static function fromIterable(iterable $data): self|static;
```

This method should try to create an instance of your collection class with data from a source that is an `iterable` (e.g. an array).

## toArray

```php
public function toArray(): array;
```

This method will convert your collection to a representation of it as an array.

## Collection

The `Collection` interface defines the methods your collection should provide.

### add

```php
public function add(mixed $value): self|static;
```

This method is defined to be a fluent version of `ArrayIterator::append`. To do stuff like:

```php
$collection->add($item1)->add($item2);
```

### diff

```php
public function diff(self $other): self|static;
```

This method will produce a collection with the difference between your collection and another instance.

### duplicates

```php
public function duplicates(bool $strict = true, bool $uniques = false): self|static;
```

This method produces a collection which contains items which occur multiple times in the collection.

- `$strict` parameter allows you to use strict comparison (e.g. if your implementation uses PHP `in_array`).
- `$uniques` parameter allows you to specify if you want to return unique duplicates values instead of all duplicates entries.

### each

```php
public function each(callable $function, bool $rewind = true): self|static;
```

This method will iterate through each item of a collection, optionally rewind it at the end of the iteration, calling an anonymous function where you can do whatever you need with each item.

Callable signature:

```php
function(mixed $element, string|float|int|bool|null $elementKey): void;
```

### empty

```php
public function empty(): bool;
```

Just a shortcut to see if your collection has a count of elements greater than zero.

### has

```php
public function has(mixed $value, bool $strict = true): bool;
```

This method will tell you if your collection contains the given value.

- `$strict` parameter allows you to use strict comparison (e.g. if your implementation uses PHP `in_array`).

### keys

```php
public function keys(): array;
```

This method will return the keys of the collection.

### map

```php
public function map(callable $function, bool $rewind = true): array;
```

This method will map your collection to an array, optionally rewind it at the end of the iteration, calling an anonymous function where you can do whatever you need with each item.

Callable signature:

```php
function(mixed $element, string|float|int|bool|null $elementKey): mixed;
```

### reduce

```php
public function reduce(callable $function, mixed $initial = null, bool $rewind = true): mixed;
```

This method will reduce your collection to a single value, optionally rewind it at the end of the iteration, calling an anonymous function where you can do whatever you need with each item.

Callable signature:

```php
function(mixed $carry, mixed $element, string|float|int|bool|null $elementKey): mixed;
```

### reverse

```php
public function reverse(): self|static;
```

This method will produce a collection with elements of your collection in the reverse order.

### unique

```php
public function unique(): self|static;
```

This method will produce a collection with distinct elements of your collection.

### values

```php
public function values(): array;
```

This method will return the values of the collection.

## FilterableCollection

The `FilterableCollection` interface defines additional methods that your collection should provide in order to filter and/or group elements in it.

### filter

```php
public function filter(CollectionFilter $filter): self|static
```

This will accept a `CollectionFilter` instance (with the definitions of the filter being applied to the collection), and returns a new collection with only the elements that have met the criteria defined in `$filter`.

### groupBy

```php
public function groupBy(bool $removeEmptyGroups, CollectionFilter ...$filters): array
```

This method allows you to apply a series of filters to a collection and group the result by each filter. The `$removeEmptyGroups` flag means if we will remove or keep groups in the result without items.

The result should be returned as an array with the following structure:

```php
[
'filter_1_key' => [
'item_key_1' => item object 1
...
'item_key_N' => item object X
],
'filter_2_key' => [
'item_key_1' => item object 1
...
'item_key_N' => item object Y
],
...
]
```
Loading