diff --git a/phpstan.neon.dist b/phpstan.neon.dist index a19e9a59..10b4d55a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,5 +10,9 @@ parameters: - src/Test/AbstractWidgetTestCase.php - tests/bootstrap.php + ignoreErrors: + - '#^Parameter \$securityContext of method Sonata\\IntlBundle\\Timezone\\UserBasedTimezoneDetector::__construct\(\) has invalid typehint type Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface\.$#' + - '#^Class Sonata\\UserBundle\\Model\\User not found\.$#' + autoload_files: - vendor/autoload.php diff --git a/src/Timezone/TimezoneAwareInterface.php b/src/Timezone/TimezoneAwareInterface.php new file mode 100644 index 00000000..a7885db3 --- /dev/null +++ b/src/Timezone/TimezoneAwareInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\IntlBundle\Timezone; + +/** + * @author Javier Spagnoletti + */ +interface TimezoneAwareInterface +{ + public function getTimezone(): ?string; +} diff --git a/src/Timezone/TimezoneAwareTrait.php b/src/Timezone/TimezoneAwareTrait.php new file mode 100644 index 00000000..41d8ab62 --- /dev/null +++ b/src/Timezone/TimezoneAwareTrait.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\IntlBundle\Timezone; + +/** + * Basic Implementation of TimezoneAwareInterface. + * + * @author Javier Spagnoletti + */ +trait TimezoneAwareTrait +{ + /** + * @var string|null + */ + private $timezone; + + final public function getTimezone(): ?string + { + return $this->timezone; + } +} diff --git a/src/Timezone/TimezoneDetectorInterface.php b/src/Timezone/TimezoneDetectorInterface.php index da858b8d..f2a0ee98 100644 --- a/src/Timezone/TimezoneDetectorInterface.php +++ b/src/Timezone/TimezoneDetectorInterface.php @@ -23,7 +23,7 @@ interface TimezoneDetectorInterface /** * Get the appropriate timezone. * - * @return string + * @return string|null */ public function getTimezone(); } diff --git a/src/Timezone/UserBasedTimezoneDetector.php b/src/Timezone/UserBasedTimezoneDetector.php index 8f347cb4..8c3db76f 100644 --- a/src/Timezone/UserBasedTimezoneDetector.php +++ b/src/Timezone/UserBasedTimezoneDetector.php @@ -36,15 +36,22 @@ public function __construct(TokenStorageInterface $securityContext) public function getTimezone() { if (!$token = $this->securityContext->getToken()) { - return; + return null; } if (!$user = $token->getUser()) { - return; + return null; } + if ($user instanceof TimezoneAwareInterface) { + return $user->getTimezone(); + } + + // NEXT_MAJOR: Remove this check when `User` implement `TimezoneAwareInterface` if ($user instanceof User) { return $user->getTimezone(); } + + return null; } } diff --git a/tests/Timezone/UserBasedTimezoneDetectorTest.php b/tests/Timezone/UserBasedTimezoneDetectorTest.php index d9917aad..27438eb2 100644 --- a/tests/Timezone/UserBasedTimezoneDetectorTest.php +++ b/tests/Timezone/UserBasedTimezoneDetectorTest.php @@ -14,6 +14,8 @@ namespace Sonata\IntlBundle\Tests\Timezone; use PHPUnit\Framework\TestCase; +use Sonata\IntlBundle\Timezone\TimezoneAwareInterface; +use Sonata\IntlBundle\Timezone\TimezoneAwareTrait; use Sonata\IntlBundle\Timezone\UserBasedTimezoneDetector; use Sonata\UserBundle\Model\User; use Sonata\UserBundle\SonataUserBundle; @@ -23,16 +25,9 @@ /** * @author Emmanuel Vella */ -class UserBasedTimezoneDetectorTest extends TestCase +final class UserBasedTimezoneDetectorTest extends TestCase { - protected function setUp(): void - { - if (!class_exists(SonataUserBundle::class)) { - $this->markTestSkipped('SonataUserBundle must be installed to run this test.'); - } - } - - public static function timezoneProvider() + public static function timezoneProvider(): iterable { return [ ['Europe/Paris'], @@ -40,13 +35,50 @@ public static function timezoneProvider() ]; } + /** + * @dataProvider timezoneProvider + */ + public function testUserTimezoneDetection(?string $timezone): void + { + $user = new class($timezone) implements TimezoneAwareInterface { + use TimezoneAwareTrait; + + public function __construct(?string $timezone) + { + $this->timezone = $timezone; + } + }; + + $token = $this->createMock(TokenInterface::class); + $token + ->expects($this->once()) + ->method('getUser') + ->willReturn($user) + ; + + $storage = $this->createMock(TokenStorageInterface::class); + + $storage + ->expects($this->once()) + ->method('getToken') + ->willReturn($token) + ; + + $timezoneDetector = new UserBasedTimezoneDetector($storage); + $this->assertSame($timezone, $timezoneDetector->getTimezone()); + } + /** * @dataProvider timezoneProvider * * @group legacy */ - public function testDetectsTimezoneForUser($timezone) + public function testDetectsTimezoneForUser(?string $timezone): void { + if (!class_exists(SonataUserBundle::class)) { + $this->markTestSkipped('SonataUserBundle must be installed to run this test.'); + } + $user = $this->createMock(User::class); $user ->method('getTimezone') @@ -70,7 +102,7 @@ public function testDetectsTimezoneForUser($timezone) $this->assertSame($timezone, $timezoneDetector->getTimezone()); } - public function testTimezoneNotDetected() + public function testTimezoneNotDetected(): void { $storage = $this->createMock(TokenStorageInterface::class);