init
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
**/*.log
|
||||||
|
**/*.md
|
||||||
|
**/*.php~
|
||||||
|
**/*.dist.php
|
||||||
|
**/*.dist
|
||||||
|
**/*.cache
|
||||||
|
**/._*
|
||||||
|
**/.dockerignore
|
||||||
|
**/.DS_Store
|
||||||
|
**/.git/
|
||||||
|
**/.gitattributes
|
||||||
|
**/.gitignore
|
||||||
|
**/.gitmodules
|
||||||
|
**/compose.*.yaml
|
||||||
|
**/compose.*.yml
|
||||||
|
**/compose.yaml
|
||||||
|
**/compose.yml
|
||||||
|
**/docker-compose.*.yaml
|
||||||
|
**/docker-compose.*.yml
|
||||||
|
**/docker-compose.yaml
|
||||||
|
**/docker-compose.yml
|
||||||
|
**/Dockerfile
|
||||||
|
**/Thumbs.db
|
||||||
|
.github/
|
||||||
|
docs/
|
||||||
|
public/bundles/
|
||||||
|
tests/
|
||||||
|
var/
|
||||||
|
vendor/
|
||||||
|
.editorconfig
|
||||||
|
.env.*.local
|
||||||
|
.env.local
|
||||||
|
.env.local.php
|
||||||
|
.env.test
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
insert_final_newline = true
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[**/{Dockerfile,Caddyfile,*.sh}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[{compose.*yaml,.devcontainer/compose.*yaml,.github/**/*.yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[**.md]
|
||||||
|
indent_size = unset
|
||||||
|
indent_style = unset
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# In all environments, the following files are loaded if they exist,
|
||||||
|
# the latter taking precedence over the former:
|
||||||
|
#
|
||||||
|
# * .env contains default values for the environment variables needed by the app
|
||||||
|
# * .env.local uncommitted file with local overrides
|
||||||
|
# * .env.$APP_ENV committed environment-specific defaults
|
||||||
|
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||||
|
#
|
||||||
|
# Real environment variables win over .env files.
|
||||||
|
#
|
||||||
|
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||||
|
# https://symfony.com/doc/current/configuration/secrets.html
|
||||||
|
#
|
||||||
|
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||||
|
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
APP_ENV=dev
|
||||||
|
APP_SECRET=
|
||||||
|
APP_SHARE_DIR=var/share
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> symfony/routing ###
|
||||||
|
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||||
|
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||||
|
DEFAULT_URI=http://localhost
|
||||||
|
###< symfony/routing ###
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
APP_SECRET=721f1c073aa9c56fd3c03089e7297bde
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.conf text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.ini text eol=lf
|
||||||
|
*.js text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.php text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
bin/console text eol=lf
|
||||||
|
composer.lock text eol=lf merge=ours
|
||||||
|
|
||||||
|
*.ico binary
|
||||||
|
*.png binary
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
/.env.local
|
||||||
|
/.env.local.php
|
||||||
|
/.env.*.local
|
||||||
|
/config/secrets/prod/prod.decrypt.private.php
|
||||||
|
/public/bundles/
|
||||||
|
/var/
|
||||||
|
/vendor/
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+70
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/clock" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/config" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dotenv" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/flex" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/password-hasher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-deepclone" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-access" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-core" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-csrf" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-http" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bridge" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/type-info" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/gym-tracker.iml" filepath="$PROJECT_DIR$/.idea/gym-tracker.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+88
@@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MessDetectorOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCSFixerOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||||
|
<option name="highlightLevel" value="WARNING" />
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpIncludePathManager">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-deepclone" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.5" />
|
||||||
|
<component name="PhpStanOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpUnit">
|
||||||
|
<phpunit_settings>
|
||||||
|
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||||
|
</phpunit_settings>
|
||||||
|
</component>
|
||||||
|
<component name="PsalmOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
+178
@@ -0,0 +1,178 @@
|
|||||||
|
#syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# Versions
|
||||||
|
FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream
|
||||||
|
|
||||||
|
# The different stages of this Dockerfile are meant to be built into separate images
|
||||||
|
# https://docs.docker.com/build/building/multi-stage/#stop-at-a-specific-build-stage
|
||||||
|
# https://docs.docker.com/reference/compose-file/build/#target
|
||||||
|
|
||||||
|
|
||||||
|
# Base FrankenPHP image
|
||||||
|
FROM frankenphp_upstream AS frankenphp_base
|
||||||
|
|
||||||
|
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# persistent deps
|
||||||
|
# hadolint ignore=DL3008
|
||||||
|
RUN <<-EOF
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
file \
|
||||||
|
git
|
||||||
|
install-php-extensions \
|
||||||
|
@composer \
|
||||||
|
apcu \
|
||||||
|
intl \
|
||||||
|
opcache \
|
||||||
|
zip
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
|
||||||
|
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||||
|
|
||||||
|
ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d"
|
||||||
|
|
||||||
|
###> recipes ###
|
||||||
|
###< recipes ###
|
||||||
|
|
||||||
|
COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/
|
||||||
|
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
|
||||||
|
COPY --link frankenphp/Caddyfile /etc/frankenphp/Caddyfile
|
||||||
|
|
||||||
|
ENTRYPOINT ["docker-entrypoint"]
|
||||||
|
|
||||||
|
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);'
|
||||||
|
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]
|
||||||
|
|
||||||
|
# Dev FrankenPHP image
|
||||||
|
FROM frankenphp_base AS frankenphp_dev
|
||||||
|
|
||||||
|
ENV APP_ENV=dev
|
||||||
|
ENV XDEBUG_MODE=off
|
||||||
|
ENV FRANKENPHP_WORKER_CONFIG=watch
|
||||||
|
|
||||||
|
# dev dependencies
|
||||||
|
# hadolint ignore=DL3008
|
||||||
|
RUN <<-EOF
|
||||||
|
mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
aggregate \
|
||||||
|
curl \
|
||||||
|
dnsmasq \
|
||||||
|
dnsutils \
|
||||||
|
iproute2 \
|
||||||
|
ipset \
|
||||||
|
iptables \
|
||||||
|
jq \
|
||||||
|
sudo
|
||||||
|
install-php-extensions xdebug
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
useradd -m -s /bin/bash nonroot
|
||||||
|
echo "nonroot ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/nonroot
|
||||||
|
git config --system --add safe.directory /app
|
||||||
|
EOF
|
||||||
|
|
||||||
|
COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/
|
||||||
|
|
||||||
|
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile", "--watch" ]
|
||||||
|
|
||||||
|
# Builder for the prod FrankenPHP image
|
||||||
|
FROM frankenphp_base AS frankenphp_prod_builder
|
||||||
|
|
||||||
|
ENV APP_ENV=prod
|
||||||
|
|
||||||
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||||
|
|
||||||
|
COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/
|
||||||
|
|
||||||
|
# prevent the reinstallation of vendors at every changes in the source code
|
||||||
|
COPY --link composer.* symfony.* ./
|
||||||
|
RUN composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress
|
||||||
|
|
||||||
|
# copy sources
|
||||||
|
COPY --link --exclude=frankenphp/ . ./
|
||||||
|
|
||||||
|
RUN <<-EOF
|
||||||
|
mkdir -p var/cache var/log var/share
|
||||||
|
composer dump-autoload --classmap-authoritative --no-dev
|
||||||
|
composer dump-env prod
|
||||||
|
composer run-script --no-dev post-install-cmd
|
||||||
|
if [ -f importmap.php ]; then
|
||||||
|
php bin/console asset-map:compile
|
||||||
|
fi
|
||||||
|
chmod +x bin/console
|
||||||
|
chmod -R g=u var
|
||||||
|
sync
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Collect shared libraries needed by FrankenPHP and PHP extensions
|
||||||
|
# hadolint ignore=DL3008,SC3054,DL4006
|
||||||
|
RUN <<-'EOF'
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends libtree
|
||||||
|
mkdir -p /tmp/libs
|
||||||
|
BINARIES=(frankenphp php file)
|
||||||
|
for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \
|
||||||
|
$(find "$(php -r 'echo ini_get("extension_dir");')" -maxdepth 2 -name "*.so"); do
|
||||||
|
libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do
|
||||||
|
[ -f "$lib" ] && cp -n "$lib" /tmp/libs/
|
||||||
|
done
|
||||||
|
done
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Prod FrankenPHP image
|
||||||
|
FROM debian:13-slim AS frankenphp_prod
|
||||||
|
|
||||||
|
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||||
|
|
||||||
|
ENV APP_ENV=prod
|
||||||
|
ENV PHP_INI_SCAN_DIR=":/usr/local/etc/php/app.conf.d"
|
||||||
|
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/bin/php /usr/local/bin/php
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/bin/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
|
||||||
|
COPY --from=frankenphp_prod_builder /tmp/libs /usr/lib
|
||||||
|
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/etc/php/php.ini /usr/local/etc/php/php.ini
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/local/etc/php/app.conf.d /usr/local/etc/php/app.conf.d
|
||||||
|
|
||||||
|
COPY --from=frankenphp_prod_builder /etc/frankenphp/Caddyfile /etc/frankenphp/Caddyfile
|
||||||
|
|
||||||
|
# CA certificates for TLS, file/libmagic for Symfony MIME type detection
|
||||||
|
COPY --from=frankenphp_prod_builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
|
COPY --from=frankenphp_prod_builder /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/bin/file /usr/bin/file
|
||||||
|
COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc
|
||||||
|
|
||||||
|
ENV OPENSSL_CONF=/etc/ssl/openssl.cnf XDG_CONFIG_HOME=/config XDG_DATA_HOME=/data
|
||||||
|
|
||||||
|
RUN <<-EOF
|
||||||
|
mkdir -p /data/caddy /config/caddy
|
||||||
|
chown -R www-data:www-data /data /config
|
||||||
|
# Remove setuid/setgid bits
|
||||||
|
find / -perm /6000 -type f -exec chmod a-s {} + 2>/dev/null || true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
COPY --link --exclude=var --from=frankenphp_prod_builder /app /app
|
||||||
|
# Group 0 + g=u for arbitrary-UID runtimes (e.g. OpenShift).
|
||||||
|
COPY --chown=www-data:0 --from=frankenphp_prod_builder /app/var /app/var
|
||||||
|
RUN chmod g=u /app/var
|
||||||
|
|
||||||
|
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
|
||||||
|
|
||||||
|
USER www-data
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENTRYPOINT ["docker-entrypoint"]
|
||||||
|
|
||||||
|
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);'
|
||||||
|
CMD [ "frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile" ]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) Fabien Potencier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Symfony Docker
|
||||||
|
|
||||||
|
A [Docker](https://www.docker.com/)-based installer and runtime for the [Symfony](https://symfony.com) web framework,
|
||||||
|
with [FrankenPHP](https://frankenphp.dev) and [Caddy](https://caddyserver.com/) inside!
|
||||||
|
|
||||||
|
Specially tailored for coding agents: ships with a [Dev Container](https://containers.dev/) configuration
|
||||||
|
that lets [Claude Code](https://claude.ai/claude-code) (and other AI coding assistants) run in fully autonomous
|
||||||
|
mode inside a sandboxed environment.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. If not already done, [install Docker Compose](https://docs.docker.com/compose/install/) (v2.10+)
|
||||||
|
2. Run `docker compose build --pull --no-cache` to build fresh images
|
||||||
|
3. Run `docker compose up --wait` to set up and start a fresh Symfony project
|
||||||
|
4. Open `https://localhost` in your favorite web browser and [accept the auto-generated TLS certificate](https://stackoverflow.com/a/15076602/1352334)
|
||||||
|
5. Run `docker compose down --remove-orphans` to stop the Docker containers.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Production, development and CI ready
|
||||||
|
- Just 1 service by default
|
||||||
|
- Super-readable configuration
|
||||||
|
- Blazing-fast performance thanks to [the worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/)
|
||||||
|
- [Installation of extra Docker Compose services](docs/extra-services.md) with Symfony Flex
|
||||||
|
- Automatic HTTPS (in dev and prod)
|
||||||
|
- HTTP/3 and [Early Hints](https://symfony.com/blog/new-in-symfony-6-3-early-hints) support
|
||||||
|
- Real-time messaging thanks to a built-in [Mercure hub](https://symfony.com/doc/current/mercure.html)
|
||||||
|
- [Vulcain](https://vulcain.rocks) support
|
||||||
|
- Native [XDebug](docs/xdebug.md) integration
|
||||||
|
- [Hot Reloading](https://frankenphp.dev/docs/hot-reload/)
|
||||||
|
- [Dev Container](https://containers.dev/) support, optimized for AI coding agents
|
||||||
|
- [AI coding agents](docs/agents.md) with sandboxing out of the box
|
||||||
|
- Rootless, slim production image
|
||||||
|
|
||||||
|
**Enjoy!**
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
1. [Options available](docs/options.md)
|
||||||
|
2. [Using Symfony Docker with an existing project](docs/existing-project.md)
|
||||||
|
3. [Support for extra services](docs/extra-services.md)
|
||||||
|
4. [Deploying in production](docs/production.md)
|
||||||
|
5. [Debugging with Xdebug](docs/xdebug.md)
|
||||||
|
6. [TLS Certificates](docs/tls.md)
|
||||||
|
7. [Using MySQL instead of PostgreSQL](docs/mysql.md)
|
||||||
|
8. [Using Alpine Linux instead of Debian](docs/alpine.md)
|
||||||
|
9. [Using a Makefile](docs/makefile.md)
|
||||||
|
10. [Updating the template](docs/updating.md)
|
||||||
|
11. [Troubleshooting](docs/troubleshooting.md)
|
||||||
|
12. [Using AI Coding Agents](docs/agents.md)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Symfony Docker is available under the MIT License.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Created by [Kévin Dunglas](https://dunglas.dev), co-maintained by [Maxime Helias](https://twitter.com/maxhelias) and sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop).
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Kernel;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
|
||||||
|
if (!is_dir(dirname(__DIR__).'/vendor')) {
|
||||||
|
throw new LogicException('Dependencies are missing. Try running "composer install".');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
|
||||||
|
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||||
|
|
||||||
|
return function (array $context) {
|
||||||
|
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||||
|
|
||||||
|
return new Application($kernel);
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
# Development environment override
|
||||||
|
services:
|
||||||
|
php:
|
||||||
|
image: ${IMAGES_PREFIX:-}app-php-dev
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: frankenphp_dev
|
||||||
|
volumes:
|
||||||
|
- ./:/app
|
||||||
|
- ./frankenphp/Caddyfile:/etc/frankenphp/Caddyfile:ro
|
||||||
|
- ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/app.conf.d/20-app.dev.ini:ro
|
||||||
|
# Keep var/ off the bind-mount for faster I/O on Mac/Windows; comment to inspect from the host.
|
||||||
|
- /app/var
|
||||||
|
# If you develop on Mac or Windows you can remove the vendor/ directory
|
||||||
|
# from the bind-mount for better performance by enabling the next line:
|
||||||
|
#- /app/vendor
|
||||||
|
environment:
|
||||||
|
FRANKENPHP_WORKER_CONFIG: watch
|
||||||
|
FRANKENPHP_SITE_CONFIG: hot_reload
|
||||||
|
MERCURE_EXTRA_DIRECTIVES: demo
|
||||||
|
# See https://xdebug.org/docs/all_settings#mode
|
||||||
|
XDEBUG_MODE: "${XDEBUG_MODE:-develop}"
|
||||||
|
APP_ENV: "${APP_ENV:-dev}"
|
||||||
|
extra_hosts:
|
||||||
|
# Ensure that host.docker.internal is correctly defined on Linux
|
||||||
|
- host.docker.internal:host-gateway
|
||||||
|
tty: true
|
||||||
|
###> symfony/mercure-bundle ###
|
||||||
|
###< symfony/mercure-bundle ###
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
# Production environment override
|
||||||
|
services:
|
||||||
|
php:
|
||||||
|
image: ${IMAGES_PREFIX:-}app-php-prod
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: frankenphp_prod
|
||||||
|
environment:
|
||||||
|
APP_SECRET: ${APP_SECRET}
|
||||||
|
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
|
||||||
|
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
php:
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
SERVER_NAME: ${SERVER_NAME:-localhost}, php:80
|
||||||
|
DEFAULT_URI: https://${SERVER_NAME:-localhost}:${HTTPS_PORT:-443}
|
||||||
|
MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
|
||||||
|
MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
|
||||||
|
# Run "composer require symfony/orm-pack" to install and configure Doctrine ORM
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8}
|
||||||
|
# Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration
|
||||||
|
MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure}
|
||||||
|
MERCURE_PUBLIC_URL: ${CADDY_MERCURE_PUBLIC_URL:-https://${SERVER_NAME:-localhost}:${HTTPS_PORT:-443}/.well-known/mercure}
|
||||||
|
MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!}
|
||||||
|
volumes:
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
target: 80
|
||||||
|
published: ${HTTP_PORT:-80}
|
||||||
|
protocol: tcp
|
||||||
|
- name: https
|
||||||
|
target: 443
|
||||||
|
published: ${HTTPS_PORT:-443}
|
||||||
|
protocol: tcp
|
||||||
|
- name: http3
|
||||||
|
target: 443
|
||||||
|
published: ${HTTP3_PORT:-443}
|
||||||
|
protocol: udp
|
||||||
|
|
||||||
|
# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service
|
||||||
|
###> symfony/mercure-bundle ###
|
||||||
|
###< symfony/mercure-bundle ###
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
|
###> symfony/mercure-bundle ###
|
||||||
|
###< symfony/mercure-bundle ###
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"name": "symfony/skeleton",
|
||||||
|
"type": "project",
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "A minimal Symfony project recommended to create bare bones applications",
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true,
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.5.7",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"doctrine/orm": "^3.6",
|
||||||
|
"symfony/console": "8.1.*",
|
||||||
|
"symfony/dotenv": "8.1.*",
|
||||||
|
"symfony/flex": "^2",
|
||||||
|
"symfony/framework-bundle": "8.1.*",
|
||||||
|
"symfony/runtime": "8.1.*",
|
||||||
|
"symfony/security-bundle": "8.1.*",
|
||||||
|
"symfony/twig-bundle": "8.1.*",
|
||||||
|
"symfony/yaml": "8.1.*"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"php-http/discovery": true,
|
||||||
|
"symfony/flex": true,
|
||||||
|
"symfony/runtime": true
|
||||||
|
},
|
||||||
|
"bump-after-update": true,
|
||||||
|
"sort-packages": true
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"symfony/polyfill-ctype": "*",
|
||||||
|
"symfony/polyfill-iconv": "*",
|
||||||
|
"symfony/polyfill-php72": "*",
|
||||||
|
"symfony/polyfill-php73": "*",
|
||||||
|
"symfony/polyfill-php74": "*",
|
||||||
|
"symfony/polyfill-php80": "*",
|
||||||
|
"symfony/polyfill-php81": "*",
|
||||||
|
"symfony/polyfill-php82": "*",
|
||||||
|
"symfony/polyfill-php83": "*",
|
||||||
|
"symfony/polyfill-php84": "*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"auto-scripts": {
|
||||||
|
"cache:clear": "symfony-cmd",
|
||||||
|
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||||
|
},
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@auto-scripts"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@auto-scripts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/symfony": "*"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"symfony": {
|
||||||
|
"allow-contrib": false,
|
||||||
|
"require": "8.1.*",
|
||||||
|
"docker": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/maker-bundle": "^1.67"
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+4723
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
|
];
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||||
|
#prefix_seed: your_vendor_name/app_name
|
||||||
|
|
||||||
|
# The "app" cache stores to the filesystem by default.
|
||||||
|
# The data in this cache should persist between deploys.
|
||||||
|
# Other options include:
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
#app: cache.adapter.redis
|
||||||
|
#default_redis_provider: redis://localhost
|
||||||
|
|
||||||
|
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||||
|
#app: cache.adapter.apcu
|
||||||
|
|
||||||
|
# Namespaced pools use the above "app" backend by default
|
||||||
|
#pools:
|
||||||
|
#my.dedicated.cache: null
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||||
|
framework:
|
||||||
|
secret: '%env(APP_SECRET)%'
|
||||||
|
|
||||||
|
# Note that the session will be started ONLY if you read or write from it.
|
||||||
|
session: true
|
||||||
|
|
||||||
|
#esi: true
|
||||||
|
#fragments: true
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
framework:
|
||||||
|
test: true
|
||||||
|
session:
|
||||||
|
storage_factory_id: session.storage.factory.mock_file
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
framework:
|
||||||
|
property_info:
|
||||||
|
with_constructor_extractor: true
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
framework:
|
||||||
|
router:
|
||||||
|
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||||
|
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||||
|
default_uri: '%env(DEFAULT_URI)%'
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
framework:
|
||||||
|
router:
|
||||||
|
strict_requirements: null
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
security:
|
||||||
|
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||||
|
password_hashers:
|
||||||
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||||
|
|
||||||
|
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||||
|
providers:
|
||||||
|
users_in_memory: { memory: null }
|
||||||
|
|
||||||
|
firewalls:
|
||||||
|
dev:
|
||||||
|
# Ensure dev tools and static assets are always allowed
|
||||||
|
pattern: ^/(_profiler|_wdt|assets|build)/
|
||||||
|
security: false
|
||||||
|
main:
|
||||||
|
lazy: true
|
||||||
|
provider: users_in_memory
|
||||||
|
|
||||||
|
# Activate different ways to authenticate:
|
||||||
|
# https://symfony.com/doc/current/security.html#the-firewall
|
||||||
|
|
||||||
|
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||||
|
# switch_user: true
|
||||||
|
|
||||||
|
# Note: Only the *first* matching rule is applied
|
||||||
|
access_control:
|
||||||
|
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||||
|
# - { path: ^/profile, roles: ROLE_USER }
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
security:
|
||||||
|
password_hashers:
|
||||||
|
# Password hashers are resource-intensive by design to ensure security.
|
||||||
|
# In tests, it's safe to reduce their cost to improve performance.
|
||||||
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||||
|
algorithm: auto
|
||||||
|
cost: 4 # Lowest possible value for bcrypt
|
||||||
|
time_cost: 3 # Lowest possible value for argon
|
||||||
|
memory_cost: 10 # Lowest possible value for argon
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
twig:
|
||||||
|
file_name_pattern: '*.twig'
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
twig:
|
||||||
|
strict_variables: true
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
|
||||||
|
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json
|
||||||
|
|
||||||
|
# This file is the entry point to configure the routes of your app.
|
||||||
|
# Methods with the #[Route] attribute are automatically imported.
|
||||||
|
# See also https://symfony.com/doc/current/routing.html
|
||||||
|
|
||||||
|
# To list all registered routes, run the following command:
|
||||||
|
# bin/console debug:router
|
||||||
|
|
||||||
|
controllers:
|
||||||
|
resource: routing.controllers
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
when@dev:
|
||||||
|
_errors:
|
||||||
|
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||||
|
prefix: /_error
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
_security_logout:
|
||||||
|
resource: security.route_loader.logout
|
||||||
|
type: service
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
||||||
|
|
||||||
|
# This file is the entry point to configure your own services.
|
||||||
|
# Files in the packages/ subdirectory configure your dependencies.
|
||||||
|
# See also https://symfony.com/doc/current/service_container/import.html
|
||||||
|
|
||||||
|
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||||
|
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
services:
|
||||||
|
# default configuration for services in *this* file
|
||||||
|
_defaults:
|
||||||
|
autowire: true # Automatically injects dependencies in your services.
|
||||||
|
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||||
|
|
||||||
|
# makes classes in src/ available to be used as services
|
||||||
|
# this creates a service per class whose id is the fully-qualified class name
|
||||||
|
App\:
|
||||||
|
resource: '../src/'
|
||||||
|
|
||||||
|
# add more service definitions when explicit configuration is needed
|
||||||
|
# please note that last definitions always *replace* previous ones
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
# Using AI Coding Agents with Dev Containers
|
||||||
|
|
||||||
|
This project ships with a [Dev Container](https://containers.dev/) configuration that enables
|
||||||
|
AI coding agents to run autonomously inside a sandboxed environment with network-level restrictions.
|
||||||
|
|
||||||
|
[Claude Code](https://claude.ai/claude-code) is pre-installed and configured out of the box,
|
||||||
|
but the setup also works with other agents such as [OpenAI Codex CLI](https://github.com/openai/codex)
|
||||||
|
and [opencode](https://opencode.ai).
|
||||||
|
|
||||||
|
This setup is ideal for letting AI agents work on your Symfony project autonomously
|
||||||
|
while ensuring they cannot reach arbitrary internet hosts.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or any Docker-compatible runtime)
|
||||||
|
- [Visual Studio Code](https://code.visualstudio.com/) with the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension
|
||||||
|
- A valid subscription or API key for the agent you want to use
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. Open the project in Visual Studio Code.
|
||||||
|
2. When prompted "Reopen in Container", click **Reopen in Container**.
|
||||||
|
Alternatively, open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run
|
||||||
|
**Dev Containers: Reopen in Container**.
|
||||||
|
3. Wait for the container to build and start. On each container start, the
|
||||||
|
`postStartCommand` configures the firewall automatically.
|
||||||
|
4. Claude Code is pre-installed and configured in YOLO mode — open the Claude Code
|
||||||
|
panel in Visual Studio Code or run `claude` in the integrated terminal to start using it.
|
||||||
|
|
||||||
|
That's it. Claude Code will run without permission prompts, and the firewall ensures
|
||||||
|
network access is restricted to only the necessary services.
|
||||||
|
|
||||||
|
## What Is YOLO Mode?
|
||||||
|
|
||||||
|
YOLO mode (also known as "bypass permissions" mode) allows Claude Code to execute
|
||||||
|
commands, edit files, and perform actions without asking for confirmation at each step.
|
||||||
|
This dramatically speeds up autonomous coding workflows.
|
||||||
|
|
||||||
|
The Dev Container configuration enables this via two Visual Studio Code settings:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"claudeCode.allowDangerouslySkipPermissions": true,
|
||||||
|
"claudeCode.initialPermissionMode": "bypassPermissions"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network Sandboxing
|
||||||
|
|
||||||
|
Running an AI agent with full autonomy requires guardrails. The Dev Container includes
|
||||||
|
a firewall script (`.devcontainer/init-firewall.sh`) that locks down outbound network
|
||||||
|
access using `iptables` and `ipset`. Only the following destinations are allowed:
|
||||||
|
|
||||||
|
| Destination | Reason |
|
||||||
|
| ------------------------------------------------- | ------------------------------- |
|
||||||
|
| GitHub (`github.com`, `api.github.com`) | Git operations, API access |
|
||||||
|
| Anthropic (`anthropic.com`) | Claude Code backend |
|
||||||
|
| npm registry (`registry.npmjs.org`) | Node.js dependencies |
|
||||||
|
| Packagist (`packagist.org`, `repo.packagist.org`) | PHP/Composer dependencies |
|
||||||
|
| Visual Studio Code Marketplace | Extension downloads |
|
||||||
|
| Sentry, Statsig | Telemetry (used by Claude Code) |
|
||||||
|
| Host gateway IP | Communication with Docker host |
|
||||||
|
|
||||||
|
All other outbound connections are **rejected**. The firewall uses
|
||||||
|
[dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html) to dynamically resolve
|
||||||
|
and whitelist IPs for allowed domains, handling CDN IP rotation gracefully.
|
||||||
|
|
||||||
|
Inbound connections from the host gateway IP are allowed on all ports,
|
||||||
|
and ports 80, 443 (TCP), and 443 (UDP/HTTP3) are open to any source
|
||||||
|
so you can access your Symfony app from the host browser.
|
||||||
|
|
||||||
|
## Customizing the Allowed Domains
|
||||||
|
|
||||||
|
To allow additional domains (e.g., a private registry or API), edit
|
||||||
|
`.devcontainer/init-firewall.sh` and add them to the `ipset` line in the
|
||||||
|
dnsmasq configuration section:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Domains are '/'-separated, ending with the ipset name
|
||||||
|
ipset=/github.com/anthropic.com/your-domain.com/allowed-domains
|
||||||
|
```
|
||||||
|
|
||||||
|
Then rebuild the Dev Container for the changes to take effect.
|
||||||
|
|
||||||
|
## Using Other Agents
|
||||||
|
|
||||||
|
The Dev Container's network sandbox and project context (`.devcontainer/AGENTS.md`) work
|
||||||
|
with any AI coding agent. You just need to install the agent and whitelist the domains it
|
||||||
|
needs to reach.
|
||||||
|
|
||||||
|
### OpenAI Codex CLI
|
||||||
|
|
||||||
|
1. Add the OpenAI API domain to the firewall allowlist in `.devcontainer/init-firewall.sh`
|
||||||
|
(see [Customizing the Allowed Domains](#customizing-the-allowed-domains)):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ipset=/.../api.openai.com/allowed-domains
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install and run Codex inside the container:
|
||||||
|
|
||||||
|
```console
|
||||||
|
npm install -g @openai/codex
|
||||||
|
export OPENAI_API_KEY=your-key
|
||||||
|
codex --full-auto
|
||||||
|
```
|
||||||
|
|
||||||
|
### opencode
|
||||||
|
|
||||||
|
1. Add the required API domain to the firewall allowlist (e.g., `api.anthropic.com`,
|
||||||
|
`api.openai.com`, or your provider's domain).
|
||||||
|
|
||||||
|
2. Install and run opencode inside the container:
|
||||||
|
|
||||||
|
```console
|
||||||
|
curl -fsSL https://opencode.ai/install | bash
|
||||||
|
opencode
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other Agents
|
||||||
|
|
||||||
|
For any other agent, follow the same pattern:
|
||||||
|
|
||||||
|
1. Add the agent's API domain(s) to the firewall allowlist.
|
||||||
|
2. Install the agent inside the container.
|
||||||
|
3. Run it — the `.devcontainer/AGENTS.md` file provides project context
|
||||||
|
to agents that support the convention.
|
||||||
|
|
||||||
|
## Using Without Visual Studio Code
|
||||||
|
|
||||||
|
The Dev Container configuration works with any tool that supports the
|
||||||
|
[Dev Container specification](https://containers.dev/), including:
|
||||||
|
|
||||||
|
- [Dev Container CLI](https://github.com/devcontainers/cli) (`devcontainer up`)
|
||||||
|
- [GitHub Codespaces](https://github.com/features/codespaces)
|
||||||
|
- JetBrains IDEs (with the Dev Containers plugin)
|
||||||
|
|
||||||
|
To use Claude Code from the terminal inside the container:
|
||||||
|
|
||||||
|
```console
|
||||||
|
claude
|
||||||
|
```
|
||||||
|
|
||||||
|
To start directly in YOLO mode from the CLI:
|
||||||
|
|
||||||
|
```console
|
||||||
|
claude --dangerously-skip-permissions
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Firewall blocks a required domain
|
||||||
|
|
||||||
|
If your agent or Composer/npm fails to reach a service, check the firewall
|
||||||
|
logs and add the domain to the dnsmasq allowlist as described above.
|
||||||
|
|
||||||
|
### Container fails to start
|
||||||
|
|
||||||
|
Ensure Docker is running and that you have allocated enough resources
|
||||||
|
(at least 2 GB of RAM for the container). The firewall setup requires
|
||||||
|
`NET_ADMIN` capability, which the Dev Container configures automatically
|
||||||
|
via Docker Compose.
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Using Alpine Linux Instead of Debian
|
||||||
|
|
||||||
|
By default, Symfony Docker uses Debian-based FrankenPHP Docker images.
|
||||||
|
This is the recommended solution.
|
||||||
|
|
||||||
|
Alternatively, it's possible to use Alpine-based images, which are smaller but
|
||||||
|
are known to be slower, and have several known issues.
|
||||||
|
|
||||||
|
To switch to Alpine-based images, apply the following changes to the `Dockerfile`:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 -->
|
||||||
|
|
||||||
|
```diff
|
||||||
|
-FROM dunglas/frankenphp:1-php8.5 AS frankenphp_upstream
|
||||||
|
+FROM dunglas/frankenphp:1-php8.5-alpine AS frankenphp_upstream
|
||||||
|
|
||||||
|
-SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||||
|
+SHELL ["/bin/ash", "-euxo", "-c"]
|
||||||
|
|
||||||
|
-# hadolint ignore=DL3008
|
||||||
|
-RUN <<-EOF
|
||||||
|
- apt-get update
|
||||||
|
- apt-get install -y --no-install-recommends \
|
||||||
|
- file \
|
||||||
|
- git
|
||||||
|
+# hadolint ignore=DL3018
|
||||||
|
+RUN <<-EOF
|
||||||
|
+ apk add --no-cache \
|
||||||
|
+ file \
|
||||||
|
+ git
|
||||||
|
install-php-extensions \
|
||||||
|
|
||||||
|
-# hadolint ignore=DL3008,SC3054,DL4006
|
||||||
|
-RUN <<-'EOF'
|
||||||
|
- apt-get update
|
||||||
|
- apt-get install -y --no-install-recommends libtree
|
||||||
|
+# hadolint ignore=DL3018,SC3054,DL4006
|
||||||
|
+RUN <<-'EOF'
|
||||||
|
+ apk add --no-cache libtree
|
||||||
|
mkdir -p /tmp/libs
|
||||||
|
- BINARIES=(frankenphp php file)
|
||||||
|
- for target in $(printf '%s\n' "${BINARIES[@]}" | xargs -I{} which {}) \
|
||||||
|
+ BINARIES="frankenphp php file"
|
||||||
|
+ for target in $(printf '%s\n' $BINARIES | xargs -I{} which {}) \
|
||||||
|
|
||||||
|
- libtree -pv "$target" 2>/dev/null | grep -oP '(?:── )\K/\S+(?= \[)' | while IFS= read -r lib; do
|
||||||
|
+ libtree -pv "$target" 2>/dev/null | sed -n 's/.*── \(\/[^ ]*\) \[.*/\1/p' | while IFS= read -r lib; do
|
||||||
|
|
||||||
|
- rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
-FROM debian:13-slim AS frankenphp_prod
|
||||||
|
+FROM alpine:3 AS frankenphp_prod
|
||||||
|
|
||||||
|
-SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||||
|
+SHELL ["/bin/ash", "-euxo", "-c"]
|
||||||
|
|
||||||
|
-COPY --from=frankenphp_prod_builder /usr/lib/file/magic.mgc /usr/lib/file/magic.mgc
|
||||||
|
+COPY --from=frankenphp_prod_builder /usr/share/misc/magic.mgc /usr/share/misc/magic.mgc
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD010 -->
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 159 KiB |
@@ -0,0 +1,81 @@
|
|||||||
|
# Installing on an Existing Project
|
||||||
|
|
||||||
|
It's also possible to use Symfony Docker with existing projects!
|
||||||
|
|
||||||
|
First, [download this skeleton](https://github.com/dunglas/symfony-docker).
|
||||||
|
|
||||||
|
If you cloned the Git repository, be sure to not copy the `.git` directory
|
||||||
|
to prevent conflicts with the `.git` directory already in your existing project.
|
||||||
|
|
||||||
|
You can copy the contents of the repository using Git and tar.
|
||||||
|
This will not contain `.git` or any uncommitted changes.
|
||||||
|
|
||||||
|
```console
|
||||||
|
git archive --format=tar HEAD | tar -xC my-existing-project/
|
||||||
|
```
|
||||||
|
|
||||||
|
If you downloaded the skeleton as a ZIP you can just copy the extracted files:
|
||||||
|
|
||||||
|
```console
|
||||||
|
cp -Rp symfony-docker/. my-existing-project/
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable the Docker support of Symfony Flex:
|
||||||
|
|
||||||
|
```console
|
||||||
|
composer config --json extra.symfony.docker 'true'
|
||||||
|
```
|
||||||
|
|
||||||
|
The [worker mode of FrankenPHP](https://frankenphp.dev/docs/worker/) is enabled by default.
|
||||||
|
To use it with Symfony ≤ 7.3, install the FrankenPHP runtime:
|
||||||
|
|
||||||
|
```console
|
||||||
|
composer require runtime/frankenphp-symfony
|
||||||
|
```
|
||||||
|
|
||||||
|
Then update worker configuration:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 -->
|
||||||
|
|
||||||
|
```diff
|
||||||
|
worker {
|
||||||
|
file ./public/index.php
|
||||||
|
+ env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
|
||||||
|
{$FRANKENPHP_WORKER_CONFIG}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD010 -->
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
>
|
||||||
|
> You can disable worker mode by removing the `worker` directive from the `frankenphp`
|
||||||
|
> global option in your `Caddyfile`.
|
||||||
|
|
||||||
|
Re-execute the recipes to update the Docker-related files according to
|
||||||
|
the packages you use:
|
||||||
|
|
||||||
|
```console
|
||||||
|
rm symfony.lock
|
||||||
|
composer recipes:install --force --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
Double-check the changes, revert the changes that you don't want to keep:
|
||||||
|
|
||||||
|
```console
|
||||||
|
git diff
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the Docker images:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose build --pull --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the project!
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
Browse `https://localhost`, your Docker configuration is ready!
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Support for Extra Services
|
||||||
|
|
||||||
|
Symfony Docker is extensible.
|
||||||
|
When you install a compatible Composer package using Symfony Flex,
|
||||||
|
the recipe will automatically modify the `Dockerfile` and `compose.yaml` files
|
||||||
|
to fulfill the requirements of this package.
|
||||||
|
|
||||||
|
The currently supported packages are:
|
||||||
|
|
||||||
|
- `symfony/orm-pack`: install a PostgreSQL service
|
||||||
|
- `symfony/mercure-bundle`: use the Mercure.rocks module shipped with Caddy
|
||||||
|
- `symfony/panther`: install Chromium and its drivers
|
||||||
|
- `symfony/mailer`: install a Mailpit service
|
||||||
|
- `blackfireio/blackfire-symfony-meta`: install a Blackfire service
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> If a recipe modifies the Dockerfile, the container needs to be rebuilt.
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
>
|
||||||
|
> We recommend that you use the `composer require` command inside the container
|
||||||
|
> in development mode so that recipes can be applied correctly.
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
Here is a Makefile template. It provides some shortcuts for the most common tasks.
|
||||||
|
To use it, create a new `Makefile` file at the root of your project. Copy/paste
|
||||||
|
the content in the template section. To view all the available commands, run `make`.
|
||||||
|
|
||||||
|
For example, in the [getting started section](/README.md#getting-started), the
|
||||||
|
`docker compose` commands could be replaced by:
|
||||||
|
|
||||||
|
1. Run `make build` to build fresh images
|
||||||
|
2. Run `make up` (detached mode without logs)
|
||||||
|
3. Run `make down` to stop the Docker containers
|
||||||
|
|
||||||
|
Of course, this template is basic for now. But, as your application is growing,
|
||||||
|
you will probably want to add some targets like running your tests as described
|
||||||
|
in [the Symfony book](https://symfony.com/doc/current/the-fast-track/en/17-tests.html#automating-your-workflow-with-a-makefile).
|
||||||
|
You can also find a more complete example in this [snippet](https://www.strangebuzz.com/en/snippets/the-perfect-makefile-for-symfony).
|
||||||
|
|
||||||
|
If you want to run make from within the `php` container, in the [Dockerfile](/Dockerfile),
|
||||||
|
add:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 -->
|
||||||
|
|
||||||
|
```diff
|
||||||
|
gettext \
|
||||||
|
git \
|
||||||
|
+ make \
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD010 -->
|
||||||
|
|
||||||
|
And rebuild the PHP image.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> If you are using Windows, you have to install [chocolatey.org](https://chocolatey.org/)
|
||||||
|
> or [Cygwin](http://cygwin.com) to use the `make` command.
|
||||||
|
>
|
||||||
|
> Check out this [StackOverflow question](https://stackoverflow.com/q/2532234/633864)
|
||||||
|
> for more explanations.
|
||||||
|
|
||||||
|
## The Template
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 MD013 -->
|
||||||
|
|
||||||
|
```Makefile
|
||||||
|
# Executables (local)
|
||||||
|
DOCKER_COMP = docker compose
|
||||||
|
|
||||||
|
# Docker containers
|
||||||
|
PHP_CONT = $(DOCKER_COMP) exec php
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
PHP = $(PHP_CONT) php
|
||||||
|
COMPOSER = $(PHP_CONT) composer
|
||||||
|
SYMFONY = $(PHP) bin/console
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DEFAULT_GOAL = help
|
||||||
|
.PHONY : help build up start down logs sh composer vendor sf cc test
|
||||||
|
|
||||||
|
## —— 🎵 🐳 The Symfony Docker Makefile 🐳 🎵 ——————————————————————————————————
|
||||||
|
help: ## Outputs this help screen
|
||||||
|
@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/'
|
||||||
|
|
||||||
|
## —— Docker 🐳 ————————————————————————————————————————————————————————————————
|
||||||
|
build: ## Builds the Docker images
|
||||||
|
@$(DOCKER_COMP) build --pull --no-cache
|
||||||
|
|
||||||
|
up: ## Start the docker hub in detached mode (no logs)
|
||||||
|
@$(DOCKER_COMP) up --detach
|
||||||
|
|
||||||
|
start: build up ## Build and start the containers
|
||||||
|
|
||||||
|
down: ## Stop the docker hub
|
||||||
|
@$(DOCKER_COMP) down --remove-orphans
|
||||||
|
|
||||||
|
logs: ## Show live logs
|
||||||
|
@$(DOCKER_COMP) logs --tail=0 --follow
|
||||||
|
|
||||||
|
sh: ## Connect to the FrankenPHP container
|
||||||
|
@$(PHP_CONT) sh
|
||||||
|
|
||||||
|
bash: ## Connect to the FrankenPHP container via bash so up and down arrows go to previous commands
|
||||||
|
@$(PHP_CONT) bash
|
||||||
|
|
||||||
|
test: ## Start tests with phpunit, pass the parameter "c=" to add options to phpunit, example: make test c="--group e2e --stop-on-failure"
|
||||||
|
@$(eval c ?=)
|
||||||
|
@$(DOCKER_COMP) exec -e APP_ENV=test php bin/phpunit $(c)
|
||||||
|
|
||||||
|
|
||||||
|
## —— Composer 🧙 ——————————————————————————————————————————————————————————————
|
||||||
|
composer: ## Run composer, pass the parameter "c=" to run a given command, example: make composer c='req symfony/orm-pack'
|
||||||
|
@$(eval c ?=)
|
||||||
|
@$(COMPOSER) $(c)
|
||||||
|
|
||||||
|
vendor: ## Install vendors according to the current composer.lock file
|
||||||
|
vendor: c=install --prefer-dist --no-dev --no-progress --no-scripts --no-interaction
|
||||||
|
vendor: composer
|
||||||
|
|
||||||
|
## —— Symfony 🎵 ———————————————————————————————————————————————————————————————
|
||||||
|
sf: ## List all Symfony commands or pass the parameter "c=" to run a given command, example: make sf c=about
|
||||||
|
@$(eval c ?=)
|
||||||
|
@$(SYMFONY) $(c)
|
||||||
|
|
||||||
|
cc: c=c:c ## Clear the cache
|
||||||
|
cc: sf
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD010 MD013 -->
|
||||||
|
|
||||||
|
## Adding and Modifying Jobs
|
||||||
|
|
||||||
|
Make sure to add this configuration to the [.editorconfig](/.editorconfig) file,
|
||||||
|
so that it forces your editor to use tabs instead of spaces.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> Makefiles are not compatible with spaces by default.
|
||||||
|
|
||||||
|
```.editorconfig
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
If you still want to use space, you can configure the prefix in the Makefile itself.
|
||||||
|
See [this answer on Stack Exchange](https://retrocomputing.stackexchange.com/a/20303).
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
# Using MySQL
|
||||||
|
|
||||||
|
The Docker configuration of this repository is extensible thanks to Flex recipes.
|
||||||
|
By default, the recipe installs PostgreSQL.
|
||||||
|
|
||||||
|
If you prefer to work with MySQL, follow these steps:
|
||||||
|
|
||||||
|
First, install the `symfony/orm-pack` package as described:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose exec php composer req symfony/orm-pack
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Configuration
|
||||||
|
|
||||||
|
Change the database image to use MySQL instead of PostgreSQL in `compose.yaml`:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
```diff
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
- image: postgres:${POSTGRES_VERSION:-16}-alpine
|
||||||
|
+ image: mysql:${MYSQL_VERSION:-8.0.32}
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB: ${POSTGRES_DB:-app}
|
||||||
|
+ MYSQL_DATABASE: ${MYSQL_DATABASE:-app}
|
||||||
|
# You should definitely change the password in production
|
||||||
|
+ MYSQL_RANDOM_ROOT_PASSWORD: "true"
|
||||||
|
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
|
||||||
|
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD:-!ChangeMe!}
|
||||||
|
- POSTGRES_USER: ${POSTGRES_USER:-app}
|
||||||
|
+ MYSQL_USER: ${MYSQL_USER:-app}
|
||||||
|
healthcheck:
|
||||||
|
- test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
|
||||||
|
+ test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 60s
|
||||||
|
volumes:
|
||||||
|
- - database_data:/var/lib/postgresql/data:rw
|
||||||
|
+ - database_data:/var/lib/mysql:rw
|
||||||
|
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
|
||||||
|
- # - ./docker/db/data:/var/lib/postgresql/data:rw
|
||||||
|
+ # - ./docker/db/data:/var/lib/mysql:rw
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
|
|
||||||
|
Depending on the database configuration,
|
||||||
|
modify the environment in the same file at `services.php.environment.DATABASE_URL`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
DATABASE_URL: mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.32}&charset=${MYSQL_CHARSET:-utf8mb4}
|
||||||
|
```
|
||||||
|
|
||||||
|
Since we changed the port, we also have to define this in the `compose.override.yaml`:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
database:
|
||||||
|
ports:
|
||||||
|
- - "5432"
|
||||||
|
+ - "3306"
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
```
|
||||||
|
|
||||||
|
Last but not least, we need to install the MySQL driver in `Dockerfile`:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
-RUN install-php-extensions pdo_pgsql
|
||||||
|
+RUN install-php-extensions pdo_mysql
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
```
|
||||||
|
|
||||||
|
## Change Environment
|
||||||
|
|
||||||
|
Change the database configuration in `.env`:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
DATABASE_URL=mysql://${MYSQL_USER:-app}:${MYSQL_PASSWORD:-!ChangeMe!}@database:3306/${MYSQL_DATABASE:-app}?serverVersion=${MYSQL_VERSION:-8.0.32}&charset=${MYSQL_CHARSET:-utf8mb4}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Final steps
|
||||||
|
|
||||||
|
Rebuild the Docker environment:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose down --remove-orphans && docker compose build --pull --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the services:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
Test your setup:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose exec php bin/console dbal:run-sql -q "SELECT 1" && echo "OK" || echo "Connection is not working"
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
# Docker Build Options
|
||||||
|
|
||||||
|
You can customize the Docker build process using these environment variables.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> All Symfony-specific environment variables are used only if no `composer.json`
|
||||||
|
> file is found in the project directory.
|
||||||
|
|
||||||
|
## Selecting a Specific Symfony Version
|
||||||
|
|
||||||
|
Use the `SYMFONY_VERSION` environment variable to select a specific Symfony version.
|
||||||
|
|
||||||
|
For instance, use the following command to install Symfony 6.4:
|
||||||
|
|
||||||
|
On Linux:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SYMFONY_VERSION=6.4.* docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
set SYMFONY_VERSION=6.4.* && docker compose up --wait&set SYMFONY_VERSION=
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 -->
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> If you're using Symfony 7.3 or earlier with FrankenPHP in worker mode, you also need to follow these steps
|
||||||
|
>
|
||||||
|
> ```console
|
||||||
|
> composer require runtime/frankenphp-symfony
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Add `env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime` in the `frankenphp/Caddyfile` in the `worker` section.
|
||||||
|
>
|
||||||
|
> ```diff
|
||||||
|
> worker {
|
||||||
|
> file ./public/index.php
|
||||||
|
> + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
|
||||||
|
> {$FRANKENPHP_WORKER_CONFIG}
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD010 -->
|
||||||
|
|
||||||
|
## Installing Development Versions of Symfony
|
||||||
|
|
||||||
|
To install a non-stable version of Symfony,
|
||||||
|
use the `STABILITY` environment variable during the build.
|
||||||
|
|
||||||
|
The value must be [a valid Composer stability option](https://getcomposer.org/doc/04-schema.md#minimum-stability).
|
||||||
|
|
||||||
|
For instance, use the following command to use the development branch of Symfony:
|
||||||
|
|
||||||
|
On Linux:
|
||||||
|
|
||||||
|
```console
|
||||||
|
STABILITY=dev docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
set STABILITY=dev && docker compose up --wait&set STABILITY=
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Custom HTTP Ports
|
||||||
|
|
||||||
|
Use the environment variables `HTTP_PORT`, `HTTPS_PORT` and/or `HTTP3_PORT`
|
||||||
|
to adjust the ports to your needs, e.g.
|
||||||
|
|
||||||
|
```console
|
||||||
|
HTTP_PORT=8000 HTTPS_PORT=4443 HTTP3_PORT=4443 docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
to access your application on [https://localhost:4443](https://localhost:4443).
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> Let's Encrypt only supports the standard HTTP and HTTPS ports.
|
||||||
|
> Creating a Let's Encrypt certificate for another port will not work,
|
||||||
|
> you have to use the standard ports or to configure Caddy to use another provider.
|
||||||
|
|
||||||
|
## `Caddyfile` Options
|
||||||
|
|
||||||
|
You can also customize the `Caddyfile` by using the following environment variables
|
||||||
|
to inject options block, directive or configuration.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
>
|
||||||
|
> All the following environment variables can be defined in your `.env` file
|
||||||
|
> at the root of the project to keep them persistent at each startup.
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
| Environment variable | Description | Default value |
|
||||||
|
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
||||||
|
| `CADDY_GLOBAL_OPTIONS` | the [global options block](https://caddyserver.com/docs/caddyfile/options#global-options), one per line | |
|
||||||
|
| `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 | |
|
||||||
|
| `CADDY_SERVER_EXTRA_DIRECTIVES` | the [`Caddyfile` directives](https://caddyserver.com/docs/caddyfile/concepts#directives) | |
|
||||||
|
| `CADDY_SERVER_LOG_OPTIONS` | the [server log options block](https://caddyserver.com/docs/caddyfile/directives/log), one per line | |
|
||||||
|
| `SERVER_NAME` | the server name or address | `localhost` |
|
||||||
|
| `FRANKENPHP_CONFIG` | a list of extra [FrankenPHP global directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | |
|
||||||
|
| `FRANKENPHP_WORKER_CONFIG` | a list of extra [FrankenPHP worker directives](https://frankenphp.dev/docs/config/#caddyfile-config), one per line | |
|
||||||
|
| `MERCURE_PUBLISHER_JWT_KEY` | the JWT key to use for publishers | |
|
||||||
|
| `MERCURE_PUBLISHER_JWT_ALG` | the JWT algorithm to use for publishers | `HS256` |
|
||||||
|
| `MERCURE_SUBSCRIBER_JWT_KEY` | the JWT key to use for subscribers | |
|
||||||
|
| `MERCURE_SUBSCRIBER_JWT_ALG` | the JWT algorithm to use for subscribers | `HS256` |
|
||||||
|
| `MERCURE_EXTRA_DIRECTIVES` | a list of extra [Mercure directives](https://mercure.rocks/docs/hub/config), one per line | |
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
|
|
||||||
|
### Customizing the Server Name
|
||||||
|
|
||||||
|
```console
|
||||||
|
SERVER_NAME="app.localhost" docker compose up --wait
|
||||||
|
```
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Deploying in Production
|
||||||
|
|
||||||
|
Symfony Docker provides Docker images and a Docker Compose definition optimized
|
||||||
|
for production usage.
|
||||||
|
In this tutorial, we will learn how to deploy our Symfony application
|
||||||
|
on a single server using Docker Compose.
|
||||||
|
|
||||||
|
## Preparing a Server
|
||||||
|
|
||||||
|
To deploy your application in production, you need a server.
|
||||||
|
In this tutorial, we will use a virtual machine provided by DigitalOcean,
|
||||||
|
but any Linux server can work.
|
||||||
|
|
||||||
|
If you already have a Linux server with Docker Compose installed,
|
||||||
|
you can skip straight to [the next section](#configuring-a-domain-name).
|
||||||
|
|
||||||
|
Otherwise, use [this affiliate link](https://m.do.co/c/5d8aabe3ab80)
|
||||||
|
to get $100 of free credit, create an account, then click on "Create a Droplet".
|
||||||
|
Then, click on the "Marketplace" tab under the "Choose an image" section
|
||||||
|
and search for the app named "Docker".
|
||||||
|
This will provision an Ubuntu server with the latest versions of Docker and
|
||||||
|
Docker Compose already installed!
|
||||||
|
|
||||||
|
For test purposes, the cheapest plans will be enough,
|
||||||
|
even though you might want at least 2GB of RAM to execute Docker Compose
|
||||||
|
for the first time.
|
||||||
|
For real production usage,
|
||||||
|
you'll probably want to pick a plan in the "general purpose" section
|
||||||
|
to fit your needs.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can keep the defaults for other settings, or tweak them according to your needs.
|
||||||
|
Don't forget to add your SSH key or create a password
|
||||||
|
then press the "Finalize and create" button.
|
||||||
|
|
||||||
|
Then, wait a few seconds while your Droplet is provisioning.
|
||||||
|
When your Droplet is ready, use SSH to connect:
|
||||||
|
|
||||||
|
```console
|
||||||
|
ssh root@<droplet-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring a Domain Name
|
||||||
|
|
||||||
|
In most cases, you'll want to associate a domain name with your site.
|
||||||
|
If you don't own a domain name yet, you'll have to buy one through a registrar.
|
||||||
|
|
||||||
|
Then create a DNS record of type `A` for your domain name pointing
|
||||||
|
to the IP address of your server:
|
||||||
|
|
||||||
|
```dns
|
||||||
|
your-domain-name.example.com. IN A 207.154.233.113
|
||||||
|
```
|
||||||
|
|
||||||
|
Example with the DigitalOcean Domains service ("Networking" > "Domains"):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> Let's Encrypt, the service used by default by Symfony Docker to automatically
|
||||||
|
> generate a TLS certificate doesn't support using bare IP addresses.
|
||||||
|
> Using a domain name is mandatory to use Let's Encrypt.
|
||||||
|
|
||||||
|
## Deploying
|
||||||
|
|
||||||
|
Copy your project on the server using `git clone`, `scp`, or any other tool
|
||||||
|
that may fit your need.
|
||||||
|
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).
|
||||||
|
Deploy keys are also [supported by GitLab](https://docs.gitlab.com/user/project/deploy_keys/).
|
||||||
|
|
||||||
|
Example with Git:
|
||||||
|
|
||||||
|
```console
|
||||||
|
git clone git@github.com:<username>/<project-name>.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Go into the directory containing your project (`<project-name>`),
|
||||||
|
and start the app in production mode:
|
||||||
|
|
||||||
|
```console
|
||||||
|
# Build fresh production image
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||||
|
|
||||||
|
# Start container
|
||||||
|
SERVER_NAME=your-domain-name.example.com \
|
||||||
|
APP_SECRET=ChangeMe \
|
||||||
|
CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
Be sure to replace `your-domain-name.example.com` with your actual domain name
|
||||||
|
and to set the values of `APP_SECRET`, `CADDY_MERCURE_JWT_SECRET`
|
||||||
|
to cryptographically secure random values.
|
||||||
|
|
||||||
|
Your server is up and running, and a HTTPS certificate has been automatically
|
||||||
|
generated for you.
|
||||||
|
Go to `https://your-domain-name.example.com` and enjoy!
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
>
|
||||||
|
> Docker can have a cache layer, make sure you have the right build
|
||||||
|
> for each deployment or rebuild your project with `--no-cache` option
|
||||||
|
> to avoid cache issues.
|
||||||
|
|
||||||
|
## Disabling HTTPS
|
||||||
|
|
||||||
|
Alternatively, if you don't want to expose an HTTPS server but only an HTTP one,
|
||||||
|
run the following command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SERVER_NAME=:80 \
|
||||||
|
APP_SECRET=ChangeMe \
|
||||||
|
CADDY_MERCURE_JWT_SECRET=ChangeThisMercureHubJWTSecretKey \
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deploying on Multiple Nodes
|
||||||
|
|
||||||
|
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/),
|
||||||
|
which is compatible with the provided Compose files.
|
||||||
|
To deploy on Kubernetes, take a look
|
||||||
|
at [the Helm chart provided with API Platform](https://api-platform.com/docs/deployment/kubernetes/),
|
||||||
|
which can be easily adapted for use with Symfony Docker.
|
||||||
|
|
||||||
|
## Passing local environment variables to containers
|
||||||
|
|
||||||
|
By default, `.env.local` and `.env.*.local` files are excluded from production images.
|
||||||
|
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):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# compose.prod.yaml
|
||||||
|
|
||||||
|
services:
|
||||||
|
php:
|
||||||
|
env_file:
|
||||||
|
- .env.prod.local
|
||||||
|
# ...
|
||||||
|
```
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
# TLS Certificates
|
||||||
|
|
||||||
|
## Trusting the Authority
|
||||||
|
|
||||||
|
With a standard installation, the authority used to sign certificates
|
||||||
|
generated in the Caddy container is not trusted by your local machine.
|
||||||
|
|
||||||
|
You must add the authority to the trust store of the host.
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
```console
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mac
|
||||||
|
|
||||||
|
```console
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
|
|
||||||
|
## Using Custom TLS Certificates
|
||||||
|
|
||||||
|
By default, Caddy will automatically generate TLS certificates using Let's Encrypt
|
||||||
|
or ZeroSSL.
|
||||||
|
But sometimes you may prefer using custom certificates.
|
||||||
|
|
||||||
|
For instance, to use self-signed certificates created with [mkcert](https://github.com/FiloSottile/mkcert)
|
||||||
|
do as follows:
|
||||||
|
|
||||||
|
1. Locally install `mkcert`
|
||||||
|
2. Create the folder storing the certs:
|
||||||
|
|
||||||
|
```console
|
||||||
|
mkdir -p frankenphp/certs
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Generate the certificates for your local host (example: "server-name.localhost"):
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
```console
|
||||||
|
mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost"
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
|
|
||||||
|
4. Add these lines to the `./compose.override.yaml` file about `CADDY_SERVER_EXTRA_DIRECTIVES`
|
||||||
|
environment and volume for the `php` service:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
php:
|
||||||
|
environment:
|
||||||
|
+ CADDY_EXTRA_CONFIG: |
|
||||||
|
+ https:// {
|
||||||
|
+ tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key
|
||||||
|
+ }
|
||||||
|
# ...
|
||||||
|
volumes:
|
||||||
|
+ - ./frankenphp/certs:/etc/caddy/certs:ro
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Restart your `php` service
|
||||||
|
|
||||||
|
## Disabling HTTPS for Local Development
|
||||||
|
|
||||||
|
To disable HTTPS, configure your environment to use HTTP by setting the following
|
||||||
|
variables and starting the project with this command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
SERVER_NAME=http://localhost \
|
||||||
|
MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \
|
||||||
|
docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure your application is accessible over HTTP by visiting `http://localhost`
|
||||||
|
in your web browser.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## Editing Permissions on Linux
|
||||||
|
|
||||||
|
If you work on Linux and cannot edit some of the project files right after
|
||||||
|
the first installation, you can run the following command
|
||||||
|
to set yourself as owner of the project files that were created by the Docker container:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose run --rm php chown -R $(id -u):$(id -g) .
|
||||||
|
```
|
||||||
|
|
||||||
|
## TLS/HTTPS Issues
|
||||||
|
|
||||||
|
See the [TLS section](tls.md) for more details.
|
||||||
|
|
||||||
|
## Production Issues
|
||||||
|
|
||||||
|
### How To Properly Build Fresh Images for Production Use
|
||||||
|
|
||||||
|
Remember that, by default, if you run `docker compose up --wait`,
|
||||||
|
only the files `compose.yaml` and `compose.override.yaml` will be used.
|
||||||
|
See ["How Compose works"](https://docs.docker.com/compose/intro/compose-application-model)
|
||||||
|
and ["Merge Compose files"](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge).
|
||||||
|
|
||||||
|
If you need to build images for production environment, you have to use the following
|
||||||
|
command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building Dev and Prod Images
|
||||||
|
|
||||||
|
Dev and prod images use distinct image names (`app-php-dev` and `app-php-prod`),
|
||||||
|
so they won't conflict with each other.
|
||||||
|
|
||||||
|
To build and start the dev image:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
To build and start the prod image:
|
||||||
|
|
||||||
|
```console
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache
|
||||||
|
docker compose -f compose.yaml -f compose.prod.yaml up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
>
|
||||||
|
> The order of `-f` arguments matters.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Updating Your Project
|
||||||
|
|
||||||
|
To import the changes made to the _Symfony Docker_ template into your project,
|
||||||
|
we recommend using [_template-sync_](https://github.com/coopTilleuls/template-sync):
|
||||||
|
|
||||||
|
1. Run the script to synchronize your project with the latest version of the skeleton:
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD013 -->
|
||||||
|
|
||||||
|
```console
|
||||||
|
curl -sSL https://raw.githubusercontent.com/coopTilleuls/template-sync/main/template-sync.sh | sh -s -- https://github.com/dunglas/symfony-docker
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- markdownlint-enable MD013 -->
|
||||||
|
|
||||||
|
2. Resolve conflicts, if any
|
||||||
|
3. Run `git cherry-pick --continue`
|
||||||
|
|
||||||
|
For more advanced options, refer to [the documentation of _template sync_](https://github.com/coopTilleuls/template-sync#template-sync).
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# Using Xdebug
|
||||||
|
|
||||||
|
The default development image is shipped with [Xdebug](https://xdebug.org/),
|
||||||
|
a popular debugger and profiler for PHP.
|
||||||
|
|
||||||
|
When using [Dev Containers](https://containers.dev/), Xdebug is pre-configured and works out of the box.
|
||||||
|
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.
|
||||||
|
|
||||||
|
For other setups, because it has a significant performance overhead, the step-by-step debugger
|
||||||
|
is disabled by default.
|
||||||
|
It can be enabled by including `debug` in the values of the `XDEBUG_MODE` environment variable.
|
||||||
|
|
||||||
|
On Linux and Mac:
|
||||||
|
|
||||||
|
```console
|
||||||
|
XDEBUG_MODE=develop,debug docker compose up --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
|
||||||
|
```console
|
||||||
|
set XDEBUG_MODE=develop,debug&& docker compose up --wait&set XDEBUG_MODE=
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging with Xdebug and PhpStorm
|
||||||
|
|
||||||
|
First, [create a PHP debug remote server configuration](https://www.jetbrains.com/help/phpstorm/creating-a-php-debug-server-configuration.html):
|
||||||
|
|
||||||
|
1. In the `Settings/Preferences` dialog, go to `PHP | Servers`
|
||||||
|
2. Create a new server:
|
||||||
|
- Name: `symfony` (or whatever you want to use for the variable `PHP_IDE_CONFIG`)
|
||||||
|
- Host: `localhost` (or the one defined using the `SERVER_NAME` environment variable)
|
||||||
|
- Port: `443`
|
||||||
|
- Debugger: `Xdebug`
|
||||||
|
- Check `Use path mappings`
|
||||||
|
- Absolute path on the server: `/app`
|
||||||
|
|
||||||
|
You can now use the debugger!
|
||||||
|
|
||||||
|
1. In PhpStorm, open the `Run` menu and click on `Start Listening for PHP Debug Connections`
|
||||||
|
2. Add the `XDEBUG_SESSION=PHPSTORM` query parameter to the URL of
|
||||||
|
the page you want to debug, or use [other available triggers](https://xdebug.org/docs/step_debug#activate_debugger)
|
||||||
|
|
||||||
|
Alternatively, you can use [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions)
|
||||||
|
for your preferred web browser.
|
||||||
|
|
||||||
|
3. On the command line, we might need to tell PhpStorm which
|
||||||
|
[path mapping configuration](https://www.jetbrains.com/help/phpstorm/zero-configuration-debugging-cli.html#configure-path-mappings)
|
||||||
|
should be used, set the value of the PHP_IDE_CONFIG environment variable to
|
||||||
|
`serverName=symfony`, where `symfony` is the name of the debug server configured
|
||||||
|
above.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```console
|
||||||
|
XDEBUG_SESSION=1 PHP_IDE_CONFIG="serverName=symfony" php bin/console ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging with Xdebug and Visual Studio Code
|
||||||
|
|
||||||
|
1. Install necessary [PHP extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=DEVSENSE.phptools-vscode).
|
||||||
|
2. Add [debug configuration](https://code.visualstudio.com/docs/debugtest/debugging-configuration#_launch-configurations)
|
||||||
|
into your `.vscode\launch.json` file.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug PHP",
|
||||||
|
"type": "php",
|
||||||
|
"request": "launch",
|
||||||
|
"pathMappings": {
|
||||||
|
"/app": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Use [Run and Debug](https://code.visualstudio.com/docs/debugtest/debugging#_start-a-debugging-session)
|
||||||
|
options and run `Debug PHP` to listen for upcoming connections
|
||||||
|
with [the **Xdebug extension**](https://xdebug.org/docs/step_debug#browser-extensions)
|
||||||
|
installed and active.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
Inspect the installation with the following command.
|
||||||
|
The Xdebug version should be displayed.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ docker compose exec php php --version
|
||||||
|
|
||||||
|
PHP ...
|
||||||
|
with Xdebug v3.x.x ...
|
||||||
|
```
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
skip_install_trust
|
||||||
|
|
||||||
|
{$CADDY_GLOBAL_OPTIONS}
|
||||||
|
|
||||||
|
frankenphp {
|
||||||
|
{$FRANKENPHP_CONFIG}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{$CADDY_EXTRA_CONFIG}
|
||||||
|
|
||||||
|
{$SERVER_NAME:localhost} {
|
||||||
|
log {
|
||||||
|
{$CADDY_SERVER_LOG_OPTIONS}
|
||||||
|
# Redact the authorization query parameter that can be set by Mercure
|
||||||
|
format filter {
|
||||||
|
request>uri query {
|
||||||
|
replace authorization REDACTED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root /app/public
|
||||||
|
encode zstd br gzip
|
||||||
|
|
||||||
|
mercure {
|
||||||
|
# Publisher JWT key
|
||||||
|
publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
|
||||||
|
# Subscriber JWT key
|
||||||
|
subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
|
||||||
|
# Allow anonymous subscribers (double-check that it's what you want)
|
||||||
|
anonymous
|
||||||
|
# Enable the subscription API (double-check that it's what you want)
|
||||||
|
subscriptions
|
||||||
|
# Extra directives
|
||||||
|
{$MERCURE_EXTRA_DIRECTIVES}
|
||||||
|
}
|
||||||
|
|
||||||
|
vulcain
|
||||||
|
|
||||||
|
{$CADDY_SERVER_EXTRA_DIRECTIVES}
|
||||||
|
|
||||||
|
# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
|
||||||
|
header ?Permissions-Policy "browsing-topics=()"
|
||||||
|
|
||||||
|
@phpRoute {
|
||||||
|
not path /.well-known/mercure*
|
||||||
|
not file {path}
|
||||||
|
}
|
||||||
|
rewrite @phpRoute index.php
|
||||||
|
|
||||||
|
@frontController path index.php
|
||||||
|
php @frontController {
|
||||||
|
{$FRANKENPHP_SITE_CONFIG}
|
||||||
|
|
||||||
|
worker {
|
||||||
|
file ./public/index.php
|
||||||
|
{$FRANKENPHP_WORKER_CONFIG}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_server {
|
||||||
|
hide *.php
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
expose_php = 0
|
||||||
|
date.timezone = UTC
|
||||||
|
apc.enable_cli = 1
|
||||||
|
session.use_strict_mode = 1
|
||||||
|
zend.detect_unicode = 0
|
||||||
|
|
||||||
|
; https://symfony.com/doc/current/performance.html
|
||||||
|
realpath_cache_size = 4096K
|
||||||
|
realpath_cache_ttl = 600
|
||||||
|
opcache.interned_strings_buffer = 16
|
||||||
|
opcache.max_accelerated_files = 32531
|
||||||
|
opcache.memory_consumption = 256
|
||||||
|
opcache.enable_file_override = 1
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
; See https://docs.docker.com/desktop/features/networking/networking-how-tos/#connect-a-container-to-a-service-on-the-host
|
||||||
|
; See https://github.com/docker/for-linux/issues/264
|
||||||
|
; The `client_host` below may optionally be replaced with `discover_client_host=yes`
|
||||||
|
; Add `start_with_request=yes` to start debug session on each request
|
||||||
|
xdebug.client_host = host.docker.internal
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
; https://symfony.com/doc/current/performance.html#use-the-opcache-class-preloading
|
||||||
|
opcache.preload_user = www-data
|
||||||
|
opcache.preload = /app/config/preload.php
|
||||||
|
; https://symfony.com/doc/current/performance.html#don-t-check-php-files-timestamps
|
||||||
|
opcache.validate_timestamps = 0
|
||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then
|
||||||
|
|
||||||
|
if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then
|
||||||
|
composer install --prefer-dist --no-progress --no-interaction
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display information about the current project
|
||||||
|
# Or about an error in project initialization
|
||||||
|
php bin/console -V
|
||||||
|
|
||||||
|
if grep -q ^DATABASE_URL= .env; then
|
||||||
|
echo 'Waiting for database to be ready...'
|
||||||
|
ATTEMPTS_LEFT_TO_REACH_DATABASE=60
|
||||||
|
until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do
|
||||||
|
if [ $? -eq 255 ]; then
|
||||||
|
# If the Doctrine command exits with 255, an unrecoverable error occurred
|
||||||
|
ATTEMPTS_LEFT_TO_REACH_DATABASE=0
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1))
|
||||||
|
echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left."
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then
|
||||||
|
echo 'The database is not up or not reachable:'
|
||||||
|
echo "$DATABASE_ERROR"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo 'The database is now ready and reachable'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(find ./migrations -iname '*.php' -print -quit)" ]; then
|
||||||
|
php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo 'PHP app ready!'
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec docker-php-entrypoint "$@"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Kernel;
|
||||||
|
|
||||||
|
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||||
|
|
||||||
|
return static function (array $context) {
|
||||||
|
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||||
|
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||||
|
|
||||||
|
class Kernel extends BaseKernel
|
||||||
|
{
|
||||||
|
use MicroKernelTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string> An array of allowed values for APP_ENV
|
||||||
|
*/
|
||||||
|
private function getAllowedEnvs(): array
|
||||||
|
{
|
||||||
|
return ['prod', 'dev', 'test'];
|
||||||
|
}
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"doctrine/deprecations": {
|
||||||
|
"version": "1.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "fdd756167454623e21f1d769c5b814b243782a67"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"symfony/console": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "5.3",
|
||||||
|
"ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bin/console"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/flex": {
|
||||||
|
"version": "2.11",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "2.4",
|
||||||
|
"ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
".env",
|
||||||
|
".env.dev"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/framework-bundle": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "8.1",
|
||||||
|
"ref": "312027aea160796a50bf2d185503afdb5d71f570"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/cache.yaml",
|
||||||
|
"config/packages/framework.yaml",
|
||||||
|
"config/preload.php",
|
||||||
|
"config/routes/framework.yaml",
|
||||||
|
"config/services.yaml",
|
||||||
|
"public/index.php",
|
||||||
|
"src/Controller/.gitignore",
|
||||||
|
"src/Kernel.php",
|
||||||
|
".editorconfig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/maker-bundle": {
|
||||||
|
"version": "1.67",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"symfony/property-info": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "7.3",
|
||||||
|
"ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/property_info.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/routing": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "7.4",
|
||||||
|
"ref": "bc94c4fd86f393f3ab3947c18b830ea343e51ded"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/routing.yaml",
|
||||||
|
"config/routes.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/security-bundle": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "7.4",
|
||||||
|
"ref": "c42fee7802181cdd50f61b8622715829f5d2335c"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/security.yaml",
|
||||||
|
"config/routes/security.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/twig-bundle": {
|
||||||
|
"version": "8.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.4",
|
||||||
|
"ref": "f250159ebe99153d0c640a3e7742876fc7453f2c"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/twig.yaml",
|
||||||
|
"templates/base.html.twig"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||||
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||||
|
{% block stylesheets %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascripts %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set frankenphpHotReload = app.request.server.get('FRANKENPHP_HOT_RELOAD') %}
|
||||||
|
{% if frankenphpHotReload %}
|
||||||
|
<meta name="frankenphp-hot-reload:url" content="{{ frankenphpHotReload }}">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/idiomorph"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/frankenphp-hot-reload/+esm" type="module"></script>
|
||||||
|
{% endif %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user