diff --git a/.env b/.env index acb50e0d..d50cb4e6 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # In all environments, the following files are loaded if they exist, -# the later taking precedence over the former: +# the latter taking precedence over the former: # # * .env contains default values for the environment variables needed by the app # * .env.local uncommitted file with local overrides @@ -9,13 +9,14 @@ # Real environment variables win over .env files. # # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# https://symfony.com/doc/current/configuration/secrets.html # # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). -# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration ###> symfony/framework-bundle ### APP_ENV=prod -APP_SECRET='s$cretf0rt3st' +APP_SECRET='$ecretf0rt3st' #TRUSTED_PROXIES=127.0.0.1,127.0.0.2 #TRUSTED_HOSTS=localhost,example.com ###< symfony/framework-bundle ### @@ -23,8 +24,14 @@ APP_SECRET='s$cretf0rt3st' ###> symfony/lock ### # Choose one of the stores below # postgresql+advisory://db_user:db_password@localhost/db_name -LOCK_DSN=semaphore +# flock is using the filesystem and is therefore supported by most operating systems, for Unix based systems you may want to use semaphore +LOCK_DSN=flock ###< symfony/lock ### + +###> symfony/mailer ### +# MAILER_DSN=null://null +###< symfony/mailer ### + ###> doctrine/phpcr-bundle ### ###< doctrine/phpcr-bundle ### @@ -33,15 +40,12 @@ LOCK_DSN=semaphore # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml # # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" -# DATABASE_URL="postgresql://symfony:ChangeMe@127.0.0.1:5432/app?serverVersion=13&charset=utf8" -DATABASE_URL="mysql://root:ChangeMe@127.0.0.1:3306/su_myapp?serverVersion=8.0.27&charset=utf8mb4" +DATABASE_URL="mysql://root:ChangeMe@127.0.0.1:3306/su_myapp?serverVersion=8.0.32&charset=utf8mb4" +# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4" +# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" ###< doctrine/doctrine-bundle ### ###> sulu/sulu ### # Email address that will receive system notifications and might be used as universal fallback value by bundles SULU_ADMIN_EMAIL=example@localhost ###< sulu/sulu ### - -###> symfony/mailer ### -# MAILER_DSN=null://null -###< symfony/mailer ### diff --git a/.env.test b/.env.test index 245847ea..9e7162f0 100644 --- a/.env.test +++ b/.env.test @@ -1,6 +1,6 @@ # define your env variables for the test env here KERNEL_CLASS='App\Kernel' -APP_SECRET='s$cretf0rt3st' +APP_SECRET='$ecretf0rt3st' SYMFONY_DEPRECATIONS_HELPER=999999 PANTHER_APP_ENV=panther PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f7c76630..5e8720f4 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -4,7 +4,7 @@ $finder = (new PhpCsFixer\Finder()) ->in(__DIR__) - ->ignoreVCSIgnored(true) + ->exclude('var') ->notName('bundles.php'); return (new PhpCsFixer\Config()) @@ -40,9 +40,13 @@ 'single_line_throw' => false, 'visibility_required' => ['elements' => ['property', 'method', 'const']], 'phpdoc_to_comment' => [ - 'ignored_tags' => ['todo', 'var'], + 'ignored_tags' => ['todo', 'var', 'see', 'phpstan-ignore-next-line'], ], 'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']], 'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false], + 'nullable_type_declaration_for_default_null_value' => true, + 'fully_qualified_strict_types' => false, + 'no_null_property_initialization' => false, + 'nullable_type_declaration' => false, ]) ->setFinder($finder); diff --git a/bin/console.php b/bin/console.php index 60633cb9..7fae9ed8 100755 --- a/bin/console.php +++ b/bin/console.php @@ -14,8 +14,12 @@ use App\Kernel; use Symfony\Bundle\FrameworkBundle\Console\Application; +if (!\is_dir(\dirname(__DIR__) . '/vendor')) { + throw new \LogicException('Dependencies are missing. Try running "composer install".'); +} + if (!\is_file(\dirname(__DIR__) . '/vendor/autoload_runtime.php')) { - throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); + throw new \LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); } require_once \dirname(__DIR__) . '/vendor/autoload_runtime.php'; diff --git a/bin/phpunit b/bin/phpunit index 93e1b47d..4d1866ea 100755 --- a/bin/phpunit +++ b/bin/phpunit @@ -1,14 +1,20 @@ #!/usr/bin/env php = 80000) { + require \dirname(__DIR__) . '/vendor/phpunit/phpunit/phpunit'; + } else { + \define('PHPUNIT_COMPOSER_INSTALL', \dirname(__DIR__) . '/vendor/autoload.php'); + require PHPUNIT_COMPOSER_INSTALL; + PHPUnit\TextUI\Command::main(); + } } else { if (!\is_file(\dirname(__DIR__) . '/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) { echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n"; diff --git a/docker-compose.override.yml b/compose.override.yaml similarity index 55% rename from docker-compose.override.yml rename to compose.override.yaml index b6a03e06..80518bbd 100644 --- a/docker-compose.override.yml +++ b/compose.override.yaml @@ -3,8 +3,13 @@ version: '3' services: ###> symfony/mailer ### mailer: - image: schickling/mailcatcher - ports: [1025, 1080] + image: axllent/mailpit + ports: + - "1025" + - "8025" + environment: + MP_SMTP_AUTH_ACCEPT_ANY: 1 + MP_SMTP_AUTH_ALLOW_INSECURE: 1 ###< symfony/mailer ### ###> doctrine/doctrine-bundle ### diff --git a/docker-compose.yml b/compose.yaml similarity index 93% rename from docker-compose.yml rename to compose.yaml index 41868ead..3ba79ea8 100644 --- a/docker-compose.yml +++ b/compose.yaml @@ -11,12 +11,12 @@ services: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-ChangeMe} MYSQL_ROOT_HOST: '%' volumes: - - db-data:/var/lib/mysql + - database-data:/var/lib/mysql # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! # - ./docker/db/data:/var/lib/mysql:rw ###< doctrine/doctrine-bundle ### volumes: ###> doctrine/doctrine-bundle ### - db-data: + database-data: ###< doctrine/doctrine-bundle ### diff --git a/composer.json b/composer.json index 51017575..636838d5 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "chat": "https://sulu.io/services-and-support#chat" }, "require": { - "php": "^8.1", + "php": "^8.2", "ext-ctype": "*", "ext-iconv": "*", "dantleech/phpcr-migrations-bundle": "^1.3", @@ -36,21 +36,21 @@ "friendsofsymfony/http-cache-bundle": "^2.17", "handcraftedinthealps/zendsearch": "^2.1", "jackalope/jackalope-doctrine-dbal": "^1.10", - "scheb/2fa-bundle": "^6.1", - "scheb/2fa-email": "^6.1", - "scheb/2fa-trusted-device": "^6.1", + "scheb/2fa-bundle": "^7.2", + "scheb/2fa-email": "^7.2", + "scheb/2fa-trusted-device": "^7.2", "stof/doctrine-extensions-bundle": "^1.8", "sulu/sulu": "~2.6.0@dev", - "symfony/config": "^6.3", - "symfony/dotenv": "^6.3", + "symfony/config": "^6.4", + "symfony/dotenv": "^6.4", "symfony/flex": "^1.17 || ^2.0", - "symfony/framework-bundle": "^6.3", - "symfony/mailer": "^6.3", - "symfony/monolog-bridge": "^6.3", + "symfony/framework-bundle": "^6.4", + "symfony/mailer": "^6.4", + "symfony/monolog-bridge": "^6.4", "symfony/monolog-bundle": "^3.4", - "symfony/runtime": "^6.3", - "symfony/security-bundle": "^6.3", - "symfony/twig-bundle": "^6.3" + "symfony/runtime": "^6.4", + "symfony/security-bundle": "^6.4", + "symfony/twig-bundle": "^6.4" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.41", @@ -66,15 +66,18 @@ "phpunit/phpunit": "^9.6", "rector/rector": "^1.0", "sulu/sulu-rector": "^1.0", - "symfony/browser-kit": "^6.3", - "symfony/css-selector": "^6.3", - "symfony/debug-bundle": "^6.3", - "symfony/error-handler": "^6.3", - "symfony/phpunit-bridge": "^6.3", + "symfony/browser-kit": "^6.4", + "symfony/css-selector": "^6.4", + "symfony/debug-bundle": "^6.4", + "symfony/error-handler": "^6.4", + "symfony/phpunit-bridge": "^6.4", "symfony/thanks": "^1.2", - "symfony/web-profiler-bundle": "^6.3", + "symfony/web-profiler-bundle": "^6.4", "thecodingmachine/phpstan-strict-rules": "^1.0" }, + "conflict": { + "symfony/symfony": "*" + }, "autoload": { "psr-4": { "App\\": "src/" @@ -113,7 +116,7 @@ ], "post-root-package-install": [ "@php -r \"file_put_contents('.env.local', 'APP_ENV=dev' . PHP_EOL);\"", - "@php -r \"file_put_contents('.env', str_replace('APP_SECRET=\\'s\\$cretf0rt3st\\'', 'APP_SECRET=' . bin2hex(random_bytes(16)), file_get_contents('.env')));\"" + "@php -r \"file_put_contents('.env', str_replace('APP_SECRET=\\'\\$ecretf0rt3st\\'', 'APP_SECRET=' . bin2hex(random_bytes(16)), file_get_contents('.env')));\"" ], "post-create-project-cmd": [ "@php -r \"file_put_contents('.gitignore', str_replace(['composer.lock' . PHP_EOL, 'symfony.lock' . PHP_EOL, 'package-lock.json' . PHP_EOL, 'yarn.lock' . PHP_EOL, 'bun.lockb' . PHP_EOL, 'pnpm-lock.yaml' . PHP_EOL], '', file_get_contents('.gitignore')));\"", @@ -187,7 +190,7 @@ "extra": { "symfony": { "allow-contrib": true, - "require": "6.3.*" + "require": "6.4.*" } } } diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 8d89a5a6..288eecb4 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -5,17 +5,25 @@ doctrine: # IMPORTANT: You MUST configure your server version, # either here or in the DATABASE_URL env var (see .env file) #server_version: '8.0.27' + + profiling_collect_backtrace: '%kernel.debug%' + use_savepoints: true orm: auto_generate_proxy_classes: true + enable_lazy_ghost_objects: true + report_fields_where_declared: true + validate_xml_mapping: false # required for gedmo/doctrine-extensions to be false naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: true mappings: App: - is_bundle: false type: attribute + is_bundle: false dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App + controller_resolver: + auto_mapping: false when@test: doctrine: @@ -27,6 +35,7 @@ when@prod: &prod doctrine: orm: auto_generate_proxy_classes: false + proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' query_cache_driver: type: pool pool: doctrine.system_cache_pool diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index e40ab1e0..debb7d4a 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -2,7 +2,9 @@ framework: secret: '%env(APP_SECRET)%' #csrf_protection: true - #http_method_override: false + annotations: true # required for rest routing loader to be true + http_method_override: true # enable also in the index.php + handle_all_throwables: true # Enables session support. Note that the session will ONLY be started if you read or write from it. # Remove or comment this section to explicitly disable session support. @@ -10,7 +12,6 @@ framework: handler_id: null cookie_secure: auto cookie_samesite: lax - storage_factory_id: session.storage.factory.native name: SULUSESSID # This avoids conflicts with other applications running on the same domain #esi: true diff --git a/config/packages/nyholm_psr7.yaml b/config/packages/nyholm_psr7.yaml deleted file mode 100644 index f1357233..00000000 --- a/config/packages/nyholm_psr7.yaml +++ /dev/null @@ -1,21 +0,0 @@ -services: - # Register nyholm/psr7 services for autowiring with PSR-17 (HTTP factories) - Psr\Http\Message\RequestFactoryInterface: '@nyholm.psr7.psr17_factory' - Psr\Http\Message\ResponseFactoryInterface: '@nyholm.psr7.psr17_factory' - Psr\Http\Message\ServerRequestFactoryInterface: '@nyholm.psr7.psr17_factory' - Psr\Http\Message\StreamFactoryInterface: '@nyholm.psr7.psr17_factory' - Psr\Http\Message\UploadedFileFactoryInterface: '@nyholm.psr7.psr17_factory' - Psr\Http\Message\UriFactoryInterface: '@nyholm.psr7.psr17_factory' - - # Register nyholm/psr7 services for autowiring with HTTPlug factories - Http\Message\MessageFactory: '@nyholm.psr7.httplug_factory' - Http\Message\RequestFactory: '@nyholm.psr7.httplug_factory' - Http\Message\ResponseFactory: '@nyholm.psr7.httplug_factory' - Http\Message\StreamFactory: '@nyholm.psr7.httplug_factory' - Http\Message\UriFactory: '@nyholm.psr7.httplug_factory' - - nyholm.psr7.psr17_factory: - class: Nyholm\Psr7\Factory\Psr17Factory - - nyholm.psr7.httplug_factory: - class: Nyholm\Psr7\Factory\HttplugFactory diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 472fe04f..4e1848c1 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -1,19 +1,14 @@ security: - enable_authenticator_manager: true - access_decision_manager: strategy: unanimous allow_if_all_abstain: true - # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: - Sulu\Bundle\SecurityBundle\Entity\User: bcrypt - + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider providers: sulu: id: sulu_security.user_provider - # Easy way to control access for large sections of your site # Note: Only the *first* access control that matches will be used access_control: @@ -78,16 +73,6 @@ security: # # https://symfony.com/doc/current/security/impersonating_user.html # # switch_user: true -sulu_security: - checker: - enabled: true - password_policy: - enabled: true - # Sulu uses the simple password_policy pattern ".{8,}" by default - # You can change it to a more complex pattern with the following lines: - #pattern: '(?=^.{8,}$)(?=.*\d)(?=.*[^a-zA-Z0-9]+)(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$' - #info_translation_key: app.password_information - when@test: security: password_hashers: @@ -96,7 +81,7 @@ when@test: # are not important, waste resources and increase test times. The following # reduces the work factor to the lowest possible values. Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: - algorithm: bcrypt + algorithm: auto cost: 4 # Lowest possible value for bcrypt time_cost: 3 # Lowest possible value for argon memory_cost: 10 # Lowest possible value for argon @@ -112,6 +97,3 @@ when@test: admin: http_basic: provider: sulu - - sulu_test: - enable_test_user_provider: true diff --git a/config/packages/stof_doctrine_extensions.yaml b/config/packages/stof_doctrine_extensions.yaml index 36442458..1ee27055 100644 --- a/config/packages/stof_doctrine_extensions.yaml +++ b/config/packages/stof_doctrine_extensions.yaml @@ -2,11 +2,3 @@ # See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc stof_doctrine_extensions: default_locale: '%default_locale%' - -when@prod: &prod - stof_doctrine_extensions: - # fix issue with gedmo/extensions 1.8.0 and stof/doctrine-extensions-bundle: 3.12.0 - # @see https://github.com/stof/StofDoctrineExtensionsBundle/issues/457 - metadata_cache_pool: doctrine.system_cache_pool - -when@stage: *prod diff --git a/config/packages/sulu_security.yaml b/config/packages/sulu_security.yaml new file mode 100644 index 00000000..f0c1c609 --- /dev/null +++ b/config/packages/sulu_security.yaml @@ -0,0 +1,9 @@ +sulu_security: + checker: + enabled: true + password_policy: + enabled: true + # Sulu uses the simple password_policy pattern ".{8,}" by default + # You can change it to a more complex pattern with the following lines: + #pattern: '(?=^.{8,}$)(?=.*\d)(?=.*[^a-zA-Z0-9]+)(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$' + #info_translation_key: app.password_information diff --git a/config/packages/sulu_test.yaml b/config/packages/sulu_test.yaml new file mode 100644 index 00000000..8c278cdc --- /dev/null +++ b/config/packages/sulu_test.yaml @@ -0,0 +1,3 @@ +when@test: + sulu_test: + enable_test_user_provider: true diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml index df87d5ce..adb7e395 100644 --- a/config/packages/translation.yaml +++ b/config/packages/translation.yaml @@ -4,10 +4,4 @@ framework: default_path: '%kernel.project_dir%/translations' fallbacks: - '%default_locale%' -# providers: -# crowdin: -# dsn: '%env(CROWDIN_DSN)%' -# loco: -# dsn: '%env(LOCO_DSN)%' -# lokalise: -# dsn: '%env(LOKALISE_DSN)%' + providers: diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index f9f4cc53..3f795d92 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -1,5 +1,5 @@ twig: - default_path: '%kernel.project_dir%/templates' + file_name_pattern: '*.twig' when@test: twig: diff --git a/config/routes.yaml b/config/routes.yaml index f1869ab0..f5d8031c 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -1 +1,24 @@ -# Define website routes in `routes_website.yaml` and admin routes in the `routes_admin.yaml` +controllers: + resource: + path: ../src/Controller/ + namespace: App\Controller + type: attribute + +#static: +# path: /static-route +# controller: App\Controller\DefaultController::index + +# If you have a simple login on your website activate the following routes +# If you need registration or profile edit have a look at the: +# https://github.com/sulu/SuluCommunityBundle +# +#login: +# path: /login +# controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController +# defaults: +# # the following template need to be created: +# # see https://github.com/sulu/sulu/blob/2.x/templates/static/login.html.twig as example +# template: static/login.html.twig +# +#logout: +# path: /logout diff --git a/config/routes/security.yaml b/config/routes/security.yaml new file mode 100644 index 00000000..0a9384ee --- /dev/null +++ b/config/routes/security.yaml @@ -0,0 +1,4 @@ +# Not in use currently for sulu: +#_security_logout: +# resource: security.route_loader.logout +# type: service diff --git a/config/routes_admin.yaml b/config/routes_admin.yaml deleted file mode 100644 index 93f0312f..00000000 --- a/config/routes_admin.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# Define your admin routes here -controllers: - resource: ../src/Controller/Admin/ - type: attribute diff --git a/config/routes_website.yaml b/config/routes_website.yaml deleted file mode 100644 index 8ed58f78..00000000 --- a/config/routes_website.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Define your website routes here -controllers: - resource: ../src/Controller/Website/ - type: attribute - -#static: -# path: /static-route -# controller: App\Controller\DefaultController::index - -# If you have a simple login on your website activate the following routes -# If you need registration or profile edit have a look at the: -# https://github.com/sulu/SuluCommunityBundle -# -#login: -# path: /login -# controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController -# defaults: -# # the following template need to be created: -# # see https://github.com/sulu/sulu/blob/2.x/templates/static/login.html.twig as example -# template: static/login.html.twig -# -#logout: -# path: /logout diff --git a/config/services.yaml b/config/services.yaml index f39b9321..87440490 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -11,11 +11,6 @@ services: _defaults: autowire: true # Automatically injects dependencies in your services. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. - # Binding arguments by name or type - # https://symfony.com/doc/current/service_container.html#binding-arguments-by-name-or-type - #bind: - # 'bool $isDebug': '%kernel.debug%' - # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 52510353..23a96578 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,8 +1,10 @@ parameters: paths: + - bin/ + - config + - public/ - src - tests - - config level: max doctrine: objectManagerLoader: tests/phpstan/object-manager.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8a0b458e..9cbf37f8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,22 @@ - + + - + + + - - - - @@ -35,10 +35,6 @@ - - diff --git a/public/index.php b/public/index.php index 2ffd1d8c..807a9ca4 100644 --- a/public/index.php +++ b/public/index.php @@ -57,12 +57,13 @@ // Comment this line if you want to use the "varnish" http // caching strategy. See http://sulu.readthedocs.org/en/latest/cookbook/caching-with-varnish.html if ('dev' !== $_SERVER['APP_ENV'] && SuluKernel::CONTEXT_WEBSITE === $suluContext) { + /** @var Sulu\Bundle\HttpCacheBundle\Cache\SuluHttpCache $kernel */ $kernel = $kernel->getHttpCache(); } // When using the HttpCache, you need to call the method in your front controller // instead of relying on the configuration parameter -// https://symfony.com/doc/3.4/reference/configuration/framework.html#http-method-override +// https://symfony.com/doc/6.4/reference/configuration/framework.html#http-method-override Request::enableHttpMethodParameterOverride(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); diff --git a/public/maintenance.php b/public/maintenance.php index 58cc4e19..64de5ae3 100644 --- a/public/maintenance.php +++ b/public/maintenance.php @@ -1,4 +1,7 @@ bootEnv(\dirname(__DIR__) . '/.env'); + +if (\file_exists(\dirname(__DIR__) . '/config/bootstrap.php')) { + require \dirname(__DIR__) . '/config/bootstrap.php'; +} elseif (\method_exists(Dotenv::class, 'bootEnv')) { + (new Dotenv())->bootEnv(\dirname(__DIR__) . '/.env'); +}