diff --git a/src/Pools/Group.php b/src/Pools/Group.php index 43e8975..f7c72f7 100644 --- a/src/Pools/Group.php +++ b/src/Pools/Group.php @@ -28,7 +28,7 @@ public function add(Pool $pool): self */ public function get(string $name): Pool { - return $this->pools[$name] ?? throw new Exception("Pool '{$name}' not found"); + return $this->pools[$name] ?? throw new Exception("Pool '{$name}' not found"); } /** @@ -53,6 +53,41 @@ public function reclaim(): self return $this; } + /** + * Execute a callback with a managed connection + * + * @param string[] $names Name of resources + * @param callable(mixed...): mixed $callback Function that receives the connection resources + * @return mixed Return value from the callback + */ + public function use(array $names, callable $callback): mixed + { + if (empty($names)) { + throw new Exception("Cannot use with empty names"); + } + return $this->useInternal($names, $callback); + } + + /** + * Internal recursive callback for `use`. + * + * @param string[] $names Name of resources + * @param callable(mixed...): mixed $callback Function that receives the connection resources + * @param mixed[] $resources + * @return mixed + * @throws Exception + */ + private function useInternal(array $names, callable $callback, array $resources = []): mixed + { + if (empty($names)) { + return $callback(...$resources); + } + + return $this + ->get(array_shift($names)) + ->use(fn ($resource) => $this->useInternal($names, $callback, array_merge($resources, [$resource]))); + } + /** * @param int $reconnectAttempts * @return self diff --git a/tests/Pools/GroupTest.php b/tests/Pools/GroupTest.php index c79e8e6..d8bc8b9 100644 --- a/tests/Pools/GroupTest.php +++ b/tests/Pools/GroupTest.php @@ -97,4 +97,33 @@ public function testReconnectSleep(): void $this->assertEquals(2, $this->object->get('test')->getReconnectSleep()); } + + public function testUse(): void + { + $pool1 = new Pool('pool1', 1, fn () => '1'); + $pool2 = new Pool('pool2', 1, fn () => '2'); + $pool3 = new Pool('pool3', 1, fn () => '3'); + + $this->object->add($pool1); + $this->object->add($pool2); + $this->object->add($pool3); + + $this->assertEquals(1, $pool1->count()); + $this->assertEquals(1, $pool2->count()); + $this->assertEquals(1, $pool3->count()); + + // @phpstan-ignore argument.type + $this->object->use(['pool1', 'pool3'], function ($one, $three) use ($pool1, $pool2, $pool3) { + $this->assertEquals('1', $one); + $this->assertEquals('3', $three); + + $this->assertEquals(0, $pool1->count()); + $this->assertEquals(1, $pool2->count()); + $this->assertEquals(0, $pool3->count()); + }); + + $this->assertEquals(1, $pool1->count()); + $this->assertEquals(1, $pool2->count()); + $this->assertEquals(1, $pool3->count()); + } }