Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,18 +361,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Cache/SelectOptionsCacher.php',
];
$ignoreErrors[] = [
'message' => '#^Cannot access offset \'host\' on array\\{scheme\\?\\: string, host\\?\\: string, port\\?\\: int\\<0, 65535\\>, user\\?\\: string, pass\\?\\: string, path\\?\\: string, query\\?\\: string, fragment\\?\\: string\\}\\|false\\.$#',
'identifier' => 'offsetAccess.nonOffsetAccessible',
'count' => 2,
'path' => __DIR__ . '/src/Canonical.php',
];
$ignoreErrors[] = [
'message' => '#^Cannot access offset \'scheme\' on array\\{scheme\\?\\: string, host\\?\\: string, port\\?\\: int\\<0, 65535\\>, user\\?\\: string, pass\\?\\: string, path\\?\\: string, query\\?\\: string, fragment\\?\\: string\\}\\|false\\.$#',
'identifier' => 'offsetAccess.nonOffsetAccessible',
'count' => 3,
'path' => __DIR__ . '/src/Canonical.php',
];
$ignoreErrors[] = [
'message' => '#^Method Bolt\\\\Canonical\\:\\:generateLink\\(\\) has parameter \\$canonical with no type specified\\.$#',
'identifier' => 'missingType.parameter',
Expand Down Expand Up @@ -1357,12 +1345,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Controller/Backend/ResetPasswordController.php',
];
$ignoreErrors[] = [
'message' => '#^Method Bolt\\\\Controller\\\\Backend\\\\ResetPasswordController\\:\\:buildResetEmail\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#',
'identifier' => 'missingType.iterableValue',
'count' => 1,
'path' => __DIR__ . '/src/Controller/Backend/ResetPasswordController.php',
];
$ignoreErrors[] = [
'message' => '#^Method Bolt\\\\Controller\\\\Backend\\\\ResetPasswordController\\:\\:buildResetEmail\\(\\) has parameter \\$resetToken with no type specified\\.$#',
'identifier' => 'missingType.parameter',
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<env name="CORS_ALLOW_ORIGIN" value="^https?://localhost(:[0-9]+)?$"/>
<!-- ###- nelmio/cors-bundle ### -->
<!-- ###+ symfony/mailer ### -->
<!-- MAILER_DSN=smtp://localhost -->
<env name="MAILER_DSN" value="null://null"/>
<!-- ###- symfony/mailer ### -->
</php>
<testsuites>
Expand Down
20 changes: 20 additions & 0 deletions src/Canonical.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ public function setRequest(?Request $request = null): void

$requestUrl = parse_url($this->request->getSchemeAndHttpHost());

// Handle test environment or malformed URLs
if ($requestUrl === false || ! isset($requestUrl['scheme'])) {
$this->setScheme('http');
$this->setHost('localhost');
$this->setPort(null);
$_SERVER['CANONICAL_HOST'] = 'localhost';
$_SERVER['CANONICAL_SCHEME'] = 'http';
return;
}

$configCanonical = (string) $this->config->get('general/canonical', $this->getRequest()->getSchemeAndHttpHost());

if (mb_strpos($configCanonical, 'http') !== 0) {
Expand All @@ -66,6 +76,16 @@ public function setRequest(?Request $request = null): void

$configUrl = parse_url($configCanonical);

// Handle malformed canonical URL
if ($configUrl === false || ! isset($configUrl['scheme']) || ! isset($configUrl['host'])) {
$this->setScheme('http');
$this->setHost('localhost');
$this->setPort(null);
$_SERVER['CANONICAL_HOST'] = 'localhost';
$_SERVER['CANONICAL_SCHEME'] = 'http';
return;
}

$this->setScheme($configUrl['scheme']);
$this->setHost($configUrl['host']);
$this->setPort($configUrl['port'] ?? null);
Expand Down
3 changes: 2 additions & 1 deletion src/Controller/Backend/ResetPasswordController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Bolt\Controller\Backend;

use Bolt\Collection\DeepCollection;
use Bolt\Configuration\Config;
use Bolt\Controller\TwigAwareController;
use Bolt\Entity\User;
Expand Down Expand Up @@ -180,7 +181,7 @@ protected function processSendingPasswordResetEmail(string $emailFormData, Maile
return $this->redirectToRoute('bolt_check_email');
}

protected function buildResetEmail(array $config, $user, $resetToken): Email
protected function buildResetEmail(DeepCollection $config, $user, $resetToken): Email
{
return (new TemplatedEmail())
->from(new Address($config['mail_from'], $config['mail_name']))
Expand Down
39 changes: 39 additions & 0 deletions tests/php/Controller/Backend/ResetPasswordControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Bolt\Tests\Controller\Backend;

use Bolt\Tests\DbAwareTestCase;

/**
* Simple smoke test to verify password reset page loads successfully.
*
* This test was created after fixing a bug where navigating to the reset password
* page caused a TypeError due to strict_types=1 enforcement when config->get()
* returned DeepCollection instead of array
*
* The bug was in Canonical::setRequest() which didn't handle test environment properly,
* causing parse_url() to return false/incomplete array, leading to TypeError when
* trying to access array keys.
*/
class ResetPasswordControllerTest extends DbAwareTestCase
{
/**
* Test that the reset password page loads successfully.
* This is the main regression test - the bug prevented this page from loading.
*/
public function testResetPasswordPageLoads(): void
{
// Navigate directly to reset password page (this is what the "Forgotten password" link does)
$crawler = $this->client->request('GET', '/bolt/reset-password');

// Verify page loads successfully (this would fail with TypeError before the fix)
$this->assertResponseIsSuccessful();
$this->assertRouteSame('bolt_forgot_password_request');

// Verify the form exists with email input
$this->assertSelectorExists('form');
$this->assertSelectorExists('input[name="reset_password_request_form[email]"]');
}
}
Loading