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

[EasyUtils] Improve CollectorHelper #479

Merged
merged 4 commits into from
Feb 2, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Use extended error response with exception message, trace, etc.
*/
'use_extended_response' => \env('EASY_ERROR_HANDLER_USE_EXTENDED_RESPONSE', false),

/**
* Use default set of error response builders.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace EonX\EasyErrorHandler\Traits;
Expand Down
49 changes: 47 additions & 2 deletions packages/EasyUtils/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ final class MyClass
public function __construct(iterable $workers)
{
// $workers now contains only WorkerInterface instances
$workers = CollectorHelper::filterByClass(WorkerInterface::class, $workers);
$workers = CollectorHelper::filterByClass($workers, WorkerInterface::class);

// The filterByClass() method still returns an iterable, a generator more precisely
// If you need an array, you can use the filterByClassAsArray() method
Expand Down Expand Up @@ -169,14 +169,49 @@ final class MyClass
public function __construct(iterable $workers)
{
// $workers now contains only WorkerInterface instances
$workers = CollectorHelper::filterByClassAsArray(WorkerInterface::class, $workers);
$workers = CollectorHelper::filterByClassAsArray($workers, WorkerInterface::class);

// $workers is now an array containing only WorkerInterface instances
$this->workers = $workers;
}
}
```

### CollectorHelper::ensureClass() and CollectorHelper::ensureClassAsArray()

Those methods are similar to the `filterByClass()` and `filterByClassAsArray()` methods, however they will throw an
exception if at least of the items is not an instance of the given class.

```php
use App\Domain\WorkerInterface;
use EonX\EasyUtils\CollectorHelper;

final class MyClass
{
/**
* @var \App\Domain\WorkerInterface[]
*/
private array $workers;

/**
* @param iterable<mixed> $workers
*/
public function __construct(iterable $workers)
{
// $workers now contains only WorkerInterface instances
$workers = CollectorHelper::ensureClass(WorkerInterface::class, $workers);

foreach ($workers as $worker) {
// This code will be executed only if all items are instances of WorkerInterface
}
}
}
```

::: warning
Please note that with the `ensureClass()` method, the exception will be thrown only when iterating through the generator.
:::

### CollectorHelper::orderHigherPriorityFirst()

The `orderHigherPriorityFirst()` method will ensure the object with the highest priority is placed first, and the object
Expand All @@ -198,6 +233,11 @@ $objects = [$foo, $bar];
$objects = CollectorHelper::orderHigherPriorityFirst($objects); // [$bar, $foo]
```

::: tip
The `orderHigherPriorityFirst()` method still returns an iterable (or, more precisely, a generator). If you need an `array`, you
can use the `orderHigherPriorityFirstAsArray()` method instead.
:::

### CollectorHelper::orderLowerPriorityFirst()

The `orderLowerPriorityFirst()` method is the opposite of `orderHigherPriorityFirst()`. It will ensure the object with
Expand All @@ -219,6 +259,11 @@ $objects = [$foo, $bar];
$objects = CollectorHelper::orderLowerPriorityFirst($objects); // [$foo, $bar]
```

::: tip
The `orderLowerPriorityFirst()` method still returns an iterable (or, more precisely, a generator). If you need an `array`, you
can use the `orderLowerPriorityFirstAsArray()` method instead.
:::

[1]: https://getcomposer.org/
[2]: https://tomasvotruba.com/blog/2018/06/14/collector-pattern-for-dummies/
[3]: https://book.cakephp.org/4.next/en/development/dependency-injection.html#tagging-services
Expand Down
73 changes: 66 additions & 7 deletions packages/EasyUtils/src/CollectorHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace EonX\EasyUtils;

use EonX\EasyUtils\Exceptions\InvalidArgumentException;
use EonX\EasyUtils\Interfaces\HasPriorityInterface;

final class CollectorHelper
Expand All @@ -18,10 +19,44 @@ public static function convertToArray(iterable $items): array
return $items instanceof \Traversable ? \iterator_to_array($items) : (array)$items;
}

/**
* @param iterable<mixed> $items
*
* @return iterable<mixed>
*
* @throws \EonX\EasyUtils\Exceptions\InvalidArgumentException
*/
public static function ensureClass(iterable $items, string $class): iterable
{
foreach ($items as $item) {
if (($item instanceof $class) === false) {
throw new InvalidArgumentException(\sprintf(
'Instance of %s expected, %s given',
$class,
\is_object($item) === false ? \gettype($item) : \get_class($item)
));
}

yield $item;
}
}

/**
* @param iterable<mixed> $items
*
* @return mixed[]
*
* @throws \EonX\EasyUtils\Exceptions\InvalidArgumentException
*/
public static function ensureClassAsArray(iterable $items, string $class): array
{
return self::convertToArray(self::ensureClass($items, $class));
}

/**
* @param iterable<mixed> $items
*
* @return iterable<mixed>
*/
public static function filterByClass(iterable $items, string $class): iterable
{
Expand All @@ -44,11 +79,11 @@ public static function filterByClassAsArray(iterable $items, string $class): arr
}

/**
* @param mixed[] $items
* @param iterable<mixed> $items
*
* @return mixed[]
* @return iterable<mixed>
*/
public static function orderHigherPriorityFirst(iterable $items): array
public static function orderHigherPriorityFirst(iterable $items): iterable
{
$items = self::convertToArray($items);

Expand All @@ -59,15 +94,27 @@ public static function orderHigherPriorityFirst(iterable $items): array
return $secondPriority <=> $firstPriority;
});

return $items;
foreach ($items as $item) {
yield $item;
}
}

/**
* @param mixed[] $items
* @param iterable<mixed> $items
*
* @return mixed[]
*/
public static function orderLowerPriorityFirst(iterable $items): array
public static function orderHigherPriorityFirstAsArray(iterable $items): array
{
return self::convertToArray(self::orderHigherPriorityFirst($items));
}

/**
* @param iterable<mixed> $items
*
* @return iterable<mixed>
*/
public static function orderLowerPriorityFirst(iterable $items): iterable
{
$items = self::convertToArray($items);

Expand All @@ -78,6 +125,18 @@ public static function orderLowerPriorityFirst(iterable $items): array
return $firstPriority <=> $secondPriority;
});

return $items;
foreach ($items as $item) {
yield $item;
}
}

/**
* @param iterable<mixed> $items
*
* @return mixed[]
*/
public static function orderLowerPriorityFirstAsArray(iterable $items): array
{
return self::convertToArray(self::orderLowerPriorityFirst($items));
}
}
12 changes: 12 additions & 0 deletions packages/EasyUtils/src/Exceptions/InvalidArgumentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace EonX\EasyUtils\Exceptions;

use EonX\EasyUtils\Interfaces\EasyUtilsExceptionInterface;

final class InvalidArgumentException extends \InvalidArgumentException implements EasyUtilsExceptionInterface
{
// No body needed.
}
10 changes: 10 additions & 0 deletions packages/EasyUtils/src/Interfaces/EasyUtilsExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace EonX\EasyUtils\Interfaces;

interface EasyUtilsExceptionInterface
{
// Marker for all exceptions of this package.
}
35 changes: 33 additions & 2 deletions packages/EasyUtils/tests/CollectorHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@
namespace EonX\EasyUtils\Tests;

use EonX\EasyUtils\CollectorHelper;
use EonX\EasyUtils\Exceptions\InvalidArgumentException;
use EonX\EasyUtils\Tests\Stubs\HasPriorityStub;

final class CollectorHelperTest extends AbstractTestCase
{
/**
* @return iterable<mixed>
*/
public function providerTestEnsureClass(): iterable
{
yield 'basic type' => [[0], true];

yield 'basic object' => [[new \stdClass()], false];

yield 'interface based' => [[new HasPriorityStub(), new \stdClass()], true];
}

/**
* @return iterable<mixed>
*
Expand Down Expand Up @@ -63,6 +76,24 @@ public function providerTestOrderLowerPriorityFirst(): iterable
yield 'same order when no priority' => [[$noPriority1, $noPriority2], [$noPriority1, $noPriority2]];
}

/**
* @param iterable<mixed> $items
*
* @dataProvider providerTestEnsureClass
*/
public function testEnsureClass(iterable $items, bool $expectException, ?string $class = null): void
{
if ($expectException) {
$this->expectException(InvalidArgumentException::class);
}

// Convert to array so it goes through the generator
CollectorHelper::ensureClassAsArray($items, $class ?? \stdClass::class);

// If it reaches here, test is valid
self::assertTrue(true);
}

/**
* @param iterable<mixed> $items
* @param null|class-string $class
Expand All @@ -89,7 +120,7 @@ public function testFilterByClass(iterable $items, int $expectedCount, ?string $
*/
public function testOrderHigherPriorityFirst(iterable $items, array $expected): void
{
self::assertEquals($expected, CollectorHelper::orderHigherPriorityFirst($items));
self::assertEquals($expected, CollectorHelper::orderHigherPriorityFirstAsArray($items));
}

/**
Expand All @@ -100,7 +131,7 @@ public function testOrderHigherPriorityFirst(iterable $items, array $expected):
*/
public function testOrderLowerPriorityFirst(iterable $items, array $expected): void
{
self::assertEquals($expected, CollectorHelper::orderLowerPriorityFirst($items));
self::assertEquals($expected, CollectorHelper::orderLowerPriorityFirstAsArray($items));
}

private function hasPriorityStub(?int $priority = null): HasPriorityStub
Expand Down