diff --git a/.gitignore b/.gitignore index 2ef07bd0..e68db33e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ # PHP /composer.lock -/vendor/ \ No newline at end of file +/vendor/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b17280b..35ee188c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v1.2.x + +- Add event Event::POOL occurs when Flow needs to count IPs to process. +- Add `Flow\IpPool` for managing pools of Ips. +- Update `Flow\Event\PullEvent` to pull multiple Ips instead one. +- Move `Flow::do` to `FlowFactory::create` +- Add `Flow\Driver\ParallelDriver` + ## v1.2.2 - Flow can now use `Flow\JobInterface` as job input diff --git a/LICENSE b/LICENSE index 545ec31a..a948175b 100644 --- a/LICENSE +++ b/LICENSE @@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 03399db5..8d648bc8 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ composer require darkwood/flow create(static function() { yield fn (D1 $data1) => new D2($data1->n1 += 1); yield fn (D2 $data2) => new D3($data2->n2 * 2); yield function(D3 $data3) { diff --git a/docs/src/content/en/docs/getting-started/flow.md b/docs/src/content/en/docs/getting-started/flow.md index eb79a45c..729cd4bd 100644 --- a/docs/src/content/en/docs/getting-started/flow.md +++ b/docs/src/content/en/docs/getting-started/flow.md @@ -43,4 +43,4 @@ YFlow use YCombinator to provide recursion. ## Make your own Flow -You can make your custom Flow by implementing `Flow\FlowInterface`. \ No newline at end of file +You can make your custom Flow by implementing `Flow\FlowInterface`. diff --git a/docs/src/content/en/docs/getting-started/ip-strategy.md b/docs/src/content/en/docs/getting-started/ip-strategy.md index e960e07a..ccf5ded2 100644 --- a/docs/src/content/en/docs/getting-started/ip-strategy.md +++ b/docs/src/content/en/docs/getting-started/ip-strategy.md @@ -32,4 +32,4 @@ You can embed it by a custom strategy with is `LinearIpStrategy` by default. ## Make your Ip Strategy -You can make your custom Ip strategy by implementing `Flow\IpStrategyInterface` \ No newline at end of file +You can make your custom Ip strategy by implementing `Flow\IpStrategyInterface` diff --git a/docs/src/content/en/docs/getting-started/license.md b/docs/src/content/en/docs/getting-started/license.md index 80071989..641c91f8 100644 --- a/docs/src/content/en/docs/getting-started/license.md +++ b/docs/src/content/en/docs/getting-started/license.md @@ -32,4 +32,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/src/layouts/_default/section.sitemap.xml b/docs/src/layouts/_default/section.sitemap.xml index 701951d6..afeebb8d 100644 --- a/docs/src/layouts/_default/section.sitemap.xml +++ b/docs/src/layouts/_default/section.sitemap.xml @@ -43,4 +43,4 @@ {{ end -}} {{ end -}} {{ end -}} - \ No newline at end of file + diff --git a/examples/Transport/Client.php b/examples/Transport/Client.php new file mode 100644 index 00000000..787cea09 --- /dev/null +++ b/examples/Transport/Client.php @@ -0,0 +1,44 @@ +sender->send($ip); + } + + /** + * @param callable[][]|HandlerDescriptor[][] $handlers + */ + public function wait(array $handlers): void + { + $bus = new MessageBus([ + new HandleMessageMiddleware(new HandlersLocator($handlers)), + ]); + $worker = new Worker(['transport' => $this->receiver], $bus); + $worker->run(); + } +} diff --git a/examples/client.php b/examples/client.php index 31a6e2ba..d40fe83b 100644 --- a/examples/client.php +++ b/examples/client.php @@ -5,45 +5,8 @@ require __DIR__ . '/../vendor/autoload.php'; use Doctrine\DBAL\DriverManager; +use Flow\Examples\Transport\Client; use Flow\Examples\Transport\DoctrineIpTransport; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Handler\HandlerDescriptor; -use Symfony\Component\Messenger\Handler\HandlersLocator; -use Symfony\Component\Messenger\MessageBus; -use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; -use Symfony\Component\Messenger\Stamp\DelayStamp; -use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; -use Symfony\Component\Messenger\Transport\Sender\SenderInterface; -use Symfony\Component\Messenger\Worker; - -class client -{ - public function __construct( - private SenderInterface $sender, - private ReceiverInterface $receiver - ) {} - - /** - * @param ?int $delay The delay in milliseconds - */ - public function call(object $data, ?int $delay = null): void - { - $ip = Envelope::wrap($data, $delay ? [new DelayStamp($delay)] : []); - $this->sender->send($ip); - } - - /** - * @param callable[][]|HandlerDescriptor[][] $handlers - */ - public function wait(array $handlers): void - { - $bus = new MessageBus([ - new HandleMessageMiddleware(new HandlersLocator($handlers)), - ]); - $worker = new Worker(['transport' => $this->receiver], $bus); - $worker->run(); - } -} $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', @@ -51,7 +14,7 @@ public function wait(array $handlers): void ]); $transport = new DoctrineIpTransport($connection, uniqid('transport_', true)); -$client = new client($transport, $transport); +$client = new Client($transport, $transport); $ip = long2ip(random_int(ip2long('10.0.0.0'), ip2long('10.255.255.255'))); for ($i = 0; $i < 3; $i++) { diff --git a/examples/flow.php b/examples/flow.php index 3a4ec3cf..6fae3db1 100644 --- a/examples/flow.php +++ b/examples/flow.php @@ -6,6 +6,7 @@ use Flow\Driver\AmpDriver; use Flow\Driver\FiberDriver; +use Flow\Driver\ParallelDriver; use Flow\Driver\ReactDriver; use Flow\Driver\SpatieDriver; use Flow\Driver\SwooleDriver; @@ -14,7 +15,7 @@ use Flow\Examples\Model\DataC; use Flow\Examples\Model\DataD; use Flow\ExceptionInterface; -use Flow\Flow\Flow; +use Flow\FlowFactory; use Flow\Ip; use Flow\IpStrategy\MaxIpStrategy; use Flow\Job\ClosureJob; @@ -25,6 +26,7 @@ 3 => new ReactDriver(), 4 => new SwooleDriver(), // 5 => new SpatieDriver(), + // 6 => new ParallelDriver(), }; printf("Use %s\n", $driver::class); printf("Calculating:\n"); @@ -35,7 +37,7 @@ $job1 = static function (DataA $dataA) use ($driver): DataB { printf("*. #%d - Job 1 Calculating %d + %d\n", $dataA->id, $dataA->a, $dataA->b); - // simulating calculating some "light" operation from 0.1 to 1 seconds + // simulating calculating some "light" operation from 1 to 3 seconds $delay = random_int(1, 3); $driver->delay($delay); $d = $dataA->a + $dataA->b; @@ -92,7 +94,7 @@ $asyncTask = static function ($job1, $job2, $job3, $errorJob1, $errorJob2, $driver) { echo "begin - flow asynchronous\n"; - $flow = Flow::do(static function () use ($job1, $job2, $job3, $errorJob1, $errorJob2) { + $flow = (new FlowFactory())->create(static function () use ($job1, $job2, $job3, $errorJob1, $errorJob2) { yield [$job1, $errorJob1, new MaxIpStrategy(2)]; yield [$job2, $errorJob2, new MaxIpStrategy(2)]; yield $job3; diff --git a/examples/server.php b/examples/server.php index 3c3375f0..6bea6c0f 100644 --- a/examples/server.php +++ b/examples/server.php @@ -12,8 +12,8 @@ use Flow\Driver\SwooleDriver; use Flow\Examples\Transport\DoctrineIpTransport; use Flow\ExceptionInterface; -use Flow\Flow\Flow; use Flow\Flow\TransportFlow; +use Flow\FlowFactory; use Flow\Ip; use Flow\IpStrategy\MaxIpStrategy; use Symfony\Component\Messenger\Envelope; @@ -74,7 +74,7 @@ printf("%s\n", $exception->getMessage()); }; -$flow = Flow::do(static function () use ($addOneJob, $multbyTwoJob, $minusThreeJob, $errorJob) { +$flow = (new FlowFactory())->create(static function () use ($addOneJob, $multbyTwoJob, $minusThreeJob, $errorJob) { yield [$addOneJob, $errorJob, new MaxIpStrategy(1)]; yield [$multbyTwoJob, $errorJob, new MaxIpStrategy(3)]; yield [$minusThreeJob, $errorJob, new MaxIpStrategy(2)]; diff --git a/examples/yflow.php b/examples/yflow.php index 7d845d63..47bb7859 100644 --- a/examples/yflow.php +++ b/examples/yflow.php @@ -7,12 +7,13 @@ use Flow\AsyncHandler\DeferAsyncHandler; use Flow\Driver\AmpDriver; use Flow\Driver\FiberDriver; +use Flow\Driver\ParallelDriver; use Flow\Driver\ReactDriver; use Flow\Driver\SpatieDriver; use Flow\Driver\SwooleDriver; use Flow\Examples\Model\YFlowData; -use Flow\Flow\Flow; use Flow\Flow\YFlow; +use Flow\FlowFactory; use Flow\Ip; use Flow\Job\YJob; use Flow\JobInterface; @@ -23,26 +24,25 @@ 3 => new FiberDriver(), 4 => new SwooleDriver(), // 5 => new SpatieDriver(), + // 6 => new ParallelDriver(), }; + printf("Use %s\n", $driver::class); -function factorial(int $n): int -{ - return ($n <= 1) ? 1 : $n * factorial($n - 1); -} +$factorial = static function (int $n) use (&$factorial): int { + return ($n <= 1) ? 1 : $n * $factorial($n - 1); +}; /** * @return JobInterface */ -function Ywrap(callable $func, callable $wrapperFunc): JobInterface -{ +$Ywrap = static function (callable $func, callable $wrapperFunc): JobInterface { $wrappedFunc = static fn ($recurse) => $wrapperFunc(static fn (...$args) => $func($recurse)(...$args)); return new YJob($wrappedFunc); -} +}; -function memoWrapperGenerator(callable $f): Closure -{ +$memoWrapperGenerator = static function (callable $f): Closure { static $cache = []; return static function ($y) use ($f, &$cache) { @@ -52,41 +52,38 @@ function memoWrapperGenerator(callable $f): Closure return $cache[$y]; }; -} +}; /** * @return JobInterface */ -function Ymemo(callable $f): JobInterface -{ - return Ywrap($f, 'memoWrapperGenerator'); -} +$Ymemo = static function (callable $f) use ($Ywrap, $memoWrapperGenerator): JobInterface { + return $Ywrap($f, $memoWrapperGenerator); +}; -function factorialGen(callable $func): Closure -{ +$factorialGen = static function (callable $func): Closure { return static function (int $n) use ($func): int { return ($n <= 1) ? 1 : $n * $func($n - 1); }; -} +}; -function factorialYMemo(int $n): int -{ - return Ymemo('factorialGen')($n); -} +$factorialYMemo = static function (int $n) use ($Ymemo, $factorialGen): int { + return $Ymemo($factorialGen)($n); +}; -$factorialJob = static function (YFlowData $data): YFlowData { - printf("*... #%d - Job 1 : Calculating factorial(%d)\n", $data->id, $data->number); +$factorialJob = static function (YFlowData $data) use ($factorial): YFlowData { + printf("*.... #%d - Job 1 : Calculating factorial(%d)\n", $data->id, $data->number); // raw factorial calculation - $result = factorial($data->number); + $result = $factorial($data->number); - printf("*... #%d - Job 1 : Result for factorial(%d) = %d\n", $data->id, $data->number, $result); + printf("*.... #%d - Job 1 : Result for factorial(%d) = %d\n", $data->id, $data->number, $result); return new YFlowData($data->id, $data->number); }; $factorialYJobBefore = static function (YFlowData $data): YFlowData { - printf(".*.. #%d - Job 2 : Calculating factorialYJob(%d)\n", $data->id, $data->number); + printf(".*... #%d - Job 2 : Calculating factorialYJob(%d)\n", $data->id, $data->number); return new YFlowData($data->id, $data->number, $data->number); }; @@ -102,37 +99,44 @@ function factorialYMemo(int $n): int }; $factorialYJobAfter = static function (YFlowData $data): YFlowData { - printf(".*.. #%d - Job 2 : Result for factorialYJob(%d) = %d\n", $data->id, $data->number, $data->result); + printf(".*... #%d - Job 2 : Result for factorialYJob(%d) = %d\n", $data->id, $data->number, $data->result); return new YFlowData($data->id, $data->number); }; -$factorialYMemoJob = static function (YFlowData $data): YFlowData { - printf("..*. #%d - Job 3 : Calculating factorialYMemo(%d)\n", $data->id, $data->number); +$factorialYMemoJob = static function (YFlowData $data) use ($driver, $factorialYMemo): YFlowData { + printf("..*.. #%d - Job 3 : Calculating factorialYMemo(%d)\n", $data->id, $data->number); - $result = factorialYMemo($data->number); + $driver->delay(3); + $result = $factorialYMemo($data->number); - printf("..*. #%d - Job 3 : Result for factorialYMemo(%d) = %d\n", $data->id, $data->number, $result); + printf("..*.. #%d - Job 3 : Result for factorialYMemo(%d) = %d\n", $data->id, $data->number, $result); return new YFlowData($data->id, $data->number); }; $factorialYJobDeferBefore = static function (YFlowData $data) { - printf("...* #%d - Job 4 : Calculating factorialYJobDefer(%d)\n", $data->id, $data->number); + printf("...*. #%d - Job 4 : Calculating factorialYJobDefer(%d)\n", $data->id, $data->number); return new YFlowData($data->id, $data->number, $data->number); }; -$factorialYJobDefer = new YJob(static function ($factorial) { - return static function ($args) use ($factorial) { +$factorialYJobDefer = new YJob(static function ($factorial) use ($driver) { + return static function ($args) use ($factorial, $driver) { [$data, $defer] = $args; - return $defer(static function ($complete, $async) use ($data, $defer, $factorial) { + return $defer(static function ($complete, $async) use ($data, $defer, $factorial, $driver) { if ($data->result <= 1) { + $delay = random_int(1, 3); + printf("...*. #%d - Job 4 : Step factorialYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay); + $driver->delay($delay); $complete([new YFlowData($data->id, $data->number, 1), $defer]); } else { - $async($factorial([new YFlowData($data->id, $data->number, $data->result - 1), $defer]), static function ($result) use ($data, $complete) { + $async($factorial([new YFlowData($data->id, $data->number, $data->result - 1), $defer]), static function ($result) use ($data, $complete, $driver) { [$resultData, $defer] = $result; + $delay = random_int(1, 3); + printf("...*. #%d - Job 4 : Step async factorialYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay); + $driver->delay($delay); $complete([new YFlowData($data->id, $data->number, $data->result * $resultData->result), $defer]); }); } @@ -144,13 +148,56 @@ function factorialYMemo(int $n): int [$data, $defer] = $args; return $defer(static function ($complete) use ($data, $defer) { - printf("...* #%d - Job 4 : Result for factorialYJobDefer(%d) = %d\n", $data->id, $data->number, $data->result); + printf("...*. #%d - Job 4 : Result for factorialYJobDefer(%d) = %d\n", $data->id, $data->number, $data->result); + + $complete([new YFlowData($data->id, $data->number), $defer]); + }); +}; + +$fibonacciYJobDeferBefore = static function (YFlowData $data) { + printf("....* #%d - Job 5 : Calculating fibonacciYJobDefer(%d)\n", $data->id, $data->number); + + return new YFlowData($data->id, $data->number, $data->number); +}; + +$fibonacciYJobDefer = new YJob(static function ($fibonacci) use ($driver) { + return static function ($args) use ($fibonacci, $driver) { + [$data, $defer] = $args; + + return $defer(static function ($complete, $async) use ($data, $defer, $fibonacci, $driver) { + if ($data->result <= 1) { + $delay = random_int(1, 3); + printf("....* #%d - Job 5 : Step fibonacciYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay); + $driver->delay($delay); + $complete([new YFlowData($data->id, $data->number, 1), $defer]); + } else { + $async($fibonacci([new YFlowData($data->id, $data->number, $data->result - 1), $defer]), static function ($result1) use ($data, $complete, $driver, $async, $fibonacci) { + [$resultData1, $defer1] = $result1; + $async($fibonacci([new YFlowData($data->id, $data->number, $data->result - 2), $defer1]), static function ($result2) use ($data, $complete, $driver, $resultData1) { + [$resultData2, $defer2] = $result2; + $delay = random_int(1, 3); + printf("....* #%d - Job 5 : Step async fibonacciYJobDefer(%d) with delay %d\n", $data->id, $data->number, $delay); + $driver->delay($delay); + $fibResult = $resultData1->result + $resultData2->result; + $complete([new YFlowData($data->id, $data->number, $fibResult), $defer2]); + }); + }); + } + }); + }; +}); + +$fibonacciYJobDeferAfter = static function ($args) { + [$data, $defer] = $args; + + return $defer(static function ($complete) use ($data, $defer) { + printf("....* #%d - Job 5 : Result for fibonacciYJobDefer(%d) = %d\n", $data->id, $data->number, $data->result); $complete([new YFlowData($data->id, $data->number), $defer]); }); }; -$flow = Flow::do(static function () use ( +$flow = (new FlowFactory())->create(static function () use ( $factorialJob, $factorialYJobBefore, $factorialYJob, @@ -158,7 +205,10 @@ function factorialYMemo(int $n): int $factorialYMemoJob, $factorialYJobDeferBefore, $factorialYJobDefer, - $factorialYJobDeferAfter + $factorialYJobDeferAfter, + $fibonacciYJobDeferBefore, + $fibonacciYJobDefer, + $fibonacciYJobDeferAfter ) { yield [$factorialJob]; yield [$factorialYJobBefore]; @@ -168,6 +218,9 @@ function factorialYMemo(int $n): int yield [$factorialYJobDeferBefore]; yield [$factorialYJobDefer, null, null, null, new DeferAsyncHandler()]; yield [$factorialYJobDeferAfter, null, null, null, new DeferAsyncHandler()]; + yield [$fibonacciYJobDeferBefore]; + yield [$fibonacciYJobDefer, null, null, null, new DeferAsyncHandler()]; + yield [$fibonacciYJobDeferAfter, null, null, null, new DeferAsyncHandler()]; }, ['driver' => $driver]); for ($i = 1; $i <= 5; $i++) { diff --git a/src/AsyncHandler/AsyncHandler.php b/src/AsyncHandler/AsyncHandler.php index c81c5cc7..941258d7 100644 --- a/src/AsyncHandler/AsyncHandler.php +++ b/src/AsyncHandler/AsyncHandler.php @@ -7,6 +7,8 @@ use Flow\AsyncHandlerInterface; use Flow\Event; use Flow\Event\AsyncEvent; +use Flow\Event\PoolEvent; +use Flow\IpPool; /** * @template T @@ -15,10 +17,21 @@ */ final class AsyncHandler implements AsyncHandlerInterface { + /** + * @var IpPool + */ + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } + public static function getSubscribedEvents() { return [ Event::ASYNC => 'async', + Event::POOL => 'pool', ]; } @@ -27,7 +40,17 @@ public function async(AsyncEvent $event): void $ip = $event->getIp(); $async = $event->getAsync(); $asyncJob = $async($event->getJob()); + + $popIp = $this->ipPool->addIp($ip); $next = $asyncJob($ip->data); - $next($event->getCallback()); + $next(static function ($data) use ($event, $popIp) { + $event->getCallback()($data); + $popIp(); + }); + } + + public function pool(PoolEvent $event): void + { + $event->addIps($this->ipPool->getIps()); } } diff --git a/src/AsyncHandler/BatchAsyncHandler.php b/src/AsyncHandler/BatchAsyncHandler.php index 54625085..9f674677 100644 --- a/src/AsyncHandler/BatchAsyncHandler.php +++ b/src/AsyncHandler/BatchAsyncHandler.php @@ -7,28 +7,28 @@ use Flow\AsyncHandlerInterface; use Flow\Event; use Flow\Event\AsyncEvent; +use Flow\Event\PoolEvent; use Symfony\Component\Messenger\Handler\Acknowledger; use Symfony\Component\Messenger\Handler\BatchHandlerInterface; use Symfony\Component\Messenger\Handler\BatchHandlerTrait; use Throwable; /** - * @template T1 - * @template T2 + * @template T * - * @implements AsyncHandlerInterface + * @implements AsyncHandlerInterface */ final class BatchAsyncHandler implements BatchHandlerInterface, AsyncHandlerInterface { use BatchHandlerTrait; /** - * @var AsyncHandlerInterface + * @var AsyncHandlerInterface */ private AsyncHandlerInterface $asyncHandler; /** - * @param null|AsyncHandlerInterface $asyncHandler + * @param null|AsyncHandlerInterface $asyncHandler */ public function __construct( private int $batchSize = 10, @@ -41,6 +41,7 @@ public static function getSubscribedEvents() { return [ Event::ASYNC => 'async', + Event::POOL => 'pool', ]; } @@ -53,12 +54,17 @@ public function async(AsyncEvent $event): void $this->handle($event, $ack); } + public function pool(PoolEvent $event): void + { + $this->asyncHandler->pool($event); + } + /** * PHPStan should normaly pass for method.unused * https://github.com/phpstan/phpstan/issues/6039 * https://phpstan.org/r/8f7de023-9888-4dcb-b12c-e2fcf9547b6c. * - * @param array{0: AsyncEvent, 1: Acknowledger}[] $jobs + * @param array{0: AsyncEvent, 1: Acknowledger}[] $jobs * * @phpstan-ignore method.unused */ diff --git a/src/AsyncHandler/DeferAsyncHandler.php b/src/AsyncHandler/DeferAsyncHandler.php index b36727a9..3c0f1d9e 100644 --- a/src/AsyncHandler/DeferAsyncHandler.php +++ b/src/AsyncHandler/DeferAsyncHandler.php @@ -7,6 +7,8 @@ use Flow\AsyncHandlerInterface; use Flow\Event; use Flow\Event\AsyncEvent; +use Flow\Event\PoolEvent; +use Flow\IpPool; /** * @template T @@ -15,10 +17,21 @@ */ final class DeferAsyncHandler implements AsyncHandlerInterface { + /** + * @var IpPool + */ + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } + public static function getSubscribedEvents() { return [ Event::ASYNC => 'async', + Event::POOL => 'pool', ]; } @@ -26,11 +39,19 @@ public function async(AsyncEvent $event): void { $ip = $event->getIp(); $job = $event->getJob(); + + $popIp = $this->ipPool->addIp($ip); $next = $job([$ip->data, $event->getDefer()]); - $next(static function ($result) use ($event) { + $next(static function ($result) use ($event, $popIp) { [$data] = $result; $callback = $event->getCallback(); $callback($data); + $popIp(); }); } + + public function pool(PoolEvent $event): void + { + $event->addIps($this->ipPool->getIps()); + } } diff --git a/src/AsyncHandlerInterface.php b/src/AsyncHandlerInterface.php index c66ce8df..01a6a1fa 100644 --- a/src/AsyncHandlerInterface.php +++ b/src/AsyncHandlerInterface.php @@ -5,6 +5,7 @@ namespace Flow; use Flow\Event\AsyncEvent; +use Flow\Event\PoolEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -16,4 +17,9 @@ interface AsyncHandlerInterface extends EventSubscriberInterface * @param AsyncEvent $event */ public function async(AsyncEvent $event): void; + + /** + * @param PoolEvent $event + */ + public function pool(PoolEvent $event): void; } diff --git a/src/Driver/AmpDriver.php b/src/Driver/AmpDriver.php index c4b95b45..6bc8ea3b 100644 --- a/src/Driver/AmpDriver.php +++ b/src/Driver/AmpDriver.php @@ -34,6 +34,8 @@ */ class AmpDriver implements DriverInterface { + use DriverTrait; + private int $ticks = 0; public function __construct(?Driver $driver = null) @@ -109,30 +111,25 @@ public function await(array &$stream): void }; $loop = function () use (&$loop, &$stream, $async, $defer) { - $nextIp = null; - do { - foreach ($stream['dispatchers'] as $index => $dispatcher) { - $nextIp = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIp(); - if ($nextIp !== null) { - $job = $stream['fnFlows'][$index]['job']; - - $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $job, $nextIp, static function ($data) use (&$stream, $index, $nextIp) { - if ($data instanceof RuntimeException and array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { - $stream['fnFlows'][$index]['errorJob']($data); - } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { - $ip = new Ip($data); - $stream['ips']++; - $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); - } - - $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); - $stream['ips']--; - }), Event::ASYNC); - } + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $job = $stream['fnFlows'][$index]['job']; + + $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $job, $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } + + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); } - } while ($nextIp !== null); + } - if ($stream['ips'] > 0 or $this->ticks > 0) { + if ($this->countIps($stream['dispatchers']) > 0 || $this->ticks > 0) { EventLoop::defer($loop); } else { EventLoop::getDriver()->stop(); diff --git a/src/Driver/DriverTrait.php b/src/Driver/DriverTrait.php new file mode 100644 index 00000000..ee4c2233 --- /dev/null +++ b/src/Driver/DriverTrait.php @@ -0,0 +1,27 @@ + $dispatchers + */ + public function countIps(array $dispatchers): int + { + $count = 0; + foreach ($dispatchers as $dispatcher) { + $count += count($dispatcher->dispatch(new PoolEvent(), Event::POOL)->getIps()); + } + + return $count; + } +} diff --git a/src/Driver/FiberDriver.php b/src/Driver/FiberDriver.php index 451297fe..42f5af41 100644 --- a/src/Driver/FiberDriver.php +++ b/src/Driver/FiberDriver.php @@ -30,6 +30,8 @@ */ class FiberDriver implements DriverInterface { + use DriverTrait; + /** * @var array */ @@ -97,9 +99,9 @@ public function await(array &$stream): void }; }; - $defer = static function ($isTick) { - return static function (Closure|JobInterface $job) use ($isTick) { - return static function (Closure $next) use ($isTick, $job) { + $defer = static function ($isTick) use (&$fiberDatas) { + return static function (Closure|JobInterface $job) use ($isTick, &$fiberDatas) { + return static function (Closure $next) use ($isTick, $job, &$fiberDatas) { $fiber = new Fiber(static function () use ($isTick, $job, $next) { try { $job(static function ($return) use ($isTick, $next) { @@ -115,13 +117,22 @@ public function await(array &$stream): void }); $fiber->start(); + + $fiberDatas[] = [ + 'fiber' => $fiber, + 'next' => static function ($return) {}, /*function ($return) use ($isTick, $next) { + if ($isTick === false) { + $next($return); + } + },*/ + ]; }; }; }; $tick = 0; $fiberDatas = []; - while ($stream['ips'] > 0 or count($this->ticks) > 0) { + do { foreach ($this->ticks as [ 'interval' => $interval, 'callback' => $callback, @@ -132,30 +143,25 @@ public function await(array &$stream): void } } - $nextIp = null; - do { - foreach ($stream['dispatchers'] as $index => $dispatcher) { - $nextIp = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIp(); - if ($nextIp !== null) { - $stream['dispatchers'][$index]->dispatch(new AsyncEvent(static function (Closure|JobInterface $job) use ($async) { - return $async(false)($job); - }, static function (Closure|JobInterface $job) use ($defer) { - return $defer(false)($job); - }, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { - if ($data instanceof RuntimeException and array_key_exists($index, $stream['fnFlows']) and $stream['fnFlows'][$index]['errorJob'] !== null) { - $stream['fnFlows'][$index]['errorJob']($data); - } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { - $ip = new Ip($data); - $stream['ips']++; - $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); - } + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $stream['dispatchers'][$index]->dispatch(new AsyncEvent(static function (Closure|JobInterface $job) use ($async) { + return $async(false)($job); + }, static function (Closure|JobInterface $job) use ($defer) { + return $defer(false)($job); + }, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } - $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); - $stream['ips']--; - }), Event::ASYNC); - } + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); } - } while ($nextIp !== null); + } foreach ($fiberDatas as $i => $fiberData) { // @phpstan-ignore-line see https://github.com/phpstan/phpstan/issues/11468 if (!$fiberData['fiber']->isTerminated() and $fiberData['fiber']->isSuspended()) { @@ -168,7 +174,7 @@ public function await(array &$stream): void } $tick++; - } + } while ($this->countIps($stream['dispatchers']) > 0 or count($this->ticks) > 0); } public function delay(float $seconds): void diff --git a/src/Driver/ParallelDriver.php b/src/Driver/ParallelDriver.php new file mode 100644 index 00000000..9174a256 --- /dev/null +++ b/src/Driver/ParallelDriver.php @@ -0,0 +1,205 @@ + + */ +class ParallelDriver implements DriverInterface +{ + use DriverTrait; + + /** + * @var array + */ + private array $ticks = []; + + public function __construct() + { + if (!class_exists(Runtime::class)) { + throw new NativeRuntimeException('Parallel extension is not loaded. Suggest install it with pecl install parallel'); + } + } + + public function async(Closure|JobInterface $callback): Closure + { + return static function (...$args) use ($callback) { + $runtime = new Runtime('vendor/autoload.php'); + + return $runtime->run(static function () use ($callback, $args) { + try { + return $callback(...$args); + } catch (Throwable $exception) { + return new RuntimeException($exception->getMessage(), $exception->getCode(), $exception); + } + }); + }; + } + + public function defer(Closure $callback): mixed + { + $runtime = new Runtime('vendor/autoload.php'); + + return $runtime->run(static function () use ($callback) { + try { + $result = null; + $callback( + static function ($value) use (&$result) { + $result = $value; + }, + static function ($fn, $next) { + $fn($next); + } + ); + + return $result; + } catch (Throwable $exception) { + return new RuntimeException($exception->getMessage(), $exception->getCode(), $exception); + } + }); + } + + public function await(array &$stream): void + { + $async = function ($isTick) use (&$parallelDatas) { + return function (Closure|JobInterface $job) use (&$parallelDatas, $isTick) { + return function (mixed $data) use (&$parallelDatas, $isTick, $job) { + $async = $this->async($job); + + $parallel = $async($data); + + $next = static function ($return) {}; + + $parallelDatas[] = [ + 'parallel' => $parallel, + 'next' => static function ($return) use (&$next) { + $next($return); + }, + ]; + + return static function (Closure $callback) use ($isTick, &$next) { + if ($isTick === false) { + $next = static function ($return) use ($callback) { + $callback($return); + }; + } + }; + }; + }; + }; + + $defer = static function ($isTick) use (&$parallelDatas) { + return static function (Closure|JobInterface $job) use ($isTick, &$parallelDatas) { + return static function (Closure $next) use ($isTick, $job, &$parallelDatas) { + $parallel = new Runtime('vendor/autoload.php'); + $parallel->run(static function () use ($isTick, $job, $next) { + try { + $job(static function ($return) use ($isTick, $next) { + if ($isTick === false) { + $next($return); + } + }, static function ($fn, $next) { + $fn($next); + }); + } catch (Throwable $exception) { + return new RuntimeException($exception->getMessage(), $exception->getCode(), $exception); + } + }); + + $parallelDatas[] = [ + 'parallel' => $parallel, + 'next' => static function ($return) {}, /*function ($return) use ($isTick, $next) { + if ($isTick === false) { + $next($return); + } + },*/ + ]; + }; + }; + }; + + $tick = 0; + $parallelDatas = []; + do { + foreach ($this->ticks as [ + 'interval' => $interval, + 'callback' => $callback, + ]) { + if ($tick % $interval === 0) { + $ip = new Ip(); + $async(true)($callback)($ip->data); + } + } + + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $stream['dispatchers'][$index]->dispatch(new AsyncEvent(static function (Closure|JobInterface $job) use ($async) { + return $async(false)($job); + }, static function (Closure|JobInterface $job) use ($defer) { + return $defer(false)($job); + }, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } + + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); + } + } + + foreach ($parallelDatas as $i => $parallelData) { // @phpstan-ignore-line see https://github.com/phpstan/phpstan/issues/11468 + if ($parallelData['parallel']->done()) { + $data = $parallelData['parallel']->value(); + $parallelData['next']($data); + unset($parallelDatas[$i]); + } + } + + $tick++; + } while ($this->countIps($stream['dispatchers']) > 0 or count($this->ticks) > 0); + } + + public function delay(float $seconds): void + { + sleep((int) $seconds); + } + + public function tick($interval, Closure $callback): Closure + { + $i = count($this->ticks) - 1; + $this->ticks[$i] = [ + 'interval' => $interval, + 'callback' => $callback, + ]; + + return function () use ($i) { + unset($this->ticks[$i]); + }; + } +} diff --git a/src/Driver/ReactDriver.php b/src/Driver/ReactDriver.php index 0d016563..0cb6ba81 100644 --- a/src/Driver/ReactDriver.php +++ b/src/Driver/ReactDriver.php @@ -34,6 +34,8 @@ */ class ReactDriver implements DriverInterface { + use DriverTrait; + private int $ticks = 0; private LoopInterface $eventLoop; @@ -102,30 +104,25 @@ public function await(array &$stream): void }; $loop = function () use (&$loop, &$stream, $async, $defer) { - $nextIp = null; - do { - foreach ($stream['dispatchers'] as $index => $dispatcher) { - $nextIp = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIp(); - if ($nextIp !== null) { - $job = $stream['fnFlows'][$index]['job']; - - $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $job, $nextIp, static function ($data) use (&$stream, $index, $nextIp) { - if ($data instanceof RuntimeException and array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { - $stream['fnFlows'][$index]['errorJob']($data); - } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { - $ip = new Ip($data); - $stream['ips']++; - $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); - } - - $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); - $stream['ips']--; - }), Event::ASYNC); - } + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $job = $stream['fnFlows'][$index]['job']; + + $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $job, $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } + + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); } - } while ($nextIp !== null); + } - if ($stream['ips'] > 0 or $this->ticks > 0) { + if ($this->countIps($stream['dispatchers']) > 0 || $this->ticks > 0) { $this->eventLoop->futureTick($loop); } else { $this->eventLoop->stop(); diff --git a/src/Driver/SpatieDriver.php b/src/Driver/SpatieDriver.php index b008e5d2..61765b3a 100644 --- a/src/Driver/SpatieDriver.php +++ b/src/Driver/SpatieDriver.php @@ -30,6 +30,8 @@ */ class SpatieDriver implements DriverInterface { + use DriverTrait; + private int $ticks = 0; private Pool $pool; @@ -88,28 +90,23 @@ public function await(array &$stream): void }; }; - $nextIp = null; - while ($stream['ips'] > 0 or $this->ticks > 0) { - do { - foreach ($stream['dispatchers'] as $index => $dispatcher) { - $nextIp = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIp(); - if ($nextIp !== null) { - $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { - if ($data instanceof RuntimeException and array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { - $stream['fnFlows'][$index]['errorJob']($data); - } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { - $ip = new Ip($data); - $stream['ips']++; - $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); - } - - $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); - $stream['ips']--; - }), Event::ASYNC); - } + do { + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } + + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); } - } while ($nextIp !== null); - } + } + } while ($this->countIps($stream['dispatchers']) > 0 or $this->ticks > 0); } public function delay(float $seconds): void diff --git a/src/Driver/SwooleDriver.php b/src/Driver/SwooleDriver.php index 413c99dd..4b4fa75f 100644 --- a/src/Driver/SwooleDriver.php +++ b/src/Driver/SwooleDriver.php @@ -30,6 +30,8 @@ */ class SwooleDriver implements DriverInterface { + use DriverTrait; + private int $ticks = 0; public function __construct() @@ -85,29 +87,24 @@ public function await(array &$stream): void }; co::run(function () use (&$stream, $async, $defer) { - while ($stream['ips'] > 0 or $this->ticks > 0) { - $nextIp = null; - do { - foreach ($stream['dispatchers'] as $index => $dispatcher) { - $nextIp = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIp(); - if ($nextIp !== null) { - $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { - if ($data instanceof RuntimeException and array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { - $stream['fnFlows'][$index]['errorJob']($data); - } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { - $ip = new Ip($data); - $stream['ips']++; - $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); - } - - $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); - $stream['ips']--; - }), Event::ASYNC); - } + do { + foreach ($stream['dispatchers'] as $index => $dispatcher) { + $nextIps = $dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($nextIps as $nextIp) { + $stream['dispatchers'][$index]->dispatch(new AsyncEvent($async, $defer, $stream['fnFlows'][$index]['job'], $nextIp, static function ($data) use (&$stream, $index, $nextIp) { + if ($data instanceof RuntimeException && array_key_exists($index, $stream['fnFlows']) && $stream['fnFlows'][$index]['errorJob'] !== null) { + $stream['fnFlows'][$index]['errorJob']($data); + } elseif (array_key_exists($index + 1, $stream['fnFlows'])) { + $ip = new Ip($data); + $stream['dispatchers'][$index + 1]->dispatch(new PushEvent($ip), Event::PUSH); + } + + $stream['dispatchers'][$index]->dispatch(new PopEvent($nextIp), Event::POP); + }), Event::ASYNC); } - co::sleep(1); - } while ($nextIp !== null); - } + } + co::sleep(1); + } while ($this->countIps($stream['dispatchers']) > 0 or $this->ticks > 0); }); } diff --git a/src/DriverInterface.php b/src/DriverInterface.php index 69a588b7..be3b8db4 100644 --- a/src/DriverInterface.php +++ b/src/DriverInterface.php @@ -30,7 +30,9 @@ public function async(Closure|JobInterface $callback): Closure; public function defer(Closure $callback): mixed; /** - * @param array{'ips': int, 'fnFlows': array, 'dispatchers': array} $stream + * Waits for all asynchronous operations in the stream to complete and rolls back to synchronous execution. + * + * @param array{'fnFlows': array, 'dispatchers': array} $stream The stream containing asynchronous operations to await */ public function await(array &$stream): void; diff --git a/src/Event.php b/src/Event.php index c8a8a02b..560597e4 100644 --- a/src/Event.php +++ b/src/Event.php @@ -27,7 +27,7 @@ final class Event /** * The PULL event occurs when Flow need a next IP to async process. * - * This event allows you to choose what IP come next from your pushed IPs and will be used for async process execution. + * This event allows you to choose what IPs come next from your pushed IPs and will be used for async process execution. * * @Event("Flow\Event\PullEvent") */ @@ -41,4 +41,13 @@ final class Event * @Event("Flow\Event\PopEvent") */ public const POP = 'pop'; + + /** + * The POOL event occurs when Flow need to get the pool IPs to process. + * + * This event allows you to get the pool IPs to process. + * + * @Event("Flow\Event\PoolEvent") + */ + public const POOL = 'pool'; } diff --git a/src/Event/PoolEvent.php b/src/Event/PoolEvent.php new file mode 100644 index 00000000..bedf7860 --- /dev/null +++ b/src/Event/PoolEvent.php @@ -0,0 +1,43 @@ + + */ + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } + + /** + * @param array> $ips + */ + public function addIps(array $ips): void + { + foreach ($ips as $ip) { + $this->ipPool->addIp($ip); + } + } + + /** + * @return array> + */ + public function getIps(): array + { + return $this->ipPool->getIps(); + } +} diff --git a/src/Event/PullEvent.php b/src/Event/PullEvent.php index f9c429fa..e401542a 100644 --- a/src/Event/PullEvent.php +++ b/src/Event/PullEvent.php @@ -5,6 +5,7 @@ namespace Flow\Event; use Flow\Ip; +use Flow\IpPool; use Symfony\Contracts\EventDispatcher\Event; /** @@ -13,23 +14,28 @@ final class PullEvent extends Event { /** - * @var null|Ip + * @var IpPool */ - private ?Ip $ip = null; + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } /** - * @return null|Ip + * @return Ip[] */ - public function getIp(): ?Ip + public function getIps(): array { - return $this->ip; + return $this->ipPool->getIps(); } /** - * @param null|Ip $ip + * @param Ip $ip */ - public function setIp(?Ip $ip): void + public function addIp(Ip $ip): void { - $this->ip = $ip; + $this->ipPool->addIp($ip); } } diff --git a/src/Flow/Flow.php b/src/Flow/Flow.php index 511bd24a..5730fad0 100644 --- a/src/Flow/Flow.php +++ b/src/Flow/Flow.php @@ -11,20 +11,16 @@ use Flow\DriverInterface; use Flow\Event; use Flow\Event\PushEvent; -use Flow\Exception\LogicException; use Flow\ExceptionInterface; +use Flow\FlowFactory; use Flow\FlowInterface; use Flow\Ip; use Flow\IpStrategy\LinearIpStrategy; use Flow\IpStrategyInterface; use Flow\JobInterface; -use Generator; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use function array_key_exists; -use function is_array; - /** * @template T1 * @template T2 @@ -37,7 +33,6 @@ class Flow implements FlowInterface * @var array */ private array $stream = [ - 'ips' => 0, 'fnFlows' => [], 'dispatchers' => [], ]; @@ -89,42 +84,12 @@ public function __construct( public function __invoke(Ip $ip): void { - $this->stream['ips']++; $this->stream['dispatchers'][0]->dispatch(new PushEvent($ip), Event::PUSH); } - public static function do(callable $callable, ?array $config = null): FlowInterface - { - /** - * @var Closure|Generator $generator - */ - $generator = $callable(); - - if ($generator instanceof Generator) { - $flows = []; - - while ($generator->valid()) { - $flow = self::flowUnwrap($generator->current(), $config); - - $generator->send($flow); - - $flows[] = $flow; - } - - $return = $generator->getReturn(); - if (!empty($return)) { - $flows[] = self::flowUnwrap($return, $config); - } - - return self::flowMap($flows); - } - - return self::flowUnwrap($generator, $config); - } - public function fn(array|Closure|FlowInterface|JobInterface $flow): FlowInterface { - $flow = self::flowUnwrap($flow, ['driver' => $this->driver]); + $flow = (new FlowFactory($this->driver))->createFlow($flow); $this->stream['fnFlows'][] = [ 'job' => $flow->job, @@ -139,59 +104,4 @@ public function await(): void { $this->driver->await($this->stream); } - - /** - * @param array|Closure|FlowInterface $flow - * @param ?array $config - * - * @return Flow - * - * #param ?array{ - * 0: Closure, - * 1?: Closure, - * 2?: IpStrategyInterface, - * 3?: EventDispatcherInterface, - * 4?: AsyncHandlerInterface, - * 5?: DriverInterface - * }|array{ - * "ipStrategy"?: IpStrategyInterface, - * "dispatcher"?: EventDispatcherInterface, - * "asyncHandler"?: AsyncHandlerInterface, - * "driver"?: DriverInterface - * } $config - */ - private static function flowUnwrap($flow, ?array $config = null): FlowInterface - { - if ($flow instanceof Closure || $flow instanceof JobInterface) { - return new self(...[...['job' => $flow], ...($config ?? [])]); - } - if (is_array($flow)) { - if (array_key_exists(0, $flow) || array_key_exists('job', $flow)) { - return new self(...[...$flow, ...($config ?? [])]); - } - - return self::flowMap($flow); - } - - return $flow; - } - - /** - * @param array> $flows - * - * @return FlowInterface - */ - private static function flowMap(array $flows) - { - $flow = array_shift($flows); - if (null === $flow) { - throw new LogicException('Flow is empty'); - } - - foreach ($flows as $flowIt) { - $flow = $flow->fn($flowIt); - } - - return $flow; - } } diff --git a/src/Flow/FlowDecorator.php b/src/Flow/FlowDecorator.php index f91e7bb3..72d335f8 100644 --- a/src/Flow/FlowDecorator.php +++ b/src/Flow/FlowDecorator.php @@ -32,11 +32,6 @@ public function fn(array|Closure|FlowInterface|JobInterface $flow): FlowInterfac return $this->flow->fn($flow); } - public static function do(callable $callable, ?array $config = null): FlowInterface - { - return Flow::do($callable, $config); - } - public function await(): void { $this->flow->await(); diff --git a/src/FlowFactory.php b/src/FlowFactory.php new file mode 100644 index 00000000..82ca7a38 --- /dev/null +++ b/src/FlowFactory.php @@ -0,0 +1,156 @@ + $driver + */ + public function __construct( + private ?DriverInterface $driver = null + ) {} + + /** + * Do-notation a.k.a. for-comprehension. + * + * Syntax sugar for sequential {@see FlowInterface::fn()} calls + * + * Syntax "$flow = yield $wrapedFlow" mean: + * 1) $wrapedFlow can be Closure as Job, array constructor arguments for Flow instanciation, array configuration for Flow instanciation or FlowInterface instance + * 2) $flow is assigned as FlowInterface instance + * 3) optionnaly you can return another wrapedFlow + * + * ```php + * $flow = (new FlowFactory())->create(static function() { + * yield new Flow(fn($a) => $a + 1); + * $flow = yield fn($b) => $b * 2; + * $flow = yield $flow->fn([fn($c) => $c * 4]) + * return [$flow, [fn($d) => $d - 8]]; + * }); + * ``` + * $config if provided will be the fallback array configuration for Flow instanciation + * + * @param callable(): Generator|Closure $callable + * @param ?array $config + * + * #param ?array{ + * 0: Closure|array, + * 1?: Closure|array, + * 2?: IpStrategyInterface, + * 3?: EventDispatcherInterface, + * 4?: AsyncHandlerInterface, + * 5?: DriverInterface + * }|array{ + * "jobs"?: JobInterface|Closure|array, + * "errorJobs"?: JobInterface|Closure|array, + * "ipStrategy"?: IpStrategyInterface, + * "dispatcher"?: EventDispatcherInterface, + * "asyncHandler"?: AsyncHandlerInterface, + * "driver"?: DriverInterface + * } $config + * + * @return FlowInterface + */ + public function create(callable $callable, ?array $config = null): FlowInterface + { + /** + * @var Closure|Generator $generator + */ + $generator = $callable(); + + if ($generator instanceof Generator) { + return $this->createFromGenerator($generator, $config); + } + + return $this->createFlow($generator, $config); + } + + /** + * @param array|Closure|FlowInterface $flow + * @param ?array $config + * + * @return Flow + * + * #param ?array{ + * 0: Closure, + * 1?: Closure, + * 2?: IpStrategyInterface, + * 3?: EventDispatcherInterface, + * 4?: AsyncHandlerInterface, + * 5?: DriverInterface + * }|array{ + * "ipStrategy"?: IpStrategyInterface, + * "dispatcher"?: EventDispatcherInterface, + * "asyncHandler"?: AsyncHandlerInterface, + * "driver"?: DriverInterface + * } $config + */ + public function createFlow($flow, ?array $config = null): Flow + { + if ($flow instanceof Closure || $flow instanceof JobInterface) { + return new Flow(...[...['job' => $flow, 'driver' => $this->driver], ...($config ?? [])]); + } + if (is_array($flow)) { + if (array_key_exists(0, $flow) || array_key_exists('job', $flow)) { + return new Flow(...[...$flow, ...['driver' => $this->driver], ...($config ?? [])]); + } + + return $this->createFlowMap($flow); + } + + return $flow; + } + + /** + * @param ?array $config + * + * @return FlowInterface + */ + private function createFromGenerator(Generator $generator, ?array $config = null): FlowInterface + { + $flows = []; + + while ($generator->valid()) { + $flow = $this->createFlow($generator->current(), $config); + $generator->send($flow); + $flows[] = $flow; + } + + $return = $generator->getReturn(); + if (!empty($return)) { + $flows[] = $this->createFlow($return, $config); + } + + return $this->createFlowMap($flows); + } + + /** + * @param array> $flows + * + * @return Flow + */ + private function createFlowMap(array $flows): Flow + { + $flow = array_shift($flows); + if (null === $flow) { + throw new LogicException('Flow is empty'); + } + + foreach ($flows as $flowIt) { + $flow = $flow->fn($flowIt); + } + + return $flow; + } +} diff --git a/src/FlowInterface.php b/src/FlowInterface.php index 6f27a20c..f718994b 100644 --- a/src/FlowInterface.php +++ b/src/FlowInterface.php @@ -5,7 +5,6 @@ namespace Flow; use Closure; -use Generator; /** * @template T1 @@ -37,49 +36,6 @@ public function __invoke(Ip $ip): void; */ public function fn(array|Closure|JobInterface|self $flow): self; - /** - * Do-notation a.k.a. for-comprehension. - * - * Syntax sugar for sequential {@see FlowInterface::fn()} calls - * - * Syntax "$flow = yield $wrapedFlow" mean: - * 1) $wrapedFlow can be Closure as Job, array constructor arguments for Flow instanciation, array configuration for Flow instanciation or FlowInterface instance - * 2) $flow is assigned as FlowInterface instance - * 3) optionnaly you can return another wrapedFlow - * - * ```php - * $flow = Flow::do(static function() { - * yield new Flow(fn($a) => $a + 1); - * $flow = yield fn($b) => $b * 2; - * $flow = yield $flow->fn([fn($c) => $c * 4]) - * return [$flow, [fn($d) => $d - 8]]; - * }); - * ``` - * $config if provided will be the fallback array configuration for Flow instanciation - * - * @param callable(): Generator|Closure $callable - * @param ?array $config - * - * #param ?array{ - * 0: Closure|array, - * 1?: Closure|array, - * 2?: IpStrategyInterface, - * 3?: EventDispatcherInterface, - * 4?: AsyncHandlerInterface, - * 5?: DriverInterface - * }|array{ - * "jobs"?: JobInterface|Closure|array, - * "errorJobs"?: JobInterface|Closure|array, - * "ipStrategy"?: IpStrategyInterface, - * "dispatcher"?: EventDispatcherInterface, - * "asyncHandler"?: AsyncHandlerInterface, - * "driver"?: DriverInterface - * } $config - * - * @return FlowInterface - */ - public static function do(callable $callable, ?array $config = null): self; - /** * Await asynchonous call for current IPs. * After await, all IPs have been proceed, it continues synchronously. diff --git a/src/IpPool.php b/src/IpPool.php new file mode 100644 index 00000000..0ee63c5a --- /dev/null +++ b/src/IpPool.php @@ -0,0 +1,56 @@ +> + */ + private array $ips = []; + + /** + * @param Ip $ip + * + * @return callable A function that removes the added IP from the pool when called + */ + public function addIp(Ip $ip): callable + { + $this->ips[] = $ip; + + return function () use ($ip) { + $this->ips = array_filter($this->ips, static function ($iteratorIp) use ($ip) { + return $iteratorIp !== $ip; + }); + }; + } + + /** + * @return array> + */ + public function getIps(): array + { + return $this->ips; + } + + /** + * @return null|Ip + */ + public function shiftIp(): ?Ip + { + return array_shift($this->ips); + } + + /** + * @return null|Ip + */ + public function popIp(): ?Ip + { + return array_pop($this->ips); + } +} diff --git a/src/IpStrategy/LinearIpStrategy.php b/src/IpStrategy/LinearIpStrategy.php index 775df2b1..133536d6 100644 --- a/src/IpStrategy/LinearIpStrategy.php +++ b/src/IpStrategy/LinearIpStrategy.php @@ -5,9 +5,10 @@ namespace Flow\IpStrategy; use Flow\Event; +use Flow\Event\PoolEvent; use Flow\Event\PullEvent; use Flow\Event\PushEvent; -use Flow\Ip; +use Flow\IpPool; use Flow\IpStrategyInterface; /** @@ -18,15 +19,21 @@ class LinearIpStrategy implements IpStrategyInterface { /** - * @var array> + * @var IpPool */ - private array $ips = []; + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } public static function getSubscribedEvents(): array { return [ Event::PUSH => 'push', Event::PULL => 'pull', + Event::POOL => 'pool', ]; } @@ -35,7 +42,7 @@ public static function getSubscribedEvents(): array */ public function push(PushEvent $event): void { - $this->ips[] = $event->getIp(); + $this->ipPool->addIp($event->getIp()); } /** @@ -43,6 +50,14 @@ public function push(PushEvent $event): void */ public function pull(PullEvent $event): void { - $event->setIp(array_shift($this->ips)); + $ip = $this->ipPool->shiftIp(); + if ($ip !== null) { + $event->addIp($ip); + } + } + + public function pool(PoolEvent $event): void + { + $event->addIps($this->ipPool->getIps()); } } diff --git a/src/IpStrategy/MaxIpStrategy.php b/src/IpStrategy/MaxIpStrategy.php index e3238399..f789a1af 100644 --- a/src/IpStrategy/MaxIpStrategy.php +++ b/src/IpStrategy/MaxIpStrategy.php @@ -5,6 +5,7 @@ namespace Flow\IpStrategy; use Flow\Event; +use Flow\Event\PoolEvent; use Flow\Event\PopEvent; use Flow\Event\PullEvent; use Flow\Event\PushEvent; @@ -47,6 +48,7 @@ public static function getSubscribedEvents() Event::PUSH => 'push', Event::PULL => 'pull', Event::POP => 'pop', + Event::POOL => 'pool', ]; } @@ -63,13 +65,14 @@ public function push(PushEvent $event): void */ public function pull(PullEvent $event): void { - if ($this->processing < $this->max) { - $ip = $this->dispatcher->dispatch($event, Event::PULL)->getIp(); - if ($ip) { + $ips = $this->dispatcher->dispatch(new PullEvent(), Event::PULL)->getIps(); + foreach ($ips as $ip) { + if ($this->processing < $this->max) { $this->processing++; + $event->addIp($ip); + } else { + $this->dispatcher->dispatch(new PushEvent($ip), Event::PUSH); } - - $event->setIp($ip); } } @@ -81,4 +84,9 @@ public function pop(PopEvent $event): void $this->dispatcher->dispatch($event, Event::POP); $this->processing--; } + + public function pool(PoolEvent $event): void + { + $event->addIps($this->dispatcher->dispatch($event, Event::POOL)->getIps()); + } } diff --git a/src/IpStrategy/StackIpStrategy.php b/src/IpStrategy/StackIpStrategy.php index af2c506d..132573fe 100644 --- a/src/IpStrategy/StackIpStrategy.php +++ b/src/IpStrategy/StackIpStrategy.php @@ -5,9 +5,10 @@ namespace Flow\IpStrategy; use Flow\Event; +use Flow\Event\PoolEvent; use Flow\Event\PullEvent; use Flow\Event\PushEvent; -use Flow\Ip; +use Flow\IpPool; use Flow\IpStrategyInterface; /** @@ -18,15 +19,21 @@ class StackIpStrategy implements IpStrategyInterface { /** - * @var array> + * @var IpPool */ - private array $ips = []; + private IpPool $ipPool; + + public function __construct() + { + $this->ipPool = new IpPool(); + } public static function getSubscribedEvents() { return [ Event::PUSH => 'push', Event::PULL => 'pull', + Event::POOL => 'pool', ]; } @@ -35,7 +42,7 @@ public static function getSubscribedEvents() */ public function push(PushEvent $event): void { - $this->ips[] = $event->getIp(); + $this->ipPool->addIp($event->getIp()); } /** @@ -43,6 +50,14 @@ public function push(PushEvent $event): void */ public function pull(PullEvent $event): void { - $event->setIp(array_pop($this->ips)); + $ip = $this->ipPool->popIp(); + if ($ip !== null) { + $event->addIp($ip); + } + } + + public function pool(PoolEvent $event): void + { + $event->addIps($this->ipPool->getIps()); } } diff --git a/src/IpStrategyInterface.php b/src/IpStrategyInterface.php index 1953c285..13e106fe 100644 --- a/src/IpStrategyInterface.php +++ b/src/IpStrategyInterface.php @@ -4,9 +4,16 @@ namespace Flow; +use Flow\Event\PoolEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @template T */ -interface IpStrategyInterface extends EventSubscriberInterface {} +interface IpStrategyInterface extends EventSubscriberInterface +{ + /** + * @param PoolEvent $event + */ + public function pool(PoolEvent $event): void; +} diff --git a/tests/AsyncHandler/AsyncHandlerTest.php b/tests/AsyncHandler/AsyncHandlerTest.php index a1f6cf78..6bddb264 100644 --- a/tests/AsyncHandler/AsyncHandlerTest.php +++ b/tests/AsyncHandler/AsyncHandlerTest.php @@ -24,8 +24,8 @@ static function ($data) use (&$result) { [$n1, $n2] = $data; $result = $n1 + $n2; - return static function ($callback) { - $callback(); + return static function ($callback) use ($result) { + $callback($result); }; }, new Ip([2, 6]), diff --git a/tests/AsyncHandler/BatchAsyncHandlerTest.php b/tests/AsyncHandler/BatchAsyncHandlerTest.php index bc2bad52..5ec6d01f 100644 --- a/tests/AsyncHandler/BatchAsyncHandlerTest.php +++ b/tests/AsyncHandler/BatchAsyncHandlerTest.php @@ -24,8 +24,8 @@ static function ($data) use (&$result1) { [$n1, $n2] = $data; $result1 = $n1 + $n2; - return static function ($callback) { - $callback(); + return static function ($callback) use ($result1) { + $callback($result1); }; }, new Ip([2, 6]), @@ -41,8 +41,8 @@ static function ($data) use (&$result2) { [$n1, $n2] = $data; $result2 = $n1 + $n2; - return static function ($callback) { - $callback(); + return static function ($callback) use ($result2) { + $callback($result2); }; }, new Ip([6, 10]), diff --git a/tests/Flow/FlowTest.php b/tests/Flow/FlowTest.php index e3c01491..c642c12a 100644 --- a/tests/Flow/FlowTest.php +++ b/tests/Flow/FlowTest.php @@ -14,6 +14,7 @@ use Flow\DriverInterface; use Flow\ExceptionInterface; use Flow\Flow\Flow; +use Flow\FlowFactory; use Flow\Ip; use Flow\IpStrategy\MaxIpStrategy; use Flow\Job\ClosureJob; @@ -124,7 +125,7 @@ static function (ExceptionInterface $exception) use ($cancel) { public function testDo(DriverInterface $driver, callable $callable, ?array $config, int $resultNumber): void { $ip = new Ip(new ArrayObject(['number' => 0])); - $flow = Flow::do($callable, [ + $flow = (new FlowFactory())->create($callable, [ ...['driver' => $driver], ...($config ?? []), ])->fn(static function (ArrayObject $data) use ($resultNumber) { diff --git a/tests/IpStrategy/LinearIpStrategyTest.php b/tests/IpStrategy/LinearIpStrategyTest.php index 10e44a07..ea5d6b22 100644 --- a/tests/IpStrategy/LinearIpStrategyTest.php +++ b/tests/IpStrategy/LinearIpStrategyTest.php @@ -23,16 +23,16 @@ public function testStrategy(): void $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNotNull($pullEvent->getIp()); - self::assertSame($ip1, $pullEvent->getIp()); + self::assertNotEmpty($pullEvent->getIps()); + self::assertSame($ip1, $pullEvent->getIps()[0]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNotNull($pullEvent->getIp()); - self::assertSame($ip2, $pullEvent->getIp()); + self::assertNotEmpty($pullEvent->getIps()); + self::assertSame($ip2, $pullEvent->getIps()[0]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNull($pullEvent->getIp()); + self::assertEmpty($pullEvent->getIps()); } } diff --git a/tests/IpStrategy/MaxIpStrategyTest.php b/tests/IpStrategy/MaxIpStrategyTest.php index 0ccb61c4..7363be3c 100644 --- a/tests/IpStrategy/MaxIpStrategyTest.php +++ b/tests/IpStrategy/MaxIpStrategyTest.php @@ -27,24 +27,24 @@ public function testStrategy(int $doneIndex): void $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - $ips[] = $pullEvent->getIp(); + $ips[] = $pullEvent->getIps()[0] ?? null; self::assertNotNull($ips[0]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - $ips[] = $pullEvent->getIp(); + $ips[] = $pullEvent->getIps()[0] ?? null; self::assertNotNull($ips[1]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - $ips[] = $pullEvent->getIp(); + $ips[] = $pullEvent->getIps()[0] ?? null; self::assertNull($ips[2]); $strategy->pop(new PopEvent($ips[$doneIndex])); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - $ips[] = $pullEvent->getIp(); + $ips[] = $pullEvent->getIps()[0] ?? null; self::assertNotNull($ips[3]); } diff --git a/tests/IpStrategy/StackIpStrategyTest.php b/tests/IpStrategy/StackIpStrategyTest.php index e3b72a60..738e5cdc 100644 --- a/tests/IpStrategy/StackIpStrategyTest.php +++ b/tests/IpStrategy/StackIpStrategyTest.php @@ -23,16 +23,16 @@ public function testStrategy(): void $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNotNull($pullEvent->getIp()); - self::assertSame($ip2, $pullEvent->getIp()); + self::assertNotEmpty($pullEvent->getIps()); + self::assertSame($ip2, $pullEvent->getIps()[0]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNotNull($pullEvent->getIp()); - self::assertSame($ip1, $pullEvent->getIp()); + self::assertNotEmpty($pullEvent->getIps()); + self::assertSame($ip1, $pullEvent->getIps()[0]); $pullEvent = new PullEvent(); $strategy->pull($pullEvent); - self::assertNull($pullEvent->getIp()); + self::assertEmpty($pullEvent->getIps()); } } diff --git a/tools/.gitignore b/tools/.gitignore index 8a78ca5a..2d57ab66 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1 +1 @@ -/.castor.stub.php \ No newline at end of file +/.castor.stub.php diff --git a/tools/dev/Dockerfile b/tools/dev/Dockerfile index 3421511d..3a588d55 100644 --- a/tools/dev/Dockerfile +++ b/tools/dev/Dockerfile @@ -1,6 +1,7 @@ # syntax=docker/dockerfile:1.6.0 -FROM php:8.3-fpm-alpine as php +#FROM php:8.3-fpm-alpine as php +FROM php:8.3-zts-alpine as php RUN apk add --update make curl @@ -18,8 +19,10 @@ RUN set -eux; \ pcntl \ pcov \ zip \ + parallel \ ; WORKDIR /flow -CMD ["php-fpm"] +#CMD ["php-fpm"] +CMD ["tail", "-f", "/dev/null"] diff --git a/tools/dev/docker-compose.yml b/tools/dev/docker-compose.yml index 3aad6efd..66bbeada 100644 --- a/tools/dev/docker-compose.yml +++ b/tools/dev/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: php: image: flow-php diff --git a/tools/phpcbf/phpcs.xml b/tools/phpcbf/phpcs.xml index 535dc3ae..9952c9e5 100644 --- a/tools/phpcbf/phpcs.xml +++ b/tools/phpcbf/phpcs.xml @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/tools/phpcs/phpcs.xml b/tools/phpcs/phpcs.xml index 535dc3ae..9952c9e5 100644 --- a/tools/phpcs/phpcs.xml +++ b/tools/phpcs/phpcs.xml @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/tools/phpmd/phpmd.xml b/tools/phpmd/phpmd.xml index 56f4c07b..24047182 100644 --- a/tools/phpmd/phpmd.xml +++ b/tools/phpmd/phpmd.xml @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/tools/phpstan/composer.json b/tools/phpstan/composer.json index b0db540c..a90b5642 100644 --- a/tools/phpstan/composer.json +++ b/tools/phpstan/composer.json @@ -7,8 +7,8 @@ "require-dev": { "amphp/amp": "^3.0", "openswoole/ide-helper": "^22.1.5", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^10.3", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^11.4", "react/async": "^4.3", "spatie/async": "^1.6", "symfony/doctrine-messenger": "^7.0", diff --git a/tools/phpstan/composer.lock b/tools/phpstan/composer.lock index d046e1be..3dc228ae 100644 --- a/tools/phpstan/composer.lock +++ b/tools/phpstan/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "465b0e63ca162f292e63dcba1bc58727", + "content-hash": "250dd2dd03dfe2e446c3aa0aa41fe5e0", "packages": [ { "name": "psr/clock", @@ -106,16 +106,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -150,9 +150,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "symfony/clock", @@ -386,16 +386,16 @@ }, { "name": "symfony/messenger", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/messenger.git", - "reference": "604e182a7758ceea35921a8ad5dd492a6e13bae4" + "reference": "e1c0ced845e3dac12ab428c5ed42dbe7a58ca576" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/messenger/zipball/604e182a7758ceea35921a8ad5dd492a6e13bae4", - "reference": "604e182a7758ceea35921a8ad5dd492a6e13bae4", + "url": "https://api.github.com/repos/symfony/messenger/zipball/e1c0ced845e3dac12ab428c5ed42dbe7a58ca576", + "reference": "e1c0ced845e3dac12ab428c5ed42dbe7a58ca576", "shasum": "" }, "require": { @@ -452,7 +452,7 @@ "description": "Helps applications send and receive messages to/from other applications or via message queues", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/messenger/tree/v7.1.3" + "source": "https://github.com/symfony/messenger/tree/v7.1.5" }, "funding": [ { @@ -468,24 +468,24 @@ "type": "tidelift" } ], - "time": "2024-07-09T19:36:07+00:00" + "time": "2024-09-08T12:32:26+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", - "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -528,7 +528,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" }, "funding": [ { @@ -544,7 +544,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:35:24+00:00" + "time": "2024-09-09T11:45:10+00:00" } ], "packages-dev": [ @@ -810,16 +810,16 @@ }, { "name": "doctrine/dbal", - "version": "3.8.6", + "version": "3.9.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "b7411825cf7efb7e51f9791dea19d86e43b399a1" + "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/b7411825cf7efb7e51f9791dea19d86e43b399a1", - "reference": "b7411825cf7efb7e51f9791dea19d86e43b399a1", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", + "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", "shasum": "" }, "require": { @@ -835,12 +835,12 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.11.5", + "phpstan/phpstan": "1.12.6", "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "9.6.19", + "phpunit/phpunit": "9.6.20", "psalm/plugin-phpunit": "0.18.4", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.10.1", + "squizlabs/php_codesniffer": "3.10.2", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/console": "^4.4|^5.4|^6.0|^7.0", "vimeo/psalm": "4.30.0" @@ -903,7 +903,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.8.6" + "source": "https://github.com/doctrine/dbal/tree/3.9.3" }, "funding": [ { @@ -919,7 +919,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T10:38:17+00:00" + "time": "2024-10-10T17:56:43+00:00" }, { "name": "doctrine/deprecations", @@ -970,16 +970,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.12.0", + "version": "2.13.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "5418e811a14724068e95e0ba43353b903ada530f" + "reference": "ca59d84b8e63143ce1aed90cdb333ba329d71563" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/5418e811a14724068e95e0ba43353b903ada530f", - "reference": "5418e811a14724068e95e0ba43353b903ada530f", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/ca59d84b8e63143ce1aed90cdb333ba329d71563", + "reference": "ca59d84b8e63143ce1aed90cdb333ba329d71563", "shasum": "" }, "require": { @@ -1070,7 +1070,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.12.0" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.13.0" }, "funding": [ { @@ -1086,7 +1086,7 @@ "type": "tidelift" } ], - "time": "2024-03-19T07:20:37+00:00" + "time": "2024-09-01T09:46:40+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -1511,16 +1511,16 @@ }, { "name": "doctrine/migrations", - "version": "3.8.0", + "version": "3.8.2", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "535a70dcbd88b8c6ba945be050977457f4f4c06c" + "reference": "5007eb1168691225ac305fe16856755c20860842" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/535a70dcbd88b8c6ba945be050977457f4f4c06c", - "reference": "535a70dcbd88b8c6ba945be050977457f4f4c06c", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/5007eb1168691225ac305fe16856755c20860842", + "reference": "5007eb1168691225ac305fe16856755c20860842", "shasum": "" }, "require": { @@ -1543,6 +1543,7 @@ "doctrine/persistence": "^2 || ^3", "doctrine/sql-formatter": "^1.0", "ext-pdo_sqlite": "*", + "fig/log-test": "^1", "phpstan/phpstan": "^1.10", "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-phpunit": "^1.3", @@ -1593,7 +1594,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.8.0" + "source": "https://github.com/doctrine/migrations/tree/3.8.2" }, "funding": [ { @@ -1609,20 +1610,20 @@ "type": "tidelift" } ], - "time": "2024-06-26T14:12:46+00:00" + "time": "2024-10-10T21:35:27+00:00" }, { "name": "doctrine/orm", - "version": "3.2.1", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "722cea6536775206e81744542b36fa7c9a4ea3e5" + "reference": "69958152e661aa9c14e80d1ee4962863485aa60b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/722cea6536775206e81744542b36fa7c9a4ea3e5", - "reference": "722cea6536775206e81744542b36fa7c9a4ea3e5", + "url": "https://api.github.com/repos/doctrine/orm/zipball/69958152e661aa9c14e80d1ee4962863485aa60b", + "reference": "69958152e661aa9c14e80d1ee4962863485aa60b", "shasum": "" }, "require": { @@ -1644,7 +1645,10 @@ "require-dev": { "doctrine/coding-standard": "^12.0", "phpbench/phpbench": "^1.0", - "phpstan/phpstan": "1.11.1", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "1.12.6", + "phpstan/phpstan-deprecation-rules": "^1.2", "phpunit/phpunit": "^10.4.0", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", @@ -1695,9 +1699,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.2.1" + "source": "https://github.com/doctrine/orm/tree/3.3.0" }, - "time": "2024-06-26T21:48:58+00:00" + "time": "2024-10-12T20:07:18+00:00" }, { "name": "doctrine/persistence", @@ -1798,16 +1802,16 @@ }, { "name": "doctrine/sql-formatter", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "7f83911cc5eba870de7ebb11283972483f7e2891" + "reference": "16ca9e39877369d664f06dacde468548298bdc40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/7f83911cc5eba870de7ebb11283972483f7e2891", - "reference": "7f83911cc5eba870de7ebb11283972483f7e2891", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/16ca9e39877369d664f06dacde468548298bdc40", + "reference": "16ca9e39877369d664f06dacde468548298bdc40", "shasum": "" }, "require": { @@ -1815,6 +1819,7 @@ }, "require-dev": { "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^10.5", "vimeo/psalm": "^5.24" @@ -1847,32 +1852,33 @@ ], "support": { "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.4.1" + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.0" }, - "time": "2024-08-05T20:32:22+00:00" + "time": "2024-09-11T07:29:40+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.3.3", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" + "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", - "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", + "reference": "1dc4a3dbfa2b7628a3114e43e32120cce7cdda9c", "shasum": "" }, "require": { "php": "^7.3|^8.0" }, "require-dev": { - "nesbot/carbon": "^2.61", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "nesbot/carbon": "^2.61|^3.0", "pestphp/pest": "^1.21.3", "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" + "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" }, "type": "library", "extra": { @@ -1909,7 +1915,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-11-08T14:08:06+00:00" + "time": "2024-09-23T13:33:08+00:00" }, { "name": "myclabs/deep-copy", @@ -1973,16 +1979,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.1.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", - "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -2025,9 +2031,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-07-01T20:03:41+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "openswoole/ide-helper", @@ -2188,16 +2194,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.9", + "version": "1.12.6", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e370bcddadaede0c1716338b262346f40d296f82" + "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82", - "reference": "e370bcddadaede0c1716338b262346f40d296f82", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc4d2f145a88ea7141ae698effd64d9df46527ae", + "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae", "shasum": "" }, "require": { @@ -2242,39 +2248,39 @@ "type": "github" } ], - "time": "2024-08-01T16:25:18+00:00" + "time": "2024-10-06T15:03:59+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.15", + "version": "11.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae" + "reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", - "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f7f08030e8811582cc459871d28d6f5a1a4d35ca", + "reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" + "nikic/php-parser": "^5.3.1", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^10.1" + "phpunit/phpunit": "^11.4.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -2283,7 +2289,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "11.0.x-dev" } }, "autoload": { @@ -2312,7 +2318,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.7" }, "funding": [ { @@ -2320,32 +2326,32 @@ "type": "github" } ], - "time": "2024-06-29T08:25:15+00:00" + "time": "2024-10-09T06:21:38+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "4.1.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2373,7 +2379,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" }, "funding": [ { @@ -2381,28 +2387,28 @@ "type": "github" } ], - "time": "2023-08-31T06:24:48+00:00" + "time": "2024-08-27T05:02:59+00:00" }, { "name": "phpunit/php-invoker", - "version": "4.0.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "suggest": { "ext-pcntl": "*" @@ -2410,7 +2416,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2436,7 +2442,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" }, "funding": [ { @@ -2444,32 +2451,32 @@ "type": "github" } ], - "time": "2023-02-03T06:56:09+00:00" + "time": "2024-07-03T05:07:44+00:00" }, { "name": "phpunit/php-text-template", - "version": "3.0.1", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2496,7 +2503,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" }, "funding": [ { @@ -2504,32 +2511,32 @@ "type": "github" } ], - "time": "2023-08-31T14:07:24+00:00" + "time": "2024-07-03T05:08:43+00:00" }, { "name": "phpunit/php-timer", - "version": "6.0.0", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -2555,7 +2562,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" }, "funding": [ { @@ -2563,20 +2571,20 @@ "type": "github" } ], - "time": "2023-02-03T06:57:52+00:00" + "time": "2024-07-03T05:09:35+00:00" }, { "name": "phpunit/phpunit", - "version": "10.5.29", + "version": "11.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f" + "reference": "7875627f15f4da7e7f0823d1f323f7295a77334e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e9e80872b4e8064401788ee8a32d40b4455318f", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7875627f15f4da7e7f0823d1f323f7295a77334e", + "reference": "7875627f15f4da7e7f0823d1f323f7295a77334e", "shasum": "" }, "require": { @@ -2589,23 +2597,22 @@ "myclabs/deep-copy": "^1.12.0", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", - "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.15", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-invoker": "^4.0.0", - "phpunit/php-text-template": "^3.0.1", - "phpunit/php-timer": "^6.0.0", - "sebastian/cli-parser": "^2.0.1", - "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.1", - "sebastian/diff": "^5.1.1", - "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.2", - "sebastian/global-state": "^6.0.2", - "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.0", - "sebastian/type": "^4.0.0", - "sebastian/version": "^4.0.1" + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.6", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.1", + "sebastian/comparator": "^6.1.0", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.0", + "sebastian/exporter": "^6.1.3", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.0", + "sebastian/version": "^5.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -2616,7 +2623,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.5-dev" + "dev-main": "11.4-dev" } }, "autoload": { @@ -2648,7 +2655,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.29" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.4.1" }, "funding": [ { @@ -2664,7 +2671,7 @@ "type": "tidelift" } ], - "time": "2024-07-30T11:08:00+00:00" + "time": "2024-10-08T15:38:37+00:00" }, { "name": "psr/cache", @@ -3062,28 +3069,28 @@ }, { "name": "sebastian/cli-parser", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3107,7 +3114,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" }, "funding": [ { @@ -3115,32 +3122,32 @@ "type": "github" } ], - "time": "2024-03-02T07:12:49+00:00" + "time": "2024-07-03T04:41:36+00:00" }, { "name": "sebastian/code-unit", - "version": "2.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + "reference": "6bb7d09d6623567178cf54126afa9c2310114268" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/6bb7d09d6623567178cf54126afa9c2310114268", + "reference": "6bb7d09d6623567178cf54126afa9c2310114268", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3163,7 +3170,8 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.1" }, "funding": [ { @@ -3171,32 +3179,32 @@ "type": "github" } ], - "time": "2023-02-03T06:58:43+00:00" + "time": "2024-07-03T04:44:28+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "3.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -3218,7 +3226,8 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" }, "funding": [ { @@ -3226,36 +3235,36 @@ "type": "github" } ], - "time": "2023-02-03T06:59:15+00:00" + "time": "2024-07-03T04:45:54+00:00" }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d", + "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -3295,7 +3304,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0" }, "funding": [ { @@ -3303,33 +3312,33 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-09-11T15:42:56+00:00" }, { "name": "sebastian/complexity", - "version": "3.2.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68ff824baeae169ec9f2137158ee529584553799" + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", - "reference": "68ff824baeae169ec9f2137158ee529584553799", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -3353,7 +3362,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" }, "funding": [ { @@ -3361,33 +3370,33 @@ "type": "github" } ], - "time": "2023-12-21T08:37:17+00:00" + "time": "2024-07-03T04:49:50+00:00" }, { "name": "sebastian/diff", - "version": "5.1.1", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3420,7 +3429,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" }, "funding": [ { @@ -3428,27 +3437,27 @@ "type": "github" } ], - "time": "2024-03-02T07:15:17+00:00" + "time": "2024-07-03T04:53:05+00:00" }, { "name": "sebastian/environment", - "version": "6.1.0", + "version": "7.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "suggest": { "ext-posix": "*" @@ -3456,7 +3465,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.1-dev" + "dev-main": "7.2-dev" } }, "autoload": { @@ -3484,7 +3493,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" }, "funding": [ { @@ -3492,34 +3501,34 @@ "type": "github" } ], - "time": "2024-03-23T08:47:14+00:00" + "time": "2024-07-03T04:54:44+00:00" }, { "name": "sebastian/exporter", - "version": "5.1.2", + "version": "6.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf" + "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e", + "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.1-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -3562,7 +3571,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/exporter/tree/6.1.3" }, "funding": [ { @@ -3570,35 +3579,35 @@ "type": "github" } ], - "time": "2024-03-02T07:17:12+00:00" + "time": "2024-07-03T04:56:19+00:00" }, { "name": "sebastian/global-state", - "version": "6.0.2", + "version": "7.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", "shasum": "" }, "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -3624,7 +3633,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" }, "funding": [ { @@ -3632,33 +3641,33 @@ "type": "github" } ], - "time": "2024-03-02T07:19:19+00:00" + "time": "2024-07-03T04:57:36+00:00" }, { "name": "sebastian/lines-of-code", - "version": "2.0.2", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" + "nikic/php-parser": "^5.0", + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -3682,7 +3691,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" }, "funding": [ { @@ -3690,34 +3699,34 @@ "type": "github" } ], - "time": "2023-12-21T08:38:20+00:00" + "time": "2024-07-03T04:58:38+00:00" }, { "name": "sebastian/object-enumerator", - "version": "5.0.0", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", "shasum": "" }, "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3739,7 +3748,8 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" }, "funding": [ { @@ -3747,32 +3757,32 @@ "type": "github" } ], - "time": "2023-02-03T07:08:32+00:00" + "time": "2024-07-03T05:00:13+00:00" }, { "name": "sebastian/object-reflector", - "version": "3.0.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -3794,7 +3804,8 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" }, "funding": [ { @@ -3802,32 +3813,32 @@ "type": "github" } ], - "time": "2023-02-03T07:06:18+00:00" + "time": "2024-07-03T05:01:32+00:00" }, { "name": "sebastian/recursion-context", - "version": "5.0.0", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -3857,7 +3868,8 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" }, "funding": [ { @@ -3865,32 +3877,32 @@ "type": "github" } ], - "time": "2023-02-03T07:05:40+00:00" + "time": "2024-07-03T05:10:34+00:00" }, { "name": "sebastian/type", - "version": "4.0.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -3913,7 +3925,8 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.0" }, "funding": [ { @@ -3921,29 +3934,29 @@ "type": "github" } ], - "time": "2023-02-03T07:10:45+00:00" + "time": "2024-09-17T13:12:04+00:00" }, { "name": "sebastian/version", - "version": "4.0.1", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -3966,7 +3979,8 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" }, "funding": [ { @@ -3974,7 +3988,7 @@ "type": "github" } ], - "time": "2023-02-07T11:34:05+00:00" + "time": "2024-10-09T05:16:32+00:00" }, { "name": "spatie/async", @@ -4045,16 +4059,16 @@ }, { "name": "symfony/cache", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "8ac37acee794372f9732fe8a61a8221f6762148e" + "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/8ac37acee794372f9732fe8a61a8221f6762148e", - "reference": "8ac37acee794372f9732fe8a61a8221f6762148e", + "url": "https://api.github.com/repos/symfony/cache/zipball/86e5296b10e4dec8c8441056ca606aedb8a3be0a", + "reference": "86e5296b10e4dec8c8441056ca606aedb8a3be0a", "shasum": "" }, "require": { @@ -4122,7 +4136,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.1.3" + "source": "https://github.com/symfony/cache/tree/v7.1.5" }, "funding": [ { @@ -4138,7 +4152,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:10:24+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/cache-contracts", @@ -4293,16 +4307,16 @@ }, { "name": "symfony/console", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", - "reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { @@ -4366,7 +4380,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.3" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -4382,20 +4396,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "8126f0be4ff984e4db0140e60917900a53facb49" + "reference": "38465f925ec4e0707b090e9147c65869837d639d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8126f0be4ff984e4db0140e60917900a53facb49", - "reference": "8126f0be4ff984e4db0140e60917900a53facb49", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/38465f925ec4e0707b090e9147c65869837d639d", + "reference": "38465f925ec4e0707b090e9147c65869837d639d", "shasum": "" }, "require": { @@ -4446,7 +4460,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.1.3" + "source": "https://github.com/symfony/dependency-injection/tree/v7.1.5" }, "funding": [ { @@ -4462,7 +4476,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T07:35:39+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4533,16 +4547,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "b526822483124b62ff3cda14237418408f444e4d" + "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/b526822483124b62ff3cda14237418408f444e4d", - "reference": "b526822483124b62ff3cda14237418408f444e4d", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/2568d0adaa5b0018b07beaa90363b880a43cc957", + "reference": "2568d0adaa5b0018b07beaa90363b880a43cc957", "shasum": "" }, "require": { @@ -4621,7 +4635,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.1.3" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.1.5" }, "funding": [ { @@ -4637,20 +4651,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-09-08T12:32:26+00:00" }, { "name": "symfony/doctrine-messenger", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-messenger.git", - "reference": "64e2195442df86a7a0c85a77162d0247601e9da9" + "reference": "29015027fb63461e035246e07d74eeab9cb03304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/64e2195442df86a7a0c85a77162d0247601e9da9", - "reference": "64e2195442df86a7a0c85a77162d0247601e9da9", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/29015027fb63461e035246e07d74eeab9cb03304", + "reference": "29015027fb63461e035246e07d74eeab9cb03304", "shasum": "" }, "require": { @@ -4693,7 +4707,7 @@ "description": "Symfony Doctrine Messenger Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-messenger/tree/v7.1.2" + "source": "https://github.com/symfony/doctrine-messenger/tree/v7.1.5" }, "funding": [ { @@ -4709,7 +4723,7 @@ "type": "tidelift" } ], - "time": "2024-06-20T15:47:37+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/error-handler", @@ -4788,16 +4802,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", "shasum": "" }, "require": { @@ -4834,7 +4848,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + "source": "https://github.com/symfony/filesystem/tree/v7.1.5" }, "funding": [ { @@ -4850,20 +4864,20 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/finder", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca" + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/717c6329886f32dc65e27461f80f2a465412fdca", - "reference": "717c6329886f32dc65e27461f80f2a465412fdca", + "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", "shasum": "" }, "require": { @@ -4898,7 +4912,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.1.3" + "source": "https://github.com/symfony/finder/tree/v7.1.4" }, "funding": [ { @@ -4914,20 +4928,20 @@ "type": "tidelift" } ], - "time": "2024-07-24T07:08:44+00:00" + "time": "2024-08-13T14:28:19+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "a32ec544bd501eb4619eb977860ad3076ee55061" + "reference": "8a792de86230c13a9de7750c0c8b23cc083183d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a32ec544bd501eb4619eb977860ad3076ee55061", - "reference": "a32ec544bd501eb4619eb977860ad3076ee55061", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/8a792de86230c13a9de7750c0c8b23cc083183d4", + "reference": "8a792de86230c13a9de7750c0c8b23cc083183d4", "shasum": "" }, "require": { @@ -4936,7 +4950,7 @@ "php": ">=8.2", "symfony/cache": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^7.1", + "symfony/dependency-injection": "^7.1.5", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", @@ -5045,7 +5059,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v7.1.3" + "source": "https://github.com/symfony/framework-bundle/tree/v7.1.5" }, "funding": [ { @@ -5061,20 +5075,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T13:24:34+00:00" + "time": "2024-09-20T13:35:23+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f602d5c17d1fa02f8019ace2687d9d136b7f4a1a" + "reference": "e30ef73b1e44eea7eb37ba69600a354e553f694b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f602d5c17d1fa02f8019ace2687d9d136b7f4a1a", - "reference": "f602d5c17d1fa02f8019ace2687d9d136b7f4a1a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e30ef73b1e44eea7eb37ba69600a354e553f694b", + "reference": "e30ef73b1e44eea7eb37ba69600a354e553f694b", "shasum": "" }, "require": { @@ -5122,7 +5136,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.1.3" + "source": "https://github.com/symfony/http-foundation/tree/v7.1.5" }, "funding": [ { @@ -5138,20 +5152,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "db9702f3a04cc471ec8c70e881825db26ac5f186" + "reference": "44204d96150a9df1fc57601ec933d23fefc2d65b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/db9702f3a04cc471ec8c70e881825db26ac5f186", - "reference": "db9702f3a04cc471ec8c70e881825db26ac5f186", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/44204d96150a9df1fc57601ec933d23fefc2d65b", + "reference": "44204d96150a9df1fc57601ec933d23fefc2d65b", "shasum": "" }, "require": { @@ -5236,7 +5250,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.1.3" + "source": "https://github.com/symfony/http-kernel/tree/v7.1.5" }, "funding": [ { @@ -5252,7 +5266,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T14:58:15+00:00" + "time": "2024-09-21T06:09:21+00:00" }, { "name": "symfony/orm-pack", @@ -5305,20 +5319,20 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -5364,7 +5378,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -5380,24 +5394,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -5442,7 +5456,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -5458,24 +5472,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -5523,7 +5537,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -5539,24 +5553,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -5603,7 +5617,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -5619,24 +5633,24 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", - "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -5683,7 +5697,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -5699,20 +5713,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca" + "reference": "5c03ee6369281177f07f7c68252a280beccba847" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca", + "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", + "reference": "5c03ee6369281177f07f7c68252a280beccba847", "shasum": "" }, "require": { @@ -5744,7 +5758,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.3" + "source": "https://github.com/symfony/process/tree/v7.1.5" }, "funding": [ { @@ -5760,20 +5774,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:44:47+00:00" + "time": "2024-09-19T21:48:23+00:00" }, { "name": "symfony/routing", - "version": "v7.1.3", + "version": "v7.1.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8a908a3f22d5a1b5d297578c2ceb41b02fa916d0" + "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8a908a3f22d5a1b5d297578c2ceb41b02fa916d0", - "reference": "8a908a3f22d5a1b5d297578c2ceb41b02fa916d0", + "url": "https://api.github.com/repos/symfony/routing/zipball/1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", + "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", "shasum": "" }, "require": { @@ -5825,7 +5839,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.1.3" + "source": "https://github.com/symfony/routing/tree/v7.1.4" }, "funding": [ { @@ -5841,7 +5855,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:10:24+00:00" + "time": "2024-08-29T08:16:25+00:00" }, { "name": "symfony/service-contracts", @@ -5990,16 +6004,16 @@ }, { "name": "symfony/string", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07", - "reference": "ea272a882be7f20cad58d5d78c215001617b7f07", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { @@ -6057,7 +6071,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.3" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -6073,20 +6087,20 @@ "type": "tidelift" } ], - "time": "2024-07-22T10:25:37+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "86af4617cca75a6e28598f49ae0690f3b9d4591f" + "reference": "e20e03889539fd4e4211e14d2179226c513c010d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/86af4617cca75a6e28598f49ae0690f3b9d4591f", - "reference": "86af4617cca75a6e28598f49ae0690f3b9d4591f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e20e03889539fd4e4211e14d2179226c513c010d", + "reference": "e20e03889539fd4e4211e14d2179226c513c010d", "shasum": "" }, "require": { @@ -6140,7 +6154,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.1.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.1.5" }, "funding": [ { @@ -6156,7 +6170,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:41:01+00:00" + "time": "2024-09-16T10:07:02+00:00" }, { "name": "symfony/var-exporter", @@ -6294,5 +6308,5 @@ "php": ">=8.3" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" }