diff --git a/composer.json b/composer.json
index a463ae88..95b71313 100644
--- a/composer.json
+++ b/composer.json
@@ -40,7 +40,7 @@
"dama/doctrine-test-bundle": "^v8.2.0",
"friendsofphp/php-cs-fixer": "v3.95.13",
"phpunit/phpunit": "^12.0",
- "rector/rector": "2.4.5",
+ "rector/rector": "2.5.4",
"roave/security-advisories": "dev-latest",
"symfony/browser-kit": "v8.0.8",
"symfony/css-selector": "v8.0.9",
diff --git a/composer.lock b/composer.lock
index 72f98a70..c7b8f75b 100644
--- a/composer.lock
+++ b/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": "3e9f02d9b3d7dd0c075fc7100d1b46ec",
+ "content-hash": "a8b3c086b9219086bc7135fb6cfd9b09",
"packages": [
{
"name": "composer/ca-bundle",
@@ -9749,21 +9749,21 @@
},
{
"name": "rector/rector",
- "version": "2.4.5",
+ "version": "2.5.4",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
- "reference": "cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c"
+ "reference": "adaa18d7cd6b3c960967cfbc98c03efb3116ac0e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rectorphp/rector/zipball/cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c",
- "reference": "cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c",
+ "url": "https://api.github.com/repos/rectorphp/rector/zipball/adaa18d7cd6b3c960967cfbc98c03efb3116ac0e",
+ "reference": "adaa18d7cd6b3c960967cfbc98c03efb3116ac0e",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0",
- "phpstan/phpstan": "^2.1.56"
+ "phpstan/phpstan": "^2.2.2"
},
"conflict": {
"rector/rector-doctrine": "*",
@@ -9797,7 +9797,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
- "source": "https://github.com/rectorphp/rector/tree/2.4.5"
+ "source": "https://github.com/rectorphp/rector/tree/2.5.4"
},
"funding": [
{
@@ -9805,7 +9805,7 @@
"type": "github"
}
],
- "time": "2026-05-26T21:03:22+00:00"
+ "time": "2026-07-06T12:41:46+00:00"
},
{
"name": "roave/security-advisories",
diff --git a/src/Command/AliasAddCommand.php b/src/Command/AliasAddCommand.php
index 9d930cf0..8c06edd2 100644
--- a/src/Command/AliasAddCommand.php
+++ b/src/Command/AliasAddCommand.php
@@ -21,7 +21,6 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class AliasAddCommand extends Command
diff --git a/src/Command/DomainAddCommand.php b/src/Command/DomainAddCommand.php
index 4c34c2f9..488cbdf6 100644
--- a/src/Command/DomainAddCommand.php
+++ b/src/Command/DomainAddCommand.php
@@ -18,7 +18,6 @@
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class DomainAddCommand extends Command
diff --git a/src/Command/InitSetupCommand.php b/src/Command/InitSetupCommand.php
index dfd455ab..8a35d7c4 100644
--- a/src/Command/InitSetupCommand.php
+++ b/src/Command/InitSetupCommand.php
@@ -20,7 +20,6 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
-use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class InitSetupCommand extends Command
diff --git a/src/Command/UserAddCommand.php b/src/Command/UserAddCommand.php
index 7c25e93d..7f820978 100644
--- a/src/Command/UserAddCommand.php
+++ b/src/Command/UserAddCommand.php
@@ -23,7 +23,6 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
-use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class UserAddCommand extends Command
diff --git a/src/Controller/Admin/DashboardController.php b/src/Controller/Admin/DashboardController.php
index 4026d6b3..f89e10b6 100644
--- a/src/Controller/Admin/DashboardController.php
+++ b/src/Controller/Admin/DashboardController.php
@@ -46,7 +46,8 @@ public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('mailserver-admin')
- ->setFaviconPath('favicon.svg');
+ ->setFaviconPath('favicon.svg')
+ ->generateRelativeUrls();
}
#[\Override]
diff --git a/templates/bundles/EasyAdminBundle/page/login.html.twig b/templates/bundles/EasyAdminBundle/page/login.html.twig
index 9b95c0a9..f6331c2c 100644
--- a/templates/bundles/EasyAdminBundle/page/login.html.twig
+++ b/templates/bundles/EasyAdminBundle/page/login.html.twig
@@ -4,7 +4,9 @@
{{ include('admin/_includes/logo.html.twig') }}
- {{ parent() }}
+
+ {{ parent() }}
+
{% endblock %}
{% block head_favicon %}
diff --git a/tests/Integration/Controller/Admin/DKIMCrudControllerTest.php b/tests/Integration/Controller/Admin/DKIMCrudControllerTest.php
index b65a6fcc..73176012 100644
--- a/tests/Integration/Controller/Admin/DKIMCrudControllerTest.php
+++ b/tests/Integration/Controller/Admin/DKIMCrudControllerTest.php
@@ -162,6 +162,25 @@ public function testRecreateKey(): void
static::assertNotEmpty($updatedDomain->getDkimPrivateKey());
}
+ public function testRecreateKeyRelativeFormUrl(): void
+ {
+ $this->loginClient($this->client);
+
+ $domainRepository = $this->entityManager->getRepository(Domain::class);
+ \assert($domainRepository instanceof DomainRepository);
+ $domain = $domainRepository->findOneBy(['name' => 'example.com']);
+ static::assertInstanceOf(Domain::class, $domain);
+
+ $this->client->request(Request::METHOD_GET, $this->generateEditFormUrl($domain->getId()));
+ static::assertResponseIsSuccessful();
+
+ $form = $this->client->getCrawler()->filter('form.action-recreateKey');
+ $action = $form->attr('action');
+
+ static::assertStringStartsNotWith('http://', $action, 'Relative URL configuration is required for the DashboardController.');
+ static::assertStringStartsNotWith('https://', $action, 'Relative URL configuration is required for the DashboardController.');
+ }
+
protected function getControllerFqcn(): string
{
return DKIMCrudController::class;
diff --git a/tests/Unit/Command/RedisSyncCommandTest.php b/tests/Unit/Command/RedisSyncCommandTest.php
index 14641ac7..bc80d9ef 100644
--- a/tests/Unit/Command/RedisSyncCommandTest.php
+++ b/tests/Unit/Command/RedisSyncCommandTest.php
@@ -23,8 +23,17 @@ class RedisSyncCommandTest extends TestCase
{
private CommandTester $commandTester;
+ /**
+ * @var MockObject&Manager
+ */
private MockObject $managerMock;
+ /**
+ * @var MockObject&AccountWriter
+ */
private MockObject $accountWriterMock;
+ /**
+ * @var MockObject&ConnectionCheckService
+ */
private MockObject $connectionCheckServiceMock;
protected function setUp(): void
diff --git a/tests/Unit/Controller/Admin/Observability/DovecotStatsControllerTest.php b/tests/Unit/Controller/Admin/Observability/DovecotStatsControllerTest.php
index 20542f16..5ebddcd0 100644
--- a/tests/Unit/Controller/Admin/Observability/DovecotStatsControllerTest.php
+++ b/tests/Unit/Controller/Admin/Observability/DovecotStatsControllerTest.php
@@ -215,8 +215,8 @@ public function testChartsFragmentWithData(): void
'auth_failures' => new RateSeriesDto('auth_failures', '/min', [], []),
];
$mailDeliveryRates = new RateSeriesDto('mail_deliveries', '/min', [], []);
- $authChart = $this->createMock(Chart::class);
- $mailDeliveriesChart = $this->createMock(Chart::class);
+ $authChart = $this->createStub(Chart::class);
+ $mailDeliveriesChart = $this->createStub(Chart::class);
$this->sampler
->expects($this->once())
diff --git a/tests/Unit/Controller/Admin/Observability/RspamdStatsControllerTest.php b/tests/Unit/Controller/Admin/Observability/RspamdStatsControllerTest.php
index dbaa4224..3a1afce3 100644
--- a/tests/Unit/Controller/Admin/Observability/RspamdStatsControllerTest.php
+++ b/tests/Unit/Controller/Admin/Observability/RspamdStatsControllerTest.php
@@ -102,7 +102,7 @@ public function testSummary(): void
public function testThroughputWithValidType(): void
{
$series = new TimeSeriesDto(TimeSeriesDto::TYPE_DAY, ['00:00'], ['spam' => [10]]);
- $chart = $this->createMock(Chart::class);
+ $chart = $this->createStub(Chart::class);
$this->statsService
->expects($this->once())
@@ -134,7 +134,7 @@ public function testThroughputWithValidType(): void
public function testThroughputWithInvalidType(): void
{
$series = TimeSeriesDto::empty('day');
- $chart = $this->createMock(Chart::class);
+ $chart = $this->createStub(Chart::class);
$this->statsService
->expects($this->once())
@@ -161,7 +161,7 @@ public function testThroughputWithInvalidType(): void
public function testActionsPie(): void
{
$distribution = new ActionDistributionDto(['reject' => 100]);
- $chart = $this->createMock(Chart::class);
+ $chart = $this->createStub(Chart::class);
$this->statsService
->expects($this->once())
diff --git a/tests/Unit/Service/ConnectionCheckServiceTest.php b/tests/Unit/Service/ConnectionCheckServiceTest.php
index 8c017cb3..b762a754 100644
--- a/tests/Unit/Service/ConnectionCheckServiceTest.php
+++ b/tests/Unit/Service/ConnectionCheckServiceTest.php
@@ -101,7 +101,7 @@ public function testCheckMySQLWithAllowEmptyDatabaseSuccess(): void
->expects($this->once())
->method('executeQuery')
->with('SELECT 1')
- ->willReturn($this->createMock(Result::class));
+ ->willReturn($this->createStub(Result::class));
$this->entityManager
->expects($this->once())
@@ -404,7 +404,7 @@ public function testCheckAllWithAllowEmptyDatabase(): void
->expects($this->once())
->method('executeQuery')
->with('SELECT 1')
- ->willReturn($this->createMock(Result::class));
+ ->willReturn($this->createStub(Result::class));
$this->entityManager
->expects($this->once())
@@ -438,7 +438,7 @@ public function testCheckAllWithAllowEmptyDatabaseAndAllServices(): void
->expects($this->once())
->method('executeQuery')
->with('SELECT 1')
- ->willReturn($this->createMock(Result::class));
+ ->willReturn($this->createStub(Result::class));
$this->entityManager
->expects($this->once())
diff --git a/tests/Unit/Service/DKIM/DomainKeyReaderServiceTest.php b/tests/Unit/Service/DKIM/DomainKeyReaderServiceTest.php
index 30ba0f05..4cb0384d 100644
--- a/tests/Unit/Service/DKIM/DomainKeyReaderServiceTest.php
+++ b/tests/Unit/Service/DKIM/DomainKeyReaderServiceTest.php
@@ -17,6 +17,9 @@
class DomainKeyReaderServiceTest extends TestCase
{
+ /**
+ * @var MockObject&DnsLookupInterface
+ */
private MockObject $resolver;
private DomainKeyReaderService $instance;
diff --git a/tests/Unit/Service/Security/User/OAuth/UserProviderTest.php b/tests/Unit/Service/Security/User/OAuth/UserProviderTest.php
index 4581702c..f9746e96 100644
--- a/tests/Unit/Service/Security/User/OAuth/UserProviderTest.php
+++ b/tests/Unit/Service/Security/User/OAuth/UserProviderTest.php
@@ -16,12 +16,14 @@
use Doctrine\ORM\EntityManagerInterface;
use HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse;
use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException;
+use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
+#[AllowMockObjectsWithoutExpectations]
class UserProviderTest extends TestCase
{
private MockObject&UserRepository $userRepository;