diff --git a/.dockerignore b/.dockerignore index b873b22..5f2b335 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,3 @@ -# Ignore Roadiz tools and cache for -# creating a docker image .dockerignore .DS_Store .git @@ -14,50 +12,38 @@ tests README.md Dockerfile Dockerfile.archive -docker-compose.yml -docker-compose.env -docker-compose.standalone.yml +compose.* +sonar-project.properties */temp* */*/temp* -docker -.vagrant -var/sessions/* -var/log/* -var/cache/* -var/secret/* +var /config/secrets/prod/prod.decrypt.private.php /config/secrets/prod/prod.encrypt.private.php -var/*.zip -var/*.sql -var/*.tar.gz *.zip *.sql *.log +*.tar *.tar.gz -themes/*/build -themes/*/node_modules -themes/*/app */*/*/node_modules files/* public/files/* */*/*/src-img */*/src-img */*.log -Vagrantfile -pimple.json +.phpcs-cache supervisord.pid project_env.sh -.phpcs-cache +.php-cs-fixer.cache +vendor +Makefile +.editorconfig +.gitignore +phpcs.* +phpstan.* +restic.* +auth.json !.env -!vendor -!docker/solr/managed-schema.xml -!docker/php-fpm-alpine/crontab.txt -!docker/php-fpm-alpine/docker-php-entrypoint -!docker/php-fpm-alpine/docker-cron-entrypoint -!docker/php-fpm-alpine/php.ini -!docker/php-fpm-alpine/php.prod.ini -!docker/php-fpm-alpine/wait-for-it.sh !public/themes/* diff --git a/.env b/.env index 029a471..487479a 100644 --- a/.env +++ b/.env @@ -14,8 +14,8 @@ # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration # Main user is 1000 on Linux -USER_UID=1000 -PUBLIC_APP_PORT=8781 +UID=1000 +PUBLIC_NGINX_PORT=8781 PUBLIC_VARNISH_PORT=8784 PUBLIC_PMA_PORT=8782 PUBLIC_DB_PORT=3306 @@ -50,7 +50,7 @@ HTTP_CACHE_STALE_WHILE_REVALIDATE=60 # Default dev env use varnish HOSTNAME_VARNISH=`roadiz-skeleton.test`,`roadiz-skeleton.local` # Use traefik path_prefix to host API and NuxtJS on the same domain -PATH_PREFIX=`/rz-admin`,`/files`,`/assets`,`/themes`,`/bundles`,`/robots.txt`,`/api`,`/_wdt`,`/_profiler`,`/css/main-color.css`,`/custom-form`,`/css/login/image` +PATH_PREFIX=`/rz-admin`,`/files`,`/assets`,`/themes`,`/bundles`,`/api`,`/_wdt`,`/_profiler`,`/css/main-color.css`,`/custom-form`,`/css/login/image` REDIRECT_REGEX=^(https?)://api\.roadiz\-skeleton\.test/(.*) ## Dollar char may be interpolated or not depending your system @@ -61,15 +61,6 @@ HOSTNAME_PMA=`pma.roadiz-skeleton.test`,`pma.roadiz-skeleton.local` HOSTNAME_SOLR=`solr.roadiz-skeleton.test`,`solr.roadiz-skeleton.local` HOSTNAME_MAILER=`mail.roadiz-skeleton.test`,`mail.roadiz-skeleton.local` -# MySQL env vars for DOCKER -MYSQL_ROOT_PASSWORD=root -MYSQL_HOST=db -MYSQL_PORT=3306 -MYSQL_DATABASE=roadiz -MYSQL_USER=roadiz -MYSQL_PASSWORD=roadiz -MYSQL_VERSION=8.0 - ###> symfony/lock ### # Choose one of the stores below # postgresql+advisory://db_user:db_password@localhost/db_name @@ -135,9 +126,9 @@ CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1|192\.168\.[0-9]+\.[0-9]+)(:[ ###< nelmio/cors-bundle ### ###> symfony/framework-bundle ### +## Do not directly set APP_DEBUG in this file +## But use .env.local or .env.$APP_ENV.local instead APP_ENV=dev -APP_RUNTIME_ENV=dev -APP_DEBUG=1 REDIS_DSN=redis://redis:6379 # When using symfony server:start #REDIS_DSN=redis://127.0.0.1:6379 @@ -157,9 +148,9 @@ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml # # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" -DATABASE_URL="mysql://roadiz:roadiz@db:3306/roadiz?serverVersion=8&charset=utf8mb4" +DATABASE_URL="mysql://roadiz:roadiz@db:3306/roadiz?serverVersion=mariadb-10.11.9&charset=utf8mb4" # When using symfony server:start -#DATABASE_URL="mysql://roadiz:roadiz@127.0.0.1:3306/roadiz?serverVersion=8&charset=utf8mb4" +#DATABASE_URL="mysql://roadiz:roadiz@127.0.0.1:3306/roadiz?serverVersion=8.0.40&charset=utf8mb4" # DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8" ###< doctrine/doctrine-bundle ### diff --git a/.github/workflows/run-test.yml b/.github/workflows/run-test.yml index 5b0323a..11f7873 100644 --- a/.github/workflows/run-test.yml +++ b/.github/workflows/run-test.yml @@ -36,6 +36,6 @@ jobs: - name: Install Dependencies run: composer install --no-scripts --no-ansi --no-interaction --no-progress - name: Run PHP Code Sniffer - run: vendor/bin/phpcs -p ./src + run: vendor/bin/php-cs-fixer check --ansi -vvv - name: Run PHPStan run: vendor/bin/phpstan analyse --no-progress -c phpstan.neon diff --git a/.gitignore b/.gitignore index 138e7a3..8eb4f37 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ ###> symfony/framework-bundle ### /!.env /.env.local +/restic.env /.env.local.php /.env.*.local /config/secrets/prod/prod.decrypt.private.php @@ -10,6 +11,7 @@ /public/themes/ /var/ /vendor/ +compose.override.yml ###< symfony/framework-bundle ### ###> symfony/phpunit-bridge ### @@ -32,10 +34,6 @@ .phpcs-cache report.txt -###> squizlabs/php_codesniffer ### -/.phpcs-cache -/phpcs.xml -###< squizlabs/php_codesniffer ### openapi.json /*.sql /*.zip @@ -57,3 +55,8 @@ openapi.json !/var/export/.gitkeep supervisord.pid + +###> friendsofphp/php-cs-fixer ### +/.php-cs-fixer.php +/.php-cs-fixer.cache +###< friendsofphp/php-cs-fixer ### diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5620939..c370124 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,6 @@ -# Gitlab CI -# Replace “roadiz_skeleton” with your project slug -image: roadiz/php83-runner - stages: - test - build - - deploy - release # AutoDevOps templates for security @@ -19,12 +14,14 @@ variables: TIMEZONE: "Europe/Paris" SENTRY_URL: "" -roadiz_skeleton_test: +test: + image: roadiz/php83-runner stage: test interruptible: true only: - develop - tags + - merge_requests cache: key: ${CI_COMMIT_REF_SLUG} paths: @@ -40,63 +37,22 @@ roadiz_skeleton_test: coverage_report: coverage_format: cobertura path: coverage/cobertura.xml - #before_script: - #- eval "$(ssh-agent -s)" - #- echo "$COMPOSER_SERVER_PRIVATE_KEY" | tr -d '\r' | ssh-add - - ## - ## Create the SSH directory and give it the right permissions - ## - #- mkdir -p ~/.ssh - #- chmod 700 ~/.ssh - ## Use your Gitlab instance URL - #- ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts - #- ssh-keyscan -H 'github.com' >> ~/.ssh/known_hosts +# If you are using private repositories, you need to provide a COMPOSER_DEPLOY_TOKEN variable +# before_script: +# - composer config gitlab-token.gitlab.com ${COMPOSER_DEPLOY_TOKEN_USER} ${COMPOSER_DEPLOY_TOKEN} script: + # + # If you are using private repositories, you need to provide a COMPOSER_DEPLOY_TOKEN variable + # in your Gitlab / GitHub CI/CD settings. This deploy-token must have read access to your private repositories. + # - composer install - - php -d memory_limit=-1 vendor/bin/phpcs -p ./src + - php -d memory_limit=-1 vendor/bin/php-cs-fixer check --ansi -vvv - php -d memory_limit=-1 vendor/bin/phpstan analyse -c phpstan.neon - php -d memory_limit=-1 vendor/bin/phpunit --colors=never -roadiz_skeleton_build: +build_develop: stage: build - interruptible: true - only: - - develop - - tags - cache: - key: ${CI_COMMIT_REF_SLUG} - paths: - - vendor/ - variables: - # temporary vars for composer scripts only - APP_ENV: prod - JWT_PASSPHRASE: changeme - APP_SECRET: changeme - artifacts: - expire_in: 1 hour - paths: - - vendor/ - # Keep themes assets to include them in docker image - - public/themes/ - - public/bundles/ - #before_script: - #- eval "$(ssh-agent -s)" - #- echo "$COMPOSER_SERVER_PRIVATE_KEY" | tr -d '\r' | ssh-add - - ## - ## Create the SSH directory and give it the right permissions - ## - #- mkdir -p ~/.ssh - #- chmod 700 ~/.ssh - ## Use your Gitlab instance URL - #- ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts - #- ssh-keyscan -H 'github.com' >> ~/.ssh/known_hosts - script: - - composer install --no-dev --optimize-autoloader - -roadiz_skeleton_dev_docker: - stage: deploy image: docker:git - # Create a docker image only when a new tag is pushed only: - develop services: @@ -104,35 +60,19 @@ roadiz_skeleton_dev_docker: variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "/certs" + # Provide env vars for docker bake + REGISTRY: ${CI_REGISTRY_IMAGE} when: on_success - needs: ["roadiz_skeleton_build"] - dependencies: ["roadiz_skeleton_build"] script: # Connect to your Gitlab Registry - "echo \"Registry image: ${CI_REGISTRY_IMAGE} for develop\"" - "docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}" - # App image build - - "docker build -t ${CI_REGISTRY_IMAGE}:develop ." - - "docker push ${CI_REGISTRY_IMAGE}:develop" - ## Solr image build - #- "docker build -t ${CI_REGISTRY_IMAGE}/solr:develop ./docker/solr" - #- "docker push ${CI_REGISTRY_IMAGE}/solr:develop" - # Nginx image build - - "docker build -t ${CI_REGISTRY_IMAGE}/nginx:develop -f docker/nginx/Dockerfile ." - - "docker push ${CI_REGISTRY_IMAGE}/nginx:develop" - # Varnish image build - - "docker build -t ${CI_REGISTRY_IMAGE}/varnish:develop ./docker/varnish" - - "docker push ${CI_REGISTRY_IMAGE}/varnish:develop" + #- "docker buildx bake --set *.args.COMPOSER_DEPLOY_TOKEN=${COMPOSER_DEPLOY_TOKEN} --push" + - "docker buildx bake --push" -# -# Build App docker image with vendor and built assets -# included. You must configure your Gitlab Runner to -# support Docker-in-docker commands. -# -roadiz_skeleton_docker: - stage: deploy +build_tag: + stage: build image: docker:git - # Create a docker image only when a new tag is pushed only: - tags services: @@ -140,34 +80,16 @@ roadiz_skeleton_docker: variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "/certs" + # Provide env vars for docker bake + VERSION: ${CI_COMMIT_TAG} + REGISTRY: ${CI_REGISTRY_IMAGE} when: on_success - needs: ["roadiz_skeleton_build"] - dependencies: ["roadiz_skeleton_build"] - before_script: - # Need curl for pushing release to Sentry - #- apk add curl script: # Connect to your Gitlab Registry - "echo \"Registry image: ${CI_REGISTRY_IMAGE} for tag ${CI_COMMIT_TAG}\"" - "docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}" - # App image build - - "docker build -t ${CI_REGISTRY_IMAGE}:latest -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} ." - - "docker push ${CI_REGISTRY_IMAGE}:latest" - - "docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}" - ## Solr image build - #- "docker build -t ${CI_REGISTRY_IMAGE}/solr:latest -t ${CI_REGISTRY_IMAGE}/solr:${CI_COMMIT_TAG} ./docker/solr" - #- "docker push ${CI_REGISTRY_IMAGE}/solr:latest" - #- "docker push ${CI_REGISTRY_IMAGE}/solr:${CI_COMMIT_TAG}" - # Nginx image build - - "docker build -t ${CI_REGISTRY_IMAGE}/nginx:latest -t ${CI_REGISTRY_IMAGE}/nginx:${CI_COMMIT_TAG} -f docker/nginx/Dockerfile ." - - "docker push ${CI_REGISTRY_IMAGE}/nginx:latest" - - "docker push ${CI_REGISTRY_IMAGE}/nginx:${CI_COMMIT_TAG}" - # Varnish image build - - "docker build -t ${CI_REGISTRY_IMAGE}/varnish:latest -t ${CI_REGISTRY_IMAGE}/varnish:${CI_COMMIT_TAG} ./docker/varnish" - - "docker push ${CI_REGISTRY_IMAGE}/varnish:latest" - - "docker push ${CI_REGISTRY_IMAGE}/varnish:${CI_COMMIT_TAG}" - # Create Release on your app on Sentry - #- "curl ${SENTRY_URL} -X POST -H \"Content-Type: application/json\" -d \"{\\\"version\\\": \\\"${CI_COMMIT_TAG}\\\"}\"" + #- "docker buildx bake --set *.args.COMPOSER_DEPLOY_TOKEN=${COMPOSER_DEPLOY_TOKEN} --push" + - "docker buildx bake --push" create_gitlab_release: stage: release @@ -176,7 +98,7 @@ create_gitlab_release: - if: $CI_COMMIT_TAG script: - echo "Running the release job." - needs: [ "roadiz_skeleton_docker" ] + needs: [ "build_tag" ] when: on_success release: tag_name: $CI_COMMIT_TAG diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..0bb1378 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,26 @@ +in(__DIR__) + ->exclude([ + 'var', + 'docker', + 'config', + // Do not fix generated PHP files + 'src/GeneratedEntity', + 'vendor', + '.data', + '.github', + ]) +; + +return (new PhpCsFixer\Config()) + ->setRules([ + '@Symfony' => true, + 'blank_line_after_opening_tag' => true, + 'declare_strict_types' => true, + ]) + ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) + ->setRiskyAllowed(true) + ->setFinder($finder) +; diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c1d70..7250c90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,49 @@ All notable changes to project will be documented in this file. +## [2.4.0](https://github.com/roadiz/skeleton/compare/v2.3.9...v2.4.0) - 2024-12-06 + +### ⚠ Breaking changes + +- Base PHP image is now `php:8.3.13-fpm-bookworm` + +### Bug Fixes + +- Enable login-link feature - ([45b947a](https://github.com/roadiz/skeleton/commit/45b947affe23e254f2f935ea9d133e398f3159ce)) - Ambroise Maupate +- Removed `themes` from Dockerfile, removed ContactFormController in favor of Custom-forms - ([79f5167](https://github.com/roadiz/skeleton/commit/79f51679990c14ec27a152012792d6d5b7de1b47)) - Ambroise Maupate +- Use DEV cron entrypoint to prevent dumping production .env during development - ([b927159](https://github.com/roadiz/skeleton/commit/b9271593018c8de9c1647209bc2eab2903083376)) - Ambroise Maupate +- Update Github Action - ([85fdd82](https://github.com/roadiz/skeleton/commit/85fdd8298cf5a5198af1f61d8ccd68dc35938e68)) - Ambroise Maupate +- Do not use SSH keys volumes to share credentials between host and container, use `COMPOSER_DEPLOY_TOKEN` - ([4d01411](https://github.com/roadiz/skeleton/commit/4d01411b82475e7434cb37f4c8dc9d1a2db73e31)) - Ambroise Maupate + +### CI/CD + +- Set default docker user to `www-data` for docker images - ([45658ff](https://github.com/roadiz/skeleton/commit/45658ff21dc53ed637fcce0cf8ae9d45a39a5ca0)) - Ambroise Maupate +- Removed Composer private key, use a deploy token instead for private packages - ([18bbe92](https://github.com/roadiz/skeleton/commit/18bbe92329aa831c639b3f56d82a22d9baeaae38)) - Ambroise Maupate +- Added ParallelConfigFactory to PhpCsFixer - ([8018801](https://github.com/roadiz/skeleton/commit/801880193767fa2efd9869164a834cede7cea1c1)) - Ambroise Maupate +- Upgraded docker compose dev environment - ([dcbf346](https://github.com/roadiz/skeleton/commit/dcbf3463c7324cbd883d6ae9fd9ef1773d95f219)) - Ambroise Maupate +- Unnecessary job prefix, allow tests on merge_requests - ([de69c2c](https://github.com/roadiz/skeleton/commit/de69c2c8e9cede23982781be506010f23e176d07)) - Ambroise Maupate + +### Documentation + +- Improve README.md - ([fcd081c](https://github.com/roadiz/skeleton/commit/fcd081c54cfedf6b2a13c1083eecaf937f695f12)) - Ambroise Maupate +- Add suggestion about create first admin user with command line ([#6](https://github.com/roadiz/skeleton/issues/6)) - ([5e50725](https://github.com/roadiz/skeleton/commit/5e50725e9d89194cb1732873a9f9bc0357851489)) - Eliot + +### Features + +- Config updates for api-platform 3.3 - ([3baf2d0](https://github.com/roadiz/skeleton/commit/3baf2d0308dd4d6de461267c8a86ec61d3225163)) - Ambroise Maupate +- Prevent cron docker entrypoint to run as non-root user - ([2dc6c62](https://github.com/roadiz/skeleton/commit/2dc6c6248a6ef72f0a557c3727ad8286ce8d0fed)) - Ambroise Maupate +- Replace `squizlabs/php_codesniffer` package with `friendsofphp/php-cs-fixer` - ([a369090](https://github.com/roadiz/skeleton/commit/a36909011b085eb91aa6a0579a14859edbd9d234)) - Ambroise Maupate +- [**breaking**]Migrate Dockerfile to multi-stage build and get rid of `roadiz/php83-fpm-alpine` base image - ([d2f3899](https://github.com/roadiz/skeleton/commit/d2f3899d10e2fc5df5e341354a387e8129f26789)) - Ambroise Maupate +- Use Docker Buildx Bake - ([f9f0fe9](https://github.com/roadiz/skeleton/commit/f9f0fe9a42af3d598e8cd5475570f7cd5a5f3eb9)) - Ambroise Maupate +- Use Docker Buildx Bake with COMPOSER_DEPLOY_TOKEN - ([ba8ef7c](https://github.com/roadiz/skeleton/commit/ba8ef7c944e0c9c6154faeecc02759535a25e3b1)) - Ambroise Maupate +- Upgraded sentry/sentry-symfony to ^5.1 - ([82ce87e](https://github.com/roadiz/skeleton/commit/82ce87e61fa21e5ceda8fee3be0381b30f2fbb5c)) - Ambroise Maupate +- Use dedicated images for php and nginx, aligned workdirs ([#4](https://github.com/roadiz/skeleton/issues/4)) - ([464b4ac](https://github.com/roadiz/skeleton/commit/464b4ac5c77247c22a77d847d9d1e3eead3309d9)) - Ambroise Maupate +- Use mariadb by default - ([3d9a3ee](https://github.com/roadiz/skeleton/commit/3d9a3ee8d80013b1f4144002ce787cfd27be717e)) - Ambroise Maupate + +### Refactor + +- Remove sensio_framework_extra - ([7c4b921](https://github.com/roadiz/skeleton/commit/7c4b921565fc52aadce661c863b10b3f70ac3c90)) - eliot lauger + ## [2.3.9](https://github.com/roadiz/skeleton/compare/v2.3.8...v2.3.9) - 2024-08-01 ### Bug Fixes diff --git a/Dockerfile b/Dockerfile index cd2a72f..c96c72f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,68 +1,324 @@ -FROM roadiz/php83-fpm-alpine:latest +ARG PHP_VERSION=8.3.14 +ARG MYSQL_VERSION=8.0.40 +ARG NGINX_VERSION=1.27.2 +ARG MARIADB_VERSION=10.11.9 +ARG SOLR_VERSION=9 +ARG VARNISH_VERSION=7.1 + +ARG UID=1000 +ARG GID=${UID} + +####### +# PHP # +####### + +FROM php:${PHP_VERSION}-fpm-bookworm AS php + LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" -ARG USER_UID=1000 -ENV APP_ENV=prod -ENV APP_RUNTIME_ENV=prod -ENV APP_DEBUG=0 +ARG UID + +ARG COMPOSER_VERSION=2.8.1 +ARG PHP_EXTENSION_INSTALLER_VERSION=2.6.0 +ARG PHP_EXTENSION_REDIS_VERSION=6.1.0 + +SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] + ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg ENV MYSQL_HOST=db ENV MYSQL_PORT=3306 -HEALTHCHECK --start-period=30s --interval=1m --timeout=6s CMD bin/console monitor:health -q +COPY --link docker/php/crontab.txt /crontab.txt +COPY --link docker/php/wait-for-it.sh /wait-for-it.sh +COPY --link docker/php/fpm.d/www.conf ${PHP_INI_DIR}-fpm.d/zz-www.conf + +RUN < /etc/sudoers.d/php + +# App +install --verbose --owner php --group php --mode 0755 --directory /app + +/usr/bin/crontab -u php /crontab.txt +chmod +x /wait-for-it.sh +chown -R php:php /app + +# Php extensions +curl -sSLf https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions \ + --output /usr/local/bin/install-php-extensions +chmod +x /usr/local/bin/install-php-extensions +install-php-extensions \ + @composer-${COMPOSER_VERSION} \ + bcmath \ + exif \ + fileinfo \ + gd \ + gmp \ + iconv \ + intl \ + json \ + mbstring \ + opcache \ + openssl \ + pcntl \ + pdo_mysql \ + simplexml \ + xsl \ + zip \ + redis-${PHP_EXTENSION_REDIS_VERSION} +EOF + +WORKDIR /app + +################### +# PHP Development # +################### + +FROM php AS php-dev + +# If you depend on private Gitlab repositories, you must use a deploy token and username +# to use composer commands inside you +#ARG COMPOSER_DEPLOY_TOKEN +#ARG COMPOSER_DEPLOY_TOKEN_USER="gitlab+deploy-token-1" + +ENV APP_ENV=dev +ENV APP_RUNTIME_ENV=dev +ENV APP_DEBUG=1 + +# Configs +RUN ln -sf ${PHP_INI_DIR}/php.ini-development ${PHP_INI_DIR}/php.ini +COPY --link docker/php/conf.d/php.dev.ini ${PHP_INI_DIR}/conf.d/zz-app.ini +COPY --link --chmod=755 docker/php/docker-php-entrypoint-dev /usr/local/bin/docker-php-entrypoint +COPY --link --chmod=755 docker/php/docker-cron-entrypoint-dev /usr/local/bin/docker-cron-entrypoint + +RUN < /etc/sudoers.d/nginx + +# App +install --verbose --owner nginx --group nginx --mode 0755 --directory /app +EOF + +ENV NGINX_ENTRYPOINT_QUIET_LOGS=1 +# Config +COPY --link docker/nginx/nginx.conf /etc/nginx/nginx.conf +COPY --link docker/nginx/redirections.conf /etc/nginx/redirections.conf +COPY --link docker/nginx/mime.types /etc/nginx/mime.types +COPY --link docker/nginx/conf.d/_gzip.conf /etc/nginx/conf.d/_gzip.conf +COPY --link docker/nginx/conf.d/_security.conf /etc/nginx/conf.d/_security.conf +COPY --link docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf + +WORKDIR /app + + + +############## +# Nginx DEV # +############## + +FROM nginx AS nginx-dev + +# Silence entrypoint logs + +# Declare a volume for development +VOLUME /app + + + +############## +# Nginx PROD # +############## + +FROM nginx AS nginx-prod +# Copy public files from API +COPY --link --from=php-prod --chown=${USER_UID}:${USER_UID} /app/public /app/public + +# Only enable healthcheck in production when the app is ready to serve requests on root path +# This could prevent Traefik or an ingress controller to route traffic to the app +#HEALTHCHECK --start-period=1m30s --interval=1m --timeout=6s CMD curl --fail -I http://localhost + +######### +# MySQL # +######### + +FROM mysql:${MYSQL_VERSION} AS mysql + +LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" + +ARG UID + +SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] + +RUN < ['all' => true], - Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 603c808..7658c96 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -4,6 +4,16 @@ parameters: env(HTTP_CACHE_SHARED_MAX_AGE): 600 api_platform: + # required for WebResponse and CommonContent endpoints + use_symfony_listeners: true + formats: + jsonld: ['application/ld+json'] + json: ['application/json'] + x-www-form-urlencoded: ['application/x-www-form-urlencoded'] + docs_formats: + jsonld: ['application/ld+json'] + jsonopenapi: ['application/vnd.openapi+json'] + html: ['text/html'] patch_formats: json: ['application/merge-patch+json'] enable_swagger_ui: true diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 058aa80..44a1194 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -4,6 +4,7 @@ framework: trusted_proxies: '%env(TRUSTED_PROXIES)%' #csrf_protection: true http_method_override: false + handle_all_throwables: true # Enables session support. Note that the session will ONLY be started if you read or write from it. # Remove or comment this section to explicitly disable session support. @@ -51,8 +52,11 @@ when@test: session: storage_factory_id: session.storage.factory.mock_file -# Use Redis for session storage in production when@prod: framework: + # Use Redis for session storage in production session: handler_id: '%env(string:REDIS_DSN)%' + php_errors: + # E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED + log: 22519 diff --git a/config/packages/security.yaml b/config/packages/security.yaml index e68ffda..23fb450 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -76,6 +76,16 @@ security: secret: '%kernel.secret%' lifetime: 604800 # 1 week in seconds path: / + # Enable login-link feature + # https://symfony.com/doc/current/security/login_link.html + login_link: + check_route: login_link_check + signature_properties: [ 'id', 'email' ] + # lifetime in seconds + lifetime: 300 + # only allow the link to be used 3 times + max_uses: 3 + success_handler: RZ\Roadiz\CoreBundle\Security\Authentication\BackofficeAuthenticationSuccessHandler login_throttling: max_attempts: 3 logout: diff --git a/config/packages/sensio_framework_extra.yaml b/config/packages/sensio_framework_extra.yaml deleted file mode 100644 index 1821ccc..0000000 --- a/config/packages/sensio_framework_extra.yaml +++ /dev/null @@ -1,3 +0,0 @@ -sensio_framework_extra: - router: - annotations: false diff --git a/config/routes.yaml b/config/routes.yaml index f7b0db3..d39cbaa 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -15,19 +15,3 @@ rz_intervention_request: api_login_check: methods: [POST] path: /api/token - -api_contact_form_definition: - methods: [GET] - path: /api/contact_form/definition - defaults: - _controller: App\Controller\ContactFormController::definitionAction - _locale: en - _format: json - -api_contact_form_post: - methods: [POST] - path: /api/contact_form/post - defaults: - _controller: App\Controller\ContactFormController::formAction - _locale: en - _format: json diff --git a/config/services.yaml b/config/services.yaml index 350b550..d301000 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -21,9 +21,6 @@ services: - '../src/Kernel.php' - '../src/Tests/' - App\Controller\ContactFormController: - tags: [ 'controller.service_arguments' ] - App\Serializer\Normalizer\MenuLinkPathNormalizer: decorates: 'api_platform.jsonld.normalizer.item' # Need a different name to avoid duplicate YAML key diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..1f5fc66 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,47 @@ +variable "REGISTRY" { + default = "registry.xxxxx.com/group/project" +} + +variable "VERSION" { + default = "" +} + +group "default" { + targets = ["api"] +} + +target "api" { + name = "api-${item.name}" + platforms = ["linux/amd64"] + matrix = { + item = [ + { + name = "mariadb" + target = "mariadb" + }, + { + name = "php" + target = "php-prod" + }, + { + name = "nginx" + target = "nginx-prod" + }, + { + name = "varnish" + target = "varnish" + }, + # { + # name = "solr" + # target = "solr" + # }, + ] + } + context = "." + dockerfile = "Dockerfile" + target = item.target + tags = [ + notequal(VERSION, "") ? "${REGISTRY}/api-${item.name}:${VERSION}" : "${REGISTRY}/api-${item.name}:develop", + notequal(VERSION, "") ? "${REGISTRY}/api-${item.name}:latest" : "", + ] +} diff --git a/docker/mariadb/performances.cnf b/docker/mariadb/performances.cnf new file mode 100644 index 0000000..44ddb87 --- /dev/null +++ b/docker/mariadb/performances.cnf @@ -0,0 +1,4 @@ +[mysqld] +tmp_table_size = 64M +max_heap_table_size = 64M +sort_buffer_size = 64M diff --git a/docker/mysql/Dockerfile b/docker/mysql/Dockerfile deleted file mode 100644 index eb1b85b..0000000 --- a/docker/mysql/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM mysql:8.0 -LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" - -ARG USER_UID=1000 - -RUN usermod -u ${USER_UID} mysql \ - && groupmod -g ${USER_UID} mysql \ - && echo "USER_UID: ${USER_UID}\n" - diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile deleted file mode 100644 index f681ef7..0000000 --- a/docker/nginx/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM roadiz/nginx-alpine -LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" - -COPY ./public /var/www/html/public diff --git a/docker/nginx/conf.d/_gzip.conf b/docker/nginx/conf.d/_gzip.conf new file mode 100644 index 0000000..d518883 --- /dev/null +++ b/docker/nginx/conf.d/_gzip.conf @@ -0,0 +1,14 @@ +gzip on; +gzip_proxied any; +gzip_vary on; +gzip_comp_level 2; +gzip_min_length 256; +gzip_types application/atom+xml application/javascript application/json application/rss+xml + application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype + application/x-font-ttf application/x-javascript application/xhtml+xml application/xml + font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon + image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; +gzip_disable "MSIE [1-6]\.(?!.*SV1)"; +# make sure gzip does not lose large gzipped js or css files +# see http://blog.leetsoft.com/2007/7/25/nginx-gzip-ssl +gzip_buffers 16 8k; diff --git a/docker/nginx/conf.d/_security.conf b/docker/nginx/conf.d/_security.conf new file mode 100644 index 0000000..497d112 --- /dev/null +++ b/docker/nginx/conf.d/_security.conf @@ -0,0 +1,6 @@ +# Do not display nginx version +server_tokens off; + +add_header X-Frame-Options "SAMEORIGIN"; +add_header X-XSS-Protection "1; mode=block"; +add_header X-Content-Type-Options "nosniff"; diff --git a/docker/nginx/conf.d/default.conf b/docker/nginx/conf.d/default.conf new file mode 100644 index 0000000..2fef40c --- /dev/null +++ b/docker/nginx/conf.d/default.conf @@ -0,0 +1,140 @@ +client_max_body_size 256m; + +map $sent_http_content_type $expires { + default 1y; + "text/html" off; + "text/html; charset=utf-8" off; +} + +server { + listen 80; + server_name localhost; + + root /app/public; + + ## Only use this block if you are using Roadiz solo + index index.php index.html; + + include /etc/nginx/redirections.conf; + + # Kick wordpress brute force attack before it + # fills Roadiz logs with not-found resources. + location ~ ^/wp\-(includes|admin|login\.php) { + access_log off; + return 404; + } + + # Enable Expire on Themes public assets + location ~* ^/(?:bundles|themes|files|assets|storage)/*.*\.(?:ico|pdf|css|js|woff2?|eot|ttf|otf|svg|gif|jpe?g|png|webp|avif|mp4|webm)$ { + # Serve not found files with PHP + try_files $uri $uri/ /index.php$is_args$args; + + expires 1y; + access_log off; + add_header "Pragma" "public"; + add_header "Cache-Control" "public"; + add_header "Vary" "Accept-Encoding"; + add_header "X-Frame-Options" "SAMEORIGIN"; + add_header "X-XSS-Protection" "1; mode=block"; + add_header "X-Content-Type-Options" "nosniff"; + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + + if ($request_method = 'OPTIONS') { + access_log off; + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + ### When using Roadiz solo + location / { + # First attempt to serve request as file, then + # as directory, then fall back to front-end controller + # (do not forget to pass GET parameters). + try_files $uri $uri/ /index.php$is_args$args; + } + + ### When using Roadiz with Nuxt.js, uncomment these blocks + ### To enable monorepo routing + + # Catch all Roadiz routes first + #location ~ ^/(rz\-admin|files|assets|themes|bundles|api|_wdt|_profiler|css\/main\-color\.css|custom\-form|css\/login\/image) { + # try_files $uri $uri/ /index.php$is_args$args; + #} + + #location ~* \.(ico|css|js|woff2?|eot|ttf|otf|svg|gif|jpe?g|png|webp|mp4|avif|webm)$ { + # expires $expires; + # add_header Pragma public; + # add_header Cache-Control "public"; + # try_files $uri $uri/ @proxy; + #} + + ## Then Nuxt.js routes + #location / { + # expires $expires; + # try_files $uri $uri/index.html @proxy; + #} + + # + # PHP API entry point. + # + location ~ ^/index\.php(/|$) { + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass app:9000; + fastcgi_index index.php; + fastcgi_split_path_info ^(.+\.php)(.*)$; + + # Bigger buffer size to handle cache invalidation headers expansion + # https://github.com/api-platform/docs/blob/2.3/extra/troubleshooting.md#upstream-sent-too-big-header-while-reading-response-header-from-upstream-502-error + fastcgi_buffer_size 32k; + fastcgi_buffers 8 16k; + + include fastcgi_params; + try_files $uri =404; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/app.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + ## Uncomment this block if you are using a Node.js server + #location @proxy { + # add_header X-Frame-Options "SAMEORIGIN"; + # add_header X-Cache-Status $upstream_cache_status; + # proxy_redirect off; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # # Force HTTPS protocol because we are behind a reverse proxy + # proxy_set_header X-Forwarded-Proto https; + # proxy_read_timeout 1m; + # proxy_connect_timeout 1m; + # proxy_pass http://node:3000; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + location ~ /\.ht { + deny all; + } + location ~ /\.git { + deny all; + } + location = /README.md { + deny all; + } + location = /.nojekyll { + deny all; + } + + # Don't log robots.txt or favicon.ico files + location = /favicon.ico { log_not_found off; access_log off; } +} diff --git a/docker/nginx/mime.types b/docker/nginx/mime.types new file mode 100644 index 0000000..e390d97 --- /dev/null +++ b/docker/nginx/mime.types @@ -0,0 +1,116 @@ + +types { + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/javascript js; + application/atom+xml atom; + application/rss+xml rss; + + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/avif avif; + image/png png; + image/svg+xml svg svgz; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + + font/woff woff; + font/woff2 woff2; + + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.apple.mpegurl m3u8; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; + application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation + pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document + docx; + application/vnd.wap.wmlc wmlc; + application/wasm wasm; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/xspf+xml xspf; + application/zip zip; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; + + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; + + video/3gpp 3gpp 3gp; + video/mp2t ts; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; + + application/x-bb-appworld bbaw; + application/x-bittorrent torrent; + application/x-chrome-extension crx; + application/x-opera-extension oex; + application/xslt+xml xsl; + application/yaml yaml yml; + image/heif heic heif; + image/vnd.radiance hdr; + model/gltf+json gltf; + model/gltf-binary glb; + text/calendar ics; + text/csv csv; + text/markdown md markdown; + text/vcard vcard vcf; + text/vnd.rim.location.xloc xloc; + text/vtt vtt; +} diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 0000000..c0252dd --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,31 @@ + +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/docker/nginx/nuxt_ip_filter.conf b/docker/nginx/nuxt_ip_filter.conf new file mode 100644 index 0000000..5a16233 --- /dev/null +++ b/docker/nginx/nuxt_ip_filter.conf @@ -0,0 +1,3 @@ +## RZ VPN +#allow 51.15.243.128; +#deny all; diff --git a/docker/nginx/redirections.conf b/docker/nginx/redirections.conf new file mode 100644 index 0000000..bc10005 --- /dev/null +++ b/docker/nginx/redirections.conf @@ -0,0 +1 @@ +# All redirections diff --git a/docker/php-fpm-alpine/Dockerfile b/docker/php-fpm-alpine/Dockerfile deleted file mode 100755 index e37699b..0000000 --- a/docker/php-fpm-alpine/Dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -FROM roadiz/php83-fpm-alpine:latest -LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" - -ARG USER_UID=1000 -ENV COMPOSER_ALLOW_SUPERUSER=1 -ENV APP_ENV=dev -ENV APP_RUNTIME_ENV=dev -ENV APP_DEBUG=1 -ENV APP_FFMPEG_PATH=/usr/bin/ffmpeg -ENV MYSQL_HOST=db -ENV MYSQL_PORT=3306 - -HEALTHCHECK --start-period=30s --interval=1m --timeout=6s CMD bin/console monitor:health -q - -RUN apk add --no-cache shadow make git ffmpeg \ - && usermod -u ${USER_UID} www-data \ - && groupmod -g ${USER_UID} www-data \ - && composer --version \ - && ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \ - && "date" \ - && echo "USER_UID: ${USER_UID}\n" \ - && version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") - -# Display errors -ADD php.ini /usr/local/etc/php/php.ini -ADD crontab.txt /crontab.txt -ADD wait-for-it.sh /wait-for-it.sh -ADD docker-php-entrypoint-dev /usr/local/bin/docker-php-entrypoint -ADD docker-cron-entrypoint /usr/local/bin/docker-cron-entrypoint - -VOLUME /var/www/html -WORKDIR /var/www/html - -RUN chown -R www-data:www-data /var/www/html/ - -RUN ln -s /var/www/html/bin/console /usr/local/bin/console \ - && /usr/bin/crontab -u www-data /crontab.txt \ - && chmod +x /wait-for-it.sh \ - && chmod +x /usr/local/bin/docker-php-entrypoint \ - && chmod +x /usr/local/bin/docker-cron-entrypoint diff --git a/docker/php-fpm-alpine/crontab.txt b/docker/php-fpm-alpine/crontab.txt deleted file mode 100644 index 83d7f1d..0000000 --- a/docker/php-fpm-alpine/crontab.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Roadiz maintenance tasks - -### Update Solr index -0 0 * * * /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console solr:reindex --no-debug -n -q - -### Maintenance tasks: erase +6 months logs and keeps only 20 node-source versions -0 8 * * 1 /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console documents:file:size -q -0 1 * * * /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console logs:cleanup --erase -n -q -0 2 * * * /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console versions:purge -c 20 -n -q -0 3 * * * /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console custom-form-answer:prune -n -q -### Empty node trashcan every month -0 0 1 * * /usr/local/bin/php -d memory_limit=-1 /var/www/html/bin/console nodes:empty-trash -n -q diff --git a/docker/php-fpm-alpine/docker-cron-entrypoint b/docker/php-fpm-alpine/docker-cron-entrypoint deleted file mode 100755 index b02406f..0000000 --- a/docker/php-fpm-alpine/docker-cron-entrypoint +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -set -e - -env >> /etc/environment - -# Print env infos -echo "APP_ENV=${APP_ENV}"; -echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; -echo "APP_DEBUG=${APP_DEBUG}"; -# Debug infos -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_ENV=${APP_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_RUNTIME_ENV=${APP_RUNTIME_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_DEBUG=${APP_DEBUG}\""; - -/bin/chown -R www-data:www-data /var/www/html/var || true; -/bin/chown -R www-data:www-data /var/www/html/config || true; - -# Print local env vars to .env.xxx.php file for performances and crontab jobs -/usr/bin/sudo -E -u www-data -- bash -c "/usr/local/bin/composer dump-env prod" -# To improve performance (i.e. avoid decrypting secrets at runtime), -# you can decrypt your secrets during deployment to the "local" vault: -/usr/bin/sudo -E -u www-data -- bash -c "APP_RUNTIME_ENV=prod /var/www/html/bin/console secrets:decrypt-to-local --force" - -# Let cron take the wheel -echo "Starting cron in foreground." -/usr/sbin/crond -f -l 8 diff --git a/docker/php-fpm-alpine/docker-php-entrypoint b/docker/php-fpm-alpine/docker-php-entrypoint deleted file mode 100755 index 19e61c0..0000000 --- a/docker/php-fpm-alpine/docker-php-entrypoint +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh -set -e - -# Print env infos -echo "APP_ENV=${APP_ENV}"; -echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; -echo "APP_DEBUG=${APP_DEBUG}"; -# Debug infos -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_ENV=${APP_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_RUNTIME_ENV=${APP_RUNTIME_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_DEBUG=${APP_DEBUG}\""; - -# -# Override default entrypoint to add some maintenance and migration commands (PROD) -# DO NOT CALL THIS SCRIPT FOR WORKERS AND CRON containers (see docker-compose.yml) -# - -# Fix volume permissions -/bin/chown -R www-data:www-data /var/www/html/var || true; -/bin/chown -R www-data:www-data /var/www/html/public || true; -/bin/chown -R www-data:www-data /var/www/html/config || true; - -# Print local env vars to .env.xxx.php file for performances and crontab jobs -/usr/bin/sudo -E -u www-data -- bash -c "/usr/local/bin/composer dump-env prod" -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console assets:install -n" -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console themes:assets:install -n Rozier" - -# To improve performance (i.e. avoid decrypting secrets at runtime), -# you can decrypt your secrets during deployment to the "local" vault: -#/usr/bin/sudo -E -u www-data -- bash -c "APP_RUNTIME_ENV=prod /var/www/html/bin/console secrets:decrypt-to-local --force" - -# -# Wait for database to be ready for next commands and migrations -# -/wait-for-it.sh -t 0 -s ${MYSQL_HOST}:${MYSQL_PORT} - -## -## Uncomment following lines to generate node-types found in database -## This disallow automatic node-type update from Docker image, and local database -## has priority over committed changes -## -#/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console generate:nsentities" -#/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console generate:api-resources" - -## -## Uncomment following lines to enable automatic migration for your theme at each docker start -## -## Perform migrations directly as database should be ready thanks to wait-for-it.sh -# /usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console doctrine:migrations:migrate -n --allow-no-migration" -# /usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console app:install -n" - -# Clear caches after migrations -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console cache:clear -n" -# Clear all cache pool on Symfony 5.4 https://symfony.com/doc/5.4/cache.html#clearing-the-cache -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console cache:pool:clear cache.global_clearer -n" - -# first arg is `-f` or `--some-option` -if [ "${1#-}" != "$1" ]; then - set -- php-fpm "$@" -fi - -exec "$@" diff --git a/docker/php-fpm-alpine/docker-php-entrypoint-dev b/docker/php-fpm-alpine/docker-php-entrypoint-dev deleted file mode 100755 index 233356a..0000000 --- a/docker/php-fpm-alpine/docker-php-entrypoint-dev +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -set -e - -# Print env infos -echo "APP_ENV=${APP_ENV}"; -echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; -echo "APP_DEBUG=${APP_DEBUG}"; -# Debug infos -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_ENV=${APP_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_RUNTIME_ENV=${APP_RUNTIME_ENV}\""; -/usr/bin/sudo -E -u www-data -- bash -c "echo \"[sudo] APP_DEBUG=${APP_DEBUG}\""; - -# -# Override default entrypoint to add some maintenance DEV only. -# DO NOT CALL THIS SCRIPT FOR WORKERS AND CRON containers (see docker-compose.yml) -# - -# Fix volume permissions -/bin/chown -R www-data:www-data /var/www/html/var || true; -/bin/chown -R www-data:www-data /var/www/html/public || true; -/bin/chown -R www-data:www-data /var/www/html/config || true; - -# Print local env vars to .env.xxx.php file for performances and crontab jobs -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console assets:install -n" -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console themes:assets:install -n Rozier --relative --symlink" - -# -# Wait for database to be ready for next commands and migrations -# -/wait-for-it.sh -t 0 -s ${MYSQL_HOST}:${MYSQL_PORT} - -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console cache:clear -n" -# Clear all cache pool on Symfony 5.4 https://symfony.com/doc/5.4/cache.html#clearing-the-cache -/usr/bin/sudo -E -u www-data -- bash -c "/var/www/html/bin/console cache:pool:clear cache.global_clearer -n" - -# first arg is `-f` or `--some-option` -if [ "${1#-}" != "$1" ]; then - set -- php-fpm "$@" -fi - -exec "$@" diff --git a/docker/php-fpm-alpine/php.prod.ini b/docker/php-fpm-alpine/php.prod.ini deleted file mode 100644 index bbe4a96..0000000 --- a/docker/php-fpm-alpine/php.prod.ini +++ /dev/null @@ -1,38 +0,0 @@ -error_reporting = E_ALL & ~E_WARNING & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED -apc.enable_cli = 1 -date.timezone = Europe/Paris -session.auto_start = Off -; Session ID cannot be passed through URLs -session.use_only_cookies = On -; Uses a secure connection (HTTPS) if possible -; session.cookie_secure = On -; Do not accept uninitialized session ID -session.use_strict_mode = On -; Do not make session cookie available to JS -session.cookie_httponly = On -short_open_tag = Off - -; http://symfony.com/doc/current/performance.html -; Configure OPcache for Maximum Performance -opcache.enable=1 -opcache.memory_consumption=256 -opcache.max_accelerated_files = 20000 -opcache.interned_strings_buffer = 16 -opcache.enable_file_override = 1 -; Don't Check PHP Files Timestamps -opcache.validate_timestamps=0 -; Configure the PHP realpath Cache -realpath_cache_size = 4096K -realpath_cache_ttl = 600 -memory_limit = 512M -post_max_size = 256M -upload_max_filesize = 128M -expose_php = Off -display_errors = Off -zend.detect_unicode = 0 -opcache.preload_user=www-data -opcache.preload=/var/www/html/config/preload.php - -;; Sessions -;session.save_handler = redis -;session.save_path = "tcp://redis:6379" diff --git a/docker/php-fpm-alpine/php.ini b/docker/php/conf.d/php.dev.ini similarity index 63% rename from docker/php-fpm-alpine/php.ini rename to docker/php/conf.d/php.dev.ini index f5831b3..900924d 100644 --- a/docker/php-fpm-alpine/php.ini +++ b/docker/php/conf.d/php.dev.ini @@ -1,7 +1,3 @@ -error_reporting = E_ALL & ~E_DEPRECATED -html_errors = On - -apc.enable_cli = 0 date.timezone = Europe/Paris session.auto_start = Off ; Session ID cannot be passed through URLs @@ -16,22 +12,17 @@ short_open_tag = Off ; http://symfony.com/doc/current/performance.html ; Configure OPcache for Maximum Performance -opcache.enable=1 -opcache.memory_consumption=256 +opcache.revalidate_freq = 0 +opcache.memory_consumption = 256 opcache.max_accelerated_files = 20000 -; Don't Check PHP Files Timestamps -opcache.revalidate_freq=0 -opcache.validate_timestamps=1 -opcache.fast_shutdown=1 +opcache.interned_strings_buffer = 16 + ; Configure the PHP realpath Cache realpath_cache_size = 4096K realpath_cache_ttl = 600 + memory_limit = 512M -post_max_size = 256M -upload_max_filesize = 128M +post_max_size = 128M +upload_max_filesize = 64M expose_php = On display_errors = On - -;; Sessions -;session.save_handler = redis -;session.save_path = "tcp://redis:6379" diff --git a/docker/php/conf.d/php.prod.ini b/docker/php/conf.d/php.prod.ini new file mode 100644 index 0000000..4b7ce3c --- /dev/null +++ b/docker/php/conf.d/php.prod.ini @@ -0,0 +1,26 @@ +date.timezone = Europe/Paris +; Do not accept uninitialized session ID +session.use_strict_mode = On +; Do not make session cookie available to JS +session.cookie_httponly = On +short_open_tag = Off + +; http://symfony.com/doc/current/performance.html +; Configure OPcache for Maximum Performance +opcache.memory_consumption = 256 +opcache.max_accelerated_files = 20000 +opcache.interned_strings_buffer = 16 +; Don't Check PHP Files Timestamps +opcache.validate_timestamps = 0 +; Class preloading +opcache.preload_user = php +opcache.preload = /app/config/preload.php + +; Configure the PHP realpath Cache +realpath_cache_size = 4096K +realpath_cache_ttl = 600 + +memory_limit = 512M +post_max_size = 128M +upload_max_filesize = 64M +expose_php = Off diff --git a/docker/php/crontab.txt b/docker/php/crontab.txt new file mode 100644 index 0000000..0fb4d8d --- /dev/null +++ b/docker/php/crontab.txt @@ -0,0 +1,15 @@ +# Roadiz maintenance tasks + +### Update Solr index +0 0 * * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console solr:reindex --no-debug -n -q + +### Maintenance tasks: erase +6 months logs and keeps only 20 node-source versions +0 8 * * 1 /usr/local/bin/php -d memory_limit=-1 /app/bin/console documents:file:size -q +0 1 * * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console logs:cleanup --erase -n -q +0 2 * * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console versions:purge -c 20 -n -q +0 3 * * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console custom-form-answer:prune -n -q +### Empty node trashcan every month +0 0 1 * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console nodes:empty-trash -n -q + +### Log last cron exec time +0 4 * * * /usr/local/bin/php -d memory_limit=-1 /app/bin/console cron:set-last-exec-date -n -q diff --git a/docker/php/docker-cron-entrypoint b/docker/php/docker-cron-entrypoint new file mode 100755 index 0000000..7e1cf77 --- /dev/null +++ b/docker/php/docker-cron-entrypoint @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +env >> /etc/environment + +# cron entrypoint must be run as root as it spawns crontab for each system user +if [ "$(id -u)" -ne 0 ]; then + echo "Please run as root" + exit 1 +fi + +# Print env infos +echo "APP_ENV=${APP_ENV}"; +echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; +echo "APP_DEBUG=${APP_DEBUG}"; +# Debug infos +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_ENV=${APP_ENV}\""; +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_RUNTIME_ENV=${APP_RUNTIME_ENV}\""; +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_DEBUG=${APP_DEBUG}\""; + +/bin/chown -R php:php /app/var || true; +/bin/chown -R php:php /app/config || true; + +# Print local env vars to .env.xxx.php file for performances and crontab jobs +/usr/bin/sudo -E -u php -- bash -c "/usr/local/bin/composer dump-env prod" +# To improve performance (i.e. avoid decrypting secrets at runtime), +# you can decrypt your secrets during deployment to the "local" vault: +/usr/bin/sudo -E -u php -- bash -c "APP_RUNTIME_ENV=prod /app/bin/console secrets:decrypt-to-local --force" + +# Let cron take the wheel +echo "Starting cron in foreground." +/usr/sbin/cron -f -l 7 diff --git a/docker/php/docker-cron-entrypoint-dev b/docker/php/docker-cron-entrypoint-dev new file mode 100755 index 0000000..b2efd64 --- /dev/null +++ b/docker/php/docker-cron-entrypoint-dev @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +env >> /etc/environment + +# cron entrypoint must be run as root as it spawns crontab for each system user +if [ "$(id -u)" -ne 0 ]; then + echo "Please run as root" + exit 1 +fi + +# Print env infos +echo "APP_ENV=${APP_ENV}"; +echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; +echo "APP_DEBUG=${APP_DEBUG}"; +# Debug infos +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_ENV=${APP_ENV}\""; +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_RUNTIME_ENV=${APP_RUNTIME_ENV}\""; +/usr/bin/sudo -E -u php -- bash -c "echo \"[sudo] APP_DEBUG=${APP_DEBUG}\""; + +/bin/chown -R php:php /app/var || true; +/bin/chown -R php:php /app/config || true; + +# DO NOT Print local env vars to .env.xxx.php file in DEV mode + +# Let cron take the wheel +echo "Starting cron in foreground." +/usr/sbin/cron -f -l 7 diff --git a/docker/php/docker-php-entrypoint b/docker/php/docker-php-entrypoint new file mode 100755 index 0000000..348e041 --- /dev/null +++ b/docker/php/docker-php-entrypoint @@ -0,0 +1,45 @@ +#!/bin/sh +set -e + +# Print env infos +echo "APP_ENV=${APP_ENV}"; +echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; +echo "APP_DEBUG=${APP_DEBUG}"; + +# +# Override default entrypoint to add some maintenance and migration commands (PROD) +# DO NOT CALL THIS SCRIPT FOR WORKERS AND CRON containers (see docker-compose.yml) +# + +# Print local env vars to .env.xxx.php file for performances and crontab jobs +/usr/local/bin/composer dump-env prod +/app/bin/console assets:install -n +/app/bin/console themes:assets:install -n Rozier + +# To improve performance (i.e. avoid decrypting secrets at runtime), +# you can decrypt your secrets during deployment to the "local" vault: +#APP_RUNTIME_ENV=prod /app/bin/console secrets:decrypt-to-local --force + +# +# Wait for database to be ready for next commands and migrations +# +/wait-for-it.sh -t 0 -s ${MYSQL_HOST}:${MYSQL_PORT} + +## +## Uncomment following lines to enable automatic migration for your theme at each docker start +## +## Perform migrations directly as database should be ready thanks to wait-for-it.sh +# /app/bin/console doctrine:migrations:migrate -n --allow-no-migration +# /app/bin/console app:install -n + +# Clear caches after migrations +/app/bin/console cache:clear -n +# Clear all cache pool on Symfony 5.4 https://symfony.com/doc/5.4/cache.html#clearing-the-cache +/app/bin/console cache:pool:clear cache.global_clearer -n + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- php-fpm "$@" +fi + +exec "$@" diff --git a/docker/php/docker-php-entrypoint-dev b/docker/php/docker-php-entrypoint-dev new file mode 100755 index 0000000..0515799 --- /dev/null +++ b/docker/php/docker-php-entrypoint-dev @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +# Print env infos +echo "APP_ENV=${APP_ENV}"; +echo "APP_RUNTIME_ENV=${APP_RUNTIME_ENV}"; +echo "APP_DEBUG=${APP_DEBUG}"; + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- php-fpm "$@" +fi + +exec "$@" diff --git a/docker/php/fpm.d/www.conf b/docker/php/fpm.d/www.conf new file mode 100644 index 0000000..c87f137 --- /dev/null +++ b/docker/php/fpm.d/www.conf @@ -0,0 +1,14 @@ +[www] +; 'user' and 'group' directives are ignored when FPM is not running as root +user = +group = + +; https://spot13.com/pmcalculator/ +pm.max_children = 25 +pm.start_servers = 6 +pm.min_spare_servers = 6 +pm.max_spare_servers = 18 +pm.max_requests = 1000 + +pm.status_path = /status +pm.status_listen = 127.0.0.1:9001 diff --git a/docker/php-fpm-alpine/wait-for-it.sh b/docker/php/wait-for-it.sh similarity index 100% rename from docker/php-fpm-alpine/wait-for-it.sh rename to docker/php/wait-for-it.sh diff --git a/docker/solr/Dockerfile b/docker/solr/Dockerfile deleted file mode 100644 index aa7bf15..0000000 --- a/docker/solr/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM solr:8-slim -LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" - -ARG USER_UID=8983 - -USER root -RUN set -ex; \ - echo "USER_UID: ${USER_UID}\n"; \ - usermod -u ${USER_UID} "$SOLR_USER"; \ - groupmod -g ${USER_UID} "$SOLR_GROUP"; \ - chown -R ${USER_UID}:${USER_UID} /var/solr; - -COPY managed-schema.xml /opt/solr/server/solr/configsets/_default/conf/managed-schema - -USER $SOLR_USER diff --git a/docker/varnish/Dockerfile b/docker/varnish/Dockerfile deleted file mode 100644 index 927f060..0000000 --- a/docker/varnish/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM varnish:7.1-alpine -LABEL org.opencontainers.image.authors="ambroise@rezo-zero.com" - -ENV VARNISH_SIZE 1G -COPY ./default.vcl /etc/varnish/ diff --git a/phpcs.xml.dist b/phpcs.xml.dist deleted file mode 100644 index 53ec356..0000000 --- a/phpcs.xml.dist +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - bin/ - config/ - public/ - src/ - tests/ - diff --git a/public/index.php b/public/index.php index 9982c21..97e228d 100644 --- a/public/index.php +++ b/public/index.php @@ -1,5 +1,7 @@ contactFormManager - ->setUseRealResponseCode(true) - ->setFormName('') - ->disableCsrfProtection(); - $builder = $this->contactFormManager->getFormBuilder(); - /* - * Do not call form builder methods BEFORE defining options. - */ - $this->contactFormManager - ->withDefaultFields() - ->withUserConsent() - ->withGoogleRecaptcha('g-recaptcha-response') - ; - $schema = json_encode($this->liform->transform($builder->getForm())); - - return new JsonResponse( - $schema, - Response::HTTP_OK, - [], - true - ); - } - - public function formAction(Request $request): Response - { - $limiter = $this->contactFormLimiter->create($request->getClientIp()); - $limit = $limiter->consume(); - $headers = [ - 'X-RateLimit-Remaining' => $limit->getRemainingTokens(), - 'X-RateLimit-Retry-After' => $limit->getRetryAfter()->getTimestamp(), - 'X-RateLimit-Limit' => $limit->getLimit(), - ]; - if (false === $limit->isAccepted()) { - throw new TooManyRequestsHttpException($limit->getRetryAfter()->getTimestamp()); - } - - // Do not forget to disable CSRF and form-name - $this->contactFormManager - ->setUseRealResponseCode(true) - ->setFormName('') - ->disableCsrfProtection(); - /* - * Do not call form builder methods BEFORE defining options. - */ - $this->contactFormManager - ->withDefaultFields() - ->withUserConsent() - ->withGoogleRecaptcha('g-recaptcha-response') - ; - - if (null !== $response = $this->contactFormManager->handle()) { - $response->headers->add($headers); - return $response; - } - throw new BadRequestHttpException('Form has not been submitted.'); - } -} diff --git a/src/Controller/GetCommonContentController.php b/src/Controller/GetCommonContentController.php index 2130189..aaf7930 100644 --- a/src/Controller/GetCommonContentController.php +++ b/src/Controller/GetCommonContentController.php @@ -25,7 +25,7 @@ public function __construct( private readonly ManagerRegistry $managerRegistry, private readonly NodesSourcesHeadFactoryInterface $nodesSourcesHeadFactory, private readonly PreviewResolverInterface $previewResolver, - private readonly TreeWalkerGenerator $treeWalkerGenerator + private readonly TreeWalkerGenerator $treeWalkerGenerator, ) { } @@ -52,6 +52,7 @@ public function __invoke(Request $request): ?CommonContent $translation, 4 ); + return $resource; } catch (ResourceNotFoundException $exception) { throw $this->createNotFoundException($exception->getMessage(), $exception); @@ -63,11 +64,12 @@ private function getErrorPage(TranslationInterface $translation): ?NodesSources if (!class_exists('\App\GeneratedEntity\NSErrorPage')) { return null; } + // @phpstan-ignore-next-line return $this->managerRegistry->getRepository('\App\GeneratedEntity\NSErrorPage') ->findOneBy([ 'translation' => $translation, - 'node.nodeName' => 'error-page' + 'node.nodeName' => 'error-page', ]); } @@ -98,8 +100,9 @@ private function getTranslationFromRequest(?Request $request): TranslationInterf ->findOneAvailableByLocaleOrOverrideLocale((string) $locale); } if (null === $translation) { - throw new NotFoundHttpException('No translation for locale ' . $locale); + throw new NotFoundHttpException('No translation for locale '.$locale); } + return $translation; } @@ -107,11 +110,9 @@ private function getTranslationRepository(): TranslationRepository { $repository = $this->managerRegistry->getRepository(TranslationInterface::class); if (!$repository instanceof TranslationRepository) { - throw new \RuntimeException( - 'Translation repository must be instance of ' . - TranslationRepository::class - ); + throw new \RuntimeException('Translation repository must be instance of '.TranslationRepository::class); } + return $repository; } } diff --git a/src/Controller/NullController.php b/src/Controller/NullController.php index b078ed0..00c491a 100644 --- a/src/Controller/NullController.php +++ b/src/Controller/NullController.php @@ -9,8 +9,6 @@ /** * Do not serve nodes-sources from their Path or Path + .json. - * - * @package App\Controller */ final class NullController { diff --git a/src/Doctrine/ProjectVersionComparator.php b/src/Doctrine/ProjectVersionComparator.php index 9160883..0434164 100644 --- a/src/Doctrine/ProjectVersionComparator.php +++ b/src/Doctrine/ProjectVersionComparator.php @@ -12,6 +12,7 @@ class ProjectVersionComparator implements Comparator private function getClassname(Version $version): string { $tokens = explode('\\', (string) $version); + return $tokens[count($tokens) - 1]; } @@ -19,6 +20,7 @@ public function compare(Version $a, Version $b): int { $classA = $this->getClassname($a); $classB = $this->getClassname($b); + /* * Only compare class-name timestamp */ diff --git a/src/Kernel.php b/src/Kernel.php index cf4518d..ccb1f38 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -1,5 +1,7 @@ import('../config/{packages}/*.yaml'); - $container->import('../config/{packages}/' . $this->environment . '/*.yaml'); + $container->import('../config/{packages}/'.$this->environment.'/*.yaml'); - if (is_file(\dirname(__DIR__) . '/config/services.yaml')) { + if (is_file(\dirname(__DIR__).'/config/services.yaml')) { $container->import('../config/services.yaml'); - $container->import('../config/{services}_' . $this->environment . '.yaml'); + $container->import('../config/{services}_'.$this->environment.'.yaml'); } else { $container->import('../config/{services}.php'); } @@ -26,10 +28,10 @@ protected function configureContainer(ContainerConfigurator $container): void protected function configureRoutes(RoutingConfigurator $routes): void { - $routes->import('../config/{routes}/' . $this->environment . '/*.yaml'); + $routes->import('../config/{routes}/'.$this->environment.'/*.yaml'); $routes->import('../config/{routes}/*.yaml'); - if (is_file(\dirname(__DIR__) . '/config/routes.yaml')) { + if (is_file(\dirname(__DIR__).'/config/routes.yaml')) { $routes->import('../config/routes.yaml'); } else { $routes->import('../config/{routes}.php'); diff --git a/src/Serializer/Normalizer/MenuLinkPathNormalizer.php b/src/Serializer/Normalizer/MenuLinkPathNormalizer.php index 8c40f7e..41c397e 100644 --- a/src/Serializer/Normalizer/MenuLinkPathNormalizer.php +++ b/src/Serializer/Normalizer/MenuLinkPathNormalizer.php @@ -11,10 +11,8 @@ final class MenuLinkPathNormalizer extends AbstractPathNormalizer { /** - * @param mixed $object - * @param string|null $format - * @param array $context * @return array|\ArrayObject|bool|float|int|mixed|string|null + * * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface */ public function normalize(mixed $object, ?string $format = null, array $context = []): mixed @@ -26,12 +24,13 @@ public function normalize(mixed $object, ?string $format = null, array $context $actualUrl = $this->urlGenerator->generate( RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [ - RouteObjectInterface::ROUTE_OBJECT => $object->getLinkInternalReferenceSources()[0] + RouteObjectInterface::ROUTE_OBJECT => $object->getLinkInternalReferenceSources()[0], ] ); } $data['url'] = $actualUrl; } + return $data; } } diff --git a/src/TreeWalker/MenuNodeSourceWalker.php b/src/TreeWalker/MenuNodeSourceWalker.php index 4591184..aacb564 100644 --- a/src/TreeWalker/MenuNodeSourceWalker.php +++ b/src/TreeWalker/MenuNodeSourceWalker.php @@ -4,16 +4,12 @@ namespace App\TreeWalker; -use Psr\Cache\InvalidArgumentException; use RZ\Roadiz\Contracts\NodeType\NodeTypeInterface; use RZ\Roadiz\CoreBundle\Api\TreeWalker\Definition\MultiTypeChildrenDefinition; use RZ\Roadiz\CoreBundle\Api\TreeWalker\NodeSourceWalkerContext; use RZ\TreeWalker\AbstractCycleAwareWalker; use RZ\TreeWalker\Definition\ZeroChildrenDefinition; -/** - * @package App\TreeWalker - */ final class MenuNodeSourceWalker extends AbstractCycleAwareWalker { protected function initializeDefinitions(): void @@ -36,10 +32,7 @@ protected function createDefinitionForNodeType(NodeTypeInterface $nodeType): cal { $context = $this->getContext(); if (!$context instanceof NodeSourceWalkerContext) { - throw new \InvalidArgumentException( - 'TreeWalker context must be instance of ' . - NodeSourceWalkerContext::class - ); + throw new \InvalidArgumentException('TreeWalker context must be instance of '.NodeSourceWalkerContext::class); } $childrenNodeTypes = $context->getNodeTypeResolver()->getChildrenNodeTypeList($nodeType); if (count($childrenNodeTypes) > 0) { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 469dcce..cc712a1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,7 @@