diff --git a/composer.json b/composer.json
index 78acaa7..9089039 100644
--- a/composer.json
+++ b/composer.json
@@ -22,8 +22,8 @@
"@composer bin all update --ansi"
],
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './build/*' -print0 | xargs -0 -n1 php -l",
- "cs:check": "php-cs-fixer fix --dry-run --diff",
- "cs:fix": "php-cs-fixer fix",
+ "cs:check": "vendor-bin/cs-fixer/vendor/php-cs-fixer/shim/php-cs-fixer fix --dry-run --diff",
+ "cs:fix": "vendor-bin/cs-fixer/vendor/php-cs-fixer/shim/php-cs-fixer fix",
"psalm": "psalm --threads=1 --no-cache",
"test:unit": "phpunit tests -c tests/phpunit.xml --colors=always --fail-on-warning --fail-on-risky"
},
diff --git a/composer.lock b/composer.lock
index 23f8795..4f86fc3 100644
--- a/composer.lock
+++ b/composer.lock
@@ -8,16 +8,16 @@
"packages": [
{
"name": "bamarni/composer-bin-plugin",
- "version": "1.8.2",
+ "version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/bamarni/composer-bin-plugin.git",
- "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880"
+ "reference": "641d0663f5ac270b1aeec4337b7856f76204df47"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
- "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
+ "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/641d0663f5ac270b1aeec4337b7856f76204df47",
+ "reference": "641d0663f5ac270b1aeec4337b7856f76204df47",
"shasum": ""
},
"require": {
@@ -25,12 +25,12 @@
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
- "composer/composer": "^2.0",
+ "composer/composer": "^2.2.26",
"ext-json": "*",
"phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpunit/phpunit": "^8.5 || ^9.5",
+ "phpstan/phpstan": "^1.8 || ^2.0",
+ "phpstan/phpstan-phpunit": "^1.1 || ^2.0",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.0",
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
@@ -59,9 +59,9 @@
],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
- "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2"
+ "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.9.1"
},
- "time": "2022-10-31T08:38:03+00:00"
+ "time": "2026-02-04T10:18:12+00:00"
},
{
"name": "ionos-productivity/ionos-mail-notification-api-client",
@@ -82,16 +82,16 @@
"packages-dev": [
{
"name": "guzzlehttp/guzzle",
- "version": "7.10.0",
+ "version": "7.10.6",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
+ "reference": "e7412b3180912c01650cc66647f18c1d1cbe9b94"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
- "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/e7412b3180912c01650cc66647f18c1d1cbe9b94",
+ "reference": "e7412b3180912c01650cc66647f18c1d1cbe9b94",
"shasum": ""
},
"require": {
@@ -109,8 +109,9 @@
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
+ "guzzlehttp/test-server": "^0.4",
"php-http/message-factory": "^1.1",
- "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "phpunit/phpunit": "^8.5.52 || ^9.6.34",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
@@ -188,7 +189,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
+ "source": "https://github.com/guzzle/guzzle/tree/7.10.6"
},
"funding": [
{
@@ -204,7 +205,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-23T22:36:01+00:00"
+ "time": "2026-06-01T13:06:22+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -460,16 +461,16 @@
},
{
"name": "nextcloud/coding-standard",
- "version": "v1.4.0",
+ "version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/nextcloud/coding-standard.git",
- "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011"
+ "reference": "80547a93236fbb9c783e05f0f0899043851b0dba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/8e06808c1423e9208d63d1bd205b9a38bd400011",
- "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011",
+ "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/80547a93236fbb9c783e05f0f0899043851b0dba",
+ "reference": "80547a93236fbb9c783e05f0f0899043851b0dba",
"shasum": ""
},
"require": {
@@ -499,22 +500,22 @@
],
"support": {
"issues": "https://github.com/nextcloud/coding-standard/issues",
- "source": "https://github.com/nextcloud/coding-standard/tree/v1.4.0"
+ "source": "https://github.com/nextcloud/coding-standard/tree/v1.5.0"
},
- "time": "2025-06-19T12:27:27+00:00"
+ "time": "2026-05-19T18:30:09+00:00"
},
{
"name": "nextcloud/ocp",
- "version": "v33.0.2",
+ "version": "v33.0.5",
"source": {
"type": "git",
"url": "https://github.com/nextcloud-deps/ocp.git",
- "reference": "f5a898fb7795fa28a135f528105b8628df6d97f5"
+ "reference": "6f53a7ad7eda8c00f335b38e392cb76494d82422"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/f5a898fb7795fa28a135f528105b8628df6d97f5",
- "reference": "f5a898fb7795fa28a135f528105b8628df6d97f5",
+ "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/6f53a7ad7eda8c00f335b38e392cb76494d82422",
+ "reference": "6f53a7ad7eda8c00f335b38e392cb76494d82422",
"shasum": ""
},
"require": {
@@ -547,9 +548,9 @@
"description": "Composer package containing Nextcloud's public OCP API and the unstable NCU API",
"support": {
"issues": "https://github.com/nextcloud-deps/ocp/issues",
- "source": "https://github.com/nextcloud-deps/ocp/tree/v33.0.2"
+ "source": "https://github.com/nextcloud-deps/ocp/tree/v33.0.5"
},
- "time": "2026-03-27T01:17:36+00:00"
+ "time": "2026-05-21T02:07:59+00:00"
},
{
"name": "php-cs-fixer/shim",
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 274b113..b2cdc53 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -1,34 +1,19 @@
+ * SPDX-FileCopyrightText: 2026 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- *
*/
-declare(strict_types=1);
-
namespace OCA\IonosProcesses\AppInfo;
-use OCA\IonosProcesses\Listener\ShareCreatedEventListener;
+use OCA\IonosProcesses\Listener\BeforeShareMailSentEventListener;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\Share\Events\ShareCreatedEvent;
class Application extends App implements IBootstrap {
public const APP_ID = 'nc_ionos_processes';
@@ -41,7 +26,10 @@ public function __construct() {
public function register(IRegistrationContext $context): void {
include_once __DIR__ . '/../../vendor/autoload.php';
- $context->registerEventListener(ShareCreatedEvent::class, ShareCreatedEventListener::class);
+ $context->registerEventListener(
+ \OCA\ShareByMail\Event\BeforeShareMailSentEvent::class,
+ BeforeShareMailSentEventListener::class,
+ );
}
public function boot(IBootContext $context): void {
diff --git a/lib/Listener/BeforeShareMailSentEventListener.php b/lib/Listener/BeforeShareMailSentEventListener.php
new file mode 100644
index 0000000..b07468e
--- /dev/null
+++ b/lib/Listener/BeforeShareMailSentEventListener.php
@@ -0,0 +1,75 @@
+
+ */
+class BeforeShareMailSentEventListener implements IEventListener {
+ public const EVENT_NAME_SHARE_BY_LINK = 'share-by-link';
+
+ /** @psalm-api */
+ public function __construct(
+ private readonly LoggerInterface $logger,
+ private readonly IL10N $l10n,
+ private readonly IonosMailerService $mailer,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof BeforeShareMailSentEvent)) {
+ return;
+ }
+
+ $share = $event->getShare();
+
+ if ($share->getShareType() !== IShare::TYPE_EMAIL) {
+ return;
+ }
+
+ $resolvedEmails = $event->getResolvedEmails();
+ if (empty($resolvedEmails)) {
+ $event->markMailHandled();
+ $this->logger->warning("empty recipients for share with token '" . $share->getToken() . "', skipping");
+ return;
+ }
+
+ $data = [
+ 'senderUserId' => $event->getSenderUserId(),
+ 'fileName' => $event->getFileName(),
+ 'resourceUrl' => $event->getResourceUrl(),
+ 'note' => $event->getNote(),
+ 'expirationDate' => $event->getExpiration()?->getTimestamp(),
+ 'language' => $this->l10n->getLanguageCode(),
+ 'receiverEmails' => $resolvedEmails,
+ ];
+
+ $event->markMailHandled();
+ $this->mailer->send(self::EVENT_NAME_SHARE_BY_LINK, $data);
+ }
+}
diff --git a/lib/Listener/ShareCreatedEventListener.php b/lib/Listener/ShareCreatedEventListener.php
deleted file mode 100644
index 9dcd5ba..0000000
--- a/lib/Listener/ShareCreatedEventListener.php
+++ /dev/null
@@ -1,89 +0,0 @@
-
- */
-class ShareCreatedEventListener implements IEventListener {
- public const EVENT_NAME_SHARE_BY_LINK = 'share-by-link';
-
- /** @psalm-api */
- public function __construct(
- private readonly LoggerInterface $logger,
- private readonly IUserManager $userManager,
- private readonly IL10N $l10n,
- private readonly IURLGenerator $urlGenerator,
- private readonly IonosMailerService $mailer,
- ) {
- }
-
- public function handle(Event $event): void {
- if (!($event instanceof ShareCreatedEvent)) {
- return;
- }
-
- $share = $event->getShare();
- $shareType = $share->getShareType();
-
- if ($shareType !== IShare::TYPE_EMAIL) {
- $this->logger->debug('share type ' . $shareType . ' ignored');
- return;
- }
-
- $user = $this->userManager->get($share->getSharedBy());
-
- if ($user === null) {
- $this->logger->error("can not find user for share with token '" . $share->getToken() . "'");
- return;
- }
-
- try {
- $filename = $share->getNode()->getName();
- } catch (NotFoundException $e) {
- $this->logger->error("can not find node for share with token '" . $share->getToken() . "': " . $e->getMessage());
- return;
- }
-
- $language = $this->l10n->getLanguageCode();
- $userId = $user->getUID();
- $note = $share->getNote();
- $expirationDate = $share->getExpirationDate();
- $recipient = $share->getSharedWith();
- $url = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', [
- 'token' => $share->getToken()
- ]);
-
- $data = [
- 'senderUserId' => $userId,
- 'fileName' => $filename,
- 'resourceUrl' => $url,
- 'note' => $note,
- 'expirationDate' => $expirationDate?->getTimestamp(),
- 'language' => $language,
- 'receiverEmails' => [
- $recipient,
- ]
- ];
-
- $this->mailer->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, $data);
- }
-}
diff --git a/lib/Service/IonosMailerService.php b/lib/Service/IonosMailerService.php
index fd73e19..0116421 100644
--- a/lib/Service/IonosMailerService.php
+++ b/lib/Service/IonosMailerService.php
@@ -10,7 +10,7 @@
use Exception;
use IONOS\MailNotificationAPI\Client\Model\ShareMessageByLink;
use OCA\IonosProcesses\AppInfo\Application;
-use OCA\IonosProcesses\Listener\ShareCreatedEventListener;
+use OCA\IonosProcesses\Listener\BeforeShareMailSentEventListener;
use OCP\Exceptions\AppConfigException;
use OCP\IAppConfig;
use Psr\Log\LoggerInterface;
@@ -70,7 +70,7 @@ public function send(string $eventName, array $variables): void {
$apiInstance = $this->apiClientService->newEventAPIApi($client, $apiBaseUrl);
- if ($eventName === ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK) {
+ if ($eventName === BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK) {
$message = new ShareMessageByLink($variables);
try {
$this->logger->debug('Send message to mailer service', ['event' => $eventName, 'variables' => $variables]);
diff --git a/psalm.xml b/psalm.xml
index cead67c..37da3df 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -17,6 +17,7 @@
+
diff --git a/tests/AppInfo/ApplicationTest.php b/tests/AppInfo/ApplicationTest.php
index 4f887f0..2df304a 100644
--- a/tests/AppInfo/ApplicationTest.php
+++ b/tests/AppInfo/ApplicationTest.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
/**
- * SPDX-FileLicenseText: 2024 STRATO AG
+ * SPDX-FileCopyrightText: 2026 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -11,14 +11,15 @@
use OC\AppFramework\Bootstrap\Coordinator;
use OCA\IonosProcesses\AppInfo\Application;
-use OCA\IonosProcesses\Listener\ShareCreatedEventListener;
+use OCA\IonosProcesses\Listener\BeforeShareMailSentEventListener;
+use OCA\ShareByMail\Event\BeforeShareMailSentEvent;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\Share\Events\ShareCreatedEvent;
+use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class ApplicationTest extends TestCase {
private Application $app;
- private IRegistrationContext $context;
+ private IRegistrationContext&MockObject $context;
protected function setUp(): void {
parent::setUp();
@@ -30,11 +31,12 @@ protected function setUp(): void {
}
public function testRegisterCallsRegisterEventListenerOnContext(): void {
- $this->context->expects($this->exactly(1))
+ $this->context
+ ->expects($this->exactly(1))
->method('registerEventListener')
->with(
- ShareCreatedEvent::class,
- ShareCreatedEventListener::class,
+ BeforeShareMailSentEvent::class,
+ BeforeShareMailSentEventListener::class,
);
$this->app->register($this->context);
diff --git a/tests/Listener/BeforeShareMailSentEventListenerTest.php b/tests/Listener/BeforeShareMailSentEventListenerTest.php
new file mode 100644
index 0000000..fe30189
--- /dev/null
+++ b/tests/Listener/BeforeShareMailSentEventListenerTest.php
@@ -0,0 +1,226 @@
+mockLogger = $this->getMockBuilder(LoggerInterface::class)->getMock();
+
+ $this->mockMailer = $this->getMockBuilder(IonosMailerService::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['send'])
+ ->getMock();
+
+ $this->mockL10N = $this->getMockBuilder(IL10N::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->mockShare = $this->getMockBuilder(IShare::class)->getMock();
+ $this->mockMessage = $this->getMockBuilder(IMessage::class)->getMock();
+
+ $this->listener = new BeforeShareMailSentEventListener(
+ $this->mockLogger,
+ $this->mockL10N,
+ $this->mockMailer,
+ );
+ }
+
+ private function makeEvent(
+ array $resolvedEmails = [self::MOCK_RECIPIENT],
+ array $templateData = [],
+ ): BeforeShareMailSentEvent {
+ if (empty($templateData)) {
+ $templateData = [
+ 'senderUserId' => self::MOCK_USER_ID,
+ 'filename' => self::MOCK_FILENAME,
+ 'link' => self::MOCK_URL,
+ 'initiator' => 'Test User',
+ 'shareWith' => 'other@example.com',
+ 'note' => self::MOCK_NOTE,
+ 'expiration' => null,
+ ];
+ }
+ return new BeforeShareMailSentEvent($this->mockShare, $resolvedEmails, $this->mockMessage, $templateData);
+ }
+
+ public function testNonShareTypeEmailIsIgnored(): void {
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_USER);
+ $this->mockMailer->expects($this->never())->method('send');
+
+ $event = $this->makeEvent();
+ $this->listener->handle($event);
+
+ $this->assertFalse($event->isMailHandled());
+ }
+
+ public function testEmptyRecipientsMarkHandledAndLogsWarning(): void {
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
+ $this->mockShare->method('getToken')->willReturn(self::MOCK_SHARE_TOKEN);
+
+ $this->mockMailer->expects($this->never())->method('send');
+ $this->mockLogger
+ ->expects($this->once())
+ ->method('warning')
+ ->with($this->stringContains(self::MOCK_SHARE_TOKEN));
+
+ $event = $this->makeEvent([]);
+ $this->listener->handle($event);
+
+ $this->assertTrue($event->isMailHandled());
+ }
+
+ public function testSuccessfulSendWithoutExpiration(): void {
+ $mockLanguageCode = 'lang_LOCALE';
+
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
+ $this->mockShare->method('getToken')->willReturn(self::MOCK_SHARE_TOKEN);
+ $this->mockL10N->method('getLanguageCode')->willReturn($mockLanguageCode);
+
+ $this->mockMailer
+ ->expects($this->once())
+ ->method('send')
+ ->with(
+ BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK,
+ [
+ 'senderUserId' => self::MOCK_USER_ID,
+ 'fileName' => self::MOCK_FILENAME,
+ 'resourceUrl' => self::MOCK_URL,
+ 'note' => self::MOCK_NOTE,
+ 'expirationDate' => null,
+ 'language' => $mockLanguageCode,
+ 'receiverEmails' => [self::MOCK_RECIPIENT],
+ ],
+ );
+
+ $event = $this->makeEvent();
+ $this->listener->handle($event);
+
+ $this->assertTrue($event->isMailHandled());
+ }
+
+ public function testSuccessfulSendWithExpiration(): void {
+ $mockLanguageCode = 'lang_LOCALE';
+ $mockTimestamp = 123456789;
+ $expiration = $this->getMockBuilder(DateTime::class)->getMock();
+ $expiration->method('getTimestamp')->willReturn($mockTimestamp);
+
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
+ $this->mockShare->method('getToken')->willReturn(self::MOCK_SHARE_TOKEN);
+ $this->mockL10N->method('getLanguageCode')->willReturn($mockLanguageCode);
+
+ $templateData = [
+ 'senderUserId' => self::MOCK_USER_ID,
+ 'filename' => self::MOCK_FILENAME,
+ 'link' => self::MOCK_URL,
+ 'initiator' => 'Test User',
+ 'shareWith' => 'other@example.com',
+ 'note' => self::MOCK_NOTE,
+ 'expiration' => $expiration,
+ ];
+
+ $this->mockMailer
+ ->expects($this->once())
+ ->method('send')
+ ->with(
+ BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK,
+ [
+ 'senderUserId' => self::MOCK_USER_ID,
+ 'fileName' => self::MOCK_FILENAME,
+ 'resourceUrl' => self::MOCK_URL,
+ 'note' => self::MOCK_NOTE,
+ 'expirationDate' => $mockTimestamp,
+ 'language' => $mockLanguageCode,
+ 'receiverEmails' => [self::MOCK_RECIPIENT],
+ ],
+ );
+
+ $event = $this->makeEvent([self::MOCK_RECIPIENT], $templateData);
+ $this->listener->handle($event);
+
+ $this->assertTrue($event->isMailHandled());
+ }
+
+ public function testUnrelatedEventIsIgnored(): void {
+ $this->mockMailer->expects($this->never())->method('send');
+
+ $this->listener->handle(new Event());
+ }
+
+ public function testMultipleRecipientsAreAllPassed(): void {
+ $recipients = ['a@example.com', 'b@example.com', 'c@example.com'];
+
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
+ $this->mockShare->method('getToken')->willReturn(self::MOCK_SHARE_TOKEN);
+ $this->mockL10N->method('getLanguageCode')->willReturn('en');
+
+ $this->mockMailer
+ ->expects($this->once())
+ ->method('send')
+ ->with(
+ BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK,
+ $this->callback(fn ($data) => $data['receiverEmails'] === $recipients),
+ );
+
+ $event = $this->makeEvent($recipients);
+ $this->listener->handle($event);
+
+ $this->assertTrue($event->isMailHandled());
+ }
+
+ public function testMailHandledBeforeSendSoNoSmtpFallbackOnMailerException(): void {
+ $this->mockShare->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
+ $this->mockShare->method('getToken')->willReturn(self::MOCK_SHARE_TOKEN);
+ $this->mockL10N->method('getLanguageCode')->willReturn('en');
+
+ $this->mockMailer
+ ->expects($this->once())
+ ->method('send')
+ ->willThrowException(new \Exception('IONOS API unreachable'));
+
+ $event = $this->makeEvent();
+
+ try {
+ $this->listener->handle($event);
+ $this->fail('Expected exception was not thrown');
+ } catch (\Exception $e) {
+ $this->assertSame('IONOS API unreachable', $e->getMessage());
+ }
+
+ // markMailHandled() is called before send(), so isMailHandled() is true
+ // even when send() throws — native SMTP is suppressed regardless.
+ $this->assertTrue($event->isMailHandled());
+ }
+}
diff --git a/tests/Listener/ShareCreatedEventListenerTest.php b/tests/Listener/ShareCreatedEventListenerTest.php
deleted file mode 100644
index 2228440..0000000
--- a/tests/Listener/ShareCreatedEventListenerTest.php
+++ /dev/null
@@ -1,326 +0,0 @@
-mockLogger = $this->getMockBuilder(LoggerInterface::class)
- ->getMock();
-
- $this->mockUser = $this->getMockBuilder(IUser::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->mockUserManager = $this->getMockBuilder(IUserManager::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->mockMailer = $this->getMockBuilder(IonosMailerService::class)
- ->disableOriginalConstructor()
- ->onlyMethods([
- 'send',
- ])
- ->getMock();
-
- $this->mockL10N = $this->getMockBuilder(IL10N::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->mockUrlGenerator = $this->getMockBuilder(IURLGenerator::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->mockNode = $this->getMockBuilder(Node::class)
- ->getMock();
-
- $this->mockTimestamp = $this->getMockBuilder(\DateTime::class)
- ->getMock();
-
- $this->mockShare = $this->getMockBuilder(IShare::class)
- ->getMock();
-
- $this->mockEvent = $this->getMockBuilder(ShareCreatedEvent::class)
- ->setConstructorArgs([$this->mockShare])
- ->getMock();
-
- $this->mockEvent
- ->method('getShare')
- ->willReturn($this->mockShare);
-
- $this->listener = new ShareCreatedEventListener(
- $this->mockLogger,
- $this->mockUserManager,
- $this->mockL10N,
- $this->mockUrlGenerator,
- $this->mockMailer,
- );
- }
-
- public function testNonShareTypeEmailShallBeIgnored(): void {
- $this->expectNotToPerformAssertions();
-
- $this->mockShare
- ->method('getShareType')
- ->willReturnOnConsecutiveCalls(
- IShare::TYPE_USER,
- IShare::TYPE_GROUP,
- IShare::TYPE_USERGROUP,
- IShare::TYPE_LINK,
- );
-
- $this->mockLogger
- ->method('debug')
- ->will($this->onConsecutiveCalls(
- 'share type ' . IShare::TYPE_USER . ' ignored',
- 'share type ' . IShare::TYPE_GROUP . ' ignored',
- 'share type ' . IShare::TYPE_USERGROUP . ' ignored',
- 'share type ' . IShare::TYPE_LINK . ' ignored',
- ));
-
-
- // Four calls for the event types
- $this->listener->handle($this->mockEvent);
- $this->listener->handle($this->mockEvent);
- $this->listener->handle($this->mockEvent);
- $this->listener->handle($this->mockEvent);
- }
-
- private function configureMocks(
- UserIs $userFound,
- string $mockLanguageCode,
- ?int $mockExpiration,
- ): void {
- $mockUserId = '123e4567-e89b-12d3-a456-426614174000';
- $mockNodeName = 'mock-name';
- $mockUrl = 'mock-url';
-
- $this->mockL10N
- ->method('getLanguageCode')
- ->willReturn($mockLanguageCode);
-
- if ($userFound == UserIs::FOUND) {
- $this->mockUser
- ->method('getUID')
- ->willReturn(ShareCreatedEventListenerTest::MOCK_USER_ID);
-
- $this->mockUserManager
- ->method('get')
- ->willReturn($this->mockUser);
- } else {
- $this->mockUserManager
- ->method('get')
- ->willReturn(null);
- }
-
- $this->mockUserManager
- ->method('get')
- ->willReturn($mockUserId);
-
- $this->mockUrlGenerator
- ->method('linkToRouteAbsolute')
- ->with(
- 'files_sharing.sharecontroller.showShare',
- [
- 'token' => ShareCreatedEventListenerTest::MOCK_SHARE_TOKEN,
- ],
- )
- ->willReturn($mockUrl);
-
- $this->mockNode
- ->method('getName')
- ->willReturn($mockNodeName);
-
- $this->mockShare
- ->method('getShareType')
- ->willReturn(IShare::TYPE_EMAIL);
-
- $this->mockShare
- ->method('getNode')
- ->willReturn($this->mockNode);
-
- $this->mockShare
- ->method('getToken')
- ->willReturn(ShareCreatedEventListenerTest::MOCK_SHARE_TOKEN);
-
- $this->mockShare
- ->method('getSharedWith')
- ->willReturn(ShareCreatedEventListenerTest::MOCK_RECIPIENT);
-
- $this->mockShare
- ->method('getNote')
- ->willReturn(ShareCreatedEventListenerTest::MOCK_NOTE);
-
- if ($mockExpiration !== null) {
- $this->mockShare
- ->method('getExpirationDate')
- ->willReturn($this->mockTimestamp);
-
- $this->mockTimestamp
- ->method('getTimestamp')
- ->willReturn($mockExpiration);
- } else {
- $this->mockShare
- ->method('getExpirationDate')
- ->willReturn(null);
- }
- }
-
- public function testShareTypeEmailNoExpirationDate(): void {
- $mockLanguageCode = 'lang_LOCALE';
- $mockNodeName = 'mock-name';
- $mockUrl = 'mock-url';
- $mockExpiration = null;
-
- $this->configureMocks(
- UserIs::FOUND,
- $mockLanguageCode,
- $mockExpiration,
- );
-
- $this->mockMailer
- ->expects($this->exactly(1))
- ->method('send')
- ->with(
- ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK,
- [
- 'senderUserId' => ShareCreatedEventListenerTest::MOCK_USER_ID,
- 'fileName' => $mockNodeName,
- 'resourceUrl' => $mockUrl,
- 'note' => ShareCreatedEventListenerTest::MOCK_NOTE,
- 'expirationDate' => $mockExpiration,
- 'language' => $mockLanguageCode,
- 'receiverEmails' => [
- ShareCreatedEventListenerTest::MOCK_RECIPIENT,
- ]
- ]
- );
-
- $this->listener->handle($this->mockEvent);
- }
-
- public function testShareTypeEmailHasExpirationDate(): void {
- $mockLanguageCode = 'lang_LOCALE';
- $mockNodeName = 'mock-name';
- $mockUrl = 'mock-url';
- $mockExpiration = 123456789;
-
- $this->configureMocks(
- UserIs::FOUND,
- $mockLanguageCode,
- $mockExpiration,
- );
-
- $this->mockMailer
- ->expects($this->exactly(1))
- ->method('send')
- ->with(
- ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK,
- [
- 'senderUserId' => ShareCreatedEventListenerTest::MOCK_USER_ID,
- 'fileName' => $mockNodeName,
- 'resourceUrl' => $mockUrl,
- 'note' => ShareCreatedEventListenerTest::MOCK_NOTE,
- 'expirationDate' => $mockExpiration,
- 'language' => $mockLanguageCode,
- 'receiverEmails' => [
- ShareCreatedEventListenerTest::MOCK_RECIPIENT,
- ]
- ]
- );
-
- $this->listener->handle($this->mockEvent);
- }
-
- public function testShareTypeEmailUserNotFound(): void {
- $mockLanguageCode = 'lang_LOCALE';
- $mockExpiration = 123456789;
-
- $this->configureMocks(
- UserIs::NOT_FOUND,
- $mockLanguageCode,
- $mockExpiration,
- );
-
- $this->mockMailer
- ->expects($this->exactly(0))
- ->method('send');
-
- $this->mockLogger
- ->method('error')
- ->with("can not find user for share with token '" . ShareCreatedEventListenerTest::MOCK_SHARE_TOKEN . "'");
-
- $this->listener->handle($this->mockEvent);
- }
-
- public function testShareTypeEmailNodeNotFound(): void {
- $mockLanguageCode = 'lang_LOCALE';
- $mockExpiration = 123456789;
-
- $this->mockShare
- ->method('getNode')
- ->willThrowException(new NotFoundException('node not found'));
-
- $this->configureMocks(
- UserIs::FOUND,
- $mockLanguageCode,
- $mockExpiration,
- );
-
- $this->mockMailer
- ->expects($this->exactly(0))
- ->method('send');
-
- $this->mockLogger
- ->method('error')
- ->with("can not find node for share with token '" . ShareCreatedEventListenerTest::MOCK_SHARE_TOKEN . "': node not found");
-
- $this->listener->handle($this->mockEvent);
- }
-}
diff --git a/tests/Service/IonosMailerServiceTest.php b/tests/Service/IonosMailerServiceTest.php
index 968a11c..cba3c18 100644
--- a/tests/Service/IonosMailerServiceTest.php
+++ b/tests/Service/IonosMailerServiceTest.php
@@ -12,7 +12,7 @@
use IONOS\MailNotificationAPI\Client\Api\EventAPIApi;
use IONOS\MailNotificationAPI\Client\Model\ShareMessageByLink;
use OCA\IonosProcesses\AppInfo\Application;
-use OCA\IonosProcesses\Listener\ShareCreatedEventListener;
+use OCA\IonosProcesses\Listener\BeforeShareMailSentEventListener;
use OCA\IonosProcesses\Service\ApiClientService;
use OCA\IonosProcesses\Service\IonosMailerService;
use OCP\Exceptions\AppConfigException;
@@ -80,7 +80,7 @@ public function testShareByMailSendMailsSuccessfully() {
->expects($matcher)
->method('debug');
- $this->service->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
+ $this->service->send(BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
}
public function testThrowExceptionWhenNoMailerServiceUrlConfigured() {
@@ -93,7 +93,7 @@ public function testThrowExceptionWhenNoMailerServiceUrlConfigured() {
$this->expectException(AppConfigException::class);
$this->expectExceptionMessage('No mailer service configured');
- $this->service->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
+ $this->service->send(BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
}
public function testThrowExceptionWhenNoMailerServiceUserConfigured() {
@@ -106,7 +106,7 @@ public function testThrowExceptionWhenNoMailerServiceUserConfigured() {
$this->expectException(AppConfigException::class);
$this->expectExceptionMessage('No mailer user configured');
- $this->service->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
+ $this->service->send(BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
}
public function testThrowExceptionWhenNoMailerServicePassConfigured() {
@@ -119,7 +119,7 @@ public function testThrowExceptionWhenNoMailerServicePassConfigured() {
$this->expectException(AppConfigException::class);
$this->expectExceptionMessage('No mailer service pass configured');
- $this->service->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
+ $this->service->send(BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
}
public function testLogErrorWhenExceptionThrownByApi() {
@@ -150,6 +150,6 @@ public function testLogErrorWhenExceptionThrownByApi() {
['exception' => $exception]
);
- $this->service->send(ShareCreatedEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
+ $this->service->send(BeforeShareMailSentEventListener::EVENT_NAME_SHARE_BY_LINK, ['key' => 'value']);
}
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 11b0339..8c6ed90 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -5,5 +5,9 @@
require_once __DIR__ . '/../../../tests/bootstrap.php';
require_once __DIR__ . '/../vendor/autoload.php';
+if (!class_exists(\OCA\ShareByMail\Event\BeforeShareMailSentEvent::class)) {
+ require_once __DIR__ . '/stubs/BeforeShareMailSentEvent.php';
+}
+
\OC_App::loadApp(OCA\IonosProcesses\AppInfo\Application::APP_ID);
OC_Hook::clear();
diff --git a/tests/stubs/BeforeShareMailSentEvent.php b/tests/stubs/BeforeShareMailSentEvent.php
new file mode 100644
index 0000000..e21eda9
--- /dev/null
+++ b/tests/stubs/BeforeShareMailSentEvent.php
@@ -0,0 +1,76 @@
+share;
+ }
+
+ /** @return string[] */
+ public function getResolvedEmails(): array {
+ return $this->resolvedEmails;
+ }
+
+ public function getMessage(): ?IMessage {
+ return $this->message;
+ }
+
+ public function markMailHandled(): void {
+ $this->mailHandled = true;
+ }
+
+ public function isMailHandled(): bool {
+ return $this->mailHandled;
+ }
+}
+
+class BeforeShareMailSentEvent extends AbstractBeforeShareMailSentEvent {
+ public function getSenderUserId(): string {
+ return (string)($this->templateData['senderUserId'] ?? '');
+ }
+
+ public function getFileName(): string {
+ return (string)($this->templateData['filename'] ?? '');
+ }
+
+ public function getResourceUrl(): string {
+ return (string)($this->templateData['link'] ?? '');
+ }
+
+ public function getNote(): string {
+ return (string)($this->templateData['note'] ?? '');
+ }
+
+ public function getExpiration(): ?\DateTime {
+ $v = $this->templateData['expiration'] ?? null;
+ return $v instanceof \DateTime ? $v : null;
+ }
+}
diff --git a/vendor-bin/cs-fixer/composer.lock b/vendor-bin/cs-fixer/composer.lock
index 0e4f971..dadc8b4 100644
--- a/vendor-bin/cs-fixer/composer.lock
+++ b/vendor-bin/cs-fixer/composer.lock
@@ -9,26 +9,26 @@
"packages-dev": [
{
"name": "kubawerlos/php-cs-fixer-custom-fixers",
- "version": "v3.30.0",
+ "version": "v3.37.2",
"source": {
"type": "git",
"url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git",
- "reference": "0cf921cf9aee50ac3091839325f5cf38ab189b97"
+ "reference": "678df979ce743466b42ddb6eea46b3f4c9a7bade"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/0cf921cf9aee50ac3091839325f5cf38ab189b97",
- "reference": "0cf921cf9aee50ac3091839325f5cf38ab189b97",
+ "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/678df979ce743466b42ddb6eea46b3f4c9a7bade",
+ "reference": "678df979ce743466b42ddb6eea46b3f4c9a7bade",
"shasum": ""
},
"require": {
"ext-filter": "*",
"ext-tokenizer": "*",
- "friendsofphp/php-cs-fixer": "^3.82",
+ "friendsofphp/php-cs-fixer": "^3.87",
"php": "^7.4 || ^8.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.6.22 || 10.5.45 || ^11.5.7"
+ "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55"
},
"type": "library",
"autoload": {
@@ -49,7 +49,7 @@
"description": "A set of custom fixers for PHP CS Fixer",
"support": {
"issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues",
- "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.30.0"
+ "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.37.2"
},
"funding": [
{
@@ -57,20 +57,20 @@
"type": "github"
}
],
- "time": "2025-07-07T22:51:31+00:00"
+ "time": "2026-05-12T16:22:19+00:00"
},
{
"name": "nextcloud/coding-standard",
- "version": "v1.4.0",
+ "version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/nextcloud/coding-standard.git",
- "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011"
+ "reference": "80547a93236fbb9c783e05f0f0899043851b0dba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/8e06808c1423e9208d63d1bd205b9a38bd400011",
- "reference": "8e06808c1423e9208d63d1bd205b9a38bd400011",
+ "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/80547a93236fbb9c783e05f0f0899043851b0dba",
+ "reference": "80547a93236fbb9c783e05f0f0899043851b0dba",
"shasum": ""
},
"require": {
@@ -100,22 +100,22 @@
],
"support": {
"issues": "https://github.com/nextcloud/coding-standard/issues",
- "source": "https://github.com/nextcloud/coding-standard/tree/v1.4.0"
+ "source": "https://github.com/nextcloud/coding-standard/tree/v1.5.0"
},
- "time": "2025-06-19T12:27:27+00:00"
+ "time": "2026-05-19T18:30:09+00:00"
},
{
"name": "php-cs-fixer/shim",
- "version": "v3.82.2",
+ "version": "v3.95.5",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/shim.git",
- "reference": "2dbabef3dae30752382cf4b9864780e78f71bc59"
+ "reference": "f6ce9082af26d7497e8a1c75c5fc77387179b856"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/2dbabef3dae30752382cf4b9864780e78f71bc59",
- "reference": "2dbabef3dae30752382cf4b9864780e78f71bc59",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/f6ce9082af26d7497e8a1c75c5fc77387179b856",
+ "reference": "f6ce9082af26d7497e8a1c75c5fc77387179b856",
"shasum": ""
},
"require": {
@@ -152,9 +152,9 @@
"description": "A tool to automatically fix PHP code style",
"support": {
"issues": "https://github.com/PHP-CS-Fixer/shim/issues",
- "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.82.2"
+ "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.95.5"
},
- "time": "2025-07-08T21:13:44+00:00"
+ "time": "2026-06-09T14:55:56+00:00"
}
],
"aliases": [],
diff --git a/vendor-bin/phpunit/composer.lock b/vendor-bin/phpunit/composer.lock
index 767a9b9..ade9fcd 100644
--- a/vendor-bin/phpunit/composer.lock
+++ b/vendor-bin/phpunit/composer.lock
@@ -9,16 +9,16 @@
"packages-dev": [
{
"name": "myclabs/deep-copy",
- "version": "1.13.3",
+ "version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
- "reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
@@ -57,7 +57,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
},
"funding": [
{
@@ -65,20 +65,20 @@
"type": "tidelift"
}
],
- "time": "2025-07-05T12:25:42+00:00"
+ "time": "2025-08-01T08:46:24+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.5.0",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
- "reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -97,7 +97,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.x-dev"
}
},
"autoload": {
@@ -121,9 +121,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
- "time": "2025-05-31T08:24:38+00:00"
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phar-io/manifest",
@@ -566,16 +566,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "10.5.47",
+ "version": "10.5.63",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3"
+ "reference": "33198268dad71e926626b618f3ec3966661e4d90"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3",
- "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90",
+ "reference": "33198268dad71e926626b618f3ec3966661e4d90",
"shasum": ""
},
"require": {
@@ -585,7 +585,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.13.1",
+ "myclabs/deep-copy": "^1.13.4",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.1",
@@ -596,13 +596,13 @@
"phpunit/php-timer": "^6.0.0",
"sebastian/cli-parser": "^2.0.1",
"sebastian/code-unit": "^2.0.0",
- "sebastian/comparator": "^5.0.3",
+ "sebastian/comparator": "^5.0.5",
"sebastian/diff": "^5.1.1",
"sebastian/environment": "^6.1.0",
- "sebastian/exporter": "^5.1.2",
+ "sebastian/exporter": "^5.1.4",
"sebastian/global-state": "^6.0.2",
"sebastian/object-enumerator": "^5.0.0",
- "sebastian/recursion-context": "^5.0.0",
+ "sebastian/recursion-context": "^5.0.1",
"sebastian/type": "^4.0.0",
"sebastian/version": "^4.0.1"
},
@@ -647,7 +647,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.47"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63"
},
"funding": [
{
@@ -671,7 +671,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-20T11:29:11+00:00"
+ "time": "2026-01-27T05:48:37+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -843,16 +843,16 @@
},
{
"name": "sebastian/comparator",
- "version": "5.0.3",
+ "version": "5.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
+ "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
- "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
+ "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d",
"shasum": ""
},
"require": {
@@ -908,15 +908,27 @@
"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.3"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
}
],
- "time": "2024-10-18T14:56:07+00:00"
+ "time": "2026-01-24T09:25:16+00:00"
},
{
"name": "sebastian/complexity",
@@ -1109,16 +1121,16 @@
},
{
"name": "sebastian/exporter",
- "version": "5.1.2",
+ "version": "5.1.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "955288482d97c19a372d3f31006ab3f37da47adf"
+ "reference": "0735b90f4da94969541dac1da743446e276defa6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
- "reference": "955288482d97c19a372d3f31006ab3f37da47adf",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0735b90f4da94969541dac1da743446e276defa6",
+ "reference": "0735b90f4da94969541dac1da743446e276defa6",
"shasum": ""
},
"require": {
@@ -1127,7 +1139,7 @@
"sebastian/recursion-context": "^5.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^10.5"
},
"type": "library",
"extra": {
@@ -1175,15 +1187,27 @@
"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/5.1.4"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
}
],
- "time": "2024-03-02T07:17:12+00:00"
+ "time": "2025-09-24T06:09:11+00:00"
},
{
"name": "sebastian/global-state",
@@ -1419,23 +1443,23 @@
},
{
"name": "sebastian/recursion-context",
- "version": "5.0.0",
+ "version": "5.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a"
},
"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/47e34210757a2f37a97dcd207d032e1b01e64c7a",
+ "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^10.5"
},
"type": "library",
"extra": {
@@ -1470,15 +1494,28 @@
"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/5.0.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
}
],
- "time": "2023-02-03T07:05:40+00:00"
+ "time": "2025-08-10T07:50:56+00:00"
},
{
"name": "sebastian/type",
@@ -1591,16 +1628,16 @@
},
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -1629,7 +1666,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
},
"funding": [
{
@@ -1637,7 +1674,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
}
],
"aliases": [],
diff --git a/vendor-bin/psalm/composer.lock b/vendor-bin/psalm/composer.lock
index 55f8757..28fdef6 100644
--- a/vendor-bin/psalm/composer.lock
+++ b/vendor-bin/psalm/composer.lock
@@ -9,16 +9,16 @@
"packages-dev": [
{
"name": "amphp/amp",
- "version": "v2.6.4",
+ "version": "v2.6.5",
"source": {
"type": "git",
"url": "https://github.com/amphp/amp.git",
- "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d"
+ "reference": "d7dda98dae26e56f3f6fcfbf1c1f819c9a993207"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/amphp/amp/zipball/ded3d9be08f526089eb7ee8d9f16a9768f9dec2d",
- "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d",
+ "url": "https://api.github.com/repos/amphp/amp/zipball/d7dda98dae26e56f3f6fcfbf1c1f819c9a993207",
+ "reference": "d7dda98dae26e56f3f6fcfbf1c1f819c9a993207",
"shasum": ""
},
"require": {
@@ -34,11 +34,6 @@
"vimeo/psalm": "^3.12"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.x-dev"
- }
- },
"autoload": {
"files": [
"lib/functions.php",
@@ -86,7 +81,7 @@
"support": {
"irc": "irc://irc.freenode.org/amphp",
"issues": "https://github.com/amphp/amp/issues",
- "source": "https://github.com/amphp/amp/tree/v2.6.4"
+ "source": "https://github.com/amphp/amp/tree/v2.6.5"
},
"funding": [
{
@@ -94,7 +89,7 @@
"type": "github"
}
],
- "time": "2024-03-21T18:52:26+00:00"
+ "time": "2025-09-03T19:41:28+00:00"
},
{
"name": "amphp/byte-stream",
@@ -169,28 +164,29 @@
},
{
"name": "composer/pcre",
- "version": "3.3.2",
+ "version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
- "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ "reference": "d5a341b3fb61f3001970940afb1d332968a183ed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
- "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed",
+ "reference": "d5a341b3fb61f3001970940afb1d332968a183ed",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
- "phpstan/phpstan": "<1.11.10"
+ "phpstan/phpstan": "<2.2.2"
},
"require-dev": {
- "phpstan/phpstan": "^1.12 || ^2",
- "phpstan/phpstan-strict-rules": "^1 || ^2",
- "phpunit/phpunit": "^8 || ^9"
+ "phpstan/phpstan": "^2",
+ "phpstan/phpstan-deprecation-rules": "^2",
+ "phpstan/phpstan-strict-rules": "^2",
+ "phpunit/phpunit": "^9"
},
"type": "library",
"extra": {
@@ -228,7 +224,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/3.3.2"
+ "source": "https://github.com/composer/pcre/tree/3.4.0"
},
"funding": [
{
@@ -238,26 +234,22 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2024-11-12T16:29:46+00:00"
+ "time": "2026-06-07T11:47:49+00:00"
},
{
"name": "composer/semver",
- "version": "3.4.3",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
@@ -309,7 +301,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.4.3"
+ "source": "https://github.com/composer/semver/tree/3.4.4"
},
"funding": [
{
@@ -319,13 +311,9 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2024-09-19T14:15:21+00:00"
+ "time": "2025-08-20T19:15:30+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -432,29 +420,29 @@
},
{
"name": "doctrine/deprecations",
- "version": "1.1.5",
+ "version": "1.1.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
+ "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
- "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
+ "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
- "phpunit/phpunit": "<=7.5 || >=13"
+ "phpunit/phpunit": "<=7.5 || >=14"
},
"require-dev": {
- "doctrine/coding-standard": "^9 || ^12 || ^13",
- "phpstan/phpstan": "1.4.10 || 2.1.11",
+ "doctrine/coding-standard": "^9 || ^12 || ^14",
+ "phpstan/phpstan": "1.4.10 || 2.1.30",
"phpstan/phpstan-phpunit": "^1.0 || ^2",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
"psr/log": "^1 || ^2 || ^3"
},
"suggest": {
@@ -474,9 +462,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
+ "source": "https://github.com/doctrine/deprecations/tree/1.1.6"
},
- "time": "2025-04-07T20:06:18+00:00"
+ "time": "2026-02-07T07:09:04+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
@@ -581,16 +569,16 @@
},
{
"name": "fidry/cpu-core-counter",
- "version": "1.2.0",
+ "version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/theofidry/cpu-core-counter.git",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f"
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
- "reference": "8520451a140d3f46ac33042715115e290cf5785f",
+ "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678",
+ "reference": "db9508f7b1474469d9d3c53b86f817e344732678",
"shasum": ""
},
"require": {
@@ -600,10 +588,10 @@
"fidry/makefile": "^0.2.0",
"fidry/php-cs-fixer-config": "^1.1.2",
"phpstan/extension-installer": "^1.2.0",
- "phpstan/phpstan": "^1.9.2",
- "phpstan/phpstan-deprecation-rules": "^1.0.0",
- "phpstan/phpstan-phpunit": "^1.2.2",
- "phpstan/phpstan-strict-rules": "^1.4.4",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^8.5.31 || ^9.5.26",
"webmozarts/strict-phpunit": "^7.5"
},
@@ -630,7 +618,7 @@
],
"support": {
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
- "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
+ "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0"
},
"funding": [
{
@@ -638,7 +626,7 @@
"type": "github"
}
],
- "time": "2024-08-06T10:04:20+00:00"
+ "time": "2025-08-14T07:29:31+00:00"
},
{
"name": "netresearch/jsonmapper",
@@ -693,16 +681,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v4.19.4",
+ "version": "v4.19.5",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
+ "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
- "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/51bd93cc741b7fc3d63d20b6bdcd99fdaa359837",
+ "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837",
"shasum": ""
},
"require": {
@@ -717,11 +705,6 @@
"bin/php-parse"
],
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "4.9-dev"
- }
- },
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
@@ -743,9 +726,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.5"
},
- "time": "2024-09-29T15:01:53+00:00"
+ "time": "2025-12-06T11:45:25+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -802,16 +785,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "5.6.2",
+ "version": "5.6.7",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62"
+ "reference": "31a105931bc8ffa3a123383829772e832fd8d903"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62",
- "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/31a105931bc8ffa3a123383829772e832fd8d903",
+ "reference": "31a105931bc8ffa3a123383829772e832fd8d903",
"shasum": ""
},
"require": {
@@ -821,7 +804,7 @@
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.7",
"phpstan/phpdoc-parser": "^1.7|^2.0",
- "webmozart/assert": "^1.9.1"
+ "webmozart/assert": "^1.9.1 || ^2"
},
"require-dev": {
"mockery/mockery": "~1.3.5 || ~1.6.0",
@@ -860,22 +843,22 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2"
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.7"
},
- "time": "2025-04-13T19:20:35+00:00"
+ "time": "2026-03-18T20:47:46+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.10.0",
+ "version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
+ "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195",
+ "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195",
"shasum": ""
},
"require": {
@@ -918,22 +901,22 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0"
},
- "time": "2024-11-09T15:12:26+00:00"
+ "time": "2025-11-21T15:09:14+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "2.1.0",
+ "version": "2.3.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68"
+ "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
- "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a",
+ "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a",
"shasum": ""
},
"require": {
@@ -965,9 +948,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2"
},
- "time": "2025-02-19T13:28:12+00:00"
+ "time": "2026-01-25T14:56:51+00:00"
},
{
"name": "psr/container",
@@ -1141,16 +1124,16 @@
},
{
"name": "spatie/array-to-xml",
- "version": "3.4.0",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/spatie/array-to-xml.git",
- "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67"
+ "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
- "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67",
+ "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224",
+ "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224",
"shasum": ""
},
"require": {
@@ -1193,7 +1176,7 @@
"xml"
],
"support": {
- "source": "https://github.com/spatie/array-to-xml/tree/3.4.0"
+ "source": "https://github.com/spatie/array-to-xml/tree/3.4.4"
},
"funding": [
{
@@ -1205,20 +1188,20 @@
"type": "github"
}
],
- "time": "2024-12-16T12:45:15+00:00"
+ "time": "2025-12-15T09:00:41+00:00"
},
{
"name": "symfony/console",
- "version": "v6.4.23",
+ "version": "v6.4.41",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93"
+ "reference": "d21b17ed158e79180fac3895ff751707970eeb57"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/9056771b8eca08d026cd3280deeec3cfd99c4d93",
- "reference": "9056771b8eca08d026cd3280deeec3cfd99c4d93",
+ "url": "https://api.github.com/repos/symfony/console/zipball/d21b17ed158e79180fac3895ff751707970eeb57",
+ "reference": "d21b17ed158e79180fac3895ff751707970eeb57",
"shasum": ""
},
"require": {
@@ -1283,7 +1266,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.4.23"
+ "source": "https://github.com/symfony/console/tree/v6.4.41"
},
"funding": [
{
@@ -1294,25 +1277,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-06-27T19:37:22+00:00"
+ "time": "2026-05-24T08:48:41+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.6.0",
+ "version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
- "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b",
+ "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b",
"shasum": ""
},
"require": {
@@ -1325,7 +1312,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.6-dev"
+ "dev-main": "3.7-dev"
}
},
"autoload": {
@@ -1350,7 +1337,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0"
},
"funding": [
{
@@ -1361,25 +1348,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-25T14:21:43+00:00"
+ "time": "2026-04-13T15:52:40+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v6.4.13",
+ "version": "v6.4.39",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3"
+ "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3",
- "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/c507b077756b4e3e09adbbe7975fac81cd3722ca",
+ "reference": "c507b077756b4e3e09adbbe7975fac81cd3722ca",
"shasum": ""
},
"require": {
@@ -1416,7 +1407,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v6.4.13"
+ "source": "https://github.com/symfony/filesystem/tree/v6.4.39"
},
"funding": [
{
@@ -1427,25 +1418,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-10-25T15:07:50+00:00"
+ "time": "2026-05-07T13:11:42+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.32.0",
+ "version": "v1.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2",
"shasum": ""
},
"require": {
@@ -1495,7 +1490,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0"
},
"funding": [
{
@@ -1506,25 +1501,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.32.0",
+ "version": "v1.38.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
+ "reference": "e9247d281d694a5120554d9afaf54e070e88a603"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603",
+ "reference": "e9247d281d694a5120554d9afaf54e070e88a603",
"shasum": ""
},
"require": {
@@ -1573,7 +1572,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1"
},
"funding": [
{
@@ -1584,25 +1583,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2026-05-26T05:58:03+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.32.0",
+ "version": "v1.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c"
+ "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
+ "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"shasum": ""
},
"require": {
@@ -1654,7 +1657,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
},
"funding": [
{
@@ -1665,25 +1668,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2026-05-25T13:48:31+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
+ "version": "v1.38.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
+ "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
"shasum": ""
},
"require": {
@@ -1735,7 +1742,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2"
},
"funding": [
{
@@ -1746,25 +1753,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-12-23T08:48:59+00:00"
+ "time": "2026-05-27T06:59:30+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.6.0",
+ "version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a",
+ "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a",
"shasum": ""
},
"require": {
@@ -1782,7 +1793,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.6-dev"
+ "dev-main": "3.7-dev"
}
},
"autoload": {
@@ -1818,7 +1829,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.7.0"
},
"funding": [
{
@@ -1829,25 +1840,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-25T09:37:31+00:00"
+ "time": "2026-03-28T09:44:51+00:00"
},
{
"name": "symfony/string",
- "version": "v6.4.21",
+ "version": "v6.4.39",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "73e2c6966a5aef1d4892873ed5322245295370c6"
+ "reference": "62e3c927de664edadb5bef260987eb047a17a113"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/73e2c6966a5aef1d4892873ed5322245295370c6",
- "reference": "73e2c6966a5aef1d4892873ed5322245295370c6",
+ "url": "https://api.github.com/repos/symfony/string/zipball/62e3c927de664edadb5bef260987eb047a17a113",
+ "reference": "62e3c927de664edadb5bef260987eb047a17a113",
"shasum": ""
},
"require": {
@@ -1861,7 +1876,6 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/http-client": "^5.4|^6.0|^7.0",
"symfony/intl": "^6.2|^7.0",
"symfony/translation-contracts": "^2.5|^3.0",
@@ -1904,7 +1918,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.4.21"
+ "source": "https://github.com/symfony/string/tree/v6.4.39"
},
"funding": [
{
@@ -1915,12 +1929,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-18T15:23:29+00:00"
+ "time": "2026-05-12T11:44:19+00:00"
},
{
"name": "vimeo/psalm",
@@ -2034,28 +2052,28 @@
},
{
"name": "webmozart/assert",
- "version": "1.11.0",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
+ "reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
+ "reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"shasum": ""
},
"require": {
"ext-ctype": "*",
+ "ext-date": "*",
+ "ext-filter": "*",
"php": "^7.2 || ^8.0"
},
- "conflict": {
- "phpstan/phpstan": "<0.12.20",
- "vimeo/psalm": "<4.6.1 || 4.6.2"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.5.13"
+ "suggest": {
+ "ext-intl": "",
+ "ext-simplexml": "",
+ "ext-spl": ""
},
"type": "library",
"extra": {
@@ -2086,9 +2104,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+ "source": "https://github.com/webmozarts/assert/tree/1.12.1"
},
- "time": "2022-06-03T18:03:27+00:00"
+ "time": "2025-10-29T15:56:20+00:00"
}
],
"aliases": [],