diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e3212f..0e7cd97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ See [keep a changelog] for information about writing changes to this log. ## [Unreleased] +- [PR-71](https://github.com/itk-dev/event-database-api/pull/71) + Require PHP 8.5 and apply the Rector PHP 8.5 rules + - [PR-70](https://github.com/itk-dev/event-database-api/pull/70) Update the docker compose template (itk-version 3.2.4) and the PHP 8.5 image diff --git a/CLAUDE.md b/CLAUDE.md index 26679fd..7cc162e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ API platform front-end for the Danish event database used by the municipality of `docker-compose.yml` is part of the standard ITK Dev Symfony image but is **not used for domain data** (the `migrations/` and `src/Entity/` directories are empty). -Stack: PHP 8.3+, Symfony 7.4, API Platform 4.3, Elasticsearch 8.x. Runs entirely in Docker via +Stack: PHP 8.5+, Symfony 7.4, API Platform 4.3, Elasticsearch 8.x. Runs entirely in Docker via `itkdev/php8.5-fpm` + nginx. ## Common commands diff --git a/composer.json b/composer.json index ffeefda..26f7f92 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "license": "proprietary", "type": "project", "require": { - "php": ">=8.3", + "php": ">=8.5", "ext-ctype": "*", "ext-iconv": "*", "api-platform/core": "~4.3.0", diff --git a/composer.lock b/composer.lock index 3c3f893..382719a 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": "747cb423309e517227c3648b1003fc5a", + "content-hash": "1c8b255e46f2edded27db7812fe8114e", "packages": [ { "name": "api-platform/core", @@ -8030,7 +8030,8 @@ "type": "github" } ], - "time": "2026-07-05T06:31:06+00:00" + "time": "2026-07-05T06:31:06+00:00", + "published-time": "2026-07-05T06:31:19+00:00" }, { "name": "phpstan/phpstan-strict-rules", @@ -11116,10 +11117,10 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.3", + "php": ">=8.5", "ext-ctype": "*", "ext-iconv": "*" }, "platform-dev": {}, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.11.0" } diff --git a/rector.php b/rector.php index 37ea484..9a2a485 100644 --- a/rector.php +++ b/rector.php @@ -13,7 +13,7 @@ // Coding style and import (`use`) management are owned by php-cs-fixer // (PostToolUse hook / coding standards), so Rector does not touch them. // - // Modernize to the language level declared in composer.json (PHP >= 8.3). + // Modernize to the language level declared in composer.json (PHP >= 8.5). ->withPhpSets() // Version-based upgrade + quality rules resolved from the installed package // versions (Symfony 7.4, PHPUnit 13). No domain Doctrine here — the entities diff --git a/src/Command/ApiKeysAddCommand.php b/src/Command/ApiKeysAddCommand.php index a343f19..4104de0 100644 --- a/src/Command/ApiKeysAddCommand.php +++ b/src/Command/ApiKeysAddCommand.php @@ -187,7 +187,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int */ private function parseApiKeys(string $contents): array { - $value = (new Dotenv())->parse($contents)[self::ENV_VAR] ?? '[]'; + $value = new Dotenv()->parse($contents)[self::ENV_VAR] ?? '[]'; return json_decode($value, true, 512, JSON_THROW_ON_ERROR); } diff --git a/src/Service/ElasticSearch/ElasticIndexException.php b/src/Service/ElasticSearch/ElasticIndexException.php index 7b0074d..3c1aa3c 100644 --- a/src/Service/ElasticSearch/ElasticIndexException.php +++ b/src/Service/ElasticSearch/ElasticIndexException.php @@ -35,7 +35,7 @@ private function parse400(string $message): string $message = json_decode($message, false, 512, JSON_THROW_ON_ERROR); // Convert snake_case type to readable format (e.g., "parse_exception" -> "Parse exception") - $type = (new UnicodeString($message->error->root_cause[0]->type)) + $type = new UnicodeString($message->error->root_cause[0]->type) ->replace('_', ' ') ->title() ->toString(); diff --git a/tests/ApiPlatform/AbstractApiTestCase.php b/tests/ApiPlatform/AbstractApiTestCase.php index 36075f9..efd7fd7 100644 --- a/tests/ApiPlatform/AbstractApiTestCase.php +++ b/tests/ApiPlatform/AbstractApiTestCase.php @@ -10,6 +10,7 @@ abstract class AbstractApiTestCase extends ApiTestCase { + #[\Override] protected static ?bool $alwaysBootKernel = false; protected static string $requestPath; @@ -52,7 +53,7 @@ protected function get(array $query, ?string $path = null, bool $authenticated = protected static function formatDateTime(string $datetime): string { - return (new \DateTimeImmutable($datetime))->format(\DateTimeImmutable::ATOM); + return new \DateTimeImmutable($datetime)->format(\DateTimeImmutable::ATOM); } /** diff --git a/tests/ApiPlatform/AuthenticationTest.php b/tests/ApiPlatform/AuthenticationTest.php index 17c391e..d209526 100644 --- a/tests/ApiPlatform/AuthenticationTest.php +++ b/tests/ApiPlatform/AuthenticationTest.php @@ -12,6 +12,7 @@ */ final class AuthenticationTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('protectedEndpointProvider')] diff --git a/tests/ApiPlatform/Consumer/AarhusguidenContractTest.php b/tests/ApiPlatform/Consumer/AarhusguidenContractTest.php index 99b7146..27120c8 100644 --- a/tests/ApiPlatform/Consumer/AarhusguidenContractTest.php +++ b/tests/ApiPlatform/Consumer/AarhusguidenContractTest.php @@ -23,6 +23,7 @@ */ final class AarhusguidenContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/daily_occurrences'; // Calendar / tag view: public events carrying a tag, within a date window, diff --git a/tests/ApiPlatform/Consumer/Os2displayContractTest.php b/tests/ApiPlatform/Consumer/Os2displayContractTest.php index 5811f6b..a6a9db8 100644 --- a/tests/ApiPlatform/Consumer/Os2displayContractTest.php +++ b/tests/ApiPlatform/Consumer/Os2displayContractTest.php @@ -30,6 +30,7 @@ */ final class Os2displayContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/occurrences'; // Subscription poster: upcoming occurrences (end[gt]) for a tag/location. diff --git a/tests/ApiPlatform/Contract/CollectionContractTest.php b/tests/ApiPlatform/Contract/CollectionContractTest.php index 7c65a30..95b5fd6 100644 --- a/tests/ApiPlatform/Contract/CollectionContractTest.php +++ b/tests/ApiPlatform/Contract/CollectionContractTest.php @@ -19,6 +19,7 @@ */ final class CollectionContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('collectionProvider')] diff --git a/tests/ApiPlatform/Contract/ContentNegotiationContractTest.php b/tests/ApiPlatform/Contract/ContentNegotiationContractTest.php index a075060..c9cb196 100644 --- a/tests/ApiPlatform/Contract/ContentNegotiationContractTest.php +++ b/tests/ApiPlatform/Contract/ContentNegotiationContractTest.php @@ -16,6 +16,7 @@ */ final class ContentNegotiationContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; public function testLdJsonIsSupported(): void diff --git a/tests/ApiPlatform/Contract/DateFormatContractTest.php b/tests/ApiPlatform/Contract/DateFormatContractTest.php index eb49f13..c0e9e72 100644 --- a/tests/ApiPlatform/Contract/DateFormatContractTest.php +++ b/tests/ApiPlatform/Contract/DateFormatContractTest.php @@ -13,6 +13,7 @@ */ final class DateFormatContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; private const string ISO_8601_OFFSET = '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/'; diff --git a/tests/ApiPlatform/Contract/ErrorContractTest.php b/tests/ApiPlatform/Contract/ErrorContractTest.php index d5656a6..56a6111 100644 --- a/tests/ApiPlatform/Contract/ErrorContractTest.php +++ b/tests/ApiPlatform/Contract/ErrorContractTest.php @@ -22,6 +22,7 @@ */ final class ErrorContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; public function testUnauthenticatedErrorShape(): void diff --git a/tests/ApiPlatform/Contract/ItemContractTest.php b/tests/ApiPlatform/Contract/ItemContractTest.php index 3c6ec51..045cb80 100644 --- a/tests/ApiPlatform/Contract/ItemContractTest.php +++ b/tests/ApiPlatform/Contract/ItemContractTest.php @@ -21,6 +21,7 @@ */ final class ItemContractTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('collectionWrappedItemProvider')] diff --git a/tests/ApiPlatform/DailyOccurrencesFilterTest.php b/tests/ApiPlatform/DailyOccurrencesFilterTest.php index 1b9efb6..db92321 100644 --- a/tests/ApiPlatform/DailyOccurrencesFilterTest.php +++ b/tests/ApiPlatform/DailyOccurrencesFilterTest.php @@ -14,6 +14,7 @@ */ final class DailyOccurrencesFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/daily_occurrences'; #[DataProvider('getDailyOccurrencesProvider')] diff --git a/tests/ApiPlatform/DailyOccurrencesTest.php b/tests/ApiPlatform/DailyOccurrencesTest.php index c7a7883..826d711 100644 --- a/tests/ApiPlatform/DailyOccurrencesTest.php +++ b/tests/ApiPlatform/DailyOccurrencesTest.php @@ -13,13 +13,17 @@ final class DailyOccurrencesTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/daily_occurrences'; + #[\Override] protected static string $resourceClass = DailyOccurrence::class; // Members are the raw Elasticsearch _source with no @id/@type, so API // Platform's self-generated collection schema does not apply (see D6). + #[\Override] protected static bool $assertsGeneratedCollectionSchema = false; + #[\Override] protected static int|string $itemId = 10; } diff --git a/tests/ApiPlatform/EventsFilterTest.php b/tests/ApiPlatform/EventsFilterTest.php index 32b5e0d..d906dab 100644 --- a/tests/ApiPlatform/EventsFilterTest.php +++ b/tests/ApiPlatform/EventsFilterTest.php @@ -15,6 +15,7 @@ */ final class EventsFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('getEventsProvider')] diff --git a/tests/ApiPlatform/EventsTest.php b/tests/ApiPlatform/EventsTest.php index 6b0f0d4..0c1c154 100644 --- a/tests/ApiPlatform/EventsTest.php +++ b/tests/ApiPlatform/EventsTest.php @@ -16,13 +16,17 @@ final class EventsTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/events'; + #[\Override] protected static string $resourceClass = Event::class; // Members are the raw Elasticsearch _source with no @id/@type, so API // Platform's self-generated collection schema does not apply (see D6). + #[\Override] protected static bool $assertsGeneratedCollectionSchema = false; + #[\Override] protected static int|string $itemId = 7; } diff --git a/tests/ApiPlatform/FilterErrorTest.php b/tests/ApiPlatform/FilterErrorTest.php index 8982021..daf88ec 100644 --- a/tests/ApiPlatform/FilterErrorTest.php +++ b/tests/ApiPlatform/FilterErrorTest.php @@ -19,6 +19,7 @@ */ final class FilterErrorTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('invalidDateRangeProvider')] diff --git a/tests/ApiPlatform/LocationsFilterTest.php b/tests/ApiPlatform/LocationsFilterTest.php index 6866c51..a3c44b6 100644 --- a/tests/ApiPlatform/LocationsFilterTest.php +++ b/tests/ApiPlatform/LocationsFilterTest.php @@ -14,6 +14,7 @@ */ final class LocationsFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/locations'; #[DataProvider('getLocationsProvider')] diff --git a/tests/ApiPlatform/LocationsTest.php b/tests/ApiPlatform/LocationsTest.php index 4db86b7..bf43a18 100644 --- a/tests/ApiPlatform/LocationsTest.php +++ b/tests/ApiPlatform/LocationsTest.php @@ -13,13 +13,17 @@ final class LocationsTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/locations'; + #[\Override] protected static string $resourceClass = Location::class; // Members are the raw Elasticsearch _source with no @id/@type, so API // Platform's self-generated collection schema does not apply (see D6). + #[\Override] protected static bool $assertsGeneratedCollectionSchema = false; + #[\Override] protected static int|string $itemId = 4; } diff --git a/tests/ApiPlatform/OccurrencesFilterTest.php b/tests/ApiPlatform/OccurrencesFilterTest.php index 6018da4..70993ef 100644 --- a/tests/ApiPlatform/OccurrencesFilterTest.php +++ b/tests/ApiPlatform/OccurrencesFilterTest.php @@ -15,6 +15,7 @@ */ final class OccurrencesFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/occurrences'; #[DataProvider('getOccurrencesProvider')] diff --git a/tests/ApiPlatform/OccurrencesTest.php b/tests/ApiPlatform/OccurrencesTest.php index b516b84..a021486 100644 --- a/tests/ApiPlatform/OccurrencesTest.php +++ b/tests/ApiPlatform/OccurrencesTest.php @@ -13,13 +13,17 @@ final class OccurrencesTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/occurrences'; + #[\Override] protected static string $resourceClass = Occurrence::class; // Members are the raw Elasticsearch _source with no @id/@type, so API // Platform's self-generated collection schema does not apply (see D6). + #[\Override] protected static bool $assertsGeneratedCollectionSchema = false; + #[\Override] protected static int|string $itemId = 10; } diff --git a/tests/ApiPlatform/OrganizationsFilterTest.php b/tests/ApiPlatform/OrganizationsFilterTest.php index 73c5251..b84dcfc 100644 --- a/tests/ApiPlatform/OrganizationsFilterTest.php +++ b/tests/ApiPlatform/OrganizationsFilterTest.php @@ -14,6 +14,7 @@ */ final class OrganizationsFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/organizations'; #[DataProvider('getOrganizationsProvider')] diff --git a/tests/ApiPlatform/OrganizationsTest.php b/tests/ApiPlatform/OrganizationsTest.php index 92e7eb6..bef3062 100644 --- a/tests/ApiPlatform/OrganizationsTest.php +++ b/tests/ApiPlatform/OrganizationsTest.php @@ -13,13 +13,17 @@ final class OrganizationsTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/organizations'; + #[\Override] protected static string $resourceClass = Organization::class; // Members are the raw Elasticsearch _source with no @id/@type, so API // Platform's self-generated collection schema does not apply (see D6). + #[\Override] protected static bool $assertsGeneratedCollectionSchema = false; + #[\Override] protected static int|string $itemId = 9; } diff --git a/tests/ApiPlatform/PaginationTest.php b/tests/ApiPlatform/PaginationTest.php index 46d4adb..5e23950 100644 --- a/tests/ApiPlatform/PaginationTest.php +++ b/tests/ApiPlatform/PaginationTest.php @@ -12,6 +12,7 @@ */ final class PaginationTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; #[DataProvider('resourceProvider')] diff --git a/tests/ApiPlatform/SortTest.php b/tests/ApiPlatform/SortTest.php index 7e707ad..bac6a23 100644 --- a/tests/ApiPlatform/SortTest.php +++ b/tests/ApiPlatform/SortTest.php @@ -16,6 +16,7 @@ */ final class SortTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/events'; public function testEventsAreSortedByTitleAscending(): void diff --git a/tests/ApiPlatform/TagsFilterTest.php b/tests/ApiPlatform/TagsFilterTest.php index f1a6d74..dc82b6e 100644 --- a/tests/ApiPlatform/TagsFilterTest.php +++ b/tests/ApiPlatform/TagsFilterTest.php @@ -15,6 +15,7 @@ */ final class TagsFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/tags'; #[DataProvider('getTagsProvider')] diff --git a/tests/ApiPlatform/TagsTest.php b/tests/ApiPlatform/TagsTest.php index c3b0610..b958e32 100644 --- a/tests/ApiPlatform/TagsTest.php +++ b/tests/ApiPlatform/TagsTest.php @@ -16,11 +16,15 @@ final class TagsTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/tags'; + #[\Override] protected static string $resourceClass = Tag::class; + #[\Override] protected static int|string $itemId = 'aros'; + #[\Override] protected static int|string $unknownItemId = 'no-such-tag-slug'; } diff --git a/tests/ApiPlatform/VocabulariesFilterTest.php b/tests/ApiPlatform/VocabulariesFilterTest.php index 51533e0..3870fff 100644 --- a/tests/ApiPlatform/VocabulariesFilterTest.php +++ b/tests/ApiPlatform/VocabulariesFilterTest.php @@ -15,6 +15,7 @@ */ final class VocabulariesFilterTest extends AbstractApiTestCase { + #[\Override] protected static string $requestPath = '/api/v2/vocabularies'; #[DataProvider('getVocabulariesProvider')] diff --git a/tests/ApiPlatform/VocabulariesTest.php b/tests/ApiPlatform/VocabulariesTest.php index 5f86b89..b569a95 100644 --- a/tests/ApiPlatform/VocabulariesTest.php +++ b/tests/ApiPlatform/VocabulariesTest.php @@ -16,11 +16,15 @@ final class VocabulariesTest extends AbstractApiTestCase use GetEntitiesTestTrait; use GetItemTestTrait; + #[\Override] protected static string $requestPath = '/api/v2/vocabularies'; + #[\Override] protected static string $resourceClass = Vocabulary::class; + #[\Override] protected static int|string $itemId = 'aarhusguiden'; + #[\Override] protected static int|string $unknownItemId = 'no-such-vocabulary-slug'; } diff --git a/tests/Command/ApiKeysAddCommandTest.php b/tests/Command/ApiKeysAddCommandTest.php index b3389ec..e5c1b79 100644 --- a/tests/Command/ApiKeysAddCommandTest.php +++ b/tests/Command/ApiKeysAddCommandTest.php @@ -60,7 +60,7 @@ public function testReplacesMultiLineValueAndKeepsOtherLines(): void $this->assertFileDoesNotExist($this->dir.'/.env.local.backup'); $this->assertFileDoesNotExist($this->dir.'/.env.local.temp'); - $env = (new Dotenv())->parse((string) file_get_contents($this->dir.'/.env.local')); + $env = new Dotenv()->parse((string) file_get_contents($this->dir.'/.env.local')); $this->assertSame('http://elasticsearch:9200', $env['INDEX_URL']); $this->assertSame('value', $env['OTHER']); $keys = $this->keys(); @@ -181,7 +181,7 @@ private function runCommand(string $username, array $answers = []): CommandTeste */ private function keys(): array { - $env = (new Dotenv())->parse((string) file_get_contents($this->dir.'/.env.local')); + $env = new Dotenv()->parse((string) file_get_contents($this->dir.'/.env.local')); return json_decode((string) $env['APP_API_KEYS'], true, 512, JSON_THROW_ON_ERROR); } diff --git a/tests/Unit/Service/ElasticSearch/SearchParamsBuilderTest.php b/tests/Unit/Service/ElasticSearch/SearchParamsBuilderTest.php index 7ba3c20..70ecf33 100644 --- a/tests/Unit/Service/ElasticSearch/SearchParamsBuilderTest.php +++ b/tests/Unit/Service/ElasticSearch/SearchParamsBuilderTest.php @@ -33,7 +33,7 @@ private function withFilters(array $clauses): array // Goal: with no filters the query defaults to match_all and pagination/sort are set. public function testDefaultsToMatchAllWithPagination(): void { - $params = (new SearchParamsBuilder())->buildParams(IndexName::Events->value, $this->noFilters(), 20, 5); + $params = new SearchParamsBuilder()->buildParams(IndexName::Events->value, $this->noFilters(), 20, 5); $this->assertSame(IndexName::Events->value, $params['index']); $this->assertEquals(['match_all' => (object) []], $params['body']['query']); @@ -45,7 +45,7 @@ public function testDefaultsToMatchAllWithPagination(): void // Goal: a single associative clause (e.g. a MatchFilter hit) is wrapped in bool/must. public function testSingleClauseWrappedInBoolMust(): void { - $params = (new SearchParamsBuilder())->buildParams( + $params = new SearchParamsBuilder()->buildParams( IndexName::Events->value, $this->withFilters([['match' => ['title' => 'x']]]), 0, @@ -59,7 +59,7 @@ public function testSingleClauseWrappedInBoolMust(): void // nested under numeric keys. public function testListClauseIsFlattenedIntoMust(): void { - $params = (new SearchParamsBuilder())->buildParams( + $params = new SearchParamsBuilder()->buildParams( IndexName::Events->value, $this->withFilters([[['terms' => ['organizer.entityId' => ['9'], 'boost' => 1.0]]]]), 0, @@ -72,7 +72,7 @@ public function testListClauseIsFlattenedIntoMust(): void // Goal: multiple clauses accumulate under a single bool/must. public function testMultipleClausesCombine(): void { - $params = (new SearchParamsBuilder())->buildParams( + $params = new SearchParamsBuilder()->buildParams( IndexName::Events->value, $this->withFilters([ ['match' => ['title' => 'x']], @@ -92,7 +92,7 @@ public function testMultipleClausesCombine(): void #[DataProvider('sortProvider')] public function testSortPerIndex(string $index, array $expectedSort): void { - $params = (new SearchParamsBuilder())->buildParams($index, $this->noFilters(), 0, 10); + $params = new SearchParamsBuilder()->buildParams($index, $this->noFilters(), 0, 10); $this->assertSame($expectedSort, $params['body']['sort']); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8e0530d..bc44ee1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -7,7 +7,7 @@ require dirname(__DIR__).'/vendor/autoload.php'; if (method_exists(Dotenv::class, 'bootEnv')) { - (new Dotenv())->bootEnv(dirname(__DIR__).'/.env'); + new Dotenv()->bootEnv(dirname(__DIR__).'/.env'); } if ($_SERVER['APP_DEBUG']) {