RSS Reader using AT Protocol rssbase.io
feed atom rss reader atproto social
2

Configure Feed

Select the types of activity you want to include in your feed.

add symfony base + dagger ci

+5764 -19
-19
.tangled/workflows/base.yml
··· 1 - when: 2 - - event: ["push", "manual"] 3 - branch: ["main"] 4 - - event: ["pull_request"] 5 - branch: ["main"] 6 - 7 - engine: microvm 8 - image: nixos 9 - 10 - clone: 11 - skip: false 12 - depth: 1 13 - 14 - dependencies: 15 - - devenv 16 - 17 - steps: 18 - - name: "Smoke test devenv" 19 - command: devenv shell echo 'hello'
+46
.tangled/workflows/build.yml
··· 1 + when: 2 + - event: ["push", "manual"] 3 + branch: ["main"] 4 + - event: ["pull_request"] 5 + branch: ["main"] 6 + 7 + engine: microvm 8 + image: nixos 9 + 10 + clone: 11 + skip: false 12 + depth: 1 13 + 14 + dependencies: 15 + - devenv 16 + 17 + steps: 18 + - name: "Initialize devenv" 19 + command: devenv shell true 20 + 21 + - name: "Build production image with Dagger" 22 + command: DAGGER_NO_NAG=1 devenv shell dagger call application build-prod sync 23 + 24 + - name: "Build production image with Docker Compose" 25 + command: | 26 + devenv shell -- bash -c ' 27 + set -euo pipefail 28 + cd application 29 + export APP_SECRET="${APP_SECRET:-ci-app-secret}" 30 + export CADDY_MERCURE_JWT_SECRET="${CADDY_MERCURE_JWT_SECRET:-ci-mercure-secret}" 31 + docker-compose -f compose.yaml -f compose.prod.yaml build --pull 32 + ' 33 + 34 + - name: "Start production services and smoke test" 35 + command: | 36 + devenv shell -- bash -c ' 37 + set -euo pipefail 38 + cd application 39 + export APP_SECRET="${APP_SECRET:-ci-app-secret}" 40 + export CADDY_MERCURE_JWT_SECRET="${CADDY_MERCURE_JWT_SECRET:-ci-mercure-secret}" 41 + trap "docker-compose -f compose.yaml -f compose.prod.yaml down --volumes --remove-orphans" EXIT 42 + docker-compose -f compose.yaml -f compose.prod.yaml down --volumes --remove-orphans 43 + docker-compose -f compose.yaml -f compose.prod.yaml up --wait --wait-timeout 120 --no-build -d 44 + curl -v --fail-with-body http://localhost 45 + curl -vI --insecure --fail-with-body "https://localhost/.well-known/mercure?topic=test" 46 + '
+22
.tangled/workflows/check.yml
··· 1 + when: 2 + - event: ["push", "manual"] 3 + branch: ["main"] 4 + - event: ["pull_request"] 5 + branch: ["main"] 6 + 7 + engine: microvm 8 + image: nixos 9 + 10 + clone: 11 + skip: false 12 + depth: 1 13 + 14 + dependencies: 15 + - devenv 16 + 17 + steps: 18 + - name: "Initialize devenv" 19 + command: devenv shell true 20 + 21 + - name: "Run Dagger checks" 22 + command: DAGGER_NO_NAG=1 devenv shell dagger check
+6
README.md
··· 42 42 # Your developer environment is ready 👨‍🚀🚀 43 43 ``` 44 44 45 + ### Devenv maintainer 46 + ```bash 47 + CACHIX_AUTH_TOKEN=... devenv shell true 48 + ``` 49 + <details> 50 + 45 51 [devenv]: https://devenv.sh 46 52 [nix]: https://search.nixos.org/packages
+17
application/.dagger/README.md
··· 1 + # RSSBase application Dagger module 2 + 3 + This module is written in [Dang](https://github.com/vito/dang) and uses the Dagger CLI packaged by this repo's devenv. 4 + 5 + The application module is configured by `application/dagger-module.toml`; the repository root `dagger.toml` installs it as the `application` workspace module. 6 + 7 + From the repository root or `application/`: 8 + 9 + ```bash 10 + dagger functions 11 + dagger check --list 12 + dagger check 13 + dagger call application php-version 14 + dagger call application composer-validate 15 + dagger call application build-prod sync 16 + dagger call application console --args about 17 + ```
+57
application/.dagger/main.dang
··· 1 + """ 2 + Dagger workflows for rssbase.io/application. 3 + """ 4 + type Application { 5 + let source: Directory! @defaultPath(path: "/application") @ignorePatterns(patterns: [ 6 + ".dagger", 7 + "var", 8 + "vendor", 9 + ]) 10 + 11 + let phpBase: Container! { 12 + source 13 + .dockerBuild(target: "frankenphp_base") 14 + .withDirectory("/app", source) 15 + .withWorkdir("/app") 16 + .withMountedCache("/tmp/composer-cache", cacheVolume("composer-cache")) 17 + .withEnvVariable("COMPOSER_CACHE_DIR", "/tmp/composer-cache") 18 + } 19 + 20 + """ 21 + Build the production FrankenPHP image from application/Dockerfile. 22 + """ 23 + pub buildProd: Container! { 24 + source.dockerBuild(target: "frankenphp_prod") 25 + } 26 + 27 + """ 28 + Validate Composer metadata. 29 + """ 30 + @check 31 + pub composerValidate: String! { 32 + phpBase 33 + .withExec(["composer", "validate", "--strict"]) 34 + .stdout 35 + } 36 + 37 + """ 38 + Run composer install in an isolated Dagger container. 39 + """ 40 + pub composerInstall: Container! { 41 + phpBase.withExec([ 42 + "composer", "install", 43 + "--no-interaction", 44 + "--prefer-dist", 45 + "--no-progress", 46 + ]) 47 + } 48 + 49 + """ 50 + Run a Symfony console command after installing dependencies. 51 + """ 52 + pub console(args: [String!]! = ["about"]): String! { 53 + composerInstall 54 + .withExec(["php", "bin/console"] + args) 55 + .stdout 56 + } 57 + }
+7
application/.devcontainer/compose.devcontainer.yaml
··· 1 + --- 2 + # Dev Container-specific overrides: enable XDebug 3 + services: 4 + php: 5 + environment: 6 + XDEBUG_MODE: "${XDEBUG_MODE:-develop,debug}" 7 + XDEBUG_CONFIG: "client_host=127.0.0.1 start_with_request=yes"
+35
application/.devcontainer/devcontainer.json
··· 1 + { 2 + "name": "Symfony Docker", 3 + "dockerComposeFile": [ 4 + "../compose.yaml", 5 + "../compose.override.yaml", 6 + "compose.devcontainer.yaml" 7 + ], 8 + "service": "php", 9 + "workspaceFolder": "/app", 10 + "features": { 11 + "ghcr.io/devcontainers/features/node:1": {} 12 + }, 13 + "remoteUser": "nonroot", 14 + "postCreateCommand": "npm install -g intelephense", 15 + "customizations": { 16 + "vscode": { 17 + "extensions": [ 18 + "bmewburn.vscode-intelephense-client", 19 + "xdebug.php-debug" 20 + ], 21 + "settings": { 22 + "launch": { 23 + "version": "0.2.0", 24 + "configurations": [ 25 + { 26 + "name": "Debug PHP", 27 + "type": "php", 28 + "request": "launch" 29 + } 30 + ] 31 + } 32 + } 33 + } 34 + } 35 + }
+35
application/.dockerignore
··· 1 + **/*.log 2 + **/*.md 3 + **/*.php~ 4 + **/*.dist.php 5 + **/*.dist 6 + **/*.cache 7 + **/._* 8 + **/.dockerignore 9 + **/.DS_Store 10 + **/.git/ 11 + **/.gitattributes 12 + **/.gitignore 13 + **/.gitmodules 14 + **/compose.*.yaml 15 + **/compose.*.yml 16 + **/compose.yaml 17 + **/compose.yml 18 + **/docker-compose.*.yaml 19 + **/docker-compose.*.yml 20 + **/docker-compose.yaml 21 + **/docker-compose.yml 22 + **/Dockerfile 23 + **/Thumbs.db 24 + .github/ 25 + docs/ 26 + public/bundles/ 27 + tests/ 28 + var/ 29 + vendor/ 30 + .dagger/ 31 + .editorconfig 32 + .env.*.local 33 + .env.local 34 + .env.local.php 35 + .env.test
+22
application/.editorconfig
··· 1 + # EditorConfig helps developers define and maintain consistent 2 + # coding styles between different editors and IDEs 3 + # editorconfig.org 4 + 5 + root = true 6 + 7 + [*] 8 + charset = utf-8 9 + insert_final_newline = true 10 + end_of_line = lf 11 + indent_style = space 12 + indent_size = 4 13 + 14 + [**/{Dockerfile,Caddyfile,*.sh}] 15 + indent_style = tab 16 + 17 + [{compose.*yaml,.devcontainer/compose.*yaml,.github/**/*.yaml}] 18 + indent_size = 2 19 + 20 + [**.md] 21 + indent_size = unset 22 + indent_style = unset
+27
application/.env
··· 1 + # In all environments, the following files are loaded if they exist, 2 + # the latter taking precedence over the former: 3 + # 4 + # * .env contains default values for the environment variables needed by the app 5 + # * .env.local uncommitted file with local overrides 6 + # * .env.$APP_ENV committed environment-specific defaults 7 + # * .env.$APP_ENV.local uncommitted environment-specific overrides 8 + # 9 + # Real environment variables win over .env files. 10 + # 11 + # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. 12 + # https://symfony.com/doc/current/configuration/secrets.html 13 + # 14 + # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). 15 + # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration 16 + 17 + ###> symfony/framework-bundle ### 18 + APP_ENV=dev 19 + APP_SECRET= 20 + APP_SHARE_DIR=var/share 21 + ###< symfony/framework-bundle ### 22 + 23 + ###> symfony/routing ### 24 + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. 25 + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands 26 + DEFAULT_URI=http://localhost 27 + ###< symfony/routing ###
+4
application/.env.dev
··· 1 + 2 + ###> symfony/framework-bundle ### 3 + APP_SECRET=fc3165aaefa2466cf01f3032200b78f0 4 + ###< symfony/framework-bundle ###
+17
application/.gitattributes
··· 1 + * text=auto eol=lf 2 + 3 + *.conf text eol=lf 4 + *.html text eol=lf 5 + *.ini text eol=lf 6 + *.js text eol=lf 7 + *.json text eol=lf 8 + *.md text eol=lf 9 + *.php text eol=lf 10 + *.sh text eol=lf 11 + *.yaml text eol=lf 12 + *.yml text eol=lf 13 + bin/console text eol=lf 14 + composer.lock text eol=lf merge=ours 15 + 16 + *.ico binary 17 + *.png binary
+10
application/.gitignore
··· 1 + 2 + ###> symfony/framework-bundle ### 3 + /.env.local 4 + /.env.local.php 5 + /.env.*.local 6 + /config/secrets/prod/prod.decrypt.private.php 7 + /public/bundles/ 8 + /var/ 9 + /vendor/ 10 + ###< symfony/framework-bundle ###
+164
application/Dockerfile
··· 1 + #syntax=docker/dockerfile:1 2 + 3 + # Versions 4 + FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream 5 + 6 + # The different stages of this Dockerfile are meant to be built into separate images 7 + # https://docs.docker.com/build/building/multi-stage/#stop-at-a-specific-build-stage 8 + # https://docs.docker.com/reference/compose-file/build/#target 9 + 10 + 11 + # Base FrankenPHP image 12 + FROM frankenphp_upstream AS frankenphp_base 13 + 14 + SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 15 + 16 + WORKDIR /app 17 + 18 + # persistent deps 19 + # hadolint ignore=DL3008 20 + RUN <<-EOF 21 + apt-get update 22 + apt-get install -y --no-install-recommends \ 23 + file \ 24 + git 25 + install-php-extensions \ 26 + @composer \ 27 + apcu \ 28 + intl \ 29 + opcache \ 30 + zip 31 + rm -rf /var/lib/apt/lists/* 32 + EOF 33 + 34 + # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser 35 + ENV COMPOSER_ALLOW_SUPERUSER=1 36 + 37 + ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d" 38 + 39 + ###> recipes ### 40 + ###< recipes ### 41 + 42 + COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/ 43 + COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint 44 + COPY --link frankenphp/Caddyfile /etc/frankenphp/Caddyfile 45 + 46 + ENTRYPOINT ["docker-entrypoint"] 47 + 48 + HEALTHCHECK --start-period=60s CMD php -r 'exit(false === @file_get_contents("http://localhost:2019/metrics", context: stream_context_create(["http" => ["timeout" => 5]])) ? 1 : 0);' 49 + CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ] 50 + 51 + # Dev FrankenPHP image 52 + FROM frankenphp_base AS frankenphp_dev 53 + 54 + ENV APP_ENV=dev 55 + ENV XDEBUG_MODE=off 56 + ENV FRANKENPHP_WORKER_CONFIG=watch 57 + 58 + # dev dependencies 59 + RUN <<-EOF 60 + mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 61 + install-php-extensions xdebug 62 + useradd -m -s /bin/bash nonroot 63 + git config --system --add safe.directory /app 64 + EOF 65 + 66 + COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/ 67 + 68 + CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile", "--watch" ] 69 + 70 + # Builder for the prod FrankenPHP image 71 + FROM frankenphp_base AS frankenphp_prod_builder 72 + 73 + ENV APP_ENV=prod 74 + 75 + RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 76 + 77 + COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/ 78 + 79 + # prevent the reinstallation of vendors at every changes in the source code 80 + COPY --link composer.* symfony.* ./ 81 + RUN composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress 82 + 83 + # copy sources 84 + COPY --link --exclude=frankenphp/ . ./ 85 + 86 + RUN <<-EOF 87 + mkdir -p var/cache var/log var/share 88 + composer dump-autoload --classmap-authoritative --no-dev 89 + composer dump-env prod 90 + composer run-script --no-dev post-install-cmd 91 + if [ -f importmap.php ]; then 92 + php bin/console asset-map:compile 93 + fi 94 + chmod +x bin/console 95 + chmod -R g=u var 96 + sync 97 + EOF 98 + 99 + # Collect shared libraries needed by FrankenPHP and PHP extensions 100 + # hadolint ignore=DL3008,SC3054,DL4006 101 + RUN <<-'EOF' 102 + apt-get update 103 + apt-get install -y --no-install-recommends libtree 104 + mkdir -p /tmp/libs 105 + BINARIES=(frankenphp php file) 106 + for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \ 107 + $(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do 108 + libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do 109 + [ -f "$lib" ] && cp -n "$lib" /tmp/libs/ 110 + done 111 + done 112 + rm -rf /var/lib/apt/lists/* 113 + EOF 114 + 115 + # Prod FrankenPHP image 116 + FROM debian:13-slim AS frankenphp_prod 117 + 118 + SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 119 + 120 + ENV APP_ENV=prod 121 + ENV PHP_INI_SCAN_DIR=":/usr/local/etc/php/app.conf.d" 122 + 123 + COPY --from=frankenphp_prod_builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp 124 + COPY --from=frankenphp_prod_builder /usr/local/bin/php /usr/local/bin/php 125 + COPY --from=frankenphp_prod_builder /usr/local/bin/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint 126 + COPY --from=frankenphp_prod_builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions 127 + COPY --from=frankenphp_prod_builder /tmp/libs /usr/lib 128 + 129 + COPY --from=frankenphp_prod_builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d 130 + COPY --from=frankenphp_prod_builder /usr/local/etc/php/php.ini /usr/local/etc/php/php.ini 131 + COPY --from=frankenphp_prod_builder /usr/local/etc/php/app.conf.d /usr/local/etc/php/app.conf.d 132 + 133 + COPY --from=frankenphp_prod_builder /etc/frankenphp/Caddyfile /etc/frankenphp/Caddyfile 134 + 135 + # CA certificates for TLS, file/libmagic for Symfony MIME type detection 136 + COPY --from=frankenphp_prod_builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 137 + COPY --from=frankenphp_prod_builder /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf 138 + COPY --from=frankenphp_prod_builder /usr/bin/file /usr/bin/file 139 + COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc 140 + 141 + ENV OPENSSL_CONF=/etc/ssl/openssl.cnf XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt 142 + 143 + RUN <<-EOF 144 + mkdir -p /data/caddy /config/caddy 145 + chown -R www-data:www-data /data /config 146 + # Remove setuid/setgid bits 147 + find / -perm /6000 -type f -exec chmod a-s {} + 2>/dev/null || true 148 + EOF 149 + 150 + COPY --link --exclude=var --from=frankenphp_prod_builder /app /app 151 + # Group 0 + g=u for arbitrary-UID runtimes (e.g. OpenShift). 152 + COPY --chown=www-data:0 --from=frankenphp_prod_builder /app/var /app/var 153 + RUN chmod g=u /app/var 154 + 155 + COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint 156 + 157 + USER www-data 158 + 159 + WORKDIR /app 160 + 161 + ENTRYPOINT ["docker-entrypoint"] 162 + 163 + HEALTHCHECK --start-period=60s CMD php -r 'exit(false === @file_get_contents("http://localhost:2019/metrics", context: stream_context_create(["http" => ["timeout" => 5]])) ? 1 : 0);' 164 + CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]
+39
application/README.md
··· 1 + # Application using Symfony 2 + 3 + ## Getting Started 4 + 5 + 1. Run `docker compose up --build --wait` to set up and start a fresh Symfony project 6 + 2. Open `https://localhost` in your favorite web browser and [accept the auto-generated TLS certificate](https://stackoverflow.com/a/15076602/1352334) 7 + 8 + 9 + ## Features 10 + 11 + - Production, development and CI ready 12 + - Just 1 service by default 13 + - Super-readable configuration 14 + - Blazing-fast performance thanks to [the worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/) 15 + - [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex 16 + - Automatic HTTPS (in dev and prod) 17 + - HTTP/3 and [Early Hints](https://symfony.com/blog/new-in-symfony-6-3-early-hints) support 18 + - Real-time messaging thanks to a built-in [Mercure hub](https://symfony.com/doc/current/mercure.html) 19 + - [Vulcain](https://vulcain.rocks) support 20 + - Native [XDebug](docs/xdebug.md) integration 21 + - [Hot Reloading](https://frankenphp.dev/docs/hot-reload/) 22 + - [Dev Container](https://containers.dev/) support 23 + - [AI coding agents](docs/agents.md) with an optional network sandbox 24 + - Rootless, slim production image 25 + 26 + ## Docs 27 + 28 + 1. [Options available](docs/options.md) 29 + 2. [Using Symfony Docker with an existing project](docs/existing-project.md) 30 + 3. [Support for extra services](docs/extra-services.md) 31 + 4. [Deploying in production](docs/production.md) 32 + 5. [Debugging with Xdebug](docs/xdebug.md) 33 + 6. [TLS Certificates](docs/tls.md) 34 + 7. [Using MySQL instead of PostgreSQL](docs/mysql.md) 35 + 8. [Using Alpine Linux instead of Debian](docs/alpine.md) 36 + 9. [Using a Makefile](docs/makefile.md) 37 + 10. [Updating the template](docs/updating.md) 38 + 11. [Troubleshooting](docs/troubleshooting.md) 39 + 12. [Using AI coding agents](docs/agents.md)
+21
application/bin/console
··· 1 + #!/usr/bin/env php 2 + <?php 3 + 4 + use App\Kernel; 5 + use Symfony\Bundle\FrameworkBundle\Console\Application; 6 + 7 + if (!is_dir(dirname(__DIR__).'/vendor')) { 8 + throw new LogicException('Dependencies are missing. Try running "composer install".'); 9 + } 10 + 11 + if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { 12 + throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); 13 + } 14 + 15 + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; 16 + 17 + return function (array $context) { 18 + $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); 19 + 20 + return new Application($kernel); 21 + };
+30
application/compose.override.yaml
··· 1 + --- 2 + # Development environment override 3 + services: 4 + php: 5 + image: ${IMAGES_PREFIX:-}app-php-dev 6 + build: 7 + context: . 8 + target: frankenphp_dev 9 + volumes: 10 + - ./:/app 11 + - ./frankenphp/Caddyfile:/etc/frankenphp/Caddyfile:ro 12 + - ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/app.conf.d/20-app.dev.ini:ro 13 + # Keep var/ off the bind-mount for faster I/O on Mac/Windows; comment to inspect from the host. 14 + - /app/var 15 + # If you develop on Mac or Windows you can remove the vendor/ directory 16 + # from the bind-mount for better performance by enabling the next line: 17 + #- /app/vendor 18 + environment: 19 + FRANKENPHP_WORKER_CONFIG: watch 20 + FRANKENPHP_SITE_CONFIG: hot_reload 21 + MERCURE_EXTRA_DIRECTIVES: demo 22 + # See https://xdebug.org/docs/all_settings#mode 23 + XDEBUG_MODE: "${XDEBUG_MODE:-develop}" 24 + APP_ENV: "${APP_ENV:-dev}" 25 + extra_hosts: 26 + # Ensure that host.docker.internal is correctly defined on Linux 27 + - host.docker.internal:host-gateway 28 + tty: true 29 + ###> symfony/mercure-bundle ### 30 + ###< symfony/mercure-bundle ###
+12
application/compose.prod.yaml
··· 1 + --- 2 + # Production environment override 3 + services: 4 + php: 5 + image: ${IMAGES_PREFIX:-}app-php-prod 6 + build: 7 + context: . 8 + target: frankenphp_prod 9 + environment: 10 + APP_SECRET: ${APP_SECRET} 11 + MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} 12 + MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
+41
application/compose.yaml
··· 1 + --- 2 + services: 3 + php: 4 + restart: unless-stopped 5 + environment: 6 + SERVER_NAME: ${SERVER_NAME:-localhost}, php:80 7 + DEFAULT_URI: https://${SERVER_NAME:-localhost}:${HTTPS_PORT:-443} 8 + MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} 9 + MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} 10 + # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM 11 + DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8} 12 + # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration 13 + MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure} 14 + MERCURE_PUBLIC_URL: ${CADDY_MERCURE_PUBLIC_URL:-https://${SERVER_NAME:-localhost}:${HTTPS_PORT:-443}/.well-known/mercure} 15 + MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} 16 + volumes: 17 + - caddy_data:/data 18 + - caddy_config:/config 19 + ports: 20 + - name: http 21 + target: 80 22 + published: ${HTTP_PORT:-80} 23 + protocol: tcp 24 + - name: https 25 + target: 443 26 + published: ${HTTPS_PORT:-443} 27 + protocol: tcp 28 + - name: http3 29 + target: 443 30 + published: ${HTTP3_PORT:-443} 31 + protocol: udp 32 + 33 + # Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service 34 + ###> symfony/mercure-bundle ### 35 + ###< symfony/mercure-bundle ### 36 + 37 + volumes: 38 + caddy_data: 39 + caddy_config: 40 + ###> symfony/mercure-bundle ### 41 + ###< symfony/mercure-bundle ###
+72
application/composer.json
··· 1 + { 2 + "name": "symfony/skeleton", 3 + "type": "project", 4 + "license": "MIT", 5 + "description": "A minimal Symfony project recommended to create bare bones applications", 6 + "minimum-stability": "stable", 7 + "prefer-stable": true, 8 + "require": { 9 + "php": ">=8.5.7", 10 + "ext-ctype": "*", 11 + "ext-iconv": "*", 12 + "symfony/console": "8.1.*", 13 + "symfony/dotenv": "8.1.*", 14 + "symfony/flex": "^2", 15 + "symfony/framework-bundle": "8.1.*", 16 + "symfony/runtime": "8.1.*", 17 + "symfony/yaml": "8.1.*" 18 + }, 19 + "config": { 20 + "allow-plugins": { 21 + "php-http/discovery": true, 22 + "symfony/flex": true, 23 + "symfony/runtime": true 24 + }, 25 + "bump-after-update": true, 26 + "sort-packages": true 27 + }, 28 + "autoload": { 29 + "psr-4": { 30 + "App\\": "src/" 31 + } 32 + }, 33 + "autoload-dev": { 34 + "psr-4": { 35 + "App\\Tests\\": "tests/" 36 + } 37 + }, 38 + "replace": { 39 + "symfony/polyfill-ctype": "*", 40 + "symfony/polyfill-iconv": "*", 41 + "symfony/polyfill-php72": "*", 42 + "symfony/polyfill-php73": "*", 43 + "symfony/polyfill-php74": "*", 44 + "symfony/polyfill-php80": "*", 45 + "symfony/polyfill-php81": "*", 46 + "symfony/polyfill-php82": "*", 47 + "symfony/polyfill-php83": "*", 48 + "symfony/polyfill-php84": "*" 49 + }, 50 + "scripts": { 51 + "auto-scripts": { 52 + "cache:clear": "symfony-cmd", 53 + "assets:install %PUBLIC_DIR%": "symfony-cmd" 54 + }, 55 + "post-install-cmd": [ 56 + "@auto-scripts" 57 + ], 58 + "post-update-cmd": [ 59 + "@auto-scripts" 60 + ] 61 + }, 62 + "conflict": { 63 + "symfony/symfony": "*" 64 + }, 65 + "extra": { 66 + "symfony": { 67 + "allow-contrib": false, 68 + "require": "8.1.*", 69 + "docker": true 70 + } 71 + } 72 + }
+2606
application/composer.lock
··· 1 + { 2 + "_readme": [ 3 + "This file locks the dependencies of your project to a known state", 4 + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 + "This file is @generated automatically" 6 + ], 7 + "content-hash": "9b8a3d2da9a156ff3b869df2d0bc4ceb", 8 + "packages": [ 9 + { 10 + "name": "psr/cache", 11 + "version": "3.0.0", 12 + "source": { 13 + "type": "git", 14 + "url": "https://github.com/php-fig/cache.git", 15 + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" 16 + }, 17 + "dist": { 18 + "type": "zip", 19 + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 20 + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", 21 + "shasum": "" 22 + }, 23 + "require": { 24 + "php": ">=8.0.0" 25 + }, 26 + "type": "library", 27 + "extra": { 28 + "branch-alias": { 29 + "dev-master": "1.0.x-dev" 30 + } 31 + }, 32 + "autoload": { 33 + "psr-4": { 34 + "Psr\\Cache\\": "src/" 35 + } 36 + }, 37 + "notification-url": "https://packagist.org/downloads/", 38 + "license": [ 39 + "MIT" 40 + ], 41 + "authors": [ 42 + { 43 + "name": "PHP-FIG", 44 + "homepage": "https://www.php-fig.org/" 45 + } 46 + ], 47 + "description": "Common interface for caching libraries", 48 + "keywords": [ 49 + "cache", 50 + "psr", 51 + "psr-6" 52 + ], 53 + "support": { 54 + "source": "https://github.com/php-fig/cache/tree/3.0.0" 55 + }, 56 + "time": "2021-02-03T23:26:27+00:00" 57 + }, 58 + { 59 + "name": "psr/container", 60 + "version": "2.0.2", 61 + "source": { 62 + "type": "git", 63 + "url": "https://github.com/php-fig/container.git", 64 + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 65 + }, 66 + "dist": { 67 + "type": "zip", 68 + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 69 + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 70 + "shasum": "" 71 + }, 72 + "require": { 73 + "php": ">=7.4.0" 74 + }, 75 + "type": "library", 76 + "extra": { 77 + "branch-alias": { 78 + "dev-master": "2.0.x-dev" 79 + } 80 + }, 81 + "autoload": { 82 + "psr-4": { 83 + "Psr\\Container\\": "src/" 84 + } 85 + }, 86 + "notification-url": "https://packagist.org/downloads/", 87 + "license": [ 88 + "MIT" 89 + ], 90 + "authors": [ 91 + { 92 + "name": "PHP-FIG", 93 + "homepage": "https://www.php-fig.org/" 94 + } 95 + ], 96 + "description": "Common Container Interface (PHP FIG PSR-11)", 97 + "homepage": "https://github.com/php-fig/container", 98 + "keywords": [ 99 + "PSR-11", 100 + "container", 101 + "container-interface", 102 + "container-interop", 103 + "psr" 104 + ], 105 + "support": { 106 + "issues": "https://github.com/php-fig/container/issues", 107 + "source": "https://github.com/php-fig/container/tree/2.0.2" 108 + }, 109 + "time": "2021-11-05T16:47:00+00:00" 110 + }, 111 + { 112 + "name": "psr/event-dispatcher", 113 + "version": "1.0.0", 114 + "source": { 115 + "type": "git", 116 + "url": "https://github.com/php-fig/event-dispatcher.git", 117 + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" 118 + }, 119 + "dist": { 120 + "type": "zip", 121 + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", 122 + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", 123 + "shasum": "" 124 + }, 125 + "require": { 126 + "php": ">=7.2.0" 127 + }, 128 + "type": "library", 129 + "extra": { 130 + "branch-alias": { 131 + "dev-master": "1.0.x-dev" 132 + } 133 + }, 134 + "autoload": { 135 + "psr-4": { 136 + "Psr\\EventDispatcher\\": "src/" 137 + } 138 + }, 139 + "notification-url": "https://packagist.org/downloads/", 140 + "license": [ 141 + "MIT" 142 + ], 143 + "authors": [ 144 + { 145 + "name": "PHP-FIG", 146 + "homepage": "http://www.php-fig.org/" 147 + } 148 + ], 149 + "description": "Standard interfaces for event handling.", 150 + "keywords": [ 151 + "events", 152 + "psr", 153 + "psr-14" 154 + ], 155 + "support": { 156 + "issues": "https://github.com/php-fig/event-dispatcher/issues", 157 + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" 158 + }, 159 + "time": "2019-01-08T18:20:26+00:00" 160 + }, 161 + { 162 + "name": "psr/log", 163 + "version": "3.0.2", 164 + "source": { 165 + "type": "git", 166 + "url": "https://github.com/php-fig/log.git", 167 + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" 168 + }, 169 + "dist": { 170 + "type": "zip", 171 + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 172 + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", 173 + "shasum": "" 174 + }, 175 + "require": { 176 + "php": ">=8.0.0" 177 + }, 178 + "type": "library", 179 + "extra": { 180 + "branch-alias": { 181 + "dev-master": "3.x-dev" 182 + } 183 + }, 184 + "autoload": { 185 + "psr-4": { 186 + "Psr\\Log\\": "src" 187 + } 188 + }, 189 + "notification-url": "https://packagist.org/downloads/", 190 + "license": [ 191 + "MIT" 192 + ], 193 + "authors": [ 194 + { 195 + "name": "PHP-FIG", 196 + "homepage": "https://www.php-fig.org/" 197 + } 198 + ], 199 + "description": "Common interface for logging libraries", 200 + "homepage": "https://github.com/php-fig/log", 201 + "keywords": [ 202 + "log", 203 + "psr", 204 + "psr-3" 205 + ], 206 + "support": { 207 + "source": "https://github.com/php-fig/log/tree/3.0.2" 208 + }, 209 + "time": "2024-09-11T13:17:53+00:00" 210 + }, 211 + { 212 + "name": "symfony/cache", 213 + "version": "v8.1.1", 214 + "source": { 215 + "type": "git", 216 + "url": "https://github.com/symfony/cache.git", 217 + "reference": "c14decc1b0755b1e8ab6babeef56e1880348e817" 218 + }, 219 + "dist": { 220 + "type": "zip", 221 + "url": "https://api.github.com/repos/symfony/cache/zipball/c14decc1b0755b1e8ab6babeef56e1880348e817", 222 + "reference": "c14decc1b0755b1e8ab6babeef56e1880348e817", 223 + "shasum": "" 224 + }, 225 + "require": { 226 + "php": ">=8.4.1", 227 + "psr/cache": "^2.0|^3.0", 228 + "psr/log": "^1.1|^2|^3", 229 + "symfony/cache-contracts": "^3.6", 230 + "symfony/service-contracts": "^2.5|^3", 231 + "symfony/var-exporter": "^8.1" 232 + }, 233 + "conflict": { 234 + "ext-redis": "<6.1", 235 + "ext-relay": "<0.12.1" 236 + }, 237 + "provide": { 238 + "psr/cache-implementation": "2.0|3.0", 239 + "psr/simple-cache-implementation": "1.0|2.0|3.0", 240 + "symfony/cache-implementation": "1.1|2.0|3.0" 241 + }, 242 + "require-dev": { 243 + "cache/integration-tests": "dev-master", 244 + "doctrine/dbal": "^4.3", 245 + "predis/predis": "^1.1|^2.0", 246 + "psr/simple-cache": "^1.0|^2.0|^3.0", 247 + "symfony/clock": "^7.4|^8.0", 248 + "symfony/config": "^7.4|^8.0", 249 + "symfony/dependency-injection": "^7.4|^8.0", 250 + "symfony/filesystem": "^7.4|^8.0", 251 + "symfony/http-kernel": "^7.4|^8.0", 252 + "symfony/messenger": "^7.4|^8.0", 253 + "symfony/var-dumper": "^7.4|^8.0" 254 + }, 255 + "type": "library", 256 + "autoload": { 257 + "psr-4": { 258 + "Symfony\\Component\\Cache\\": "" 259 + }, 260 + "classmap": [ 261 + "Traits/ValueWrapper.php" 262 + ], 263 + "exclude-from-classmap": [ 264 + "/Tests/" 265 + ] 266 + }, 267 + "notification-url": "https://packagist.org/downloads/", 268 + "license": [ 269 + "MIT" 270 + ], 271 + "authors": [ 272 + { 273 + "name": "Nicolas Grekas", 274 + "email": "p@tchwork.com" 275 + }, 276 + { 277 + "name": "Symfony Community", 278 + "homepage": "https://symfony.com/contributors" 279 + } 280 + ], 281 + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", 282 + "homepage": "https://symfony.com", 283 + "keywords": [ 284 + "caching", 285 + "psr6" 286 + ], 287 + "support": { 288 + "source": "https://github.com/symfony/cache/tree/v8.1.1" 289 + }, 290 + "funding": [ 291 + { 292 + "url": "https://symfony.com/sponsor", 293 + "type": "custom" 294 + }, 295 + { 296 + "url": "https://github.com/fabpot", 297 + "type": "github" 298 + }, 299 + { 300 + "url": "https://github.com/nicolas-grekas", 301 + "type": "github" 302 + }, 303 + { 304 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 305 + "type": "tidelift" 306 + } 307 + ], 308 + "time": "2026-06-17T15:04:37+00:00" 309 + }, 310 + { 311 + "name": "symfony/cache-contracts", 312 + "version": "v3.7.1", 313 + "source": { 314 + "type": "git", 315 + "url": "https://github.com/symfony/cache-contracts.git", 316 + "reference": "9789738bc19af1106dc54d6afba9a0b467516cf2" 317 + }, 318 + "dist": { 319 + "type": "zip", 320 + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/9789738bc19af1106dc54d6afba9a0b467516cf2", 321 + "reference": "9789738bc19af1106dc54d6afba9a0b467516cf2", 322 + "shasum": "" 323 + }, 324 + "require": { 325 + "php": ">=8.1", 326 + "psr/cache": "^3.0" 327 + }, 328 + "type": "library", 329 + "extra": { 330 + "thanks": { 331 + "url": "https://github.com/symfony/contracts", 332 + "name": "symfony/contracts" 333 + }, 334 + "branch-alias": { 335 + "dev-main": "3.7-dev" 336 + } 337 + }, 338 + "autoload": { 339 + "psr-4": { 340 + "Symfony\\Contracts\\Cache\\": "" 341 + } 342 + }, 343 + "notification-url": "https://packagist.org/downloads/", 344 + "license": [ 345 + "MIT" 346 + ], 347 + "authors": [ 348 + { 349 + "name": "Nicolas Grekas", 350 + "email": "p@tchwork.com" 351 + }, 352 + { 353 + "name": "Symfony Community", 354 + "homepage": "https://symfony.com/contributors" 355 + } 356 + ], 357 + "description": "Generic abstractions related to caching", 358 + "homepage": "https://symfony.com", 359 + "keywords": [ 360 + "abstractions", 361 + "contracts", 362 + "decoupling", 363 + "interfaces", 364 + "interoperability", 365 + "standards" 366 + ], 367 + "support": { 368 + "source": "https://github.com/symfony/cache-contracts/tree/v3.7.1" 369 + }, 370 + "funding": [ 371 + { 372 + "url": "https://symfony.com/sponsor", 373 + "type": "custom" 374 + }, 375 + { 376 + "url": "https://github.com/fabpot", 377 + "type": "github" 378 + }, 379 + { 380 + "url": "https://github.com/nicolas-grekas", 381 + "type": "github" 382 + }, 383 + { 384 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 385 + "type": "tidelift" 386 + } 387 + ], 388 + "time": "2026-06-05T06:23:12+00:00" 389 + }, 390 + { 391 + "name": "symfony/config", 392 + "version": "v8.1.1", 393 + "source": { 394 + "type": "git", 395 + "url": "https://github.com/symfony/config.git", 396 + "reference": "c18ae45733f9a5006ba81a13047d08a93e0dea1c" 397 + }, 398 + "dist": { 399 + "type": "zip", 400 + "url": "https://api.github.com/repos/symfony/config/zipball/c18ae45733f9a5006ba81a13047d08a93e0dea1c", 401 + "reference": "c18ae45733f9a5006ba81a13047d08a93e0dea1c", 402 + "shasum": "" 403 + }, 404 + "require": { 405 + "php": ">=8.4.1", 406 + "symfony/deprecation-contracts": "^2.5|^3", 407 + "symfony/filesystem": "^7.4|^8.0", 408 + "symfony/polyfill-ctype": "^1.8" 409 + }, 410 + "conflict": { 411 + "symfony/service-contracts": "<2.5" 412 + }, 413 + "require-dev": { 414 + "symfony/event-dispatcher": "^7.4|^8.0", 415 + "symfony/finder": "^7.4|^8.0", 416 + "symfony/messenger": "^7.4|^8.0", 417 + "symfony/service-contracts": "^2.5|^3", 418 + "symfony/yaml": "^7.4|^8.0" 419 + }, 420 + "type": "library", 421 + "autoload": { 422 + "psr-4": { 423 + "Symfony\\Component\\Config\\": "" 424 + }, 425 + "exclude-from-classmap": [ 426 + "/Tests/" 427 + ] 428 + }, 429 + "notification-url": "https://packagist.org/downloads/", 430 + "license": [ 431 + "MIT" 432 + ], 433 + "authors": [ 434 + { 435 + "name": "Fabien Potencier", 436 + "email": "fabien@symfony.com" 437 + }, 438 + { 439 + "name": "Symfony Community", 440 + "homepage": "https://symfony.com/contributors" 441 + } 442 + ], 443 + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", 444 + "homepage": "https://symfony.com", 445 + "support": { 446 + "source": "https://github.com/symfony/config/tree/v8.1.1" 447 + }, 448 + "funding": [ 449 + { 450 + "url": "https://symfony.com/sponsor", 451 + "type": "custom" 452 + }, 453 + { 454 + "url": "https://github.com/fabpot", 455 + "type": "github" 456 + }, 457 + { 458 + "url": "https://github.com/nicolas-grekas", 459 + "type": "github" 460 + }, 461 + { 462 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 463 + "type": "tidelift" 464 + } 465 + ], 466 + "time": "2026-06-09T10:54:51+00:00" 467 + }, 468 + { 469 + "name": "symfony/console", 470 + "version": "v8.1.1", 471 + "source": { 472 + "type": "git", 473 + "url": "https://github.com/symfony/console.git", 474 + "reference": "b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d" 475 + }, 476 + "dist": { 477 + "type": "zip", 478 + "url": "https://api.github.com/repos/symfony/console/zipball/b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d", 479 + "reference": "b711a8ab808b6c074c6b8caef70d0fd8d6b6d07d", 480 + "shasum": "" 481 + }, 482 + "require": { 483 + "php": ">=8.4.1", 484 + "symfony/deprecation-contracts": "^2.5|^3", 485 + "symfony/polyfill-mbstring": "^1.0", 486 + "symfony/polyfill-php85": "^1.32", 487 + "symfony/service-contracts": "^2.5|^3", 488 + "symfony/string": "^7.4.6|^8.0.6" 489 + }, 490 + "conflict": { 491 + "symfony/dependency-injection": "<8.1", 492 + "symfony/event-dispatcher": "<8.1" 493 + }, 494 + "provide": { 495 + "psr/log-implementation": "1.0|2.0|3.0" 496 + }, 497 + "require-dev": { 498 + "psr/log": "^1|^2|^3", 499 + "symfony/config": "^7.4|^8.0", 500 + "symfony/dependency-injection": "^8.1", 501 + "symfony/event-dispatcher": "^8.1", 502 + "symfony/filesystem": "^7.4|^8.0", 503 + "symfony/http-foundation": "^7.4|^8.0", 504 + "symfony/http-kernel": "^7.4|^8.0", 505 + "symfony/lock": "^7.4|^8.0", 506 + "symfony/messenger": "^7.4|^8.0", 507 + "symfony/mime": "^7.4|^8.0", 508 + "symfony/process": "^7.4|^8.0", 509 + "symfony/stopwatch": "^7.4|^8.0", 510 + "symfony/uid": "^7.4|^8.0", 511 + "symfony/validator": "^7.4|^8.0", 512 + "symfony/var-dumper": "^7.4|^8.0" 513 + }, 514 + "type": "library", 515 + "autoload": { 516 + "psr-4": { 517 + "Symfony\\Component\\Console\\": "" 518 + }, 519 + "exclude-from-classmap": [ 520 + "/Tests/" 521 + ] 522 + }, 523 + "notification-url": "https://packagist.org/downloads/", 524 + "license": [ 525 + "MIT" 526 + ], 527 + "authors": [ 528 + { 529 + "name": "Fabien Potencier", 530 + "email": "fabien@symfony.com" 531 + }, 532 + { 533 + "name": "Symfony Community", 534 + "homepage": "https://symfony.com/contributors" 535 + } 536 + ], 537 + "description": "Eases the creation of beautiful and testable command line interfaces", 538 + "homepage": "https://symfony.com", 539 + "keywords": [ 540 + "cli", 541 + "command-line", 542 + "console", 543 + "terminal" 544 + ], 545 + "support": { 546 + "source": "https://github.com/symfony/console/tree/v8.1.1" 547 + }, 548 + "funding": [ 549 + { 550 + "url": "https://symfony.com/sponsor", 551 + "type": "custom" 552 + }, 553 + { 554 + "url": "https://github.com/fabpot", 555 + "type": "github" 556 + }, 557 + { 558 + "url": "https://github.com/nicolas-grekas", 559 + "type": "github" 560 + }, 561 + { 562 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 563 + "type": "tidelift" 564 + } 565 + ], 566 + "time": "2026-06-16T12:55:20+00:00" 567 + }, 568 + { 569 + "name": "symfony/dependency-injection", 570 + "version": "v8.1.1", 571 + "source": { 572 + "type": "git", 573 + "url": "https://github.com/symfony/dependency-injection.git", 574 + "reference": "99ced9d6305c43b25a7d48fe6a7d169df275a597" 575 + }, 576 + "dist": { 577 + "type": "zip", 578 + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/99ced9d6305c43b25a7d48fe6a7d169df275a597", 579 + "reference": "99ced9d6305c43b25a7d48fe6a7d169df275a597", 580 + "shasum": "" 581 + }, 582 + "require": { 583 + "php": ">=8.4.1", 584 + "psr/container": "^1.1|^2.0", 585 + "symfony/deprecation-contracts": "^2.5|^3", 586 + "symfony/service-contracts": "^3.6", 587 + "symfony/var-exporter": "^8.1" 588 + }, 589 + "conflict": { 590 + "ext-psr": "<1.1|>=2" 591 + }, 592 + "provide": { 593 + "psr/container-implementation": "1.1|2.0", 594 + "symfony/service-implementation": "1.1|2.0|3.0" 595 + }, 596 + "require-dev": { 597 + "symfony/config": "^7.4|^8.0", 598 + "symfony/expression-language": "^7.4|^8.0", 599 + "symfony/yaml": "^7.4|^8.0" 600 + }, 601 + "type": "library", 602 + "autoload": { 603 + "psr-4": { 604 + "Symfony\\Component\\DependencyInjection\\": "" 605 + }, 606 + "exclude-from-classmap": [ 607 + "/Tests/" 608 + ] 609 + }, 610 + "notification-url": "https://packagist.org/downloads/", 611 + "license": [ 612 + "MIT" 613 + ], 614 + "authors": [ 615 + { 616 + "name": "Fabien Potencier", 617 + "email": "fabien@symfony.com" 618 + }, 619 + { 620 + "name": "Symfony Community", 621 + "homepage": "https://symfony.com/contributors" 622 + } 623 + ], 624 + "description": "Allows you to standardize and centralize the way objects are constructed in your application", 625 + "homepage": "https://symfony.com", 626 + "support": { 627 + "source": "https://github.com/symfony/dependency-injection/tree/v8.1.1" 628 + }, 629 + "funding": [ 630 + { 631 + "url": "https://symfony.com/sponsor", 632 + "type": "custom" 633 + }, 634 + { 635 + "url": "https://github.com/fabpot", 636 + "type": "github" 637 + }, 638 + { 639 + "url": "https://github.com/nicolas-grekas", 640 + "type": "github" 641 + }, 642 + { 643 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 644 + "type": "tidelift" 645 + } 646 + ], 647 + "time": "2026-06-27T06:18:14+00:00" 648 + }, 649 + { 650 + "name": "symfony/deprecation-contracts", 651 + "version": "v3.7.1", 652 + "source": { 653 + "type": "git", 654 + "url": "https://github.com/symfony/deprecation-contracts.git", 655 + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" 656 + }, 657 + "dist": { 658 + "type": "zip", 659 + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", 660 + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", 661 + "shasum": "" 662 + }, 663 + "require": { 664 + "php": ">=8.1" 665 + }, 666 + "type": "library", 667 + "extra": { 668 + "thanks": { 669 + "url": "https://github.com/symfony/contracts", 670 + "name": "symfony/contracts" 671 + }, 672 + "branch-alias": { 673 + "dev-main": "3.7-dev" 674 + } 675 + }, 676 + "autoload": { 677 + "files": [ 678 + "function.php" 679 + ] 680 + }, 681 + "notification-url": "https://packagist.org/downloads/", 682 + "license": [ 683 + "MIT" 684 + ], 685 + "authors": [ 686 + { 687 + "name": "Nicolas Grekas", 688 + "email": "p@tchwork.com" 689 + }, 690 + { 691 + "name": "Symfony Community", 692 + "homepage": "https://symfony.com/contributors" 693 + } 694 + ], 695 + "description": "A generic function and convention to trigger deprecation notices", 696 + "homepage": "https://symfony.com", 697 + "support": { 698 + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" 699 + }, 700 + "funding": [ 701 + { 702 + "url": "https://symfony.com/sponsor", 703 + "type": "custom" 704 + }, 705 + { 706 + "url": "https://github.com/fabpot", 707 + "type": "github" 708 + }, 709 + { 710 + "url": "https://github.com/nicolas-grekas", 711 + "type": "github" 712 + }, 713 + { 714 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 715 + "type": "tidelift" 716 + } 717 + ], 718 + "time": "2026-06-05T06:23:12+00:00" 719 + }, 720 + { 721 + "name": "symfony/dotenv", 722 + "version": "v8.1.0", 723 + "source": { 724 + "type": "git", 725 + "url": "https://github.com/symfony/dotenv.git", 726 + "reference": "7ed4e3a11e3c98235c70ded047d7ddf9e6ae854c" 727 + }, 728 + "dist": { 729 + "type": "zip", 730 + "url": "https://api.github.com/repos/symfony/dotenv/zipball/7ed4e3a11e3c98235c70ded047d7ddf9e6ae854c", 731 + "reference": "7ed4e3a11e3c98235c70ded047d7ddf9e6ae854c", 732 + "shasum": "" 733 + }, 734 + "require": { 735 + "php": ">=8.4.1" 736 + }, 737 + "require-dev": { 738 + "symfony/console": "^7.4|^8.0", 739 + "symfony/process": "^7.4|^8.0" 740 + }, 741 + "type": "library", 742 + "autoload": { 743 + "psr-4": { 744 + "Symfony\\Component\\Dotenv\\": "" 745 + }, 746 + "exclude-from-classmap": [ 747 + "/Tests/" 748 + ] 749 + }, 750 + "notification-url": "https://packagist.org/downloads/", 751 + "license": [ 752 + "MIT" 753 + ], 754 + "authors": [ 755 + { 756 + "name": "Fabien Potencier", 757 + "email": "fabien@symfony.com" 758 + }, 759 + { 760 + "name": "Symfony Community", 761 + "homepage": "https://symfony.com/contributors" 762 + } 763 + ], 764 + "description": "Registers environment variables from a .env file", 765 + "homepage": "https://symfony.com", 766 + "keywords": [ 767 + "dotenv", 768 + "env", 769 + "environment" 770 + ], 771 + "support": { 772 + "source": "https://github.com/symfony/dotenv/tree/v8.1.0" 773 + }, 774 + "funding": [ 775 + { 776 + "url": "https://symfony.com/sponsor", 777 + "type": "custom" 778 + }, 779 + { 780 + "url": "https://github.com/fabpot", 781 + "type": "github" 782 + }, 783 + { 784 + "url": "https://github.com/nicolas-grekas", 785 + "type": "github" 786 + }, 787 + { 788 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 789 + "type": "tidelift" 790 + } 791 + ], 792 + "time": "2026-05-29T05:06:50+00:00" 793 + }, 794 + { 795 + "name": "symfony/error-handler", 796 + "version": "v8.1.0", 797 + "source": { 798 + "type": "git", 799 + "url": "https://github.com/symfony/error-handler.git", 800 + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5" 801 + }, 802 + "dist": { 803 + "type": "zip", 804 + "url": "https://api.github.com/repos/symfony/error-handler/zipball/d8aeb1abd3fef84795567850d3a567bdb5945ee5", 805 + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5", 806 + "shasum": "" 807 + }, 808 + "require": { 809 + "php": ">=8.4.1", 810 + "psr/log": "^1|^2|^3", 811 + "symfony/polyfill-php85": "^1.32", 812 + "symfony/var-dumper": "^7.4|^8.0" 813 + }, 814 + "conflict": { 815 + "symfony/deprecation-contracts": "<2.5" 816 + }, 817 + "require-dev": { 818 + "symfony/console": "^7.4|^8.0", 819 + "symfony/deprecation-contracts": "^2.5|^3", 820 + "symfony/http-kernel": "^7.4|^8.0", 821 + "symfony/serializer": "^7.4|^8.0", 822 + "symfony/webpack-encore-bundle": "^1.0|^2.0" 823 + }, 824 + "bin": [ 825 + "Resources/bin/patch-type-declarations" 826 + ], 827 + "type": "library", 828 + "autoload": { 829 + "psr-4": { 830 + "Symfony\\Component\\ErrorHandler\\": "" 831 + }, 832 + "exclude-from-classmap": [ 833 + "/Tests/" 834 + ] 835 + }, 836 + "notification-url": "https://packagist.org/downloads/", 837 + "license": [ 838 + "MIT" 839 + ], 840 + "authors": [ 841 + { 842 + "name": "Fabien Potencier", 843 + "email": "fabien@symfony.com" 844 + }, 845 + { 846 + "name": "Symfony Community", 847 + "homepage": "https://symfony.com/contributors" 848 + } 849 + ], 850 + "description": "Provides tools to manage errors and ease debugging PHP code", 851 + "homepage": "https://symfony.com", 852 + "support": { 853 + "source": "https://github.com/symfony/error-handler/tree/v8.1.0" 854 + }, 855 + "funding": [ 856 + { 857 + "url": "https://symfony.com/sponsor", 858 + "type": "custom" 859 + }, 860 + { 861 + "url": "https://github.com/fabpot", 862 + "type": "github" 863 + }, 864 + { 865 + "url": "https://github.com/nicolas-grekas", 866 + "type": "github" 867 + }, 868 + { 869 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 870 + "type": "tidelift" 871 + } 872 + ], 873 + "time": "2026-05-29T05:06:50+00:00" 874 + }, 875 + { 876 + "name": "symfony/event-dispatcher", 877 + "version": "v8.1.1", 878 + "source": { 879 + "type": "git", 880 + "url": "https://github.com/symfony/event-dispatcher.git", 881 + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0" 882 + }, 883 + "dist": { 884 + "type": "zip", 885 + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abd6c11dc468725d1627302ad10f6cd486e9e3d0", 886 + "reference": "abd6c11dc468725d1627302ad10f6cd486e9e3d0", 887 + "shasum": "" 888 + }, 889 + "require": { 890 + "php": ">=8.4.1", 891 + "symfony/deprecation-contracts": "^2.5|^3", 892 + "symfony/event-dispatcher-contracts": "^2.5|^3" 893 + }, 894 + "conflict": { 895 + "symfony/security-http": "<7.4", 896 + "symfony/service-contracts": "<2.5" 897 + }, 898 + "provide": { 899 + "psr/event-dispatcher-implementation": "1.0", 900 + "symfony/event-dispatcher-implementation": "2.0|3.0" 901 + }, 902 + "require-dev": { 903 + "psr/log": "^1|^2|^3", 904 + "symfony/config": "^7.4|^8.0", 905 + "symfony/dependency-injection": "^7.4|^8.0", 906 + "symfony/error-handler": "^7.4|^8.0", 907 + "symfony/expression-language": "^7.4|^8.0", 908 + "symfony/framework-bundle": "^7.4|^8.0", 909 + "symfony/http-foundation": "^7.4|^8.0", 910 + "symfony/service-contracts": "^2.5|^3", 911 + "symfony/stopwatch": "^7.4|^8.0" 912 + }, 913 + "type": "library", 914 + "autoload": { 915 + "psr-4": { 916 + "Symfony\\Component\\EventDispatcher\\": "" 917 + }, 918 + "exclude-from-classmap": [ 919 + "/Tests/" 920 + ] 921 + }, 922 + "notification-url": "https://packagist.org/downloads/", 923 + "license": [ 924 + "MIT" 925 + ], 926 + "authors": [ 927 + { 928 + "name": "Fabien Potencier", 929 + "email": "fabien@symfony.com" 930 + }, 931 + { 932 + "name": "Symfony Community", 933 + "homepage": "https://symfony.com/contributors" 934 + } 935 + ], 936 + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", 937 + "homepage": "https://symfony.com", 938 + "support": { 939 + "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.1" 940 + }, 941 + "funding": [ 942 + { 943 + "url": "https://symfony.com/sponsor", 944 + "type": "custom" 945 + }, 946 + { 947 + "url": "https://github.com/fabpot", 948 + "type": "github" 949 + }, 950 + { 951 + "url": "https://github.com/nicolas-grekas", 952 + "type": "github" 953 + }, 954 + { 955 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 956 + "type": "tidelift" 957 + } 958 + ], 959 + "time": "2026-06-09T12:28:30+00:00" 960 + }, 961 + { 962 + "name": "symfony/event-dispatcher-contracts", 963 + "version": "v3.7.1", 964 + "source": { 965 + "type": "git", 966 + "url": "https://github.com/symfony/event-dispatcher-contracts.git", 967 + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" 968 + }, 969 + "dist": { 970 + "type": "zip", 971 + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", 972 + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", 973 + "shasum": "" 974 + }, 975 + "require": { 976 + "php": ">=8.1", 977 + "psr/event-dispatcher": "^1" 978 + }, 979 + "type": "library", 980 + "extra": { 981 + "thanks": { 982 + "url": "https://github.com/symfony/contracts", 983 + "name": "symfony/contracts" 984 + }, 985 + "branch-alias": { 986 + "dev-main": "3.7-dev" 987 + } 988 + }, 989 + "autoload": { 990 + "psr-4": { 991 + "Symfony\\Contracts\\EventDispatcher\\": "" 992 + } 993 + }, 994 + "notification-url": "https://packagist.org/downloads/", 995 + "license": [ 996 + "MIT" 997 + ], 998 + "authors": [ 999 + { 1000 + "name": "Nicolas Grekas", 1001 + "email": "p@tchwork.com" 1002 + }, 1003 + { 1004 + "name": "Symfony Community", 1005 + "homepage": "https://symfony.com/contributors" 1006 + } 1007 + ], 1008 + "description": "Generic abstractions related to dispatching event", 1009 + "homepage": "https://symfony.com", 1010 + "keywords": [ 1011 + "abstractions", 1012 + "contracts", 1013 + "decoupling", 1014 + "interfaces", 1015 + "interoperability", 1016 + "standards" 1017 + ], 1018 + "support": { 1019 + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" 1020 + }, 1021 + "funding": [ 1022 + { 1023 + "url": "https://symfony.com/sponsor", 1024 + "type": "custom" 1025 + }, 1026 + { 1027 + "url": "https://github.com/fabpot", 1028 + "type": "github" 1029 + }, 1030 + { 1031 + "url": "https://github.com/nicolas-grekas", 1032 + "type": "github" 1033 + }, 1034 + { 1035 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1036 + "type": "tidelift" 1037 + } 1038 + ], 1039 + "time": "2026-06-05T06:23:12+00:00" 1040 + }, 1041 + { 1042 + "name": "symfony/filesystem", 1043 + "version": "v8.1.0", 1044 + "source": { 1045 + "type": "git", 1046 + "url": "https://github.com/symfony/filesystem.git", 1047 + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2" 1048 + }, 1049 + "dist": { 1050 + "type": "zip", 1051 + "url": "https://api.github.com/repos/symfony/filesystem/zipball/99aec13b82b4967ec5088222c4a3ecca955949c2", 1052 + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2", 1053 + "shasum": "" 1054 + }, 1055 + "require": { 1056 + "php": ">=8.4.1", 1057 + "symfony/deprecation-contracts": "^2.5|^3", 1058 + "symfony/polyfill-ctype": "~1.8", 1059 + "symfony/polyfill-mbstring": "~1.8" 1060 + }, 1061 + "require-dev": { 1062 + "symfony/process": "^7.4|^8.0" 1063 + }, 1064 + "type": "library", 1065 + "autoload": { 1066 + "psr-4": { 1067 + "Symfony\\Component\\Filesystem\\": "" 1068 + }, 1069 + "exclude-from-classmap": [ 1070 + "/Tests/" 1071 + ] 1072 + }, 1073 + "notification-url": "https://packagist.org/downloads/", 1074 + "license": [ 1075 + "MIT" 1076 + ], 1077 + "authors": [ 1078 + { 1079 + "name": "Fabien Potencier", 1080 + "email": "fabien@symfony.com" 1081 + }, 1082 + { 1083 + "name": "Symfony Community", 1084 + "homepage": "https://symfony.com/contributors" 1085 + } 1086 + ], 1087 + "description": "Provides basic utilities for the filesystem", 1088 + "homepage": "https://symfony.com", 1089 + "support": { 1090 + "source": "https://github.com/symfony/filesystem/tree/v8.1.0" 1091 + }, 1092 + "funding": [ 1093 + { 1094 + "url": "https://symfony.com/sponsor", 1095 + "type": "custom" 1096 + }, 1097 + { 1098 + "url": "https://github.com/fabpot", 1099 + "type": "github" 1100 + }, 1101 + { 1102 + "url": "https://github.com/nicolas-grekas", 1103 + "type": "github" 1104 + }, 1105 + { 1106 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1107 + "type": "tidelift" 1108 + } 1109 + ], 1110 + "time": "2026-05-29T05:06:50+00:00" 1111 + }, 1112 + { 1113 + "name": "symfony/finder", 1114 + "version": "v8.1.1", 1115 + "source": { 1116 + "type": "git", 1117 + "url": "https://github.com/symfony/finder.git", 1118 + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531" 1119 + }, 1120 + "dist": { 1121 + "type": "zip", 1122 + "url": "https://api.github.com/repos/symfony/finder/zipball/e2989e762c70f9490fa3a00a0ac0fae5aa97a531", 1123 + "reference": "e2989e762c70f9490fa3a00a0ac0fae5aa97a531", 1124 + "shasum": "" 1125 + }, 1126 + "require": { 1127 + "php": ">=8.4.1" 1128 + }, 1129 + "require-dev": { 1130 + "symfony/filesystem": "^7.4|^8.0" 1131 + }, 1132 + "type": "library", 1133 + "autoload": { 1134 + "psr-4": { 1135 + "Symfony\\Component\\Finder\\": "" 1136 + }, 1137 + "exclude-from-classmap": [ 1138 + "/Tests/" 1139 + ] 1140 + }, 1141 + "notification-url": "https://packagist.org/downloads/", 1142 + "license": [ 1143 + "MIT" 1144 + ], 1145 + "authors": [ 1146 + { 1147 + "name": "Fabien Potencier", 1148 + "email": "fabien@symfony.com" 1149 + }, 1150 + { 1151 + "name": "Symfony Community", 1152 + "homepage": "https://symfony.com/contributors" 1153 + } 1154 + ], 1155 + "description": "Finds files and directories via an intuitive fluent interface", 1156 + "homepage": "https://symfony.com", 1157 + "support": { 1158 + "source": "https://github.com/symfony/finder/tree/v8.1.1" 1159 + }, 1160 + "funding": [ 1161 + { 1162 + "url": "https://symfony.com/sponsor", 1163 + "type": "custom" 1164 + }, 1165 + { 1166 + "url": "https://github.com/fabpot", 1167 + "type": "github" 1168 + }, 1169 + { 1170 + "url": "https://github.com/nicolas-grekas", 1171 + "type": "github" 1172 + }, 1173 + { 1174 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1175 + "type": "tidelift" 1176 + } 1177 + ], 1178 + "time": "2026-06-27T09:05:56+00:00" 1179 + }, 1180 + { 1181 + "name": "symfony/flex", 1182 + "version": "v2.11.0", 1183 + "source": { 1184 + "type": "git", 1185 + "url": "https://github.com/symfony/flex.git", 1186 + "reference": "4a6d98eea3ebc7f68d82810cb682eedca2649e99" 1187 + }, 1188 + "dist": { 1189 + "type": "zip", 1190 + "url": "https://api.github.com/repos/symfony/flex/zipball/4a6d98eea3ebc7f68d82810cb682eedca2649e99", 1191 + "reference": "4a6d98eea3ebc7f68d82810cb682eedca2649e99", 1192 + "shasum": "" 1193 + }, 1194 + "require": { 1195 + "composer-plugin-api": "^2.1", 1196 + "php": ">=8.1" 1197 + }, 1198 + "conflict": { 1199 + "composer/semver": "<1.7.2", 1200 + "symfony/dotenv": "<5.4" 1201 + }, 1202 + "require-dev": { 1203 + "composer/composer": "^2.1", 1204 + "phpunit/phpunit": "^12.4", 1205 + "symfony/dotenv": "^6.4.41|^7.4.13|^8.0.13", 1206 + "symfony/filesystem": "^6.4|^7.4|^8.0", 1207 + "symfony/process": "^6.4|^7.4|^8.0" 1208 + }, 1209 + "type": "composer-plugin", 1210 + "extra": { 1211 + "class": "Symfony\\Flex\\Flex" 1212 + }, 1213 + "autoload": { 1214 + "psr-4": { 1215 + "Symfony\\Flex\\": "src" 1216 + } 1217 + }, 1218 + "notification-url": "https://packagist.org/downloads/", 1219 + "license": [ 1220 + "MIT" 1221 + ], 1222 + "authors": [ 1223 + { 1224 + "name": "Fabien Potencier", 1225 + "email": "fabien.potencier@gmail.com" 1226 + } 1227 + ], 1228 + "description": "Composer plugin for Symfony", 1229 + "support": { 1230 + "issues": "https://github.com/symfony/flex/issues", 1231 + "source": "https://github.com/symfony/flex/tree/v2.11.0" 1232 + }, 1233 + "funding": [ 1234 + { 1235 + "url": "https://symfony.com/sponsor", 1236 + "type": "custom" 1237 + }, 1238 + { 1239 + "url": "https://github.com/fabpot", 1240 + "type": "github" 1241 + }, 1242 + { 1243 + "url": "https://github.com/nicolas-grekas", 1244 + "type": "github" 1245 + }, 1246 + { 1247 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1248 + "type": "tidelift" 1249 + } 1250 + ], 1251 + "time": "2026-05-29T17:25:22+00:00" 1252 + }, 1253 + { 1254 + "name": "symfony/framework-bundle", 1255 + "version": "v8.1.1", 1256 + "source": { 1257 + "type": "git", 1258 + "url": "https://github.com/symfony/framework-bundle.git", 1259 + "reference": "a3ca5c9df0bb88c1378d230570746ef6271c812e" 1260 + }, 1261 + "dist": { 1262 + "type": "zip", 1263 + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a3ca5c9df0bb88c1378d230570746ef6271c812e", 1264 + "reference": "a3ca5c9df0bb88c1378d230570746ef6271c812e", 1265 + "shasum": "" 1266 + }, 1267 + "require": { 1268 + "composer-runtime-api": ">=2.1", 1269 + "ext-xml": "*", 1270 + "php": ">=8.4.1", 1271 + "symfony/cache": "^7.4|^8.0", 1272 + "symfony/config": "^7.4.4|^8.0.4", 1273 + "symfony/dependency-injection": "^8.1", 1274 + "symfony/deprecation-contracts": "^2.5|^3", 1275 + "symfony/error-handler": "^7.4|^8.0", 1276 + "symfony/event-dispatcher": "^8.1", 1277 + "symfony/filesystem": "^7.4|^8.0", 1278 + "symfony/finder": "^7.4|^8.0", 1279 + "symfony/http-foundation": "^7.4|^8.0", 1280 + "symfony/http-kernel": "^8.1", 1281 + "symfony/polyfill-mbstring": "^1.0", 1282 + "symfony/polyfill-php85": "^1.33", 1283 + "symfony/routing": "^7.4|^8.0", 1284 + "symfony/service-contracts": "^3.7.1", 1285 + "symfony/var-exporter": "^8.1" 1286 + }, 1287 + "conflict": { 1288 + "doctrine/persistence": "<1.3", 1289 + "phpdocumentor/reflection-docblock": "<5.2|>=7", 1290 + "phpdocumentor/type-resolver": "<1.5.1", 1291 + "symfony/console": "<8.1", 1292 + "symfony/form": "<7.4", 1293 + "symfony/json-streamer": "<7.4", 1294 + "symfony/messenger": "<7.4.10|>=8.0,<8.0.10", 1295 + "symfony/mime": "<7.4.9|>=8.0,<8.0.9", 1296 + "symfony/security-csrf": "<7.4", 1297 + "symfony/serializer": "<7.4", 1298 + "symfony/translation": "<7.4", 1299 + "symfony/webhook": "<7.4", 1300 + "symfony/workflow": "<7.4" 1301 + }, 1302 + "require-dev": { 1303 + "doctrine/persistence": "^1.3|^2|^3", 1304 + "dragonmantank/cron-expression": "^3.1", 1305 + "phpdocumentor/reflection-docblock": "^5.2|^6.0", 1306 + "phpstan/phpdoc-parser": "^1.0|^2.0", 1307 + "seld/jsonlint": "^1.10", 1308 + "symfony/asset": "^7.4|^8.0", 1309 + "symfony/asset-mapper": "^7.4|^8.0", 1310 + "symfony/browser-kit": "^7.4|^8.0", 1311 + "symfony/clock": "^7.4|^8.0", 1312 + "symfony/console": "^8.1", 1313 + "symfony/css-selector": "^7.4|^8.0", 1314 + "symfony/dom-crawler": "^7.4|^8.0", 1315 + "symfony/dotenv": "^7.4|^8.0", 1316 + "symfony/expression-language": "^7.4|^8.0", 1317 + "symfony/form": "^7.4|^8.0", 1318 + "symfony/html-sanitizer": "^7.4|^8.0", 1319 + "symfony/http-client": "^7.4|^8.0", 1320 + "symfony/json-streamer": "^7.4|^8.0", 1321 + "symfony/lock": "^7.4|^8.0", 1322 + "symfony/mailer": "^7.4|^8.0", 1323 + "symfony/messenger": "^7.4.10|^8.0.10", 1324 + "symfony/mime": "^7.4.9|^8.0.9", 1325 + "symfony/notifier": "^7.4|^8.0", 1326 + "symfony/object-mapper": "^7.4.9|^8.0.9", 1327 + "symfony/polyfill-intl-icu": "^1.0", 1328 + "symfony/process": "^7.4|^8.0", 1329 + "symfony/property-info": "^7.4|^8.0", 1330 + "symfony/rate-limiter": "^7.4|^8.0", 1331 + "symfony/runtime": "^7.4|^8.0", 1332 + "symfony/scheduler": "^7.4|^8.0", 1333 + "symfony/security-bundle": "^7.4|^8.0", 1334 + "symfony/semaphore": "^7.4|^8.0", 1335 + "symfony/serializer": "^7.4|^8.0", 1336 + "symfony/stopwatch": "^7.4|^8.0", 1337 + "symfony/string": "^7.4|^8.0", 1338 + "symfony/translation": "^7.4|^8.0", 1339 + "symfony/twig-bundle": "^7.4|^8.0", 1340 + "symfony/type-info": "^7.4.1|^8.0.1", 1341 + "symfony/uid": "^7.4|^8.0", 1342 + "symfony/validator": "^7.4|^8.0", 1343 + "symfony/web-link": "^7.4|^8.0", 1344 + "symfony/webhook": "^7.4|^8.0", 1345 + "symfony/workflow": "^7.4|^8.0", 1346 + "symfony/yaml": "^7.4|^8.0" 1347 + }, 1348 + "type": "symfony-bundle", 1349 + "autoload": { 1350 + "psr-4": { 1351 + "Symfony\\Bundle\\FrameworkBundle\\": "" 1352 + }, 1353 + "exclude-from-classmap": [ 1354 + "/Tests/" 1355 + ] 1356 + }, 1357 + "notification-url": "https://packagist.org/downloads/", 1358 + "license": [ 1359 + "MIT" 1360 + ], 1361 + "authors": [ 1362 + { 1363 + "name": "Fabien Potencier", 1364 + "email": "fabien@symfony.com" 1365 + }, 1366 + { 1367 + "name": "Symfony Community", 1368 + "homepage": "https://symfony.com/contributors" 1369 + } 1370 + ], 1371 + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", 1372 + "homepage": "https://symfony.com", 1373 + "support": { 1374 + "source": "https://github.com/symfony/framework-bundle/tree/v8.1.1" 1375 + }, 1376 + "funding": [ 1377 + { 1378 + "url": "https://symfony.com/sponsor", 1379 + "type": "custom" 1380 + }, 1381 + { 1382 + "url": "https://github.com/fabpot", 1383 + "type": "github" 1384 + }, 1385 + { 1386 + "url": "https://github.com/nicolas-grekas", 1387 + "type": "github" 1388 + }, 1389 + { 1390 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1391 + "type": "tidelift" 1392 + } 1393 + ], 1394 + "time": "2026-06-27T09:05:56+00:00" 1395 + }, 1396 + { 1397 + "name": "symfony/http-foundation", 1398 + "version": "v8.1.1", 1399 + "source": { 1400 + "type": "git", 1401 + "url": "https://github.com/symfony/http-foundation.git", 1402 + "reference": "6a168c8fcee806b57ac020244da14293d1f9a883" 1403 + }, 1404 + "dist": { 1405 + "type": "zip", 1406 + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6a168c8fcee806b57ac020244da14293d1f9a883", 1407 + "reference": "6a168c8fcee806b57ac020244da14293d1f9a883", 1408 + "shasum": "" 1409 + }, 1410 + "require": { 1411 + "php": ">=8.4.1", 1412 + "symfony/deprecation-contracts": "^2.5|^3", 1413 + "symfony/polyfill-mbstring": "^1.1" 1414 + }, 1415 + "conflict": { 1416 + "doctrine/dbal": "<4.3" 1417 + }, 1418 + "require-dev": { 1419 + "doctrine/dbal": "^4.3", 1420 + "predis/predis": "^1.1|^2.0", 1421 + "symfony/cache": "^7.4|^8.0", 1422 + "symfony/clock": "^7.4|^8.0", 1423 + "symfony/dependency-injection": "^7.4|^8.0", 1424 + "symfony/expression-language": "^7.4|^8.0", 1425 + "symfony/http-kernel": "^7.4|^8.0", 1426 + "symfony/mime": "^7.4|^8.0", 1427 + "symfony/rate-limiter": "^7.4|^8.0" 1428 + }, 1429 + "type": "library", 1430 + "autoload": { 1431 + "psr-4": { 1432 + "Symfony\\Component\\HttpFoundation\\": "" 1433 + }, 1434 + "exclude-from-classmap": [ 1435 + "/Tests/" 1436 + ] 1437 + }, 1438 + "notification-url": "https://packagist.org/downloads/", 1439 + "license": [ 1440 + "MIT" 1441 + ], 1442 + "authors": [ 1443 + { 1444 + "name": "Fabien Potencier", 1445 + "email": "fabien@symfony.com" 1446 + }, 1447 + { 1448 + "name": "Symfony Community", 1449 + "homepage": "https://symfony.com/contributors" 1450 + } 1451 + ], 1452 + "description": "Defines an object-oriented layer for the HTTP specification", 1453 + "homepage": "https://symfony.com", 1454 + "support": { 1455 + "source": "https://github.com/symfony/http-foundation/tree/v8.1.1" 1456 + }, 1457 + "funding": [ 1458 + { 1459 + "url": "https://symfony.com/sponsor", 1460 + "type": "custom" 1461 + }, 1462 + { 1463 + "url": "https://github.com/fabpot", 1464 + "type": "github" 1465 + }, 1466 + { 1467 + "url": "https://github.com/nicolas-grekas", 1468 + "type": "github" 1469 + }, 1470 + { 1471 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1472 + "type": "tidelift" 1473 + } 1474 + ], 1475 + "time": "2026-06-12T08:43:41+00:00" 1476 + }, 1477 + { 1478 + "name": "symfony/http-kernel", 1479 + "version": "v8.1.1", 1480 + "source": { 1481 + "type": "git", 1482 + "url": "https://github.com/symfony/http-kernel.git", 1483 + "reference": "89d8d6e7fbab3d9eda89ccb5ecdf44a74c4ec9d2" 1484 + }, 1485 + "dist": { 1486 + "type": "zip", 1487 + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/89d8d6e7fbab3d9eda89ccb5ecdf44a74c4ec9d2", 1488 + "reference": "89d8d6e7fbab3d9eda89ccb5ecdf44a74c4ec9d2", 1489 + "shasum": "" 1490 + }, 1491 + "require": { 1492 + "php": ">=8.4.1", 1493 + "psr/log": "^1|^2|^3", 1494 + "symfony/deprecation-contracts": "^2.5|^3", 1495 + "symfony/error-handler": "^7.4|^8.0", 1496 + "symfony/event-dispatcher": "^7.4|^8.0", 1497 + "symfony/http-foundation": "^7.4|^8.0", 1498 + "symfony/polyfill-ctype": "^1.8" 1499 + }, 1500 + "conflict": { 1501 + "symfony/dependency-injection": "<8.1", 1502 + "symfony/flex": "<2.10", 1503 + "symfony/http-client-contracts": "<2.5", 1504 + "symfony/translation-contracts": "<2.5", 1505 + "symfony/var-dumper": "<8.1", 1506 + "symfony/web-profiler-bundle": "<8.1", 1507 + "twig/twig": "<3.21" 1508 + }, 1509 + "provide": { 1510 + "psr/log-implementation": "1.0|2.0|3.0" 1511 + }, 1512 + "require-dev": { 1513 + "psr/cache": "^1.0|^2.0|^3.0", 1514 + "symfony/browser-kit": "^7.4|^8.0", 1515 + "symfony/clock": "^7.4|^8.0", 1516 + "symfony/config": "^7.4|^8.0", 1517 + "symfony/console": "^7.4|^8.0", 1518 + "symfony/css-selector": "^7.4|^8.0", 1519 + "symfony/dependency-injection": "^8.1", 1520 + "symfony/dom-crawler": "^7.4|^8.0", 1521 + "symfony/expression-language": "^7.4|^8.0", 1522 + "symfony/finder": "^7.4|^8.0", 1523 + "symfony/http-client-contracts": "^2.5|^3", 1524 + "symfony/process": "^7.4|^8.0", 1525 + "symfony/property-access": "^7.4|^8.0", 1526 + "symfony/rate-limiter": "^7.4|^8.0", 1527 + "symfony/routing": "^7.4|^8.0", 1528 + "symfony/serializer": "^7.4|^8.0", 1529 + "symfony/stopwatch": "^7.4|^8.0", 1530 + "symfony/translation": "^7.4|^8.0", 1531 + "symfony/translation-contracts": "^2.5|^3", 1532 + "symfony/uid": "^7.4|^8.0", 1533 + "symfony/validator": "^7.4|^8.0", 1534 + "symfony/var-dumper": "^8.1", 1535 + "symfony/var-exporter": "^7.4|^8.0", 1536 + "twig/twig": "^3.21" 1537 + }, 1538 + "type": "library", 1539 + "autoload": { 1540 + "psr-4": { 1541 + "Symfony\\Component\\HttpKernel\\": "" 1542 + }, 1543 + "exclude-from-classmap": [ 1544 + "/Tests/" 1545 + ] 1546 + }, 1547 + "notification-url": "https://packagist.org/downloads/", 1548 + "license": [ 1549 + "MIT" 1550 + ], 1551 + "authors": [ 1552 + { 1553 + "name": "Fabien Potencier", 1554 + "email": "fabien@symfony.com" 1555 + }, 1556 + { 1557 + "name": "Symfony Community", 1558 + "homepage": "https://symfony.com/contributors" 1559 + } 1560 + ], 1561 + "description": "Provides a structured process for converting a Request into a Response", 1562 + "homepage": "https://symfony.com", 1563 + "support": { 1564 + "source": "https://github.com/symfony/http-kernel/tree/v8.1.1" 1565 + }, 1566 + "funding": [ 1567 + { 1568 + "url": "https://symfony.com/sponsor", 1569 + "type": "custom" 1570 + }, 1571 + { 1572 + "url": "https://github.com/fabpot", 1573 + "type": "github" 1574 + }, 1575 + { 1576 + "url": "https://github.com/nicolas-grekas", 1577 + "type": "github" 1578 + }, 1579 + { 1580 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1581 + "type": "tidelift" 1582 + } 1583 + ], 1584 + "time": "2026-06-27T09:27:36+00:00" 1585 + }, 1586 + { 1587 + "name": "symfony/polyfill-deepclone", 1588 + "version": "v1.40.0", 1589 + "source": { 1590 + "type": "git", 1591 + "url": "https://github.com/symfony/polyfill-deepclone.git", 1592 + "reference": "dca4ccba5f360070b574414dce4c1e7a559844fa" 1593 + }, 1594 + "dist": { 1595 + "type": "zip", 1596 + "url": "https://api.github.com/repos/symfony/polyfill-deepclone/zipball/dca4ccba5f360070b574414dce4c1e7a559844fa", 1597 + "reference": "dca4ccba5f360070b574414dce4c1e7a559844fa", 1598 + "shasum": "" 1599 + }, 1600 + "require": { 1601 + "php": ">=8.1" 1602 + }, 1603 + "provide": { 1604 + "ext-deepclone": "*" 1605 + }, 1606 + "suggest": { 1607 + "ext-deepclone": "For best performance" 1608 + }, 1609 + "type": "library", 1610 + "extra": { 1611 + "thanks": { 1612 + "url": "https://github.com/symfony/polyfill", 1613 + "name": "symfony/polyfill" 1614 + } 1615 + }, 1616 + "autoload": { 1617 + "files": [ 1618 + "bootstrap.php" 1619 + ], 1620 + "psr-4": { 1621 + "Symfony\\Polyfill\\DeepClone\\": "" 1622 + }, 1623 + "classmap": [ 1624 + "Resources/stubs" 1625 + ] 1626 + }, 1627 + "notification-url": "https://packagist.org/downloads/", 1628 + "license": [ 1629 + "MIT" 1630 + ], 1631 + "authors": [ 1632 + { 1633 + "name": "Nicolas Grekas", 1634 + "email": "p@tchwork.com" 1635 + }, 1636 + { 1637 + "name": "Symfony Community", 1638 + "homepage": "https://symfony.com/contributors" 1639 + } 1640 + ], 1641 + "description": "Symfony polyfill for the deepclone extension", 1642 + "homepage": "https://symfony.com", 1643 + "keywords": [ 1644 + "compatibility", 1645 + "deepclone", 1646 + "polyfill", 1647 + "portable", 1648 + "shim" 1649 + ], 1650 + "support": { 1651 + "source": "https://github.com/symfony/polyfill-deepclone/tree/v1.40.0" 1652 + }, 1653 + "funding": [ 1654 + { 1655 + "url": "https://symfony.com/sponsor", 1656 + "type": "custom" 1657 + }, 1658 + { 1659 + "url": "https://github.com/fabpot", 1660 + "type": "github" 1661 + }, 1662 + { 1663 + "url": "https://github.com/nicolas-grekas", 1664 + "type": "github" 1665 + }, 1666 + { 1667 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1668 + "type": "tidelift" 1669 + } 1670 + ], 1671 + "time": "2026-06-12T07:27:17+00:00" 1672 + }, 1673 + { 1674 + "name": "symfony/polyfill-intl-grapheme", 1675 + "version": "v1.38.1", 1676 + "source": { 1677 + "type": "git", 1678 + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 1679 + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" 1680 + }, 1681 + "dist": { 1682 + "type": "zip", 1683 + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", 1684 + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", 1685 + "shasum": "" 1686 + }, 1687 + "require": { 1688 + "php": ">=7.2" 1689 + }, 1690 + "suggest": { 1691 + "ext-intl": "For best performance" 1692 + }, 1693 + "type": "library", 1694 + "extra": { 1695 + "thanks": { 1696 + "url": "https://github.com/symfony/polyfill", 1697 + "name": "symfony/polyfill" 1698 + } 1699 + }, 1700 + "autoload": { 1701 + "files": [ 1702 + "bootstrap.php" 1703 + ], 1704 + "psr-4": { 1705 + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 1706 + } 1707 + }, 1708 + "notification-url": "https://packagist.org/downloads/", 1709 + "license": [ 1710 + "MIT" 1711 + ], 1712 + "authors": [ 1713 + { 1714 + "name": "Nicolas Grekas", 1715 + "email": "p@tchwork.com" 1716 + }, 1717 + { 1718 + "name": "Symfony Community", 1719 + "homepage": "https://symfony.com/contributors" 1720 + } 1721 + ], 1722 + "description": "Symfony polyfill for intl's grapheme_* functions", 1723 + "homepage": "https://symfony.com", 1724 + "keywords": [ 1725 + "compatibility", 1726 + "grapheme", 1727 + "intl", 1728 + "polyfill", 1729 + "portable", 1730 + "shim" 1731 + ], 1732 + "support": { 1733 + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" 1734 + }, 1735 + "funding": [ 1736 + { 1737 + "url": "https://symfony.com/sponsor", 1738 + "type": "custom" 1739 + }, 1740 + { 1741 + "url": "https://github.com/fabpot", 1742 + "type": "github" 1743 + }, 1744 + { 1745 + "url": "https://github.com/nicolas-grekas", 1746 + "type": "github" 1747 + }, 1748 + { 1749 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1750 + "type": "tidelift" 1751 + } 1752 + ], 1753 + "time": "2026-05-26T05:58:03+00:00" 1754 + }, 1755 + { 1756 + "name": "symfony/polyfill-intl-normalizer", 1757 + "version": "v1.38.0", 1758 + "source": { 1759 + "type": "git", 1760 + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 1761 + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" 1762 + }, 1763 + "dist": { 1764 + "type": "zip", 1765 + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", 1766 + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", 1767 + "shasum": "" 1768 + }, 1769 + "require": { 1770 + "php": ">=7.2" 1771 + }, 1772 + "suggest": { 1773 + "ext-intl": "For best performance" 1774 + }, 1775 + "type": "library", 1776 + "extra": { 1777 + "thanks": { 1778 + "url": "https://github.com/symfony/polyfill", 1779 + "name": "symfony/polyfill" 1780 + } 1781 + }, 1782 + "autoload": { 1783 + "files": [ 1784 + "bootstrap.php" 1785 + ], 1786 + "psr-4": { 1787 + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 1788 + }, 1789 + "classmap": [ 1790 + "Resources/stubs" 1791 + ] 1792 + }, 1793 + "notification-url": "https://packagist.org/downloads/", 1794 + "license": [ 1795 + "MIT" 1796 + ], 1797 + "authors": [ 1798 + { 1799 + "name": "Nicolas Grekas", 1800 + "email": "p@tchwork.com" 1801 + }, 1802 + { 1803 + "name": "Symfony Community", 1804 + "homepage": "https://symfony.com/contributors" 1805 + } 1806 + ], 1807 + "description": "Symfony polyfill for intl's Normalizer class and related functions", 1808 + "homepage": "https://symfony.com", 1809 + "keywords": [ 1810 + "compatibility", 1811 + "intl", 1812 + "normalizer", 1813 + "polyfill", 1814 + "portable", 1815 + "shim" 1816 + ], 1817 + "support": { 1818 + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" 1819 + }, 1820 + "funding": [ 1821 + { 1822 + "url": "https://symfony.com/sponsor", 1823 + "type": "custom" 1824 + }, 1825 + { 1826 + "url": "https://github.com/fabpot", 1827 + "type": "github" 1828 + }, 1829 + { 1830 + "url": "https://github.com/nicolas-grekas", 1831 + "type": "github" 1832 + }, 1833 + { 1834 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1835 + "type": "tidelift" 1836 + } 1837 + ], 1838 + "time": "2026-05-25T13:48:31+00:00" 1839 + }, 1840 + { 1841 + "name": "symfony/polyfill-mbstring", 1842 + "version": "v1.38.2", 1843 + "source": { 1844 + "type": "git", 1845 + "url": "https://github.com/symfony/polyfill-mbstring.git", 1846 + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" 1847 + }, 1848 + "dist": { 1849 + "type": "zip", 1850 + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", 1851 + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", 1852 + "shasum": "" 1853 + }, 1854 + "require": { 1855 + "ext-iconv": "*", 1856 + "php": ">=7.2" 1857 + }, 1858 + "provide": { 1859 + "ext-mbstring": "*" 1860 + }, 1861 + "suggest": { 1862 + "ext-mbstring": "For best performance" 1863 + }, 1864 + "type": "library", 1865 + "extra": { 1866 + "thanks": { 1867 + "url": "https://github.com/symfony/polyfill", 1868 + "name": "symfony/polyfill" 1869 + } 1870 + }, 1871 + "autoload": { 1872 + "files": [ 1873 + "bootstrap.php" 1874 + ], 1875 + "psr-4": { 1876 + "Symfony\\Polyfill\\Mbstring\\": "" 1877 + } 1878 + }, 1879 + "notification-url": "https://packagist.org/downloads/", 1880 + "license": [ 1881 + "MIT" 1882 + ], 1883 + "authors": [ 1884 + { 1885 + "name": "Nicolas Grekas", 1886 + "email": "p@tchwork.com" 1887 + }, 1888 + { 1889 + "name": "Symfony Community", 1890 + "homepage": "https://symfony.com/contributors" 1891 + } 1892 + ], 1893 + "description": "Symfony polyfill for the Mbstring extension", 1894 + "homepage": "https://symfony.com", 1895 + "keywords": [ 1896 + "compatibility", 1897 + "mbstring", 1898 + "polyfill", 1899 + "portable", 1900 + "shim" 1901 + ], 1902 + "support": { 1903 + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" 1904 + }, 1905 + "funding": [ 1906 + { 1907 + "url": "https://symfony.com/sponsor", 1908 + "type": "custom" 1909 + }, 1910 + { 1911 + "url": "https://github.com/fabpot", 1912 + "type": "github" 1913 + }, 1914 + { 1915 + "url": "https://github.com/nicolas-grekas", 1916 + "type": "github" 1917 + }, 1918 + { 1919 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1920 + "type": "tidelift" 1921 + } 1922 + ], 1923 + "time": "2026-05-27T06:59:30+00:00" 1924 + }, 1925 + { 1926 + "name": "symfony/polyfill-php85", 1927 + "version": "v1.38.1", 1928 + "source": { 1929 + "type": "git", 1930 + "url": "https://github.com/symfony/polyfill-php85.git", 1931 + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1" 1932 + }, 1933 + "dist": { 1934 + "type": "zip", 1935 + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", 1936 + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", 1937 + "shasum": "" 1938 + }, 1939 + "require": { 1940 + "php": ">=7.2" 1941 + }, 1942 + "type": "library", 1943 + "extra": { 1944 + "thanks": { 1945 + "url": "https://github.com/symfony/polyfill", 1946 + "name": "symfony/polyfill" 1947 + } 1948 + }, 1949 + "autoload": { 1950 + "files": [ 1951 + "bootstrap.php" 1952 + ], 1953 + "psr-4": { 1954 + "Symfony\\Polyfill\\Php85\\": "" 1955 + }, 1956 + "classmap": [ 1957 + "Resources/stubs" 1958 + ] 1959 + }, 1960 + "notification-url": "https://packagist.org/downloads/", 1961 + "license": [ 1962 + "MIT" 1963 + ], 1964 + "authors": [ 1965 + { 1966 + "name": "Nicolas Grekas", 1967 + "email": "p@tchwork.com" 1968 + }, 1969 + { 1970 + "name": "Symfony Community", 1971 + "homepage": "https://symfony.com/contributors" 1972 + } 1973 + ], 1974 + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", 1975 + "homepage": "https://symfony.com", 1976 + "keywords": [ 1977 + "compatibility", 1978 + "polyfill", 1979 + "portable", 1980 + "shim" 1981 + ], 1982 + "support": { 1983 + "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1" 1984 + }, 1985 + "funding": [ 1986 + { 1987 + "url": "https://symfony.com/sponsor", 1988 + "type": "custom" 1989 + }, 1990 + { 1991 + "url": "https://github.com/fabpot", 1992 + "type": "github" 1993 + }, 1994 + { 1995 + "url": "https://github.com/nicolas-grekas", 1996 + "type": "github" 1997 + }, 1998 + { 1999 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2000 + "type": "tidelift" 2001 + } 2002 + ], 2003 + "time": "2026-05-26T02:25:22+00:00" 2004 + }, 2005 + { 2006 + "name": "symfony/routing", 2007 + "version": "v8.1.0", 2008 + "source": { 2009 + "type": "git", 2010 + "url": "https://github.com/symfony/routing.git", 2011 + "reference": "fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3" 2012 + }, 2013 + "dist": { 2014 + "type": "zip", 2015 + "url": "https://api.github.com/repos/symfony/routing/zipball/fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3", 2016 + "reference": "fe0bfec72c8a806109fb9c3a5f2b898fe0c76eb3", 2017 + "shasum": "" 2018 + }, 2019 + "require": { 2020 + "php": ">=8.4.1", 2021 + "symfony/deprecation-contracts": "^2.5|^3" 2022 + }, 2023 + "require-dev": { 2024 + "psr/log": "^1|^2|^3", 2025 + "symfony/config": "^7.4|^8.0", 2026 + "symfony/dependency-injection": "^7.4|^8.0", 2027 + "symfony/expression-language": "^7.4|^8.0", 2028 + "symfony/http-foundation": "^7.4|^8.0", 2029 + "symfony/yaml": "^7.4|^8.0" 2030 + }, 2031 + "type": "library", 2032 + "autoload": { 2033 + "psr-4": { 2034 + "Symfony\\Component\\Routing\\": "" 2035 + }, 2036 + "exclude-from-classmap": [ 2037 + "/Tests/" 2038 + ] 2039 + }, 2040 + "notification-url": "https://packagist.org/downloads/", 2041 + "license": [ 2042 + "MIT" 2043 + ], 2044 + "authors": [ 2045 + { 2046 + "name": "Fabien Potencier", 2047 + "email": "fabien@symfony.com" 2048 + }, 2049 + { 2050 + "name": "Symfony Community", 2051 + "homepage": "https://symfony.com/contributors" 2052 + } 2053 + ], 2054 + "description": "Maps an HTTP request to a set of configuration variables", 2055 + "homepage": "https://symfony.com", 2056 + "keywords": [ 2057 + "router", 2058 + "routing", 2059 + "uri", 2060 + "url" 2061 + ], 2062 + "support": { 2063 + "source": "https://github.com/symfony/routing/tree/v8.1.0" 2064 + }, 2065 + "funding": [ 2066 + { 2067 + "url": "https://symfony.com/sponsor", 2068 + "type": "custom" 2069 + }, 2070 + { 2071 + "url": "https://github.com/fabpot", 2072 + "type": "github" 2073 + }, 2074 + { 2075 + "url": "https://github.com/nicolas-grekas", 2076 + "type": "github" 2077 + }, 2078 + { 2079 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2080 + "type": "tidelift" 2081 + } 2082 + ], 2083 + "time": "2026-05-29T05:06:50+00:00" 2084 + }, 2085 + { 2086 + "name": "symfony/runtime", 2087 + "version": "v8.1.0", 2088 + "source": { 2089 + "type": "git", 2090 + "url": "https://github.com/symfony/runtime.git", 2091 + "reference": "b7ea1abe04561e814b3134db0f56c287cedb35cc" 2092 + }, 2093 + "dist": { 2094 + "type": "zip", 2095 + "url": "https://api.github.com/repos/symfony/runtime/zipball/b7ea1abe04561e814b3134db0f56c287cedb35cc", 2096 + "reference": "b7ea1abe04561e814b3134db0f56c287cedb35cc", 2097 + "shasum": "" 2098 + }, 2099 + "require": { 2100 + "composer-plugin-api": "^1.0|^2.0", 2101 + "php": ">=8.4.1" 2102 + }, 2103 + "conflict": { 2104 + "symfony/error-handler": "<7.4" 2105 + }, 2106 + "require-dev": { 2107 + "composer/composer": "^2.6", 2108 + "symfony/console": "^7.4|^8.0", 2109 + "symfony/dependency-injection": "^7.4|^8.0", 2110 + "symfony/dotenv": "^7.4|^8.0", 2111 + "symfony/http-foundation": "^7.4|^8.0", 2112 + "symfony/http-kernel": "^7.4|^8.0" 2113 + }, 2114 + "type": "composer-plugin", 2115 + "extra": { 2116 + "class": "Symfony\\Component\\Runtime\\Internal\\ComposerPlugin" 2117 + }, 2118 + "autoload": { 2119 + "psr-4": { 2120 + "Symfony\\Component\\Runtime\\": "", 2121 + "Symfony\\Runtime\\Symfony\\Component\\": "Internal/" 2122 + }, 2123 + "exclude-from-classmap": [ 2124 + "/Tests/" 2125 + ] 2126 + }, 2127 + "notification-url": "https://packagist.org/downloads/", 2128 + "license": [ 2129 + "MIT" 2130 + ], 2131 + "authors": [ 2132 + { 2133 + "name": "Nicolas Grekas", 2134 + "email": "p@tchwork.com" 2135 + }, 2136 + { 2137 + "name": "Symfony Community", 2138 + "homepage": "https://symfony.com/contributors" 2139 + } 2140 + ], 2141 + "description": "Enables decoupling PHP applications from global state", 2142 + "homepage": "https://symfony.com", 2143 + "keywords": [ 2144 + "runtime" 2145 + ], 2146 + "support": { 2147 + "source": "https://github.com/symfony/runtime/tree/v8.1.0" 2148 + }, 2149 + "funding": [ 2150 + { 2151 + "url": "https://symfony.com/sponsor", 2152 + "type": "custom" 2153 + }, 2154 + { 2155 + "url": "https://github.com/fabpot", 2156 + "type": "github" 2157 + }, 2158 + { 2159 + "url": "https://github.com/nicolas-grekas", 2160 + "type": "github" 2161 + }, 2162 + { 2163 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2164 + "type": "tidelift" 2165 + } 2166 + ], 2167 + "time": "2026-05-29T05:06:50+00:00" 2168 + }, 2169 + { 2170 + "name": "symfony/service-contracts", 2171 + "version": "v3.7.1", 2172 + "source": { 2173 + "type": "git", 2174 + "url": "https://github.com/symfony/service-contracts.git", 2175 + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" 2176 + }, 2177 + "dist": { 2178 + "type": "zip", 2179 + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", 2180 + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", 2181 + "shasum": "" 2182 + }, 2183 + "require": { 2184 + "php": ">=8.1", 2185 + "psr/container": "^1.1|^2.0", 2186 + "symfony/deprecation-contracts": "^2.5|^3" 2187 + }, 2188 + "conflict": { 2189 + "ext-psr": "<1.1|>=2" 2190 + }, 2191 + "type": "library", 2192 + "extra": { 2193 + "thanks": { 2194 + "url": "https://github.com/symfony/contracts", 2195 + "name": "symfony/contracts" 2196 + }, 2197 + "branch-alias": { 2198 + "dev-main": "3.7-dev" 2199 + } 2200 + }, 2201 + "autoload": { 2202 + "psr-4": { 2203 + "Symfony\\Contracts\\Service\\": "" 2204 + }, 2205 + "exclude-from-classmap": [ 2206 + "/Test/" 2207 + ] 2208 + }, 2209 + "notification-url": "https://packagist.org/downloads/", 2210 + "license": [ 2211 + "MIT" 2212 + ], 2213 + "authors": [ 2214 + { 2215 + "name": "Nicolas Grekas", 2216 + "email": "p@tchwork.com" 2217 + }, 2218 + { 2219 + "name": "Symfony Community", 2220 + "homepage": "https://symfony.com/contributors" 2221 + } 2222 + ], 2223 + "description": "Generic abstractions related to writing services", 2224 + "homepage": "https://symfony.com", 2225 + "keywords": [ 2226 + "abstractions", 2227 + "contracts", 2228 + "decoupling", 2229 + "interfaces", 2230 + "interoperability", 2231 + "standards" 2232 + ], 2233 + "support": { 2234 + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" 2235 + }, 2236 + "funding": [ 2237 + { 2238 + "url": "https://symfony.com/sponsor", 2239 + "type": "custom" 2240 + }, 2241 + { 2242 + "url": "https://github.com/fabpot", 2243 + "type": "github" 2244 + }, 2245 + { 2246 + "url": "https://github.com/nicolas-grekas", 2247 + "type": "github" 2248 + }, 2249 + { 2250 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2251 + "type": "tidelift" 2252 + } 2253 + ], 2254 + "time": "2026-06-16T09:55:08+00:00" 2255 + }, 2256 + { 2257 + "name": "symfony/string", 2258 + "version": "v8.1.0", 2259 + "source": { 2260 + "type": "git", 2261 + "url": "https://github.com/symfony/string.git", 2262 + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" 2263 + }, 2264 + "dist": { 2265 + "type": "zip", 2266 + "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", 2267 + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", 2268 + "shasum": "" 2269 + }, 2270 + "require": { 2271 + "php": ">=8.4.1", 2272 + "symfony/polyfill-ctype": "^1.8", 2273 + "symfony/polyfill-intl-grapheme": "^1.33", 2274 + "symfony/polyfill-intl-normalizer": "^1.0", 2275 + "symfony/polyfill-mbstring": "^1.0" 2276 + }, 2277 + "conflict": { 2278 + "symfony/translation-contracts": "<2.5" 2279 + }, 2280 + "require-dev": { 2281 + "symfony/emoji": "^7.4|^8.0", 2282 + "symfony/http-client": "^7.4|^8.0", 2283 + "symfony/intl": "^7.4|^8.0", 2284 + "symfony/translation-contracts": "^2.5|^3.0", 2285 + "symfony/var-exporter": "^7.4|^8.0" 2286 + }, 2287 + "type": "library", 2288 + "autoload": { 2289 + "files": [ 2290 + "Resources/functions.php" 2291 + ], 2292 + "psr-4": { 2293 + "Symfony\\Component\\String\\": "" 2294 + }, 2295 + "exclude-from-classmap": [ 2296 + "/Tests/" 2297 + ] 2298 + }, 2299 + "notification-url": "https://packagist.org/downloads/", 2300 + "license": [ 2301 + "MIT" 2302 + ], 2303 + "authors": [ 2304 + { 2305 + "name": "Nicolas Grekas", 2306 + "email": "p@tchwork.com" 2307 + }, 2308 + { 2309 + "name": "Symfony Community", 2310 + "homepage": "https://symfony.com/contributors" 2311 + } 2312 + ], 2313 + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", 2314 + "homepage": "https://symfony.com", 2315 + "keywords": [ 2316 + "grapheme", 2317 + "i18n", 2318 + "string", 2319 + "unicode", 2320 + "utf-8", 2321 + "utf8" 2322 + ], 2323 + "support": { 2324 + "source": "https://github.com/symfony/string/tree/v8.1.0" 2325 + }, 2326 + "funding": [ 2327 + { 2328 + "url": "https://symfony.com/sponsor", 2329 + "type": "custom" 2330 + }, 2331 + { 2332 + "url": "https://github.com/fabpot", 2333 + "type": "github" 2334 + }, 2335 + { 2336 + "url": "https://github.com/nicolas-grekas", 2337 + "type": "github" 2338 + }, 2339 + { 2340 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2341 + "type": "tidelift" 2342 + } 2343 + ], 2344 + "time": "2026-05-29T05:06:50+00:00" 2345 + }, 2346 + { 2347 + "name": "symfony/var-dumper", 2348 + "version": "v8.1.1", 2349 + "source": { 2350 + "type": "git", 2351 + "url": "https://github.com/symfony/var-dumper.git", 2352 + "reference": "40096a2515a979f3125c5c928603995b8664c62a" 2353 + }, 2354 + "dist": { 2355 + "type": "zip", 2356 + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/40096a2515a979f3125c5c928603995b8664c62a", 2357 + "reference": "40096a2515a979f3125c5c928603995b8664c62a", 2358 + "shasum": "" 2359 + }, 2360 + "require": { 2361 + "php": ">=8.4.1", 2362 + "symfony/polyfill-mbstring": "^1.0" 2363 + }, 2364 + "conflict": { 2365 + "symfony/console": "<7.4", 2366 + "symfony/error-handler": "<7.4" 2367 + }, 2368 + "require-dev": { 2369 + "symfony/console": "^7.4|^8.0", 2370 + "symfony/http-kernel": "^7.4|^8.0", 2371 + "symfony/process": "^7.4|^8.0", 2372 + "symfony/uid": "^7.4|^8.0", 2373 + "twig/twig": "^3.12" 2374 + }, 2375 + "bin": [ 2376 + "Resources/bin/var-dump-server" 2377 + ], 2378 + "type": "library", 2379 + "autoload": { 2380 + "files": [ 2381 + "Resources/functions/dump.php" 2382 + ], 2383 + "psr-4": { 2384 + "Symfony\\Component\\VarDumper\\": "" 2385 + }, 2386 + "exclude-from-classmap": [ 2387 + "/Tests/" 2388 + ] 2389 + }, 2390 + "notification-url": "https://packagist.org/downloads/", 2391 + "license": [ 2392 + "MIT" 2393 + ], 2394 + "authors": [ 2395 + { 2396 + "name": "Nicolas Grekas", 2397 + "email": "p@tchwork.com" 2398 + }, 2399 + { 2400 + "name": "Symfony Community", 2401 + "homepage": "https://symfony.com/contributors" 2402 + } 2403 + ], 2404 + "description": "Provides mechanisms for walking through any arbitrary PHP variable", 2405 + "homepage": "https://symfony.com", 2406 + "keywords": [ 2407 + "debug", 2408 + "dump" 2409 + ], 2410 + "support": { 2411 + "source": "https://github.com/symfony/var-dumper/tree/v8.1.1" 2412 + }, 2413 + "funding": [ 2414 + { 2415 + "url": "https://symfony.com/sponsor", 2416 + "type": "custom" 2417 + }, 2418 + { 2419 + "url": "https://github.com/fabpot", 2420 + "type": "github" 2421 + }, 2422 + { 2423 + "url": "https://github.com/nicolas-grekas", 2424 + "type": "github" 2425 + }, 2426 + { 2427 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2428 + "type": "tidelift" 2429 + } 2430 + ], 2431 + "time": "2026-06-09T10:54:51+00:00" 2432 + }, 2433 + { 2434 + "name": "symfony/var-exporter", 2435 + "version": "v8.1.1", 2436 + "source": { 2437 + "type": "git", 2438 + "url": "https://github.com/symfony/var-exporter.git", 2439 + "reference": "75b74315b4e4be40e5534cf9c5cc30dd0907ed71" 2440 + }, 2441 + "dist": { 2442 + "type": "zip", 2443 + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/75b74315b4e4be40e5534cf9c5cc30dd0907ed71", 2444 + "reference": "75b74315b4e4be40e5534cf9c5cc30dd0907ed71", 2445 + "shasum": "" 2446 + }, 2447 + "require": { 2448 + "php": ">=8.4.1", 2449 + "symfony/deprecation-contracts": "^2.5|^3", 2450 + "symfony/polyfill-deepclone": "^1.40" 2451 + }, 2452 + "require-dev": { 2453 + "symfony/property-access": "^7.4|^8.0", 2454 + "symfony/serializer": "^7.4|^8.0", 2455 + "symfony/var-dumper": "^7.4|^8.0" 2456 + }, 2457 + "type": "library", 2458 + "autoload": { 2459 + "psr-4": { 2460 + "Symfony\\Component\\VarExporter\\": "" 2461 + }, 2462 + "exclude-from-classmap": [ 2463 + "/Tests/" 2464 + ] 2465 + }, 2466 + "notification-url": "https://packagist.org/downloads/", 2467 + "license": [ 2468 + "MIT" 2469 + ], 2470 + "authors": [ 2471 + { 2472 + "name": "Nicolas Grekas", 2473 + "email": "p@tchwork.com" 2474 + }, 2475 + { 2476 + "name": "Symfony Community", 2477 + "homepage": "https://symfony.com/contributors" 2478 + } 2479 + ], 2480 + "description": "Provides tools to export, instantiate, hydrate, clone and lazy-load PHP objects", 2481 + "homepage": "https://symfony.com", 2482 + "keywords": [ 2483 + "clone", 2484 + "construct", 2485 + "deep-clone", 2486 + "export", 2487 + "hydrate", 2488 + "instantiate", 2489 + "lazy-loading", 2490 + "proxy", 2491 + "serialize" 2492 + ], 2493 + "support": { 2494 + "source": "https://github.com/symfony/var-exporter/tree/v8.1.1" 2495 + }, 2496 + "funding": [ 2497 + { 2498 + "url": "https://symfony.com/sponsor", 2499 + "type": "custom" 2500 + }, 2501 + { 2502 + "url": "https://github.com/fabpot", 2503 + "type": "github" 2504 + }, 2505 + { 2506 + "url": "https://github.com/nicolas-grekas", 2507 + "type": "github" 2508 + }, 2509 + { 2510 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2511 + "type": "tidelift" 2512 + } 2513 + ], 2514 + "time": "2026-06-27T09:05:56+00:00" 2515 + }, 2516 + { 2517 + "name": "symfony/yaml", 2518 + "version": "v8.1.1", 2519 + "source": { 2520 + "type": "git", 2521 + "url": "https://github.com/symfony/yaml.git", 2522 + "reference": "8e4cdd4311683516be06944f4b85244063cdb886" 2523 + }, 2524 + "dist": { 2525 + "type": "zip", 2526 + "url": "https://api.github.com/repos/symfony/yaml/zipball/8e4cdd4311683516be06944f4b85244063cdb886", 2527 + "reference": "8e4cdd4311683516be06944f4b85244063cdb886", 2528 + "shasum": "" 2529 + }, 2530 + "require": { 2531 + "php": ">=8.4.1", 2532 + "symfony/polyfill-ctype": "^1.8" 2533 + }, 2534 + "conflict": { 2535 + "symfony/console": "<7.4" 2536 + }, 2537 + "require-dev": { 2538 + "symfony/console": "^7.4|^8.0", 2539 + "yaml/yaml-test-suite": "*" 2540 + }, 2541 + "bin": [ 2542 + "Resources/bin/yaml-lint" 2543 + ], 2544 + "type": "library", 2545 + "autoload": { 2546 + "psr-4": { 2547 + "Symfony\\Component\\Yaml\\": "" 2548 + }, 2549 + "exclude-from-classmap": [ 2550 + "/Tests/" 2551 + ] 2552 + }, 2553 + "notification-url": "https://packagist.org/downloads/", 2554 + "license": [ 2555 + "MIT" 2556 + ], 2557 + "authors": [ 2558 + { 2559 + "name": "Fabien Potencier", 2560 + "email": "fabien@symfony.com" 2561 + }, 2562 + { 2563 + "name": "Symfony Community", 2564 + "homepage": "https://symfony.com/contributors" 2565 + } 2566 + ], 2567 + "description": "Loads and dumps YAML files", 2568 + "homepage": "https://symfony.com", 2569 + "support": { 2570 + "source": "https://github.com/symfony/yaml/tree/v8.1.1" 2571 + }, 2572 + "funding": [ 2573 + { 2574 + "url": "https://symfony.com/sponsor", 2575 + "type": "custom" 2576 + }, 2577 + { 2578 + "url": "https://github.com/fabpot", 2579 + "type": "github" 2580 + }, 2581 + { 2582 + "url": "https://github.com/nicolas-grekas", 2583 + "type": "github" 2584 + }, 2585 + { 2586 + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2587 + "type": "tidelift" 2588 + } 2589 + ], 2590 + "time": "2026-06-09T11:06:24+00:00" 2591 + } 2592 + ], 2593 + "packages-dev": [], 2594 + "aliases": [], 2595 + "minimum-stability": "stable", 2596 + "stability-flags": {}, 2597 + "prefer-stable": true, 2598 + "prefer-lowest": false, 2599 + "platform": { 2600 + "php": ">=8.5.7", 2601 + "ext-ctype": "*", 2602 + "ext-iconv": "*" 2603 + }, 2604 + "platform-dev": {}, 2605 + "plugin-api-version": "2.9.0" 2606 + }
+5
application/config/bundles.php
··· 1 + <?php 2 + 3 + return [ 4 + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], 5 + ];
+19
application/config/packages/cache.yaml
··· 1 + framework: 2 + cache: 3 + # Unique name of your app: used to compute stable namespaces for cache keys. 4 + #prefix_seed: your_vendor_name/app_name 5 + 6 + # The "app" cache stores to the filesystem by default. 7 + # The data in this cache should persist between deploys. 8 + # Other options include: 9 + 10 + # Redis 11 + #app: cache.adapter.redis 12 + #default_redis_provider: redis://localhost 13 + 14 + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) 15 + #app: cache.adapter.apcu 16 + 17 + # Namespaced pools use the above "app" backend by default 18 + #pools: 19 + #my.dedicated.cache: null
+15
application/config/packages/framework.yaml
··· 1 + # see https://symfony.com/doc/current/reference/configuration/framework.html 2 + framework: 3 + secret: '%env(APP_SECRET)%' 4 + 5 + # Note that the session will be started ONLY if you read or write from it. 6 + session: true 7 + 8 + #esi: true 9 + #fragments: true 10 + 11 + when@test: 12 + framework: 13 + test: true 14 + session: 15 + storage_factory_id: session.storage.factory.mock_file
+10
application/config/packages/routing.yaml
··· 1 + framework: 2 + router: 3 + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. 4 + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands 5 + default_uri: '%env(DEFAULT_URI)%' 6 + 7 + when@prod: 8 + framework: 9 + router: 10 + strict_requirements: null
+5
application/config/preload.php
··· 1 + <?php 2 + 3 + if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) { 4 + require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php'; 5 + }
+826
application/config/reference.php
··· 1 + <?php 2 + 3 + // This file is auto-generated and is for apps only. Bundles SHOULD NOT rely on its content. 4 + 5 + namespace Symfony\Component\DependencyInjection\Loader\Configurator; 6 + 7 + use Symfony\Component\Config\Loader\ParamConfigurator as Param; 8 + 9 + /** 10 + * This class provides array-shapes for configuring the services and bundles of an application. 11 + * 12 + * Services declared with the config() method below are autowired and autoconfigured by default. 13 + * 14 + * This is for apps only. Bundles SHOULD NOT use it. 15 + * 16 + * Example: 17 + * 18 + * ```php 19 + * // config/services.php 20 + * namespace Symfony\Component\DependencyInjection\Loader\Configurator; 21 + * 22 + * return App::config([ 23 + * 'services' => [ 24 + * 'App\\' => [ 25 + * 'resource' => '../src/', 26 + * ], 27 + * ], 28 + * ]); 29 + * ``` 30 + * 31 + * @psalm-type ImportsConfig = list<string|array{ 32 + * resource: string, 33 + * type?: string|null, 34 + * ignore_errors?: bool, 35 + * }> 36 + * @psalm-type ParametersConfig = array<string, scalar|\UnitEnum|array<scalar|\UnitEnum|array<mixed>|Param|null>|Param|null> 37 + * @psalm-type ArgumentsType = list<mixed>|array<string, mixed> 38 + * @psalm-type CallType = array<string, ArgumentsType>|array{0:string, 1?:ArgumentsType, 2?:bool}|array{method:string, arguments?:ArgumentsType, returns_clone?:bool} 39 + * @psalm-type TagsType = list<string|array<string, array<string, mixed>>> // arrays inside the list must have only one element, with the tag name as the key 40 + * @psalm-type CallbackType = string|array{0:string|ReferenceConfigurator,1:string}|\Closure|ReferenceConfigurator 41 + * @psalm-type DeprecationType = array{package: string, version: string, message?: string} 42 + * @psalm-type DefaultsType = array{ 43 + * public?: bool, 44 + * tags?: TagsType, 45 + * resource_tags?: TagsType, 46 + * autowire?: bool, 47 + * autoconfigure?: bool, 48 + * bind?: array<string, mixed>, 49 + * } 50 + * @psalm-type InstanceofType = array{ 51 + * shared?: bool, 52 + * lazy?: bool|string, 53 + * public?: bool, 54 + * properties?: array<string, mixed>, 55 + * configurator?: CallbackType, 56 + * calls?: list<CallType>, 57 + * tags?: TagsType, 58 + * resource_tags?: TagsType, 59 + * autowire?: bool, 60 + * bind?: array<string, mixed>, 61 + * constructor?: string, 62 + * } 63 + * @psalm-type DefinitionType = array{ 64 + * class?: string, 65 + * file?: string, 66 + * parent?: string, 67 + * shared?: bool, 68 + * synthetic?: bool, 69 + * lazy?: bool|string, 70 + * public?: bool, 71 + * abstract?: bool, 72 + * deprecated?: DeprecationType, 73 + * factory?: CallbackType, 74 + * configurator?: CallbackType, 75 + * arguments?: ArgumentsType, 76 + * properties?: array<string, mixed>, 77 + * calls?: list<CallType>, 78 + * tags?: TagsType, 79 + * resource_tags?: TagsType, 80 + * decorates?: string, 81 + * decorates_tag?: string, 82 + * decoration_inner_name?: string, 83 + * decoration_priority?: int, 84 + * decoration_on_invalid?: 'exception'|'ignore'|null, 85 + * autowire?: bool, 86 + * autoconfigure?: bool, 87 + * bind?: array<string, mixed>, 88 + * constructor?: string, 89 + * from_callable?: CallbackType, 90 + * } 91 + * @psalm-type AliasType = string|array{ 92 + * alias: string, 93 + * public?: bool, 94 + * deprecated?: DeprecationType, 95 + * } 96 + * @psalm-type PrototypeType = array{ 97 + * resource: string, 98 + * namespace?: string, 99 + * exclude?: string|list<string>, 100 + * parent?: string, 101 + * shared?: bool, 102 + * lazy?: bool|string, 103 + * public?: bool, 104 + * abstract?: bool, 105 + * deprecated?: DeprecationType, 106 + * factory?: CallbackType, 107 + * arguments?: ArgumentsType, 108 + * properties?: array<string, mixed>, 109 + * configurator?: CallbackType, 110 + * calls?: list<CallType>, 111 + * tags?: TagsType, 112 + * resource_tags?: TagsType, 113 + * autowire?: bool, 114 + * autoconfigure?: bool, 115 + * bind?: array<string, mixed>, 116 + * constructor?: string, 117 + * } 118 + * @psalm-type StackType = array{ 119 + * stack: list<DefinitionType|AliasType|PrototypeType|array<class-string, ArgumentsType|null>>, 120 + * public?: bool, 121 + * deprecated?: DeprecationType, 122 + * decorates?: string, 123 + * decorates_tag?: string, 124 + * decoration_inner_name?: string, 125 + * decoration_priority?: int, 126 + * decoration_on_invalid?: 'exception'|'ignore'|null, 127 + * } 128 + * @psalm-type ServicesConfig = array{ 129 + * _defaults?: DefaultsType, 130 + * _instanceof?: array<class-string, InstanceofType>, 131 + * ...<string, DefinitionType|AliasType|PrototypeType|StackType|ArgumentsType|null> 132 + * } 133 + * @psalm-type ExtensionType = array<string, mixed> 134 + * @psalm-type FrameworkConfig = array{ 135 + * secret?: scalar|Param|null, 136 + * http_method_override?: bool|Param, // Set true to enable support for the '_method' request parameter to determine the intended HTTP method on POST requests. // Default: false 137 + * allowed_http_method_override?: null|list<string|Param>, 138 + * trust_x_sendfile_type_header?: scalar|Param|null, // Set true to enable support for xsendfile in binary file responses. // Default: "%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%" 139 + * ide?: scalar|Param|null, // Default: "%env(default::SYMFONY_IDE)%" 140 + * test?: bool|Param, 141 + * default_locale?: scalar|Param|null, // Default: "en" 142 + * set_locale_from_accept_language?: bool|Param, // Whether to use the Accept-Language HTTP header to set the Request locale (only when the "_locale" request attribute is not passed). // Default: false 143 + * set_content_language_from_locale?: bool|Param, // Whether to set the Content-Language HTTP header on the Response using the Request locale. // Default: false 144 + * enabled_locales?: list<scalar|Param|null>, 145 + * trusted_hosts?: string|list<scalar|Param|null>, 146 + * trusted_proxies?: mixed, // Default: ["%env(default::SYMFONY_TRUSTED_PROXIES)%"] 147 + * trusted_headers?: string|list<scalar|Param|null>, 148 + * error_controller?: scalar|Param|null, // Default: "error_controller" 149 + * handle_all_throwables?: bool|Param, // HttpKernel will handle all kinds of \Throwable. // Default: true 150 + * csrf_protection?: bool|array{ 151 + * enabled?: scalar|Param|null, // Default: null 152 + * stateless_token_ids?: list<scalar|Param|null>, 153 + * check_header?: scalar|Param|null, // Whether to check the CSRF token in a header in addition to a cookie when using stateless protection. // Default: false 154 + * cookie_name?: scalar|Param|null, // The name of the cookie to use when using stateless protection. // Default: "csrf-token" 155 + * }, 156 + * form?: bool|array{ // Form configuration 157 + * enabled?: bool|Param, // Default: false 158 + * csrf_protection?: bool|array{ 159 + * enabled?: scalar|Param|null, // Default: null 160 + * token_id?: scalar|Param|null, // Default: null 161 + * field_name?: scalar|Param|null, // Default: "_token" 162 + * field_attr?: array<string, scalar|Param|null>, 163 + * }, 164 + * }, 165 + * http_cache?: bool|array{ // HTTP cache configuration 166 + * enabled?: bool|Param, // Default: false 167 + * debug?: bool|Param, // Default: "%kernel.debug%" 168 + * trace_level?: "none"|"short"|"full"|Param, 169 + * trace_header?: scalar|Param|null, 170 + * default_ttl?: int|Param, 171 + * private_headers?: list<scalar|Param|null>, 172 + * skip_response_headers?: list<scalar|Param|null>, 173 + * allow_reload?: bool|Param, 174 + * allow_revalidate?: bool|Param, 175 + * stale_while_revalidate?: int|Param, 176 + * stale_if_error?: int|Param, 177 + * terminate_on_cache_hit?: bool|Param, // Deprecated: Setting the "framework.http_cache.terminate_on_cache_hit.terminate_on_cache_hit" configuration option is deprecated. It will be removed in version 9.0. 178 + * }, 179 + * esi?: bool|array{ // ESI configuration 180 + * enabled?: bool|Param, // Default: false 181 + * }, 182 + * ssi?: bool|array{ // SSI configuration 183 + * enabled?: bool|Param, // Default: false 184 + * }, 185 + * fragments?: bool|array{ // Fragments configuration 186 + * enabled?: bool|Param, // Default: false 187 + * hinclude_default_template?: scalar|Param|null, // Default: null 188 + * path?: scalar|Param|null, // Default: "/_fragment" 189 + * }, 190 + * profiler?: bool|array{ // Profiler configuration 191 + * enabled?: bool|Param, // Default: false 192 + * collect?: bool|Param, // Default: true 193 + * collect_parameter?: scalar|Param|null, // The name of the parameter to use to enable or disable collection on a per request basis. // Default: null 194 + * only_exceptions?: bool|Param, // Default: false 195 + * only_main_requests?: bool|Param, // Default: false 196 + * dsn?: scalar|Param|null, // Default: "file:%kernel.cache_dir%/profiler" 197 + * collect_serializer_data?: true|Param, // Deprecated: Setting the "framework.profiler.collect_serializer_data.collect_serializer_data" configuration option is deprecated. It will be removed in version 9.0. // Default: true 198 + * }, 199 + * workflows?: bool|array{ 200 + * enabled?: bool|Param, // Default: false 201 + * workflows?: array<string, array{ // Default: [] 202 + * audit_trail?: bool|array{ 203 + * enabled?: bool|Param, // Default: false 204 + * }, 205 + * type?: "workflow"|"state_machine"|Param, // Default: "state_machine" 206 + * marking_store?: array{ 207 + * type?: "method"|Param, 208 + * property?: scalar|Param|null, 209 + * service?: scalar|Param|null, 210 + * }, 211 + * supports?: string|list<scalar|Param|null>, 212 + * definition_validators?: list<scalar|Param|null>, 213 + * support_strategy?: scalar|Param|null, 214 + * initial_marking?: \BackedEnum|string|list<scalar|Param|null>, 215 + * events_to_dispatch?: null|list<string|Param>, 216 + * places?: string|list<array{ // Default: [] 217 + * name?: scalar|Param|null, 218 + * metadata?: array<string, mixed>, 219 + * }>, 220 + * transitions?: list<array{ // Default: [] 221 + * name?: string|Param, 222 + * guard?: string|Param, // An expression to block the transition. 223 + * from?: \BackedEnum|string|list<array{ // Default: [] 224 + * place?: string|Param, 225 + * weight?: int|Param, // Default: 1 226 + * }>, 227 + * to?: \BackedEnum|string|list<array{ // Default: [] 228 + * place?: string|Param, 229 + * weight?: int|Param, // Default: 1 230 + * }>, 231 + * weight?: int|Param, // Default: 1 232 + * metadata?: array<string, mixed>, 233 + * }>, 234 + * metadata?: array<string, mixed>, 235 + * }>, 236 + * }, 237 + * router?: bool|array{ // Router configuration 238 + * enabled?: bool|Param, // Default: false 239 + * resource?: scalar|Param|null, 240 + * type?: scalar|Param|null, 241 + * default_uri?: scalar|Param|null, // The default URI used to generate URLs in a non-HTTP context. // Default: null 242 + * http_port?: scalar|Param|null, // Default: 80 243 + * https_port?: scalar|Param|null, // Default: 443 244 + * strict_requirements?: scalar|Param|null, // set to true to throw an exception when a parameter does not match the requirements set to false to disable exceptions when a parameter does not match the requirements (and return null instead) set to null to disable parameter checks against requirements 'true' is the preferred configuration in development mode, while 'false' or 'null' might be preferred in production // Default: true 245 + * utf8?: bool|Param, // Default: true 246 + * }, 247 + * session?: bool|array{ // Session configuration 248 + * enabled?: bool|Param, // Default: false 249 + * storage_factory_id?: scalar|Param|null, // Default: "session.storage.factory.native" 250 + * handler_id?: scalar|Param|null, // Defaults to using the native session handler, or to the native *file* session handler if "save_path" is not null. 251 + * name?: scalar|Param|null, 252 + * cookie_lifetime?: scalar|Param|null, 253 + * cookie_path?: scalar|Param|null, 254 + * cookie_domain?: scalar|Param|null, 255 + * cookie_secure?: true|false|"auto"|Param, // Default: "auto" 256 + * cookie_httponly?: bool|Param, // Default: true 257 + * cookie_samesite?: null|"lax"|"strict"|"none"|Param, // Default: "lax" 258 + * use_cookies?: bool|Param, 259 + * gc_divisor?: scalar|Param|null, 260 + * gc_probability?: scalar|Param|null, 261 + * gc_maxlifetime?: scalar|Param|null, 262 + * save_path?: scalar|Param|null, // Defaults to "%kernel.cache_dir%/sessions" if the "handler_id" option is not null. 263 + * metadata_update_threshold?: int|Param, // Seconds to wait between 2 session metadata updates. // Default: 0 264 + * }, 265 + * request?: bool|array{ // Request configuration 266 + * enabled?: bool|Param, // Default: false 267 + * formats?: array<string, string|list<scalar|Param|null>>, 268 + * }, 269 + * assets?: bool|array{ // Assets configuration 270 + * enabled?: bool|Param, // Default: false 271 + * strict_mode?: bool|Param, // Throw an exception if an entry is missing from the manifest.json. // Default: false 272 + * version_strategy?: scalar|Param|null, // Default: null 273 + * version?: scalar|Param|null, // Default: null 274 + * version_format?: scalar|Param|null, // Default: "%%s?%%s" 275 + * json_manifest_path?: scalar|Param|null, // Default: null 276 + * base_path?: scalar|Param|null, // Default: "" 277 + * base_urls?: string|list<scalar|Param|null>, 278 + * packages?: array<string, array{ // Default: [] 279 + * strict_mode?: bool|Param, // Throw an exception if an entry is missing from the manifest.json. // Default: false 280 + * version_strategy?: scalar|Param|null, // Default: null 281 + * version?: scalar|Param|null, 282 + * version_format?: scalar|Param|null, // Default: null 283 + * json_manifest_path?: scalar|Param|null, // Default: null 284 + * base_path?: scalar|Param|null, // Default: "" 285 + * base_urls?: string|list<scalar|Param|null>, 286 + * }>, 287 + * }, 288 + * asset_mapper?: bool|array{ // Asset Mapper configuration 289 + * enabled?: bool|Param, // Default: false 290 + * paths?: string|array<string, scalar|Param|null>, 291 + * excluded_patterns?: list<scalar|Param|null>, 292 + * exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true 293 + * server?: bool|Param, // If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default). // Default: true 294 + * public_prefix?: scalar|Param|null, // The public path where the assets will be written to (and served from when "server" is true). // Default: "/assets/" 295 + * missing_import_mode?: "strict"|"warn"|"ignore"|Param, // Behavior if an asset cannot be found when imported from JavaScript or CSS files - e.g. "import './non-existent.js'". "strict" means an exception is thrown, "warn" means a warning is logged, "ignore" means the import is left as-is. // Default: "warn" 296 + * extensions?: array<string, scalar|Param|null>, 297 + * importmap_path?: scalar|Param|null, // The path of the importmap.php file. // Default: "%kernel.project_dir%/importmap.php" 298 + * importmap_polyfill?: scalar|Param|null, // The importmap name that will be used to load the polyfill. Set to false to disable. // Default: "es-module-shims" 299 + * importmap_script_attributes?: array<string, scalar|Param|null>, 300 + * vendor_dir?: scalar|Param|null, // The directory to store JavaScript vendors. // Default: "%kernel.project_dir%/assets/vendor" 301 + * precompress?: bool|array{ // Precompress assets with Brotli, Zstandard and gzip. 302 + * enabled?: bool|Param, // Default: false 303 + * formats?: list<scalar|Param|null>, 304 + * extensions?: list<scalar|Param|null>, 305 + * }, 306 + * }, 307 + * translator?: bool|array{ // Translator configuration 308 + * enabled?: bool|Param, // Default: false 309 + * fallbacks?: string|list<scalar|Param|null>, 310 + * logging?: bool|Param, // Default: false 311 + * formatter?: scalar|Param|null, // Default: "translator.formatter.default" 312 + * cache_dir?: scalar|Param|null, // Default: "%kernel.cache_dir%/translations" 313 + * default_path?: scalar|Param|null, // The default path used to load translations. // Default: "%kernel.project_dir%/translations" 314 + * paths?: list<scalar|Param|null>, 315 + * pseudo_localization?: bool|array{ 316 + * enabled?: bool|Param, // Default: false 317 + * accents?: bool|Param, // Default: true 318 + * expansion_factor?: float|Param, // Default: 1.0 319 + * brackets?: bool|Param, // Default: true 320 + * parse_html?: bool|Param, // Default: false 321 + * localizable_html_attributes?: list<scalar|Param|null>, 322 + * }, 323 + * providers?: array<string, array{ // Default: [] 324 + * dsn?: scalar|Param|null, 325 + * domains?: list<scalar|Param|null>, 326 + * locales?: list<scalar|Param|null>, 327 + * }>, 328 + * globals?: array<string, string|array{ // Default: [] 329 + * value?: mixed, 330 + * message?: string|Param, 331 + * parameters?: array<string, scalar|Param|null>, 332 + * domain?: string|Param, 333 + * }>, 334 + * }, 335 + * validation?: bool|array{ // Validation configuration 336 + * enabled?: bool|Param, // Default: false 337 + * enable_attributes?: bool|Param, // Default: true 338 + * static_method?: string|list<scalar|Param|null>, 339 + * translation_domain?: scalar|Param|null, // Default: "validators" 340 + * email_validation_mode?: "html5"|"html5-allow-no-tld"|"strict"|Param, // Default: "html5" 341 + * mapping?: array{ 342 + * paths?: list<scalar|Param|null>, 343 + * }, 344 + * not_compromised_password?: bool|array{ 345 + * enabled?: bool|Param, // When disabled, compromised passwords will be accepted as valid. // Default: true 346 + * endpoint?: scalar|Param|null, // API endpoint for the NotCompromisedPassword Validator. // Default: null 347 + * }, 348 + * disable_translation?: bool|Param, // Default: false 349 + * property_metadata_existence_check?: bool|Param, // When enabled, validateProperty() and validatePropertyValue() throw an exception if no metadata is found for the given property. // Default: false 350 + * auto_mapping?: array<string, array{ // Default: [] 351 + * services?: list<scalar|Param|null>, 352 + * }>, 353 + * }, 354 + * serializer?: bool|array{ // Serializer configuration 355 + * enabled?: bool|Param, // Default: false 356 + * enable_attributes?: bool|Param, // Default: true 357 + * name_converter?: scalar|Param|null, 358 + * circular_reference_handler?: scalar|Param|null, 359 + * max_depth_handler?: scalar|Param|null, 360 + * mapping?: array{ 361 + * paths?: list<scalar|Param|null>, 362 + * }, 363 + * default_context?: array<string, mixed>, 364 + * named_serializers?: array<string, array{ // Default: [] 365 + * name_converter?: scalar|Param|null, 366 + * default_context?: array<string, mixed>, 367 + * include_built_in_normalizers?: bool|Param, // Whether to include the built-in normalizers // Default: true 368 + * include_built_in_encoders?: bool|Param, // Whether to include the built-in encoders // Default: true 369 + * }>, 370 + * }, 371 + * property_access?: bool|array{ // Property access configuration 372 + * enabled?: bool|Param, // Default: false 373 + * magic_call?: bool|Param, // Default: false 374 + * magic_get?: bool|Param, // Default: true 375 + * magic_set?: bool|Param, // Default: true 376 + * throw_exception_on_invalid_index?: bool|Param, // Default: false 377 + * throw_exception_on_invalid_property_path?: bool|Param, // Default: true 378 + * }, 379 + * type_info?: bool|array{ // Type info configuration 380 + * enabled?: bool|Param, // Default: false 381 + * aliases?: array<string, scalar|Param|null>, 382 + * }, 383 + * property_info?: bool|array{ // Property info configuration 384 + * enabled?: bool|Param, // Default: false 385 + * with_constructor_extractor?: bool|Param, // Registers the constructor extractor. // Default: true 386 + * }, 387 + * cache?: array{ // Cache configuration 388 + * prefix_seed?: scalar|Param|null, // Used to namespace cache keys when using several apps with the same shared backend. // Default: "_%kernel.project_dir%.%kernel.container_class%" 389 + * app?: scalar|Param|null, // App related cache pools configuration. // Default: "cache.adapter.filesystem" 390 + * system?: scalar|Param|null, // System related cache pools configuration. // Default: "cache.adapter.system" 391 + * directory?: scalar|Param|null, // Default: "%kernel.share_dir%/pools/app" 392 + * default_psr6_provider?: scalar|Param|null, 393 + * default_redis_provider?: scalar|Param|null, // Default: "redis://localhost" 394 + * default_valkey_provider?: scalar|Param|null, // Default: "valkey://localhost" 395 + * default_memcached_provider?: scalar|Param|null, // Default: "memcached://localhost" 396 + * default_doctrine_dbal_provider?: scalar|Param|null, // Default: "database_connection" 397 + * default_pdo_provider?: scalar|Param|null, // Default: null 398 + * pools?: array<string, array{ // Default: [] 399 + * adapters?: string|list<scalar|Param|null>, 400 + * tags?: scalar|Param|null, // Default: null 401 + * public?: bool|Param, // Default: false 402 + * default_lifetime?: scalar|Param|null, // Default lifetime of the pool. 403 + * provider?: scalar|Param|null, // Overwrite the setting from the default provider for this adapter. 404 + * early_expiration_message_bus?: scalar|Param|null, 405 + * clearer?: scalar|Param|null, 406 + * marshaller?: scalar|Param|null, // The marshaller service to use for this pool. 407 + * }>, 408 + * }, 409 + * php_errors?: array{ // PHP errors handling configuration 410 + * log?: mixed, // Use the application logger instead of the PHP logger for logging PHP errors. // Default: true 411 + * throw?: bool|Param, // Throw PHP errors as \ErrorException instances. // Default: true 412 + * }, 413 + * exceptions?: array<string, array{ // Default: [] 414 + * log_level?: scalar|Param|null, // The level of log message. Null to let Symfony decide. // Default: null 415 + * status_code?: scalar|Param|null, // The status code of the response. Null or 0 to let Symfony decide. // Default: null 416 + * log_channel?: scalar|Param|null, // The channel of log message. Null to let Symfony decide. // Default: null 417 + * }>, 418 + * web_link?: bool|array{ // Web links configuration 419 + * enabled?: bool|Param, // Default: false 420 + * }, 421 + * lock?: bool|string|array{ // Lock configuration 422 + * enabled?: bool|Param, // Default: false 423 + * resources?: string|array<string, string|list<scalar|Param|null>>, 424 + * }, 425 + * semaphore?: bool|string|array{ // Semaphore configuration 426 + * enabled?: bool|Param, // Default: false 427 + * resources?: string|array<string, scalar|Param|null>, 428 + * }, 429 + * messenger?: bool|array{ // Messenger configuration 430 + * enabled?: bool|Param, // Default: false 431 + * routing?: array<string, string|list<scalar|Param|null>>, 432 + * serializer?: array{ 433 + * default_serializer?: scalar|Param|null, // Service id to use as the default serializer for the transports. // Default: "messenger.transport.native_php_serializer" 434 + * symfony_serializer?: array{ 435 + * format?: scalar|Param|null, // Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default). // Default: "json" 436 + * context?: array<string, mixed>, 437 + * }, 438 + * }, 439 + * transports?: array<string, string|array{ // Default: [] 440 + * dsn?: scalar|Param|null, 441 + * serializer?: scalar|Param|null, // Service id of a custom serializer to use. // Default: null 442 + * options?: array<string, mixed>, 443 + * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null 444 + * retry_strategy?: string|array{ 445 + * service?: scalar|Param|null, // Service id to override the retry strategy entirely. // Default: null 446 + * max_retries?: int|Param, // Default: 3 447 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 448 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries)). // Default: 2 449 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 450 + * jitter?: float|Param, // Randomness to apply to the delay (between 0 and 1). // Default: 0.1 451 + * }, 452 + * rate_limiter?: scalar|Param|null, // Rate limiter name to use when processing messages. // Default: null 453 + * }>, 454 + * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null 455 + * stop_worker_on_signals?: int|string|list<scalar|Param|null>, 456 + * default_bus?: scalar|Param|null, // Default: null 457 + * buses?: array<string, array{ // Default: {"messenger.bus.default":{"default_middleware":{"enabled":true,"allow_no_handlers":false,"allow_no_senders":true},"middleware":[]}} 458 + * default_middleware?: bool|string|array{ 459 + * enabled?: bool|Param, // Default: true 460 + * allow_no_handlers?: bool|Param, // Default: false 461 + * allow_no_senders?: bool|Param, // Default: true 462 + * }, 463 + * middleware?: string|list<string|array{ // Default: [] 464 + * id?: scalar|Param|null, 465 + * arguments?: list<mixed>, 466 + * }>, 467 + * }>, 468 + * }, 469 + * scheduler?: bool|array{ // Scheduler configuration 470 + * enabled?: bool|Param, // Default: false 471 + * }, 472 + * disallow_search_engine_index?: bool|Param, // Enabled by default when debug is enabled. // Default: true 473 + * http_client?: bool|array{ // HTTP Client configuration 474 + * enabled?: bool|Param, // Default: false 475 + * max_host_connections?: int|Param, // The maximum number of connections to a single host. 476 + * default_options?: array{ 477 + * headers?: array<string, mixed>, 478 + * vars?: array<string, mixed>, 479 + * max_redirects?: int|Param, // The maximum number of redirects to follow. 480 + * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. 481 + * resolve?: array<string, scalar|Param|null>, 482 + * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. 483 + * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. 484 + * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. 485 + * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. 486 + * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. 487 + * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. 488 + * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. 489 + * cafile?: scalar|Param|null, // A certificate authority file. 490 + * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. 491 + * local_cert?: scalar|Param|null, // A PEM formatted certificate file. 492 + * local_pk?: scalar|Param|null, // A private key file. 493 + * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. 494 + * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...) 495 + * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). 496 + * sha1?: mixed, 497 + * pin-sha256?: mixed, 498 + * md5?: mixed, 499 + * }, 500 + * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. 501 + * extra?: array<string, mixed>, 502 + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null 503 + * caching?: bool|array{ // Caching configuration. 504 + * enabled?: bool|Param, // Default: false 505 + * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" 506 + * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true 507 + * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. // Default: 86400 508 + * }, 509 + * retry_failed?: bool|array{ 510 + * enabled?: bool|Param, // Default: false 511 + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null 512 + * http_codes?: int|string|array<string, array{ // Default: [] 513 + * code?: int|Param, 514 + * methods?: string|list<string|Param>, 515 + * }>, 516 + * max_retries?: int|Param, // Default: 3 517 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 518 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 519 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 520 + * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 521 + * }, 522 + * }, 523 + * mock_response_factory?: scalar|Param|null, // `true` to always return empty 200 responses, or the id of the service to use to generate mock responses - which should be either an invokable or an iterable. 524 + * scoped_clients?: array<string, string|array{ // Default: [] 525 + * scope?: scalar|Param|null, // The regular expression that the request URL must match before adding the other options. When none is provided, the base URI is used instead. 526 + * base_uri?: scalar|Param|null, // The URI to resolve relative URLs, following rules in RFC 3985, section 2. 527 + * auth_basic?: scalar|Param|null, // An HTTP Basic authentication "username:password". 528 + * auth_bearer?: scalar|Param|null, // A token enabling HTTP Bearer authorization. 529 + * auth_ntlm?: scalar|Param|null, // A "username:password" pair to use Microsoft NTLM authentication (requires the cURL extension). 530 + * query?: array<string, scalar|Param|null>, 531 + * headers?: array<string, mixed>, 532 + * max_redirects?: int|Param, // The maximum number of redirects to follow. 533 + * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. 534 + * resolve?: array<string, scalar|Param|null>, 535 + * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. 536 + * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. 537 + * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. 538 + * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. 539 + * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. 540 + * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. 541 + * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. 542 + * cafile?: scalar|Param|null, // A certificate authority file. 543 + * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. 544 + * local_cert?: scalar|Param|null, // A PEM formatted certificate file. 545 + * local_pk?: scalar|Param|null, // A private key file. 546 + * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. 547 + * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...). 548 + * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). 549 + * sha1?: mixed, 550 + * pin-sha256?: mixed, 551 + * md5?: mixed, 552 + * }, 553 + * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. 554 + * mock_response_factory?: scalar|Param|null, // `true` to always return empty 200 responses, `false` to disable mocking, or the id of the service to use to generate mock responses (invokable or iterable). 555 + * extra?: array<string, mixed>, 556 + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null 557 + * caching?: bool|array{ // Caching configuration. 558 + * enabled?: bool|Param, // Default: false 559 + * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" 560 + * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true 561 + * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. // Default: 86400 562 + * }, 563 + * retry_failed?: bool|array{ 564 + * enabled?: bool|Param, // Default: false 565 + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null 566 + * http_codes?: int|string|array<string, array{ // Default: [] 567 + * code?: int|Param, 568 + * methods?: string|list<string|Param>, 569 + * }>, 570 + * max_retries?: int|Param, // Default: 3 571 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 572 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 573 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 574 + * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 575 + * }, 576 + * }>, 577 + * }, 578 + * mailer?: bool|array{ // Mailer configuration 579 + * enabled?: bool|Param, // Default: false 580 + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null 581 + * dsn?: scalar|Param|null, // Default: null 582 + * transports?: array<string, scalar|Param|null>, 583 + * envelope?: array{ // Mailer Envelope configuration 584 + * sender?: scalar|Param|null, 585 + * recipients?: string|list<scalar|Param|null>, 586 + * allowed_recipients?: string|list<scalar|Param|null>, 587 + * }, 588 + * headers?: array<string, string|array{ // Default: [] 589 + * value?: mixed, 590 + * }>, 591 + * dkim_signer?: bool|array{ // DKIM signer configuration 592 + * enabled?: bool|Param, // Default: false 593 + * key?: scalar|Param|null, // Key content, or path to key (in PEM format with the `file://` prefix) // Default: "" 594 + * domain?: scalar|Param|null, // Default: "" 595 + * select?: scalar|Param|null, // Default: "" 596 + * passphrase?: scalar|Param|null, // The private key passphrase // Default: "" 597 + * options?: array<string, mixed>, 598 + * }, 599 + * smime_signer?: bool|array{ // S/MIME signer configuration 600 + * enabled?: bool|Param, // Default: false 601 + * key?: scalar|Param|null, // Path to key (in PEM format) // Default: "" 602 + * certificate?: scalar|Param|null, // Path to certificate (in PEM format without the `file://` prefix) // Default: "" 603 + * passphrase?: scalar|Param|null, // The private key passphrase // Default: null 604 + * extra_certificates?: scalar|Param|null, // Default: null 605 + * sign_options?: int|Param, // Default: null 606 + * }, 607 + * smime_encrypter?: bool|array{ // S/MIME encrypter configuration 608 + * enabled?: bool|Param, // Default: false 609 + * repository?: scalar|Param|null, // S/MIME certificate repository service. This service shall implement the `Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface`. // Default: "" 610 + * cipher?: int|Param, // A set of algorithms used to encrypt the message // Default: null 611 + * }, 612 + * }, 613 + * secrets?: bool|array{ 614 + * enabled?: bool|Param, // Default: true 615 + * vault_directory?: scalar|Param|null, // Default: "%kernel.project_dir%/config/secrets/%kernel.runtime_environment%" 616 + * local_dotenv_file?: scalar|Param|null, // Default: "%kernel.project_dir%/.env.%kernel.environment%.local" 617 + * decryption_env_var?: scalar|Param|null, // Default: "base64:default::SYMFONY_DECRYPTION_SECRET" 618 + * }, 619 + * notifier?: bool|array{ // Notifier configuration 620 + * enabled?: bool|Param, // Default: false 621 + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null 622 + * chatter_transports?: array<string, scalar|Param|null>, 623 + * texter_transports?: array<string, scalar|Param|null>, 624 + * notification_on_failed_messages?: bool|Param, // Default: false 625 + * channel_policy?: array<string, string|list<scalar|Param|null>>, 626 + * admin_recipients?: list<array{ // Default: [] 627 + * email?: scalar|Param|null, 628 + * phone?: scalar|Param|null, // Default: "" 629 + * }>, 630 + * }, 631 + * rate_limiter?: bool|array{ // Rate limiter configuration 632 + * enabled?: bool|Param, // Default: false 633 + * limiters?: array<string, array{ // Default: [] 634 + * lock_factory?: scalar|Param|null, // The service ID of the lock factory used by this limiter (or null to disable locking). // Default: "auto" 635 + * cache_pool?: scalar|Param|null, // The cache pool to use for storing the current limiter state. // Default: "cache.rate_limiter" 636 + * storage_service?: scalar|Param|null, // The service ID of a custom storage implementation, this precedes any configured "cache_pool". // Default: null 637 + * policy?: "fixed_window"|"token_bucket"|"sliding_window"|"compound"|"no_limit"|Param, // The algorithm to be used by this limiter. 638 + * limiters?: string|list<scalar|Param|null>, 639 + * limit?: int|Param, // The maximum allowed hits in a fixed interval or burst. 640 + * interval?: scalar|Param|null, // Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). 641 + * rate?: array{ // Configures the fill rate if "policy" is set to "token_bucket". 642 + * interval?: scalar|Param|null, // Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). 643 + * amount?: int|Param, // Amount of tokens to add each interval. // Default: 1 644 + * }, 645 + * anchor_at?: scalar|Param|null, // Aligns the "fixed_window" policy to a calendar (e.g. "2024-01-05 00:00:00 UTC" combined with `interval: 1 month` resets the counter on the 5th of each month). UTC if not specified. // Default: null 646 + * }>, 647 + * }, 648 + * uid?: bool|array{ // Uid configuration 649 + * enabled?: bool|Param, // Default: false 650 + * default_uuid_version?: 7|6|4|1|Param, // Default: 7 651 + * name_based_uuid_version?: 5|3|Param, // Default: 5 652 + * name_based_uuid_namespace?: scalar|Param|null, 653 + * time_based_uuid_version?: 7|6|1|Param, // Default: 7 654 + * time_based_uuid_node?: scalar|Param|null, 655 + * uuid47_secret?: scalar|Param|null, // A high-entropy secret used by the "uuid47_transformer" service. Defaults to "kernel.secret". // Default: null 656 + * }, 657 + * html_sanitizer?: bool|array{ // HtmlSanitizer configuration 658 + * enabled?: bool|Param, // Default: false 659 + * sanitizers?: array<string, array{ // Default: [] 660 + * default_action?: "drop"|"block"|"allow"|Param, // Defines how the sanitizer must behave by default. 661 + * allow_safe_elements?: bool|Param, // Allows "safe" elements and attributes. // Default: false 662 + * allow_static_elements?: bool|Param, // Allows all static elements and attributes from the W3C Sanitizer API standard. // Default: false 663 + * allow_elements?: array<string, mixed>, 664 + * block_elements?: string|list<string|Param>, 665 + * drop_elements?: string|list<string|Param>, 666 + * allow_attributes?: array<string, mixed>, 667 + * drop_attributes?: array<string, mixed>, 668 + * force_attributes?: array<string, array<string, string|Param>>, 669 + * force_https_urls?: bool|Param, // Transforms URLs using the HTTP scheme to use the HTTPS scheme instead. // Default: false 670 + * allowed_link_schemes?: string|list<string|Param>, 671 + * allowed_link_hosts?: null|string|list<string|Param>, 672 + * allow_relative_links?: bool|Param, // Allows relative URLs to be used in links href attributes. // Default: false 673 + * allowed_media_schemes?: string|list<string|Param>, 674 + * allowed_media_hosts?: null|string|list<string|Param>, 675 + * allow_relative_medias?: bool|Param, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false 676 + * with_attribute_sanitizers?: string|list<string|Param>, 677 + * without_attribute_sanitizers?: string|list<string|Param>, 678 + * max_input_length?: int|Param, // The maximum length allowed for the sanitized input. // Default: 0 679 + * }>, 680 + * }, 681 + * webhook?: bool|array{ // Webhook configuration 682 + * enabled?: bool|Param, // Default: false 683 + * message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus" 684 + * event_header_name?: scalar|Param|null, // Default: "Webhook-Event" 685 + * id_header_name?: scalar|Param|null, // Default: "Webhook-Id" 686 + * signature_header_name?: scalar|Param|null, // Default: "Webhook-Signature" 687 + * signing_algorithm?: scalar|Param|null, // Default: "sha256" 688 + * routing?: array<string, array{ // Default: [] 689 + * service?: scalar|Param|null, 690 + * secret?: scalar|Param|null, // Default: "" 691 + * }>, 692 + * }, 693 + * remote-event?: bool|array{ // RemoteEvent configuration 694 + * enabled?: bool|Param, // Default: false 695 + * }, 696 + * json_streamer?: bool|array{ // JSON streamer configuration 697 + * enabled?: bool|Param, // Default: false 698 + * default_options?: array{ 699 + * include_null_properties?: bool|Param, // Encode the properties with null value // Default: false 700 + * ...<string, mixed> 701 + * }, 702 + * }, 703 + * } 704 + * @psalm-type ConfigType = array{ 705 + * imports?: ImportsConfig, 706 + * parameters?: ParametersConfig, 707 + * services?: ServicesConfig, 708 + * framework?: FrameworkConfig, 709 + * "when@dev"?: array{ 710 + * imports?: ImportsConfig, 711 + * parameters?: ParametersConfig, 712 + * services?: ServicesConfig, 713 + * framework?: FrameworkConfig, 714 + * }, 715 + * "when@prod"?: array{ 716 + * imports?: ImportsConfig, 717 + * parameters?: ParametersConfig, 718 + * services?: ServicesConfig, 719 + * framework?: FrameworkConfig, 720 + * }, 721 + * "when@test"?: array{ 722 + * imports?: ImportsConfig, 723 + * parameters?: ParametersConfig, 724 + * services?: ServicesConfig, 725 + * framework?: FrameworkConfig, 726 + * }, 727 + * ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias 728 + * imports?: ImportsConfig, 729 + * parameters?: ParametersConfig, 730 + * services?: ServicesConfig, 731 + * ...<string, ExtensionType>, 732 + * }> 733 + * } 734 + */ 735 + final class App 736 + { 737 + /** 738 + * @param ConfigType $config 739 + * 740 + * @psalm-return ConfigType 741 + */ 742 + public static function config(array $config): array 743 + { 744 + /** @var ConfigType $config */ 745 + $config = AppReference::config($config); 746 + 747 + return $config; 748 + } 749 + } 750 + 751 + namespace Symfony\Component\Routing\Loader\Configurator; 752 + 753 + /** 754 + * This class provides array-shapes for configuring the routes of an application. 755 + * 756 + * Example: 757 + * 758 + * ```php 759 + * // config/routes.php 760 + * namespace Symfony\Component\Routing\Loader\Configurator; 761 + * 762 + * return Routes::config([ 763 + * 'controllers' => [ 764 + * 'resource' => 'routing.controllers', 765 + * ], 766 + * ]); 767 + * ``` 768 + * 769 + * @psalm-type RouteConfig = array{ 770 + * path: string|array<string,string>, 771 + * controller?: string, 772 + * methods?: string|list<string>, 773 + * requirements?: array<string,string>, 774 + * defaults?: array<string,mixed>, 775 + * options?: array<string,mixed>, 776 + * host?: string|array<string,string>, 777 + * schemes?: string|list<string>, 778 + * condition?: string, 779 + * locale?: string, 780 + * format?: string, 781 + * utf8?: bool, 782 + * stateless?: bool, 783 + * } 784 + * @psalm-type ImportConfig = array{ 785 + * resource: string, 786 + * type?: string, 787 + * exclude?: string|list<string>, 788 + * prefix?: string|array<string,string>, 789 + * name_prefix?: string, 790 + * trailing_slash_on_root?: bool, 791 + * controller?: string, 792 + * methods?: string|list<string>, 793 + * requirements?: array<string,string>, 794 + * defaults?: array<string,mixed>, 795 + * options?: array<string,mixed>, 796 + * host?: string|array<string,string>, 797 + * schemes?: string|list<string>, 798 + * condition?: string, 799 + * locale?: string, 800 + * format?: string, 801 + * utf8?: bool, 802 + * stateless?: bool, 803 + * } 804 + * @psalm-type AliasConfig = array{ 805 + * alias: string, 806 + * deprecated?: array{package:string, version:string, message?:string}, 807 + * } 808 + * @psalm-type RoutesConfig = array{ 809 + * "when@dev"?: array<string, RouteConfig|ImportConfig|AliasConfig>, 810 + * "when@prod"?: array<string, RouteConfig|ImportConfig|AliasConfig>, 811 + * "when@test"?: array<string, RouteConfig|ImportConfig|AliasConfig>, 812 + * ...<string, RouteConfig|ImportConfig|AliasConfig> 813 + * } 814 + */ 815 + final class Routes 816 + { 817 + /** 818 + * @param RoutesConfig $config 819 + * 820 + * @psalm-return RoutesConfig 821 + */ 822 + public static function config(array $config): array 823 + { 824 + return $config; 825 + } 826 + }
+11
application/config/routes.yaml
··· 1 + # yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json 2 + 3 + # This file is the entry point to configure the routes of your app. 4 + # Methods with the #[Route] attribute are automatically imported. 5 + # See also https://symfony.com/doc/current/routing.html 6 + 7 + # To list all registered routes, run the following command: 8 + # bin/console debug:router 9 + 10 + controllers: 11 + resource: routing.controllers
+4
application/config/routes/framework.yaml
··· 1 + when@dev: 2 + _errors: 3 + resource: '@FrameworkBundle/Resources/config/routing/errors.php' 4 + prefix: /_error
+23
application/config/services.yaml
··· 1 + # yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json 2 + 3 + # This file is the entry point to configure your own services. 4 + # Files in the packages/ subdirectory configure your dependencies. 5 + # See also https://symfony.com/doc/current/service_container/import.html 6 + 7 + # Put parameters here that don't need to change on each machine where the app is deployed 8 + # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration 9 + parameters: 10 + 11 + services: 12 + # default configuration for services in *this* file 13 + _defaults: 14 + autowire: true # Automatically injects dependencies in your services. 15 + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 16 + 17 + # makes classes in src/ available to be used as services 18 + # this creates a service per class whose id is the fully-qualified class name 19 + App\: 20 + resource: '../src/' 21 + 22 + # add more service definitions when explicit configuration is needed 23 + # please note that last definitions always *replace* previous ones
+6
application/dagger-module.toml
··· 1 + name = "application" 2 + engineVersion = "v0.20.5" 3 + source = ".dagger" 4 + 5 + [runtime] 6 + source = "dang"
+371
application/docs/agents.md
··· 1 + # Using AI coding agents 2 + 3 + This project ships a [Dev Container](https://containers.dev/) ready for AI coding agents. 4 + No agent is installed by default: you pick one, add it to `.devcontainer/devcontainer.json`, 5 + and rebuild the container. The recommended agent is [OpenCode](https://opencode.ai), which is 6 + open source and works with both local and remote models. 7 + 8 + You can run an agent against a model on your own machine (no data leaves your computer) or 9 + against a remote provider. An optional [network firewall](#optional-network-sandbox) restricts 10 + the container's outbound traffic when you let an agent run autonomously. 11 + 12 + ## Prerequisites 13 + 14 + - [Docker Engine](https://docs.docker.com/engine/) (or any Docker-compatible runtime) 15 + - [A _Development Container_-compatible editor](https://containers.dev/supporting#editors) (Visual Studio Code, PhpStorm, Emacs...) 16 + 17 + In Visual Studio Code, after editing `.devcontainer/devcontainer.json`, run **Dev Containers: Rebuild Container** from 18 + the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) to apply the change. 19 + 20 + ## OpenCode (recommended) 21 + 22 + There is no official Dev Container feature for OpenCode yet, so install the CLI from the 23 + `postCreateCommand` and add the Visual Studio Code extension. Edit `.devcontainer/devcontainer.json`: 24 + 25 + ```jsonc 26 + { 27 + // Install the CLI on container creation (alongside the existing intelephense install) 28 + "postCreateCommand": "npm install -g intelephense && curl -fsSL https://opencode.ai/install | bash", 29 + "customizations": { 30 + "vscode": { 31 + "extensions": [ 32 + "sst-dev.opencode", 33 + "bmewburn.vscode-intelephense-client", 34 + "xdebug.php-debug", 35 + ], 36 + }, 37 + }, 38 + } 39 + ``` 40 + 41 + Rebuild the container, then run `opencode` in the integrated terminal or open the OpenCode panel. 42 + 43 + ### Using a local model 44 + 45 + Run [Ollama](https://ollama.com) (FOSS) or [LM Studio](https://lmstudio.ai) (proprietary) on your host machine. The 46 + Dev Container reaches the host through `host.docker.internal`, which is already mapped in 47 + `compose.override.yaml`. No internet access is required, and this keeps working with the 48 + [firewall](#optional-network-sandbox) enabled (private networks and the host gateway are allowed). 49 + 50 + Point OpenCode at the host endpoint, for example Ollama on its default port: 51 + 52 + ```console 53 + http://host.docker.internal:11434 54 + ``` 55 + 56 + LM Studio listens on `http://host.docker.internal:1234` by default. See the 57 + [OpenCode providers documentation](https://opencode.ai/docs/providers/) for the exact 58 + configuration. 59 + 60 + ### Using a remote model 61 + 62 + Set the API key for your provider (Anthropic, OpenAI, OpenRouter, etc.) as documented by 63 + OpenCode. With the [firewall](#optional-network-sandbox) enabled, add the provider's API domain 64 + to the allowlist. 65 + 66 + ## Claude Code 67 + 68 + Install [Claude Code](https://claude.ai/claude-code) (proprietary) through a Dev Container feature and add its 69 + Visual Studio Code extension. Edit `.devcontainer/devcontainer.json`: 70 + 71 + ```jsonc 72 + { 73 + "features": { 74 + "ghcr.io/devcontainers/features/node:1": {}, 75 + "ghcr.io/devcontainers-extra/features/claude-code:2": {}, 76 + }, 77 + "customizations": { 78 + "vscode": { 79 + "extensions": [ 80 + "anthropic.claude-code", 81 + "bmewburn.vscode-intelephense-client", 82 + "xdebug.php-debug", 83 + ], 84 + }, 85 + }, 86 + } 87 + ``` 88 + 89 + Rebuild the container, then run `claude` in the integrated terminal or open the Claude Code panel. 90 + 91 + Without the firewall, this is all you need. To let Claude Code run autonomously, enable the 92 + [network sandbox](#optional-network-sandbox) first and add `anthropic.com`, `sentry.io`, and 93 + `statsig.com` to the allowlist. 94 + 95 + ## Optional: network sandbox 96 + 97 + Letting an agent edit files and run commands without confirmation (autonomous, or "YOLO", mode) 98 + is convenient but unguarded. Pair it with a firewall that restricts the container's outbound 99 + traffic to a short allowlist. Only run an agent autonomously with the firewall on. 100 + 101 + ### 1. Add the required tools to the dev image 102 + 103 + Edit the `frankenphp_dev` stage in the `Dockerfile`: 104 + 105 + ```dockerfile 106 + # hadolint ignore=DL3008 107 + RUN <<-EOF 108 + mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 109 + apt-get update 110 + apt-get install -y --no-install-recommends \ 111 + aggregate \ 112 + curl \ 113 + dnsmasq \ 114 + dnsutils \ 115 + iproute2 \ 116 + ipset \ 117 + iptables \ 118 + jq \ 119 + sudo 120 + install-php-extensions xdebug 121 + rm -rf /var/lib/apt/lists/* 122 + useradd -m -s /bin/bash nonroot 123 + # Allow nonroot to run only the firewall script as root, without a password 124 + echo "nonroot ALL=(root) NOPASSWD: /app/.devcontainer/init-firewall.sh" > /etc/sudoers.d/init-firewall 125 + chmod 0440 /etc/sudoers.d/init-firewall 126 + git config --system --add safe.directory /app 127 + EOF 128 + ``` 129 + 130 + ### 2. Grant the firewall capability 131 + 132 + The firewall needs `NET_ADMIN`. Add it to the `php` service in 133 + `.devcontainer/compose.devcontainer.yaml`: 134 + 135 + ```yaml 136 + services: 137 + php: 138 + cap_add: 139 + - NET_ADMIN 140 + ``` 141 + 142 + ### 3. Add the firewall script 143 + 144 + Save the following as `.devcontainer/init-firewall.sh`. It uses `iptables` and `ipset` to drop 145 + all outbound traffic except the allowlisted domains, and [dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html) 146 + to resolve those domains dynamically so CDN IP rotation is handled gracefully. 147 + 148 + ```bash 149 + #!/bin/bash 150 + # Locks down outbound network access to an allowlist using iptables + ipset. 151 + # dnsmasq intercepts DNS queries and adds the resolved IPs for allowed domains 152 + # to the ipset dynamically, so the ipset stays current despite CDN IP rotation. 153 + set -euo pipefail 154 + IFS=$'\n\t' 155 + 156 + # 1. Extract Docker DNS info BEFORE any flushing 157 + DOCKER_DNS_RULES=$(iptables-save -t nat | grep "127\.0\.0\.11" || true) 158 + 159 + # Flush existing rules and delete existing ipsets 160 + iptables -F 161 + iptables -X 162 + iptables -t nat -F 163 + iptables -t nat -X 164 + iptables -t mangle -F 165 + iptables -t mangle -X 166 + ipset destroy allowed-domains 2>/dev/null || true 167 + 168 + # 2. Selectively restore ONLY internal Docker DNS resolution 169 + # These rules redirect queries to 127.0.0.11:53 to Docker's actual DNS port. 170 + # These are restored first; later, our DNS redirect rules are inserted with 171 + # `iptables -t nat -I OUTPUT ...`, so they precede these Docker rules. Only 172 + # dnsmasq's upstream queries (which are exempt from our redirect) pass through them. 173 + if [ -n "$DOCKER_DNS_RULES" ]; then 174 + echo "Restoring Docker DNS rules..." 175 + iptables -t nat -N DOCKER_OUTPUT 2>/dev/null || true 176 + iptables -t nat -N DOCKER_POSTROUTING 2>/dev/null || true 177 + echo "$DOCKER_DNS_RULES" | xargs -L 1 iptables -t nat 178 + else 179 + echo "No Docker DNS rules to restore" 180 + fi 181 + 182 + # Allow DNS (outbound only; return traffic is handled by ESTABLISHED,RELATED) 183 + # and localhost (covers dnsmasq ↔ Docker DNS on 127.0.0.11). 184 + iptables -A OUTPUT -p udp --dport 53 -j ACCEPT 185 + iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT 186 + iptables -A INPUT -i lo -j ACCEPT 187 + iptables -A OUTPUT -o lo -j ACCEPT 188 + 189 + # Create ipset with CIDR support 190 + ipset create allowed-domains hash:net 191 + 192 + # GitHub IP ranges 193 + echo "Fetching GitHub IP ranges..." 194 + gh_ranges=$(curl -s --connect-timeout 10 --max-time 30 --fail https://api.github.com/meta) 195 + [ -z "$gh_ranges" ] && { 196 + echo "ERROR: Failed to fetch GitHub IP ranges" 197 + exit 1 198 + } 199 + echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null || 200 + { 201 + echo "ERROR: GitHub API response missing required fields" 202 + exit 1 203 + } 204 + 205 + while read -r cidr; do 206 + [[ "$cidr" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]] || 207 + { 208 + echo "ERROR: Invalid CIDR: $cidr" 209 + exit 1 210 + } 211 + echo "Adding GitHub range $cidr" 212 + ipset add allowed-domains "$cidr" -exist 213 + done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | grep -v ':' | aggregate -q) 214 + 215 + # Extract Docker's actual DNS port so dnsmasq can connect to it directly. 216 + # Docker's embedded DNS listens on a random high port and uses iptables NAT to 217 + # redirect 127.0.0.11:53 → 127.0.0.11:<port>. By pointing dnsmasq at the real 218 + # port, its upstream queries naturally bypass our port-53 DNAT rules (no 219 + # uid-owner tricks needed) and don't require the DOCKER_OUTPUT NAT chain. 220 + DOCKER_DNS_PORT=$(echo "$DOCKER_DNS_RULES" | sed -n 's/.*udp.*--to-destination 127\.0\.0\.11:\([0-9]*\).*/\1/p' | head -1) 221 + [ -z "$DOCKER_DNS_PORT" ] && { 222 + echo "ERROR: Failed to extract Docker DNS port" 223 + exit 1 224 + } 225 + echo "Docker DNS port: $DOCKER_DNS_PORT" 226 + 227 + # Configure dnsmasq to dynamically populate the ipset as domains are resolved. 228 + # This means the ipset always contains current IPs regardless of CDN rotation — 229 + # the IP is added to the ipset the moment it is resolved, before the connection 230 + # is made, so no connection is ever blocked due to stale IPs. 231 + # Add your agent's provider domain here (e.g. anthropic.com, api.openai.com). 232 + cat >/etc/dnsmasq.d/firewall-ipset.conf <<EOF 233 + # Forward all queries to Docker's embedded DNS (actual port, not 53) 234 + server=127.0.0.11#${DOCKER_DNS_PORT} 235 + # Listen only on an alternate loopback address to avoid conflicting with 236 + # any existing resolver on 127.0.0.1 237 + listen-address=127.0.0.2 238 + bind-interfaces 239 + # Populate the allowed-domains ipset with every IP returned when resolving 240 + # any of these domains (or their subdomains) 241 + ipset=/github.com/registry.npmjs.org/packagist.org/cdn.jsdelivr.net/marketplace.visualstudio.com/vscode.blob.core.windows.net/update.code.visualstudio.com/allowed-domains 242 + EOF 243 + 244 + # Ensure idempotency when run as a postStartCommand: stop any existing dnsmasq. 245 + pkill dnsmasq 2>/dev/null || true 246 + 247 + dnsmasq --conf-dir=/etc/dnsmasq.d 248 + echo "dnsmasq started" 249 + 250 + # Redirect all outbound DNS queries (port 53) through dnsmasq so it can 251 + # populate the ipset before each connection. dnsmasq's own upstream queries 252 + # go to Docker's actual DNS port (not 53), so they are unaffected by these rules. 253 + iptables -t nat -I OUTPUT -p tcp --dport 53 -j DNAT --to-destination 127.0.0.2:53 254 + iptables -t nat -I OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.2:53 255 + 256 + # Allow traffic to/from the host gateway IP 257 + HOST_IP=$(ip route | grep default | cut -d" " -f3) 258 + [ -z "$HOST_IP" ] && { 259 + echo "ERROR: Failed to detect host IP" 260 + exit 1 261 + } 262 + echo "Host gateway IP: $HOST_IP" 263 + iptables -A INPUT -s "$HOST_IP" -j ACCEPT 264 + iptables -A OUTPUT -d "$HOST_IP" -j ACCEPT 265 + 266 + # Allow inbound connections to published service ports (HTTP/HTTPS) 267 + iptables -A INPUT -p tcp --dport 80 -j ACCEPT 268 + iptables -A INPUT -p tcp --dport 443 -j ACCEPT 269 + iptables -A INPUT -p udp --dport 443 -j ACCEPT 270 + 271 + # Default DROP policies 272 + iptables -P INPUT DROP 273 + iptables -P FORWARD DROP 274 + iptables -P OUTPUT DROP 275 + 276 + # Allow established connections 277 + iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 278 + iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 279 + 280 + # Allow outbound traffic to local/private networks (e.g., Docker Compose services 281 + # and a model running on the host via host.docker.internal) 282 + iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT 283 + iptables -A OUTPUT -d 172.16.0.0/12 -j ACCEPT 284 + iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT 285 + 286 + # Allow outbound to whitelisted IPs only (GitHub CIDRs + IPs populated by dnsmasq) 287 + iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT 288 + 289 + # Reject everything else with immediate feedback 290 + iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited 291 + 292 + echo "Firewall configuration complete" 293 + 294 + # Verify 295 + if curl --connect-timeout 5 https://example.com >/dev/null 2>&1; then 296 + echo "ERROR: Firewall check failed — able to reach example.com" 297 + exit 1 298 + else 299 + echo "OK: example.com is blocked" 300 + fi 301 + 302 + if ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then 303 + echo "ERROR: Firewall check failed — unable to reach api.github.com" 304 + exit 1 305 + else 306 + echo "OK: api.github.com is reachable" 307 + fi 308 + ``` 309 + 310 + ### 4. Run the firewall on container start 311 + 312 + Add a `postStartCommand` to `.devcontainer/devcontainer.json`: 313 + 314 + ```jsonc 315 + { 316 + "postStartCommand": "sudo /app/.devcontainer/init-firewall.sh", 317 + } 318 + ``` 319 + 320 + ### 5. Enable autonomous mode 321 + 322 + With the sandbox in place, you can let the agent skip confirmation prompts. For Claude Code, add 323 + these settings to `customizations.vscode.settings` in `.devcontainer/devcontainer.json`: 324 + 325 + ```json 326 + { 327 + "claudeCode.allowDangerouslySkipPermissions": true, 328 + "claudeCode.initialPermissionMode": "bypassPermissions" 329 + } 330 + ``` 331 + 332 + Or from the terminal: 333 + 334 + ```console 335 + claude --dangerously-skip-permissions 336 + ``` 337 + 338 + The default allowlist covers GitHub, Packagist, the npm registry, jsDelivr, and the Visual Studio Code 339 + marketplace. Add any domain your agent needs (its provider API, a private registry) to the 340 + `ipset=` line in the script, then rebuild the container: 341 + 342 + ```bash 343 + # Domains are '/'-separated, ending with the ipset name 344 + ipset=/github.com/.../your-domain.com/allowed-domains 345 + ``` 346 + 347 + ## Without Visual Studio Code 348 + 349 + The Dev Container configuration works with any tool that supports the 350 + [Dev Container specification](https://containers.dev/), including: 351 + 352 + - [Dev Container CLI](https://github.com/devcontainers/cli) (`devcontainer up`) 353 + - [GitHub Codespaces](https://github.com/features/codespaces) 354 + - JetBrains IDEs (with the Dev Containers plugin) 355 + 356 + The `customizations.vscode.extensions` entries only apply to Visual Studio Code. In other 357 + editors the agent CLI still installs from `postCreateCommand`; run it from the integrated 358 + terminal, or install the editor's own extension if one exists. 359 + 360 + ## Troubleshooting 361 + 362 + ### The firewall blocks a required domain 363 + 364 + If the agent, Composer, or npm fails to reach a service, add the domain to the `ipset=` line in 365 + `.devcontainer/init-firewall.sh` and rebuild the container. 366 + 367 + ### The container fails to start 368 + 369 + Ensure Docker is running and that you have allocated enough resources (at least 2 GB of RAM). 370 + The firewall requires the `NET_ADMIN` capability, granted in 371 + `.devcontainer/compose.devcontainer.yaml`.
+61
application/docs/alpine.md
··· 1 + # Using Alpine Linux Instead of Debian 2 + 3 + By default, Symfony Docker uses Debian-based FrankenPHP Docker images. 4 + This is the recommended solution. 5 + 6 + Alternatively, it's possible to use Alpine-based images, which are smaller but 7 + are known to be slower, and have several known issues. 8 + 9 + To switch to Alpine-based images, apply the following changes to the `Dockerfile`: 10 + 11 + <!-- markdownlint-disable MD010 --> 12 + 13 + ```diff 14 + -FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream 15 + +FROM dunglas/frankenphp:1-php8.5-alpine AS frankenphp_upstream 16 + 17 + -SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 18 + +SHELL ["/bin/ash", "-euxo", "-c"] 19 + 20 + -# hadolint ignore=DL3008 21 + -RUN <<-EOF 22 + - apt-get update 23 + - apt-get install -y --no-install-recommends \ 24 + - file \ 25 + - git 26 + +# hadolint ignore=DL3018 27 + +RUN <<-EOF 28 + + apk add --no-cache \ 29 + + file \ 30 + + git 31 + install-php-extensions \ 32 + 33 + -# hadolint ignore=DL3008,SC3054,DL4006 34 + -RUN <<-'EOF' 35 + - apt-get update 36 + - apt-get install -y --no-install-recommends libtree 37 + +# hadolint ignore=DL3018,SC3054,DL4006 38 + +RUN <<-'EOF' 39 + + apk add --no-cache libtree 40 + mkdir -p /tmp/libs 41 + - BINARIES=(frankenphp php file) 42 + - for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \ 43 + + BINARIES="frankenphp php file" 44 + + for target in $(printf '%s\n' $BINARIES | xargs -I{} which {}) \ 45 + 46 + - libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do 47 + + libtree -pv "$target" 2>/dev/null | sed -n 's/.*── \(\/[^ ]*\) \[.*/\1/p' | while IFS= read -r lib; do 48 + 49 + - rm -rf /var/lib/apt/lists/* 50 + 51 + -FROM debian:13-slim AS frankenphp_prod 52 + +FROM alpine:3 AS frankenphp_prod 53 + 54 + -SHELL ["/bin/bash", "-euxo", "pipefail", "-c"] 55 + +SHELL ["/bin/ash", "-euxo", "-c"] 56 + 57 + -COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc 58 + +COPY --from=frankenphp_prod_builder /usr/share/misc/magic.mgc /usr/share/misc/magic.mgc 59 + ``` 60 + 61 + <!-- markdownlint-enable MD010 -->
application/docs/digitalocean-dns.png

This is a binary file and will not be displayed.

application/docs/digitalocean-droplet.png

This is a binary file and will not be displayed.

+81
application/docs/existing-project.md
··· 1 + # Installing on an Existing Project 2 + 3 + It's also possible to use Symfony Docker with existing projects! 4 + 5 + First, [download this skeleton](https://github.com/dunglas/symfony-docker). 6 + 7 + If you cloned the Git repository, be sure to not copy the `.git` directory 8 + to prevent conflicts with the `.git` directory already in your existing project. 9 + 10 + You can copy the contents of the repository using Git and tar. 11 + This will not contain `.git` or any uncommitted changes. 12 + 13 + ```console 14 + git archive --format=tar HEAD | tar -xC my-existing-project/ 15 + ``` 16 + 17 + If you downloaded the skeleton as a ZIP you can just copy the extracted files: 18 + 19 + ```console 20 + cp -Rp symfony-docker/. my-existing-project/ 21 + ``` 22 + 23 + Enable the Docker support of Symfony Flex: 24 + 25 + ```console 26 + composer config --json extra.symfony.docker 'true' 27 + ``` 28 + 29 + The [worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/) is enabled by default. 30 + To use it with Symfony ≤ 7.3, install the FrankenPHP runtime: 31 + 32 + ```console 33 + composer require runtime/frankenphp-symfony 34 + ``` 35 + 36 + Then update worker configuration: 37 + 38 + <!-- markdownlint-disable MD010 --> 39 + 40 + ```diff 41 + worker { 42 + file ./public/index.php 43 + + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime 44 + {$FRANKENPHP_WORKER_CONFIG} 45 + } 46 + ``` 47 + 48 + <!-- markdownlint-enable MD010 --> 49 + 50 + > [!TIP] 51 + > 52 + > You can disable worker mode by removing the `worker` directive from the `frankenphp` 53 + > global option in your `Caddyfile`. 54 + 55 + Re-execute the recipes to update the Docker-related files according to 56 + the packages you use: 57 + 58 + ```console 59 + rm symfony.lock 60 + composer recipes:install --force --verbose 61 + ``` 62 + 63 + Double-check the changes, revert the changes that you don't want to keep: 64 + 65 + ```console 66 + git diff 67 + ``` 68 + 69 + Build the Docker images: 70 + 71 + ```console 72 + docker compose build --pull --no-cache 73 + ``` 74 + 75 + Start the project! 76 + 77 + ```console 78 + docker compose up --wait 79 + ``` 80 + 81 + Browse `https://localhost`, your Docker configuration is ready!
+25
application/docs/extra-services.md
··· 1 + # Support for Extra Services 2 + 3 + Symfony Docker is extensible. 4 + When you install a compatible Composer package using Symfony Flex, 5 + the recipe will automatically modify the `Dockerfile` and `compose.yaml` files 6 + to fulfill the requirements of this package. 7 + 8 + The currently supported packages are: 9 + 10 + - `symfony/orm-pack`: install a PostgreSQL service 11 + - `symfony/mercure-bundle`: use the Mercure.rocks module shipped with Caddy 12 + - `symfony/panther`: install Chromium and its drivers 13 + - `symfony/mailer`: install a Mailpit service 14 + - `blackfireio/blackfire-symfony-meta`: install a Blackfire service 15 + 16 + > [!NOTE] 17 + > 18 + > If a recipe modifies the Dockerfile, the container needs to be rebuilt. 19 + 20 + <!-- --> 21 + 22 + > [!WARNING] 23 + > 24 + > We recommend that you use the `composer require` command inside the container 25 + > in development mode so that recipes can be applied correctly.
+129
application/docs/makefile.md
··· 1 + # Makefile 2 + 3 + Here is a Makefile template. It provides some shortcuts for the most common tasks. 4 + To use it, create a new `Makefile` file at the root of your project. Copy/paste 5 + the content in the template section. To view all the available commands, run `make`. 6 + 7 + For example, in the [getting started section](/README.md#getting-started), the 8 + `docker compose` commands could be replaced by: 9 + 10 + 1. Run `make build` to build fresh images 11 + 2. Run `make up` (detached mode without logs) 12 + 3. Run `make down` to stop the Docker containers 13 + 14 + Of course, this template is basic for now. But, as your application is growing, 15 + you will probably want to add some targets like running your tests as described 16 + in [the Symfony book](https://symfony.com/doc/current/the-fast-track/en/17-tests.html#automating-your-workflow-with-a-makefile). 17 + You can also find a more complete example in this [snippet](https://www.strangebuzz.com/en/snippets/the-perfect-makefile-for-symfony). 18 + 19 + If you want to run make from within the `php` container, in the [Dockerfile](/Dockerfile), 20 + add: 21 + 22 + <!-- markdownlint-disable MD010 --> 23 + 24 + ```diff 25 + gettext \ 26 + git \ 27 + + make \ 28 + ``` 29 + 30 + <!-- markdownlint-enable MD010 --> 31 + 32 + And rebuild the PHP image. 33 + 34 + > [!NOTE] 35 + > 36 + > If you are using Windows, you have to install [chocolatey.org](https://chocolatey.org/) 37 + > or [Cygwin](http://cygwin.com) to use the `make` command. 38 + > 39 + > Check out this [StackOverflow question](https://stackoverflow.com/q/2532234/633864) 40 + > for more explanations. 41 + 42 + ## The Template 43 + 44 + <!-- markdownlint-disable MD010 MD013 --> 45 + 46 + ```Makefile 47 + # Executables (local) 48 + DOCKER_COMP = docker compose 49 + 50 + # Docker containers 51 + PHP_CONT = $(DOCKER_COMP) exec php 52 + 53 + # Executables 54 + PHP = $(PHP_CONT) php 55 + COMPOSER = $(PHP_CONT) composer 56 + SYMFONY = $(PHP) bin/console 57 + 58 + # Misc 59 + .DEFAULT_GOAL = help 60 + .PHONY : help build up start down logs sh composer vendor sf cc test 61 + 62 + ## —— 🎵 🐳 The Symfony Docker Makefile 🐳 🎵 —————————————————————————————————— 63 + help: ## Outputs this help screen 64 + @grep -E '(^[a-zA-Z0-9\./_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}{printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' 65 + 66 + ## —— Docker 🐳 ———————————————————————————————————————————————————————————————— 67 + build: ## Builds the Docker images 68 + @$(DOCKER_COMP) build --pull --no-cache 69 + 70 + up: ## Start the docker hub in detached mode (no logs) 71 + @$(DOCKER_COMP) up --detach 72 + 73 + start: build up ## Build and start the containers 74 + 75 + down: ## Stop the docker hub 76 + @$(DOCKER_COMP) down --remove-orphans 77 + 78 + logs: ## Show live logs 79 + @$(DOCKER_COMP) logs --tail=0 --follow 80 + 81 + sh: ## Connect to the FrankenPHP container 82 + @$(PHP_CONT) sh 83 + 84 + bash: ## Connect to the FrankenPHP container via bash so up and down arrows go to previous commands 85 + @$(PHP_CONT) bash 86 + 87 + test: ## Start tests with phpunit, pass the parameter "c=" to add options to phpunit, example: make test c="--group e2e --stop-on-failure" 88 + @$(eval c ?=) 89 + @$(DOCKER_COMP) exec -e APP_ENV=test php bin/phpunit $(c) 90 + 91 + 92 + ## —— Composer 🧙 —————————————————————————————————————————————————————————————— 93 + composer: ## Run composer, pass the parameter "c=" to run a given command, example: make composer c='req symfony/orm-pack' 94 + @$(eval c ?=) 95 + @$(COMPOSER) $(c) 96 + 97 + vendor: ## Install vendors according to the current composer.lock file 98 + vendor: c=install --prefer-dist --no-dev --no-progress --no-scripts --no-interaction 99 + vendor: composer 100 + 101 + ## —— Symfony 🎵 ——————————————————————————————————————————————————————————————— 102 + sf: ## List all Symfony commands or pass the parameter "c=" to run a given command, example: make sf c=about 103 + @$(eval c ?=) 104 + @$(SYMFONY) $(c) 105 + 106 + cc: c=c:c ## Clear the cache 107 + cc: sf 108 + ``` 109 + 110 + <!-- markdownlint-enable MD010 MD013 --> 111 + 112 + ## Adding and Modifying Jobs 113 + 114 + Make sure to add this configuration to the [.editorconfig](/.editorconfig) file, 115 + so that it forces your editor to use tabs instead of spaces. 116 + 117 + > [!NOTE] 118 + > 119 + > Makefiles are not compatible with spaces by default. 120 + 121 + ```.editorconfig 122 + 123 + [Makefile] 124 + indent_style = tab 125 + 126 + ``` 127 + 128 + If you still want to use space, you can configure the prefix in the Makefile itself. 129 + See [this answer on Stack Exchange](https://retrocomputing.stackexchange.com/a/20303).
+107
application/docs/mysql.md
··· 1 + # Using MySQL 2 + 3 + The Docker configuration of this repository is extensible thanks to Flex recipes. 4 + By default, the recipe installs PostgreSQL. 5 + 6 + If you prefer to work with MySQL, follow these steps: 7 + 8 + First, install the `symfony/orm-pack` package as described: 9 + 10 + ```console 11 + docker compose exec php composer req symfony/orm-pack 12 + ``` 13 + 14 + ## Docker Configuration 15 + 16 + Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`: 17 + 18 + <!-- markdownlint-disable MD013 --> 19 + 20 + ```diff 21 + ###> doctrine/doctrine-bundle ### 22 + - image: postgres:${POSTGRES_VERSION:-16}-alpine 23 + + image: mysql:${MYSQL_VERSION:-8.0.32} 24 + environment: 25 + - POSTGRES_DB: ${POSTGRES_DB:-app} 26 + + MYSQL_DATABASE: ${MYSQL_DATABASE:-app} 27 + # You should definitely change the password in production 28 + + MYSQL_RANDOM_ROOT_PASSWORD: "true" 29 + - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} 30 + + MYSQL_PASSWORD: ${MYSQL_PASSWORD:-!ChangeMe!} 31 + - POSTGRES_USER: ${POSTGRES_USER:-app} 32 + + MYSQL_USER: ${MYSQL_USER:-app} 33 + healthcheck: 34 + - test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"] 35 + + test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] 36 + timeout: 5s 37 + retries: 5 38 + start_period: 60s 39 + volumes: 40 + - - database_data:/var/lib/postgresql/data:rw 41 + + - database_data:/var/lib/mysql:rw 42 + # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! 43 + - # - ./docker/db/data:/var/lib/postgresql/data:rw 44 + + # - ./docker/db/data:/var/lib/mysql:rw 45 + ###< doctrine/doctrine-bundle ### 46 + ``` 47 + 48 + <!-- markdownlint-enable MD013 --> 49 + 50 + Depending on the database configuration, 51 + modify the environment in the same file at `services.php.environment.DATABASE_URL`: 52 + 53 + ```yaml 54 + DATABASE_URL: mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.32}&charset=${MYSQL_CHARSET:-utf8mb4} 55 + ``` 56 + 57 + Since we changed the port, we also have to define this in the `compose.override.yaml`: 58 + 59 + ```diff 60 + ###> doctrine/doctrine-bundle ### 61 + database: 62 + ports: 63 + - - "5432" 64 + + - "3306" 65 + ###< doctrine/doctrine-bundle ### 66 + ``` 67 + 68 + Last but not least, we need to install the MySQL driver in `Dockerfile`: 69 + 70 + ```diff 71 + ###> doctrine/doctrine-bundle ### 72 + -RUN install-php-extensions pdo_pgsql 73 + +RUN install-php-extensions pdo_mysql 74 + ###< doctrine/doctrine-bundle ### 75 + ``` 76 + 77 + ## Change Environment 78 + 79 + Change the database configuration in `.env`: 80 + 81 + ```dotenv 82 + DATABASE_URL=mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.32}&charset=${MYSQL_CHARSET:-utf8mb4} 83 + ``` 84 + 85 + ## Final steps 86 + 87 + Rebuild the Docker environment: 88 + 89 + ```console 90 + docker compose down --remove-orphans && docker compose build --pull --no-cache 91 + ``` 92 + 93 + Start the services: 94 + 95 + ```console 96 + docker compose up --wait 97 + ``` 98 + 99 + Test your setup: 100 + 101 + <!-- markdownlint-disable MD013 --> 102 + 103 + ```console 104 + docker compose exec php bin/console dbal:run-sql -q "SELECT 1" && echo "OK" || echo "Connection is not working" 105 + ``` 106 + 107 + <!-- markdownlint-enable MD013 -->
+121
application/docs/options.md
··· 1 + # Docker Build Options 2 + 3 + You can customize the Docker build process using these environment variables. 4 + 5 + > [!NOTE] 6 + > 7 + > All Symfony-specific environment variables are used only if no `composer.json` 8 + > file is found in the project directory. 9 + 10 + ## Selecting a Specific Symfony Version 11 + 12 + Use the `SYMFONY_VERSION` environment variable to select a specific Symfony version. 13 + 14 + For instance, use the following command to install Symfony 6.4: 15 + 16 + On Linux: 17 + 18 + ```console 19 + SYMFONY_VERSION=6.4.* docker compose up --wait 20 + ``` 21 + 22 + On Windows: 23 + 24 + ```console 25 + set SYMFONY_VERSION=6.4.* && docker compose up --wait&set SYMFONY_VERSION= 26 + ``` 27 + 28 + <!-- markdownlint-disable MD010 --> 29 + 30 + > [!NOTE] 31 + > 32 + > If you're using Symfony 7.3 or earlier with FrankenPHP in worker mode, you also need to follow these steps 33 + > 34 + > ```console 35 + > composer require runtime/frankenphp-symfony 36 + > ``` 37 + > 38 + > Add `env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime` in the `frankenphp/Caddyfile` in the `worker` section. 39 + > 40 + > ```diff 41 + > worker { 42 + > file ./public/index.php 43 + > + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime 44 + > {$FRANKENPHP_WORKER_CONFIG} 45 + > } 46 + > ``` 47 + 48 + <!-- markdownlint-enable MD010 --> 49 + 50 + ## Installing Development Versions of Symfony 51 + 52 + To install a non-stable version of Symfony, 53 + use the `STABILITY` environment variable during the build. 54 + 55 + The value must be [a valid Composer stability option](https://getcomposer.org/doc/04-schema.md#minimum-stability). 56 + 57 + For instance, use the following command to use the development branch of Symfony: 58 + 59 + On Linux: 60 + 61 + ```console 62 + STABILITY=dev docker compose up --wait 63 + ``` 64 + 65 + On Windows: 66 + 67 + ```console 68 + set STABILITY=dev && docker compose up --wait&set STABILITY= 69 + ``` 70 + 71 + ## Using Custom HTTP Ports 72 + 73 + Use the environment variables `HTTP_PORT`, `HTTPS_PORT` and/or `HTTP3_PORT` 74 + to adjust the ports to your needs, e.g. 75 + 76 + ```console 77 + HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --wait 78 + ``` 79 + 80 + to access your application on [https://localhost:4443](https://localhost:4443). 81 + 82 + > [!NOTE] 83 + > 84 + > Let's Encrypt only supports the standard HTTP and HTTPS ports. 85 + > Creating a Let's Encrypt certificate for another port will not work, 86 + > you have to use the standard ports or to configure Caddy to use another provider. 87 + 88 + ## `Caddyfile` Options 89 + 90 + You can also customize the `Caddyfile` by using the following environment variables 91 + to inject options block, directive or configuration. 92 + 93 + > [!TIP] 94 + > 95 + > All the following environment variables can be defined in your `.env` file 96 + > at the root of the project to keep them persistent at each startup. 97 + 98 + <!-- markdownlint-disable MD013 --> 99 + 100 + | Environment variable | Description | Default value | 101 + | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | 102 + | `CADDY_GLOBAL_OPTIONS` | the [global options block](https://caddyserver.com/docs/caddyfile/options#global-options), one per line | | 103 + | `CADDY_EXTRA_CONFIG` | the [snippet](https://caddyserver.com/docs/caddyfile/concepts#snippets) or the [named-routes](https://caddyserver.com/docs/caddyfile/concepts#named-routes) options block, one per line | | 104 + | `CADDY_SERVER_EXTRA_DIRECTIVES` | the [`Caddyfile` directives](https://caddyserver.com/docs/caddyfile/concepts#directives) | | 105 + | `CADDY_SERVER_LOG_OPTIONS` | the [server log options block](https://caddyserver.com/docs/caddyfile/directives/log), one per line | | 106 + | `SERVER_NAME` | the server name or address | `localhost` | 107 + | `FRANKENPHP_CONFIG` | a list of extra [FrankenPHP global directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | | 108 + | `FRANKENPHP_WORKER_CONFIG` | a list of extra [FrankenPHP worker directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | | 109 + | `MERCURE_PUBLISHER_JWT_KEY` | the JWT key to use for publishers | | 110 + | `MERCURE_PUBLISHER_JWT_ALG` | the JWT algorithm to use for publishers | `HS256` | 111 + | `MERCURE_SUBSCRIBER_JWT_KEY` | the JWT key to use for subscribers | | 112 + | `MERCURE_SUBSCRIBER_JWT_ALG` | the JWT algorithm to use for subscribers | `HS256` | 113 + | `MERCURE_EXTRA_DIRECTIVES` | a list of extra [Mercure directives](https://mercure.rocks/docs/hub/config), one per line | | 114 + 115 + <!-- markdownlint-enable MD013 --> 116 + 117 + ### Customizing the Server Name 118 + 119 + ```console 120 + SERVER_NAME="app.localhost" docker compose up --wait 121 + ```
+140
application/docs/production.md
··· 1 + # Deploying in Production 2 + 3 + Symfony Docker provides Docker images and a Docker Compose definition optimized 4 + for production usage. 5 + In this tutorial, we will learn how to deploy our Symfony application 6 + on a single server using Docker Compose. 7 + 8 + ## Preparing a Server 9 + 10 + To deploy your application in production, you need a server. 11 + In this tutorial, we will use a virtual machine provided by DigitalOcean, 12 + but any Linux server can work. 13 + 14 + If you already have a Linux server with Docker Compose installed, 15 + you can skip straight to [the next section](#configuring-a-domain-name). 16 + 17 + Otherwise, use [this affiliate link](https://m.do.co/c/5d8aabe3ab80) 18 + to get $100 of free credit, create an account, then click on "Create a Droplet". 19 + Then, click on the "Marketplace" tab under the "Choose an image" section 20 + and search for the app named "Docker". 21 + This will provision an Ubuntu server with the latest versions of Docker and 22 + Docker Compose already installed! 23 + 24 + For test purposes, the cheapest plans will be enough, 25 + even though you might want at least 2GB of RAM to execute Docker Compose 26 + for the first time. 27 + For real production usage, 28 + you'll probably want to pick a plan in the "general purpose" section 29 + to fit your needs. 30 + 31 + ![Deploying a Symfony app on DigitalOcean with Docker Compose](digitalocean-droplet.png) 32 + 33 + You can keep the defaults for other settings, or tweak them according to your needs. 34 + Don't forget to add your SSH key or create a password 35 + then press the "Finalize and create" button. 36 + 37 + Then, wait a few seconds while your Droplet is provisioning. 38 + When your Droplet is ready, use SSH to connect: 39 + 40 + ```console 41 + ssh root@<droplet-ip> 42 + ``` 43 + 44 + ## Configuring a Domain Name 45 + 46 + In most cases, you'll want to associate a domain name with your site. 47 + If you don't own a domain name yet, you'll have to buy one through a registrar. 48 + 49 + Then create a DNS record of type `A` for your domain name pointing 50 + to the IP address of your server: 51 + 52 + ```dns 53 + your-domain-name.example.com. IN A 207.154.233.113 54 + ``` 55 + 56 + Example with the DigitalOcean Domains service ("Networking" > "Domains"): 57 + 58 + ![Configuring DNS on DigitalOcean](digitalocean-dns.png) 59 + 60 + > [!NOTE] 61 + > 62 + > Let's Encrypt, the service used by default by Symfony Docker to automatically 63 + > generate a TLS certificate doesn't support using bare IP addresses. 64 + > Using a domain name is mandatory to use Let's Encrypt. 65 + 66 + ## Deploying 67 + 68 + Copy your project on the server using `git clone`, `scp`, or any other tool 69 + that may fit your need. 70 + If you use GitHub, you may want to use [a deploy key](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys). 71 + Deploy keys are also [supported by GitLab](https://docs.gitlab.com/user/project/deploy_keys/). 72 + 73 + Example with Git: 74 + 75 + ```console 76 + git clone git@github.com:<username>/<project-name>.git 77 + ``` 78 + 79 + Go into the directory containing your project (`<project-name>`), 80 + and start the app in production mode: 81 + 82 + ```console 83 + # Build fresh production image 84 + docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache 85 + 86 + # Start container 87 + SERVER_NAME=your-domain-name.example.com \ 88 + APP_SECRET=ChangeMe \ 89 + CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \ 90 + docker compose -f compose.yaml -f compose.prod.yaml up --wait 91 + ``` 92 + 93 + Be sure to replace `your-domain-name.example.com` with your actual domain name 94 + and to set the values of `APP_SECRET`, `CADDY_MERCURE_JWT_SECRET` 95 + to cryptographically secure random values. 96 + 97 + Your server is up and running, and a HTTPS certificate has been automatically 98 + generated for you. 99 + Go to `https://your-domain-name.example.com` and enjoy! 100 + 101 + > [!CAUTION] 102 + > 103 + > Docker can have a cache layer, make sure you have the right build 104 + > for each deployment or rebuild your project with `--no-cache` option 105 + > to avoid cache issues. 106 + 107 + ## Disabling HTTPS 108 + 109 + Alternatively, if you don't want to expose an HTTPS server but only an HTTP one, 110 + run the following command: 111 + 112 + ```console 113 + SERVER_NAME=:80 \ 114 + APP_SECRET=ChangeMe \ 115 + CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \ 116 + docker compose -f compose.yaml -f compose.prod.yaml up --wait 117 + ``` 118 + 119 + ## Deploying on Multiple Nodes 120 + 121 + If you want to deploy your app on a cluster of machines, you can use [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/), 122 + which is compatible with the provided Compose files. 123 + To deploy on Kubernetes, take a look 124 + at [the Helm chart provided with API Platform](https://api-platform.com/docs/deployment/kubernetes/), 125 + which can be easily adapted for use with Symfony Docker. 126 + 127 + ## Passing local environment variables to containers 128 + 129 + By default, `.env.local` and `.env.*.local` files are excluded from production images. 130 + If you want to pass them to your containers, you can use the [`env_file` attribute](https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/#use-the-env_file-attribute): 131 + 132 + ```yaml 133 + # compose.prod.yaml 134 + 135 + services: 136 + php: 137 + env_file: 138 + - .env.prod.local 139 + # ... 140 + ```
+88
application/docs/tls.md
··· 1 + # TLS Certificates 2 + 3 + ## Trusting the Authority 4 + 5 + With a standard installation, the authority used to sign certificates 6 + generated in the Caddy container is not trusted by your local machine. 7 + 8 + You must add the authority to the trust store of the host. 9 + 10 + <!-- markdownlint-disable MD013 --> 11 + 12 + ### Linux 13 + 14 + ```console 15 + docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates 16 + ``` 17 + 18 + ### Mac 19 + 20 + ```console 21 + docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /tmp/root.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt 22 + ``` 23 + 24 + ### Windows 25 + 26 + ```console 27 + docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt 28 + ``` 29 + 30 + <!-- markdownlint-enable MD013 --> 31 + 32 + ## Using Custom TLS Certificates 33 + 34 + By default, Caddy will automatically generate TLS certificates using Let's Encrypt 35 + or ZeroSSL. 36 + But sometimes you may prefer using custom certificates. 37 + 38 + For instance, to use self-signed certificates created with [mkcert](https://github.com/FiloSottile/mkcert) 39 + do as follows: 40 + 41 + 1. Locally install `mkcert` 42 + 2. Create the folder storing the certs: 43 + 44 + ```console 45 + mkdir -p frankenphp/certs 46 + ``` 47 + 48 + 3. Generate the certificates for your local host (example: "server-name.localhost"): 49 + 50 + <!-- markdownlint-disable MD013 --> 51 + 52 + ```console 53 + mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost" 54 + ``` 55 + 56 + <!-- markdownlint-enable MD013 --> 57 + 58 + 4. Add these lines to the `./compose.override.yaml` file about `CADDY_SERVER_EXTRA_DIRECTIVES` 59 + environment and volume for the `php` service: 60 + 61 + ```diff 62 + php: 63 + environment: 64 + + CADDY_EXTRA_CONFIG: | 65 + + https:// { 66 + + tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key 67 + + } 68 + # ... 69 + volumes: 70 + + - ./frankenphp/certs:/etc/caddy/certs:ro 71 + # ... 72 + ``` 73 + 74 + 5. Restart your `php` service 75 + 76 + ## Disabling HTTPS for Local Development 77 + 78 + To disable HTTPS, configure your environment to use HTTP by setting the following 79 + variables and starting the project with this command: 80 + 81 + ```console 82 + SERVER_NAME=http://localhost \ 83 + MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ 84 + docker compose up --wait 85 + ``` 86 + 87 + Ensure your application is accessible over HTTP by visiting `http://localhost` 88 + in your web browser.
+53
application/docs/troubleshooting.md
··· 1 + # Troubleshooting 2 + 3 + ## Editing Permissions on Linux 4 + 5 + If you work on Linux and cannot edit some of the project files right after 6 + the first installation, you can run the following command 7 + to set yourself as owner of the project files that were created by the Docker container: 8 + 9 + ```console 10 + docker compose run --rm php chown -R $(id -u):$(id -g) . 11 + ``` 12 + 13 + ## TLS/HTTPS Issues 14 + 15 + See the [TLS section](tls.md) for more details. 16 + 17 + ## Production Issues 18 + 19 + ### How To Properly Build Fresh Images for Production Use 20 + 21 + Remember that, by default, if you run `docker compose up --wait`, 22 + only the files `compose.yaml` and `compose.override.yaml` will be used. 23 + See ["How Compose works"](https://docs.docker.com/compose/intro/compose-application-model) 24 + and ["Merge Compose files"](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge). 25 + 26 + If you need to build images for production environment, you have to use the following 27 + command: 28 + 29 + ```console 30 + docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache 31 + ``` 32 + 33 + ### Building Dev and Prod Images 34 + 35 + Dev and prod images use distinct image names (`app-php-dev` and `app-php-prod`), 36 + so they won't conflict with each other. 37 + 38 + To build and start the dev image: 39 + 40 + ```console 41 + docker compose up --wait 42 + ``` 43 + 44 + To build and start the prod image: 45 + 46 + ```console 47 + docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache 48 + docker compose -f compose.yaml -f compose.prod.yaml up --wait 49 + ``` 50 + 51 + > [!WARNING] 52 + > 53 + > The order of `-f` arguments matters.
+19
application/docs/updating.md
··· 1 + # Updating Your Project 2 + 3 + To import the changes made to the _Symfony Docker_ template into your project, 4 + we recommend using [_template-sync_](https://github.com/coopTilleuls/template-sync): 5 + 6 + 1. Run the script to synchronize your project with the latest version of the skeleton: 7 + 8 + <!-- markdownlint-disable MD013 --> 9 + 10 + ```console 11 + curl -sSL https://raw.githubusercontent.com/coopTilleuls/template-sync/main/template-sync.sh | sh -s -- https://github.com/dunglas/symfony-docker 12 + ``` 13 + 14 + <!-- markdownlint-enable MD013 --> 15 + 16 + 2. Resolve conflicts, if any 17 + 3. Run `git cherry-pick --continue` 18 + 19 + For more advanced options, refer to [the documentation of _template sync_](https://github.com/coopTilleuls/template-sync#template-sync).
+98
application/docs/xdebug.md
··· 1 + # Using Xdebug 2 + 3 + The default development image is shipped with [Xdebug](https://xdebug.org/), 4 + a popular debugger and profiler for PHP. 5 + 6 + When using [Dev Containers](https://containers.dev/), Xdebug is pre-configured and works out of the box. 7 + Open the **Run and Debug** panel in Visual Studio Code and start the **Debug PHP** launch configuration, then set your breakpoints and load a page. 8 + 9 + For other setups, because it has a significant performance overhead, the step-by-step debugger 10 + is disabled by default. 11 + It can be enabled by including `debug` in the values of the `XDEBUG_MODE` environment variable. 12 + 13 + On Linux and Mac: 14 + 15 + ```console 16 + XDEBUG_MODE=develop,debug docker compose up --wait 17 + ``` 18 + 19 + On Windows: 20 + 21 + ```console 22 + set XDEBUG_MODE=develop,debug&& docker compose up --wait&set XDEBUG_MODE= 23 + ``` 24 + 25 + ## Debugging with Xdebug and PhpStorm 26 + 27 + First, [create a PHP debug remote server configuration](https://www.jetbrains.com/help/phpstorm/creating-a-php-debug-server-configuration.html): 28 + 29 + 1. In the `Settings/Preferences` dialog, go to `PHP | Servers` 30 + 2. Create a new server: 31 + - Name: `symfony` (or whatever you want to use for the variable `PHP_IDE_CONFIG`) 32 + - Host: `localhost` (or the one defined using the `SERVER_NAME` environment variable) 33 + - Port: `443` 34 + - Debugger: `Xdebug` 35 + - Check `Use path mappings` 36 + - Absolute path on the server: `/app` 37 + 38 + You can now use the debugger! 39 + 40 + 1. In PhpStorm, open the `Run` menu and click on `Start Listening for PHP Debug Connections` 41 + 2. Add the `XDEBUG_SESSION=PHPSTORM` query parameter to the URL of 42 + the page you want to debug, or use [other available triggers](https://xdebug.org/docs/step_debug#activate_debugger) 43 + 44 + Alternatively, you can use [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) 45 + for your preferred web browser. 46 + 47 + 3. On the command line, we might need to tell PhpStorm which 48 + [path mapping configuration](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging-cli.html#configure-path-mappings) 49 + should be used, set the value of the PHP_IDE_CONFIG environment variable to 50 + `serverName=symfony`, where `symfony` is the name of the debug server configured 51 + above. 52 + 53 + Example: 54 + 55 + ```console 56 + XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=symfony" php bin/console ... 57 + ``` 58 + 59 + ## Debugging with Xdebug and Visual Studio Code 60 + 61 + 1. Install necessary [PHP extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=DEVSENSE.phptools-vscode). 62 + 2. Add [debug configuration](https://code.visualstudio.com/docs/debugtest/debugging-configuration#_launch-configurations) 63 + into your `.vscode\launch.json` file. 64 + 65 + Example: 66 + 67 + ```json 68 + { 69 + "version": "0.2.0", 70 + "configurations": [ 71 + { 72 + "name": "Debug PHP", 73 + "type": "php", 74 + "request": "launch", 75 + "pathMappings": { 76 + "/app": "${workspaceFolder}" 77 + } 78 + } 79 + ] 80 + } 81 + ``` 82 + 83 + 3. Use [Run and Debug](https://code.visualstudio.com/docs/debugtest/debugging#_start-a-debugging-session) 84 + options and run `Debug PHP` to listen for upcoming connections 85 + with [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions) 86 + installed and active. 87 + 88 + ## Troubleshooting 89 + 90 + Inspect the installation with the following command. 91 + The Xdebug version should be displayed. 92 + 93 + ```console 94 + $ docker compose exec php php --version 95 + 96 + PHP ... 97 + with Xdebug v3.x.x ... 98 + ```
+66
application/frankenphp/Caddyfile
··· 1 + { 2 + skip_install_trust 3 + 4 + {$CADDY_GLOBAL_OPTIONS} 5 + 6 + frankenphp { 7 + {$FRANKENPHP_CONFIG} 8 + } 9 + } 10 + 11 + {$CADDY_EXTRA_CONFIG} 12 + 13 + {$SERVER_NAME:localhost} { 14 + log { 15 + {$CADDY_SERVER_LOG_OPTIONS} 16 + # Redact the authorization query parameter that can be set by Mercure 17 + format filter { 18 + request>uri query { 19 + replace authorization REDACTED 20 + } 21 + } 22 + } 23 + 24 + root /app/public 25 + encode zstd br gzip 26 + 27 + mercure { 28 + # Publisher JWT key 29 + publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG} 30 + # Subscriber JWT key 31 + subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG} 32 + # Allow anonymous subscribers (double-check that it's what you want) 33 + anonymous 34 + # Enable the subscription API (double-check that it's what you want) 35 + subscriptions 36 + # Extra directives 37 + {$MERCURE_EXTRA_DIRECTIVES} 38 + } 39 + 40 + vulcain 41 + 42 + {$CADDY_SERVER_EXTRA_DIRECTIVES} 43 + 44 + # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics 45 + header ?Permissions-Policy "browsing-topics=()" 46 + 47 + @phpRoute { 48 + not path /.well-known/mercure* 49 + not file {path} 50 + } 51 + rewrite @phpRoute index.php 52 + 53 + @frontController path index.php 54 + php @frontController { 55 + {$FRANKENPHP_SITE_CONFIG} 56 + 57 + worker { 58 + file ./public/index.php 59 + {$FRANKENPHP_WORKER_CONFIG} 60 + } 61 + } 62 + 63 + file_server { 64 + hide *.php 65 + } 66 + }
+13
application/frankenphp/conf.d/10-app.ini
··· 1 + expose_php = 0 2 + date.timezone = UTC 3 + apc.enable_cli = 1 4 + session.use_strict_mode = 1 5 + zend.detect_unicode = 0 6 + 7 + ; https://symfony.com/doc/current/performance.html 8 + realpath_cache_size = 4096K 9 + realpath_cache_ttl = 600 10 + opcache.interned_strings_buffer = 16 11 + opcache.max_accelerated_files = 32531 12 + opcache.memory_consumption = 256 13 + opcache.enable_file_override = 1
+5
application/frankenphp/conf.d/20-app.dev.ini
··· 1 + ; See https://docs.docker.com/desktop/features/networking/networking-how-tos/#connect-a-container-to-a-service-on-the-host 2 + ; See https://github.com/docker/for-linux/issues/264 3 + ; The `client_host` below may optionally be replaced with `discover_client_host=yes` 4 + ; Add `start_with_request=yes` to start debug session on each request 5 + xdebug.client_host = host.docker.internal
+5
application/frankenphp/conf.d/20-app.prod.ini
··· 1 + ; https://symfony.com/doc/current/performance.html#use-the-opcache-class-preloading 2 + opcache.preload_user = www-data 3 + opcache.preload = /app/config/preload.php 4 + ; https://symfony.com/doc/current/performance.html#don-t-check-php-files-timestamps 5 + opcache.validate_timestamps = 0
+44
application/frankenphp/docker-entrypoint.sh
··· 1 + #!/bin/sh 2 + set -e 3 + 4 + if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then 5 + 6 + if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then 7 + composer install --prefer-dist --no-progress --no-interaction 8 + fi 9 + 10 + # Display information about the current project 11 + # Or about an error in project initialization 12 + php bin/console -V 13 + 14 + if grep -q ^DATABASE_URL= .env; then 15 + echo 'Waiting for database to be ready...' 16 + ATTEMPTS_LEFT_TO_REACH_DATABASE=60 17 + until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do 18 + if [ $? -eq 255 ]; then 19 + # If the Doctrine command exits with 255, an unrecoverable error occurred 20 + ATTEMPTS_LEFT_TO_REACH_DATABASE=0 21 + break 22 + fi 23 + sleep 1 24 + ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1)) 25 + echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left." 26 + done 27 + 28 + if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then 29 + echo 'The database is not up or not reachable:' 30 + echo "$DATABASE_ERROR" 31 + exit 1 32 + else 33 + echo 'The database is now ready and reachable' 34 + fi 35 + 36 + if [ "$(find ./migrations -iname '*.php' -print -quit)" ]; then 37 + php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing 38 + fi 39 + fi 40 + 41 + echo 'PHP app ready!' 42 + fi 43 + 44 + exec docker-php-entrypoint "$@"
+9
application/public/index.php
··· 1 + <?php 2 + 3 + use App\Kernel; 4 + 5 + require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; 6 + 7 + return static function (array $context) { 8 + return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); 9 + };
application/src/Controller/.gitignore

This is a binary file and will not be displayed.

+19
application/src/Kernel.php
··· 1 + <?php 2 + 3 + namespace App; 4 + 5 + use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; 6 + use Symfony\Component\HttpKernel\Kernel as BaseKernel; 7 + 8 + class Kernel extends BaseKernel 9 + { 10 + use MicroKernelTrait; 11 + 12 + /** 13 + * @return list<string> An array of allowed values for APP_ENV 14 + */ 15 + private function getAllowedEnvs(): array 16 + { 17 + return ['prod', 'dev', 'test']; 18 + } 19 + }
+60
application/symfony.lock
··· 1 + { 2 + "symfony/console": { 3 + "version": "8.1", 4 + "recipe": { 5 + "repo": "github.com/symfony/recipes", 6 + "branch": "main", 7 + "version": "5.3", 8 + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" 9 + }, 10 + "files": [ 11 + "bin/console" 12 + ] 13 + }, 14 + "symfony/flex": { 15 + "version": "2.11", 16 + "recipe": { 17 + "repo": "github.com/symfony/recipes", 18 + "branch": "main", 19 + "version": "2.4", 20 + "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" 21 + }, 22 + "files": [ 23 + ".env", 24 + ".env.dev" 25 + ] 26 + }, 27 + "symfony/framework-bundle": { 28 + "version": "8.1", 29 + "recipe": { 30 + "repo": "github.com/symfony/recipes", 31 + "branch": "main", 32 + "version": "8.1", 33 + "ref": "312027aea160796a50bf2d185503afdb5d71f570" 34 + }, 35 + "files": [ 36 + "config/packages/cache.yaml", 37 + "config/packages/framework.yaml", 38 + "config/preload.php", 39 + "config/routes/framework.yaml", 40 + "config/services.yaml", 41 + "public/index.php", 42 + "src/Controller/.gitignore", 43 + "src/Kernel.php", 44 + ".editorconfig" 45 + ] 46 + }, 47 + "symfony/routing": { 48 + "version": "8.1", 49 + "recipe": { 50 + "repo": "github.com/symfony/recipes", 51 + "branch": "main", 52 + "version": "7.4", 53 + "ref": "bc94c4fd86f393f3ab3947c18b830ea343e51ded" 54 + }, 55 + "files": [ 56 + "config/packages/routing.yaml", 57 + "config/routes.yaml" 58 + ] 59 + } 60 + }
+4
dagger.toml
··· 1 + [modules.application] 2 + source = "application" 3 + legacy-default-path = true 4 + # settings.source = "./path"
+32
dagger/README.md
··· 11 11 dagger --help 12 12 ``` 13 13 14 + RSSBase uses Dagger's workspace/module config split: 15 + 16 + - root [`../dagger.toml`](../dagger.toml) is the workspace config 17 + - [`../application/dagger-module.toml`](../application/dagger-module.toml) is the application module config 18 + - module code lives in [`../application/.dagger`](../application/.dagger) 19 + 20 + From the repository root: 21 + 22 + ```bash 23 + # Inspect workspace modules 24 + dagger workspace 25 + dagger installed 26 + 27 + # List workspace entrypoints; currently this exposes the application module 28 + dagger functions 29 + 30 + # List and run checks declared with @check 31 + dagger check --list 32 + dagger check 33 + 34 + # Build the production FrankenPHP image 35 + dagger call application build-prod sync 36 + 37 + # Validate Composer metadata 38 + dagger call application composer-validate 39 + ``` 40 + 41 + Tip: set `DAGGER_NO_NAG=1` to hide the Dagger Cloud setup prompt in local runs: 42 + ```bash 43 + DAGGER_NO_NAG=1 dagger call application php-version 44 + ``` 45 + 14 46 ## Updating 15 47 16 48 This package follows Dagger's dev-build endpoint, but pins a concrete commit and hashes for reproducibility.