Page MenuHomeDevCentral

No OneTemporary

diff --git a/omnitools/src/Collections/MultipleOperation.php b/omnitools/src/Collections/MultipleOperation.php
new file mode 100644
index 0000000..7a17988
--- /dev/null
+++ b/omnitools/src/Collections/MultipleOperation.php
@@ -0,0 +1,104 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Collections;
+
+use Keruald\OmniTools\Reflection\CallableElement;
+
+/**
+ * Allows to run a callable on each item of a collection.
+ *
+ * Tracks the result of this operation:
+ * - by default, the operation is successful
+ * - if a call returns a falsy value, the operation is failed
+ * - if all call returns truthy values, the operation is successful
+ *
+ * That allows to run a multiple operation with a consolidate result
+ * answering the question "Were all calls successful?".
+ *
+ * If a call fails, the subsequent calls still run.
+ *
+ * @see \array_walk
+ * @see \iterator_apply
+ */
+class MultipleOperation {
+
+ private bool $result = true;
+
+ ///
+ /// Constructors
+ ///
+
+ public function __construct (
+ private readonly iterable $iterable,
+ ) {
+
+ }
+
+ /**
+ * Applies the specified callable to each collection item.
+ *
+ * The callable should return a boolean. If not, result will be converted
+ * to a boolean, which can lead to unexpected behavior.
+ *
+ * The callable can has 0, 1 or 2 arguments:
+ * - if it has one argument, it represents the value
+ * - if it has two arguments, they represent (key, value)
+ *
+ * The result of one operation is false if the calable returns a falsy value.
+ * The result of all operations are true if every callable returns a truthy value.
+ *
+ * Returns if ALL the operation were successful.
+ */
+ public static function do (iterable $iterable, callable $callable) : bool {
+ $operation = new self($iterable);
+ $operation->apply($callable);
+
+ return $operation->isOk();
+ }
+
+ ///
+ /// Operation
+ ///
+
+ /**
+ * Applies the specified callable to each collection item.
+ *
+ * The callable should return a boolean. If not, result will be converted
+ * to a boolean, which can lead to unexpected behavior.
+ *
+ * The callable can has 0, 1 or 2 arguments:
+ * - if it has one argument, it represents the value
+ * - if it has two arguments, they represent (key, value)
+ *
+ * Flips the global result to false if any of the callable
+ * returns a falsy value.
+ */
+ public function apply (callable $callable) : void {
+ $argc = (new CallableElement($callable))->countArguments();
+
+ foreach ($this->iterable as $key => $value) {
+ $result = match($argc) {
+ 0 => $callable(),
+ 1 => $callable($value),
+ default => $callable($key, $value),
+ };
+
+ if ((bool)$result === false) {
+ $this->result = false;
+ }
+ }
+ }
+
+ ///
+ /// Result
+ ///
+
+ /**
+ * Determines if ALL the operations are successful so far
+ */
+ public function isOk () : bool {
+ return $this->result;
+ }
+
+}
diff --git a/omnitools/tests/Collections/MultipleOperationTest.php b/omnitools/tests/Collections/MultipleOperationTest.php
new file mode 100644
index 0000000..27fa71d
--- /dev/null
+++ b/omnitools/tests/Collections/MultipleOperationTest.php
@@ -0,0 +1,78 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Tests\Collections;
+
+use Keruald\OmniTools\Collections\MultipleOperation;
+
+use PHPUnit\Framework\TestCase;
+
+class MultipleOperationTest extends TestCase {
+
+ public function testIsOkAtFirst () {
+ $operation = new MultipleOperation([]);
+ $this->assertTrue($operation->isOk());
+ }
+
+ public function testIsOkWhenItIs () {
+ $operation = new MultipleOperation([1, 2, 3]);
+
+ $operation->apply(fn () => true);
+
+ $this->assertTrue($operation->isOk());
+ }
+
+ public function testIsOkWhenItIsNever () {
+ $operation = new MultipleOperation([1, 2, 3]);
+
+ $operation->apply(fn () => false);
+ $this->assertFalse($operation->isOk());
+ }
+
+ public function testIsOkWhenItIsNot () {
+ $operation = new MultipleOperation([1, 2, 3]);
+
+ $fn = fn($n) => match ($n) {
+ 2 => false, // second operation will fail
+ default => true,
+ };
+
+ $operation->apply($fn);
+ $this->assertFalse($operation->isOk());
+ }
+
+ public function testApply () {
+ $toProcess = [1, 2, 3];
+ $processed = [];
+
+ $fn = function ($n) use (&$processed) {
+ $processed[] = $n;
+
+ return true;
+ };
+
+ $operation = new MultipleOperation($toProcess);
+ $operation->apply($fn);
+ $this->assertEquals([1, 2, 3], $processed);
+ }
+
+ public function testDo () {
+ $toProcess = [1, 2, 3];
+ $processed = [];
+
+ $fn = function ($n) use (&$processed) {
+ if ($n == 2) {
+ // second operation will fail
+ return false;
+ }
+
+ $processed[] = $n;
+ return true;
+ };
+
+ $result = MultipleOperation::do($toProcess, $fn);
+ $this->assertFalse($result);
+ $this->assertEquals([1, 3], $processed);
+ }
+
+}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 03:12 (21 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2259421
Default Alt Text
(5 KB)

Event Timeline