diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..dc5a8752
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,34 @@
+**/*.log
+**/*.md
+**/*.php~
+**/*.dist.php
+**/*.dist
+**/*.cache
+**/._*
+**/.dockerignore
+**/.DS_Store
+**/.git/
+**/.gitattributes
+**/.gitignore
+**/.gitmodules
+**/compose.*.yaml
+**/compose.*.yml
+**/compose.yaml
+**/compose.yml
+**/docker-compose.*.yaml
+**/docker-compose.*.yml
+**/docker-compose.yaml
+**/docker-compose.yml
+**/Dockerfile
+**/Thumbs.db
+.github/
+docs/
+public/bundles/
+tests/
+var/
+vendor/
+.editorconfig
+.env.*.local
+.env.local
+.env.local.php
+.env.test
diff --git a/.env b/.env
index 476df852..745bff94 100644
--- a/.env
+++ b/.env
@@ -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.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
-APP_SECRET=6feff92fb5278f215ddca9545d19fcd3
+APP_SECRET=421f03e82270a0883f2db17c436d6b81
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
@@ -23,14 +24,13 @@ APP_SECRET=6feff92fb5278f215ddca9545d19fcd3
# 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="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
+DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.35&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=15&charset=utf8"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
# MAILER_DSN=smtp://user:pass@smtp.example.com
-# MAILER_DSN=gmail://USERNAME:PASSWORD@default
MAILER_DSN=null://localhost
###< symfony/mailer ###
@@ -41,9 +41,6 @@ MAILER_DSN=null://localhost
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
-# Select default language (en, ru, bg, nl)
-LANGUAGE_CODE=en
-
###> symfony/google-mailer ###
# Gmail SHOULD NOT be used on production, use it in development only.
# MAILER_DSN=gmail://USERNAME:PASSWORD@default
@@ -54,3 +51,6 @@ LANGUAGE_CODE=en
# postgresql+advisory://db_user:db_password@localhost/db_name
LOCK_DSN=flock
###< symfony/lock ###
+
+# Select default language (en, ru, bg, nl)
+LANGUAGE_CODE=en
diff --git a/.env.test b/.env.test
index 0812ddfb..4362c7ed 100644
--- a/.env.test
+++ b/.env.test
@@ -4,4 +4,7 @@ APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=test
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
-DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
+DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.35&charset=utf8mb4"
+
+PANTHER_CHROME_ARGUMENTS="--disable-dev-shm-usage"
+PANTHER_NO_SANDBOX="1"
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..642c91f2
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,17 @@
+* text=auto eol=lf
+
+*.conf text eol=lf
+*.html text eol=lf
+*.ini text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.md text eol=lf
+*.php text eol=lf
+*.sh text eol=lf
+*.yaml text eol=lf
+*.yml text eol=lf
+bin/console text eol=lf
+composer.lock text eol=lf merge=ours
+
+*.ico binary
+*.png binary
diff --git a/.github/workflows/frankenphp.yml b/.github/workflows/frankenphp.yml
new file mode 100644
index 00000000..0de5daea
--- /dev/null
+++ b/.github/workflows/frankenphp.yml
@@ -0,0 +1,57 @@
+name: FrankenPHP
+
+on:
+ push:
+ branches:
+ - master
+ - 2.x
+ - docker
+ pull_request: ~
+ workflow_dispatch: ~
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ tests:
+ name: Tests
+ runs-on: ubuntu-latest
+ steps:
+ -
+ name: Checkout
+ uses: actions/checkout@v4
+ -
+ name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ -
+ name: Build Docker images
+ uses: docker/bake-action@v4
+ with:
+ pull: true
+ load: true
+ files: |
+ compose.yaml
+ compose.override.yaml
+ set: |
+ *.cache-from=type=gha,scope=${{github.ref}}
+ *.cache-from=type=gha,scope=refs/heads/main
+ *.cache-to=type=gha,scope=${{github.ref}},mode=max
+ -
+ name: Start services
+ run: docker compose up --wait --no-build
+ -
+ name: Check HTTP reachability
+ run: curl -v -o /dev/null http://localhost
+ -
+ name: Check HTTPS reachability
+ run: curl -vk -o /dev/null https://localhost
+ -
+ name: Install the app
+ run: docker compose exec -T php bin/console -e test app:install
+ -
+ name: Run PHPUnit
+ run: docker compose exec -T php bin/phpunit
+ -
+ name: Doctrine Schema Validator
+ run: docker compose exec -T php bin/console -e test doctrine:schema:validate
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..c49a3920
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,113 @@
+#syntax=docker/dockerfile:1.4
+
+# Versions
+FROM dunglas/frankenphp:1-alpine AS frankenphp_upstream
+FROM composer/composer:2-bin AS composer_upstream
+
+
+# The different stages of this Dockerfile are meant to be built into separate images
+# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
+# https://docs.docker.com/compose/compose-file/#target
+
+
+# Base FrankenPHP image
+FROM frankenphp_upstream AS frankenphp_base
+
+WORKDIR /app
+
+# persistent / runtime deps
+# hadolint ignore=DL3018
+RUN apk add --no-cache \
+ acl \
+ file \
+ gettext \
+ git \
+ ;
+
+RUN set -eux; \
+ install-php-extensions \
+ apcu \
+ gd \
+ intl \
+ opcache \
+ zip \
+ ;
+
+###> recipes ###
+###> symfony/panther ###
+# Chromium and ChromeDriver
+ENV PANTHER_NO_SANDBOX 1
+# Not mandatory, but recommended
+ENV PANTHER_CHROME_ARGUMENTS='--disable-dev-shm-usage'
+RUN apk add --no-cache chromium chromium-chromedriver
+
+# Firefox and geckodriver
+#ARG GECKODRIVER_VERSION=0.29.0
+#RUN apk add --no-cache firefox
+#RUN wget -q https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz; \
+# tar -zxf geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz -C /usr/bin; \
+# rm geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz
+###< symfony/panther ###
+###> doctrine/doctrine-bundle ###
+RUN install-php-extensions pdo_mysql
+###< doctrine/doctrine-bundle ###
+###< recipes ###
+
+COPY --link frankenphp/conf.d/app.ini $PHP_INI_DIR/conf.d/
+COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
+COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile
+
+ENTRYPOINT ["docker-entrypoint"]
+
+# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
+ENV COMPOSER_ALLOW_SUPERUSER=1
+ENV PATH="${PATH}:/root/.composer/vendor/bin"
+
+COPY --from=composer_upstream --link /composer /usr/bin/composer
+
+HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1
+CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ]
+
+# Dev FrankenPHP image
+FROM frankenphp_base AS frankenphp_dev
+
+ENV APP_ENV=dev XDEBUG_MODE=off
+VOLUME /app/var/
+
+RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
+
+RUN set -eux; \
+ install-php-extensions \
+ xdebug \
+ ;
+
+COPY --link frankenphp/conf.d/app.dev.ini $PHP_INI_DIR/conf.d/
+
+CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ]
+
+# Prod FrankenPHP image
+FROM frankenphp_base AS frankenphp_prod
+
+ENV APP_ENV=prod
+ENV FRANKENPHP_CONFIG="import worker.Caddyfile"
+
+RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
+
+COPY --link frankenphp/conf.d/app.prod.ini $PHP_INI_DIR/conf.d/
+COPY --link frankenphp/worker.Caddyfile /etc/caddy/worker.Caddyfile
+
+# prevent the reinstallation of vendors at every changes in the source code
+COPY --link composer.* symfony.* ./
+RUN set -eux; \
+ composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress
+
+# copy sources
+COPY --link . ./
+RUN rm -Rf frankenphp/
+
+RUN set -eux; \
+ mkdir -p var/cache var/log; \
+ composer dump-autoload --classmap-authoritative --no-dev; \
+ composer dump-env prod; \
+ composer run-script --no-dev post-install-cmd; \
+ chmod +x bin/console; sync;
diff --git a/babel.config.js b/babel.config.js
index b14943fe..d7dd5f85 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,19 +1,19 @@
-module.exports = {
- presets: [
- [
- '@babel/preset-env',
- {
- modules: 'auto',
- targets: { node: 'current' }
- }
- ]
- ],
- plugins: [
- [
- '@babel/plugin-proposal-class-properties',
- {
- loose: true
- }
- ]
- ]
-};
+module.exports = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ modules: 'auto',
+ targets: { node: 'current' }
+ }
+ ]
+ ],
+ plugins: [
+ [
+ '@babel/plugin-proposal-class-properties',
+ {
+ loose: true
+ }
+ ]
+ ]
+};
diff --git a/compose.override.yaml b/compose.override.yaml
new file mode 100644
index 00000000..5317a972
--- /dev/null
+++ b/compose.override.yaml
@@ -0,0 +1,38 @@
+# Development environment override
+services:
+ php:
+ build:
+ context: .
+ target: frankenphp_dev
+ volumes:
+ - ./:/app
+ - ./frankenphp/Caddyfile:/etc/caddy/Caddyfile:ro
+ - ./frankenphp/conf.d/app.dev.ini:/usr/local/etc/php/conf.d/app.dev.ini:ro
+ # If you develop on Mac or Windows you can remove the vendor/ directory
+ # from the bind-mount for better performance by enabling the next line:
+ #- /app/vendor
+ environment:
+ MERCURE_EXTRA_DIRECTIVES: demo
+ # See https://xdebug.org/docs/all_settings#mode
+ XDEBUG_MODE: "${XDEBUG_MODE:-off}"
+ extra_hosts:
+ # Ensure that host.docker.internal is correctly defined on Linux
+ - host.docker.internal:host-gateway
+ tty: true
+
+###> symfony/mercure-bundle ###
+###< symfony/mercure-bundle ###
+
+###> doctrine/doctrine-bundle ###
+ mysql:
+ ports:
+ - "3306"
+###< doctrine/doctrine-bundle ###
+
+###> symfony/mailer ###
+ mailhog:
+ image: mailhog/mailhog
+ ports:
+ - "1025:1025"
+ - "8025:8025"
+###< symfony/mailer ###
diff --git a/compose.prod.yaml b/compose.prod.yaml
new file mode 100644
index 00000000..f0db05da
--- /dev/null
+++ b/compose.prod.yaml
@@ -0,0 +1,10 @@
+# Production environment override
+services:
+ php:
+ build:
+ context: .
+ target: frankenphp_prod
+ environment:
+ APP_SECRET: ${APP_SECRET}
+ MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
+ MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 00000000..e7543115
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,68 @@
+services:
+ php:
+ image: ${IMAGES_PREFIX:-}app-php
+ restart: unless-stopped
+ environment:
+ SERVER_NAME: ${SERVER_NAME:-localhost}, php:80
+ MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ TRUSTED_PROXIES: ${TRUSTED_PROXIES:-127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16}
+ TRUSTED_HOSTS: ^${SERVER_NAME:-example\.com|localhost}|php$$
+ # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM
+ DATABASE_URL: mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@mysql:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.35}&charset=utf8mb4
+ # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration
+ MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure}
+ MERCURE_PUBLIC_URL: https://${SERVER_NAME:-localhost}/.well-known/mercure
+ MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
+ # The two next lines can be removed after initial installation
+ SYMFONY_VERSION: ${SYMFONY_VERSION:-}
+ STABILITY: ${STABILITY:-stable}
+ volumes:
+ - caddy_data:/data
+ - caddy_config:/config
+ ports:
+ # HTTP
+ - target: 80
+ published: ${HTTP_PORT:-80}
+ protocol: tcp
+ # HTTPS
+ - target: 443
+ published: ${HTTPS_PORT:-443}
+ protocol: tcp
+ # HTTP/3
+ - target: 443
+ published: ${HTTP3_PORT:-443}
+ protocol: udp
+
+# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service
+###> symfony/mercure-bundle ###
+###< symfony/mercure-bundle ###
+
+###> doctrine/doctrine-bundle ###
+ mysql:
+ image: mysql:${MYSQL_VERSION:-8.0.35}
+ environment:
+ MYSQL_DATABASE: ${MYSQL_DATABASE:-app}
+ # You should definitely change the password in production
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD:-!ChangeMe!}
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root}
+ MYSQL_USER: ${MYSQL_USER:-app}
+ volumes:
+ - db_data:/var/lib/mysql
+ ports:
+ - 3306:3306
+###< doctrine/doctrine-bundle ###
+
+ phpmyadmin:
+ image: phpmyadmin/phpmyadmin
+ restart: always
+ environment:
+ PMA_HOST: mysql
+ PMA_PORT: 3306
+ ports:
+ - 8081:80
+
+volumes:
+ caddy_data:
+ caddy_config:
+ db_data:
diff --git a/composer.json b/composer.json
index af2f8895..5f441f96 100644
--- a/composer.json
+++ b/composer.json
@@ -125,7 +125,8 @@
"extra": {
"symfony": {
"allow-contrib": true,
- "require": "6.4.*"
+ "require": "6.4.*",
+ "docker": true
}
}
}
diff --git a/config/routes/scheb_2fa.yaml b/config/routes/scheb_2fa.yaml
new file mode 100644
index 00000000..17f89595
--- /dev/null
+++ b/config/routes/scheb_2fa.yaml
@@ -0,0 +1,7 @@
+2fa_login:
+ path: /{_locale}/2fa
+ defaults:
+ _controller: "scheb_two_factor.form_controller::form"
+
+2fa_login_check:
+ path: /{_locale}/2fa_check
diff --git a/config/routes/sched_2fa.yaml b/config/routes/sched_2fa.yaml
deleted file mode 100644
index 33020f10..00000000
--- a/config/routes/sched_2fa.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-2fa_login:
- path: /{_locale}/2fa
- defaults:
- _controller: "scheb_two_factor.form_controller::form"
-
-2fa_login_check:
- path: /{_locale}/2fa_check
diff --git a/config/routes/security.yaml b/config/routes/security.yaml
new file mode 100644
index 00000000..f853be15
--- /dev/null
+++ b/config/routes/security.yaml
@@ -0,0 +1,3 @@
+_security_logout:
+ resource: security.route_loader.logout
+ type: service
diff --git a/docs/docker.md b/docs/docker.md
index 7201b034..7c2e615a 100644
--- a/docs/docker.md
+++ b/docs/docker.md
@@ -1,43 +1,36 @@
## How to run Residence CMS in Docker Containers ##
-1. Clone repositories
-```
-$ git clone https://github.com/eko/docker-symfony.git
-$ cd docker-symfony
-$ git checkout 62c9592
-$ git clone https://github.com/Coderberg/ResidenceCMS.git symfony
+1. Clone repository
+```shell
+git clone https://github.com/Coderberg/ResidenceCMS.git
+cd ResidenceCMS
```
-2. Create ```.env``` files
+2. Create a `.env.local` file and update the `MAILER_DSN` variable to use MailHog
+```shell
+cp .env .env.local
+sed -i 's/MAILER_DSN=.*/MAILER_DSN=smtp:\/\/mailhog:1025/' .env.local
```
-$ echo -e '
-DATABASE_URL=mysql://symfony:symfony@db/symfony?serverVersion=5.7\r
-LOCK_DSN=flock\r
-LANGUAGE_CODE=en' > ./symfony/.env.local
-
-$ echo -e "\
-KERNEL_CLASS='App\Kernel'\r\
-APP_SECRET=34c32c8b0a7cc951fd105659f77ec1b6\r\
-SYMFONY_DEPRECATIONS_HELPER=999999\r\
-PANTHER_APP_ENV=panther\r\
-DATABASE_URL=mysql://symfony:symfony@db/symfony\r\
-" > ./symfony/.env.test.local
+3. Build and run containers
+```shell
+docker compose build --no-cache
+docker compose up --pull always -d --wait
```
-3. Run containers
+4. Install the app
```
-$ docker-compose up -d
-$ docker exec -it docker-symfony-php-1 /bin/sh
+docker compose exec -T php bin/console app:install
+docker compose exec -T php bin/phpunit
```
-4. Install app
-```
-# composer install
-# php bin/console app:install
-# find ./public/uploads -type d -print | xargs chmod 777
+5. Open `https://localhost` in your favorite web browser and [accept the auto-generated TLS certificate](https://stackoverflow.com/a/15076602/1352334)
-# php bin/phpunit --testsuite=main
-```
+---
+
+Additional services:
+
+- PhpMyAdmin http://localhost:8081
+- MailHog http://localhost:8025
-5. Go to http://symfony.localhost
+See more detailed documentation here https://github.com/dunglas/symfony-docker
diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile
new file mode 100644
index 00000000..3056acdf
--- /dev/null
+++ b/frankenphp/Caddyfile
@@ -0,0 +1,55 @@
+{
+ {$CADDY_GLOBAL_OPTIONS}
+
+ frankenphp {
+ {$FRANKENPHP_CONFIG}
+ }
+
+ # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
+ order mercure after encode
+ order vulcain after reverse_proxy
+ order php_server before file_server
+}
+
+{$CADDY_EXTRA_CONFIG}
+
+{$SERVER_NAME:localhost} {
+ log {
+ # Redact the authorization query parameter that can be set by Mercure
+ format filter {
+ wrap console
+ fields {
+ uri query {
+ replace authorization REDACTED
+ }
+ }
+ }
+ }
+
+ root * /app/public
+ encode zstd gzip
+
+ mercure {
+ # Transport to use (default to Bolt)
+ transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
+ # Publisher JWT key
+ publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
+ # Subscriber JWT key
+ subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
+ # Allow anonymous subscribers (double-check that it's what you want)
+ anonymous
+ # Enable the subscription API (double-check that it's what you want)
+ subscriptions
+ # Extra directives
+ {$MERCURE_EXTRA_DIRECTIVES}
+ }
+
+ vulcain
+
+ {$CADDY_SERVER_EXTRA_DIRECTIVES}
+
+ # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
+ header ?Permissions-Policy "browsing-topics=()"
+
+ php_server
+}
diff --git a/frankenphp/conf.d/app.dev.ini b/frankenphp/conf.d/app.dev.ini
new file mode 100644
index 00000000..e50f43d0
--- /dev/null
+++ b/frankenphp/conf.d/app.dev.ini
@@ -0,0 +1,5 @@
+; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host
+; See https://github.com/docker/for-linux/issues/264
+; The `client_host` below may optionally be replaced with `discover_client_host=yes`
+; Add `start_with_request=yes` to start debug session on each request
+xdebug.client_host = host.docker.internal
diff --git a/frankenphp/conf.d/app.ini b/frankenphp/conf.d/app.ini
new file mode 100644
index 00000000..501fa84f
--- /dev/null
+++ b/frankenphp/conf.d/app.ini
@@ -0,0 +1,14 @@
+variables_order = EGPCS
+expose_php = 0
+date.timezone = UTC
+apc.enable_cli = 1
+session.use_strict_mode = 1
+zend.detect_unicode = 0
+
+; https://symfony.com/doc/current/performance.html
+realpath_cache_size = 4096K
+realpath_cache_ttl = 600
+opcache.interned_strings_buffer = 16
+opcache.max_accelerated_files = 20000
+opcache.memory_consumption = 256
+opcache.enable_file_override = 1
diff --git a/frankenphp/conf.d/app.prod.ini b/frankenphp/conf.d/app.prod.ini
new file mode 100644
index 00000000..3bcaa71e
--- /dev/null
+++ b/frankenphp/conf.d/app.prod.ini
@@ -0,0 +1,2 @@
+opcache.preload_user = root
+opcache.preload = /app/config/preload.php
diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh
new file mode 100644
index 00000000..bdddc3ac
--- /dev/null
+++ b/frankenphp/docker-entrypoint.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
+ # Install the project the first time PHP is started
+ # After the installation, the following block can be deleted
+ if [ ! -f composer.json ]; then
+ rm -Rf tmp/
+ composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install
+
+ cd tmp
+ cp -Rp . ..
+ cd -
+ rm -Rf tmp/
+
+ composer require "php:>=$PHP_VERSION" runtime/frankenphp-symfony
+ composer config --json extra.symfony.docker 'true'
+
+ if grep -q ^DATABASE_URL= .env; then
+ echo "To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait"
+ sleep infinity
+ fi
+ fi
+
+ if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
+ composer install --prefer-dist --no-progress --no-interaction
+ fi
+
+ if grep -q ^DATABASE_URL= .env; then
+ echo "Waiting for database to be ready..."
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=60
+ until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do
+ if [ $? -eq 255 ]; then
+ # If the Doctrine command exits with 255, an unrecoverable error occurred
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=0
+ break
+ fi
+ sleep 1
+ ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1))
+ echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left."
+ done
+
+ if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then
+ echo "The database is not up or not reachable:"
+ echo "$DATABASE_ERROR"
+ exit 1
+ else
+ echo "The database is now ready and reachable"
+ fi
+
+ if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then
+ php bin/console doctrine:migrations:migrate --no-interaction
+ fi
+ fi
+
+ setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var
+ setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var
+fi
+
+exec docker-php-entrypoint "$@"
diff --git a/frankenphp/worker.Caddyfile b/frankenphp/worker.Caddyfile
new file mode 100644
index 00000000..d384ae4c
--- /dev/null
+++ b/frankenphp/worker.Caddyfile
@@ -0,0 +1,4 @@
+worker {
+ file ./public/index.php
+ env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
+}
diff --git a/phpstan.neon b/phpstan.dist.neon
similarity index 100%
rename from phpstan.neon
rename to phpstan.dist.neon
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 890644a1..7b2293f8 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -16,6 +16,7 @@
+
diff --git a/symfony.lock b/symfony.lock
index 894b1484..6fffb4ce 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -1,6 +1,6 @@
{
"doctrine/annotations": {
- "version": "1.13",
+ "version": "2.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -9,12 +9,12 @@
}
},
"doctrine/doctrine-bundle": {
- "version": "2.10",
+ "version": "2.11",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.10",
- "ref": "0db4b12b5df45f5122213b4ecd18733ab7fa7d53"
+ "ref": "0b4a11ee7e60b36227502ed26874edd7e8b66353"
},
"files": [
"config/packages/doctrine.yaml",
@@ -23,7 +23,7 @@
]
},
"doctrine/doctrine-fixtures-bundle": {
- "version": "3.4",
+ "version": "3.5",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -35,7 +35,7 @@
]
},
"doctrine/doctrine-migrations-bundle": {
- "version": "3.2",
+ "version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -48,7 +48,7 @@
]
},
"friendsofphp/php-cs-fixer": {
- "version": "3.13",
+ "version": "3.40",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -60,7 +60,7 @@
]
},
"knplabs/knp-paginator-bundle": {
- "version": "v5.9.0"
+ "version": "v6.3.0"
},
"phpstan/phpstan": {
"version": "1.10",
@@ -68,10 +68,10 @@
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "1.0",
- "ref": "d74d4d719d5f53856c9c13544aa22d44144b1819"
+ "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767"
},
"files": [
- "phpstan.neon"
+ "phpstan.dist.neon"
]
},
"phpunit/phpunit": {
@@ -89,7 +89,7 @@
]
},
"scheb/2fa-bundle": {
- "version": "6.8",
+ "version": "6.12",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -102,7 +102,7 @@
]
},
"symfony/console": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -114,7 +114,7 @@
]
},
"symfony/debug-bundle": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -126,7 +126,7 @@
]
},
"symfony/flex": {
- "version": "2.2",
+ "version": "2.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -157,7 +157,7 @@
]
},
"symfony/google-mailer": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -166,7 +166,7 @@
}
},
"symfony/lock": {
- "version": "6.1",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -178,7 +178,7 @@
]
},
"symfony/mailer": {
- "version": "6.3",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -190,7 +190,7 @@
]
},
"symfony/maker-bundle": {
- "version": "1.48",
+ "version": "1.52",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -199,7 +199,7 @@
}
},
"symfony/messenger": {
- "version": "6.3",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -211,7 +211,7 @@
]
},
"symfony/monolog-bundle": {
- "version": "3.8",
+ "version": "3.10",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -223,12 +223,12 @@
]
},
"symfony/notifier": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.0",
- "ref": "c31585e252b32fe0e1f30b1f256af553f4a06eb9"
+ "ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc"
},
"files": [
"config/packages/notifier.yaml"
@@ -244,12 +244,12 @@
}
},
"symfony/phpunit-bridge": {
- "version": "6.3",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
- "version": "5.3",
- "ref": "819d3d2ffa4590eba0b8f4f3e5e89415ee4e45c3"
+ "version": "6.3",
+ "ref": "1f5830c331065b6e4c9d5fa2105e322d29fcd573"
},
"files": [
".env.test",
@@ -259,7 +259,7 @@
]
},
"symfony/routing": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -272,24 +272,25 @@
]
},
"symfony/security-bundle": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
- "version": "6.0",
- "ref": "8a5b112826f7d3d5b07027f93786ae11a1c7de48"
+ "version": "6.4",
+ "ref": "2ae08430db28c8eb4476605894296c82a642028f"
},
"files": [
- "config/packages/security.yaml"
+ "config/packages/security.yaml",
+ "config/routes/security.yaml"
]
},
"symfony/translation": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
- "version": "5.3",
- "ref": "da64f5a2b6d96f5dc24914517c0350a5f91dee43"
+ "version": "6.3",
+ "ref": "64fe617084223633e1dedf9112935d8c95410d3e"
},
"files": [
"config/packages/translation.yaml",
@@ -297,7 +298,7 @@
]
},
"symfony/twig-bundle": {
- "version": "6.3",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -310,7 +311,7 @@
]
},
"symfony/validator": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -322,7 +323,7 @@
]
},
"symfony/web-profiler-bundle": {
- "version": "6.2",
+ "version": "6.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
@@ -335,12 +336,12 @@
]
},
"symfony/webpack-encore-bundle": {
- "version": "2.0",
+ "version": "2.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.0",
- "ref": "13ebe04e25085e2ff0bcb0f9218b561d8b5089f3"
+ "ref": "082d754b3bd54b3fc669f278f1eea955cfd23cf5"
},
"files": [
"assets/app.js",
@@ -351,9 +352,9 @@
]
},
"symfonycasts/verify-email-bundle": {
- "version": "v1.12.0"
+ "version": "v1.15.0"
},
"twig/extra-bundle": {
- "version": "v3.4.0"
+ "version": "v3.8.0"
}
}