diff --git a/.docker/data/.gitignore b/.docker/data/.gitignore new file mode 100644 index 0000000..4ce1020 --- /dev/null +++ b/.docker/data/.gitignore @@ -0,0 +1,5 @@ +# Ignore everything in this directory +* +# Except +!.gitignore +!README.md diff --git a/.docker/data/README.md b/.docker/data/README.md new file mode 100644 index 0000000..fddfcf8 --- /dev/null +++ b/.docker/data/README.md @@ -0,0 +1,29 @@ +# .docker/data + +Please map persistent volumes to this directory on the servers. + +If a container needs to persist data between restarts you can map the relevant files in the container to +`.docker/data/`. + +## RabbitMQ example + +If you are using RabbitMQ running in a container as a message broker you need to configure a persistent volume for +RabbitMQs data directory to avoid losing message on container restarts. +x +```yaml +# docker-compose.server.override.yml + +services: + rabbit: + image: rabbitmq:3.9-management-alpine + hostname: "${COMPOSE_PROJECT_NAME}" + networks: + - app + - frontend + environment: + - "RABBITMQ_DEFAULT_USER=${RABBITMQ_USER}" + - "RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD}" + - "RABBITMQ_ERLANG_COOKIE=${RABBITMQ_ERLANG_COOKIE}" + volumes: + - ".docker/data/rabbitmq:/var/lib/rabbitmq/mnesia/" +``` diff --git a/.docker/nginx.conf b/.docker/nginx.conf new file mode 100644 index 0000000..ec278a5 --- /dev/null +++ b/.docker/nginx.conf @@ -0,0 +1,34 @@ +worker_processes auto; + +error_log /dev/stderr notice; +pid /tmp/nginx.pid; + +events { + worker_connections 1024; +} + +http { + proxy_temp_path /tmp/proxy_temp; + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Note: set_real_ip_from is set in the server block + + log_format main '$http_x_real_ip - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /dev/stdout main; + + sendfile on; + keepalive_timeout 65; + + gzip on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/.docker/templates/default.conf.template b/.docker/templates/default.conf.template new file mode 100644 index 0000000..e77213b --- /dev/null +++ b/.docker/templates/default.conf.template @@ -0,0 +1,108 @@ +server { + listen ${NGINX_PORT}; + server_name localhost; + + root ${NGINX_WEB_ROOT}; + + client_max_body_size ${NGINX_MAX_BODY_SIZE}; + + set_real_ip_from 172.16.0.0/16; + set_real_ip_from 192.168.39.0/24; + real_ip_recursive on; + real_ip_header X-Forwarded-For; + + location = /cron-metrics { + # Proxy to supercronic metrics + proxy_pass http://${NGINX_CRON_METRICS}/metrics; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + location ~* \.(txt|log)$ { + deny all; + } + + location ~ \..*/.*\.php$ { + return 403; + } + + location ~ ^/sites/.*/private/ { + return 403; + } + + # Block access to scripts in site files directory + location ~ ^/sites/[^/]+/files/.*\.php$ { + deny all; + } + + # Block access to "hidden" files and directories whose names begin with a + # period. + location ~ (^|/)\. { + return 403; + } + + location / { + try_files $uri /index.php?$query_string; + } + + location @rewrite { + rewrite ^ /index.php; + } + + # Don't allow direct access to PHP files in the vendor directory. + location ~ /vendor/.*\.php$ { + deny all; + return 404; + } + + # Protect files and directories from prying eyes. + location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|.tar|.gz|.bz2|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ { + deny all; + return 404; + } + + location ~ '\.php$|^/update.php' { + include fastcgi_params; + + fastcgi_buffers 16 32k; + fastcgi_buffer_size 64k; + fastcgi_busy_buffers_size 64k; + + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + + # Ensure the php file exists. Mitigates CVE-2019-11043 + try_files $fastcgi_script_name =404; + + fastcgi_param HTTP_PROXY ""; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + + fastcgi_intercept_errors on; + fastcgi_pass ${NGINX_FPM_SERVICE}; + } + + # Enforce clean URLs + # + # Removes index.php from urls like www.example.com/index.php/my-page --> www.example.com/my-page + # Could be done with 301 for permanent or other redirect codes. + if ($request_uri ~* "^(.*/)index\.php/(.*)") { + return 307 $1$2; + } + + error_log /dev/stderr; + access_log /dev/stdout main; +} diff --git a/.docker/vhost.conf b/.docker/vhost.conf deleted file mode 100644 index eaf572a..0000000 --- a/.docker/vhost.conf +++ /dev/null @@ -1,114 +0,0 @@ -# @see https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ -server { - proxy_buffer_size 128k; - proxy_buffers 4 256k; - proxy_busy_buffers_size 256k; - - listen 80; - server_name localhost; - - root /app/web; - - location = /favicon.ico { - log_not_found off; - access_log off; - } - - location = /robots.txt { - allow all; - log_not_found off; - access_log off; - } - - # Very rarely should these ever be accessed outside of your lan - location ~* \.(txt|log)$ { - allow 192.168.0.0/16; - deny all; - } - - location ~ \..*/.*\.php$ { - return 403; - } - - location ~ ^/sites/.*/private/ { - return 403; - } - - # Block access to scripts in site files directory - location ~ ^/sites/[^/]+/files/.*\.php$ { - deny all; - } - - # Allow "Well-Known URIs" as per RFC 5785 - location ~* ^/.well-known/ { - allow all; - } - - # Block access to "hidden" files and directories whose names begin with a - # period. This includes directories used by version control systems such - # as Subversion or Git to store control files. - location ~ (^|/)\. { - return 403; - } - - location / { - # try_files $uri @rewrite; # For Drupal <= 6 - try_files $uri /index.php?$query_string; # For Drupal >= 7 - } - - location @rewrite { - rewrite ^/(.*)$ /index.php?q=$1; - } - - # Don't allow direct access to PHP files in the vendor directory. - location ~ /vendor/.*\.php$ { - deny all; - return 404; - } - - # In Drupal 8, we must also match new paths where the '.php' appears in - # the middle, such as update.php/selection. The rule we use is strict, - # and only allows this pattern with the update.php front controller. - # This allows legacy path aliases in the form of - # blog/index.php/legacy-path to continue to route to Drupal nodes. If - # you do not have any paths like that, then you might prefer to use a - # laxer rule, such as: - # location ~ \.php(/|$) { - # The laxer rule will continue to work if Drupal uses this new URL - # pattern with front controllers other than update.php in a future - # release. - location ~ '\.php$|^/update.php' { - fastcgi_split_path_info ^(.+?\.php)(|/.*)$; - # Security note: If you're running a version of PHP older than the - # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. - # See http://serverfault.com/q/627903/94922 for details. - include fastcgi_params; - # Block httpoxy attacks. See https://httpoxy.org/. - fastcgi_param HTTP_PROXY ""; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param QUERY_STRING $query_string; - fastcgi_intercept_errors on; - fastcgi_pass phpfpm:9000; - fastcgi_buffers 16 16k; - fastcgi_buffer_size 32k; - } - - # Fighting with Styles? This little gem is amazing. - # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 - location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 - try_files $uri @rewrite; - } - - # Handle private files through Drupal. Private file's path can come - # with a language prefix. - location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 - try_files $uri /index.php?$query_string; - } - - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { - try_files $uri @rewrite; - expires max; - log_not_found off; - } -} diff --git a/.env b/.env index fd056f2..ee768f5 100644 --- a/.env +++ b/.env @@ -1,2 +1,4 @@ COMPOSE_PROJECT_NAME=project-database COMPOSE_DOMAIN=project-database.local.itkdev.dk +ITKDEV_TEMPLATE=drupal-11 +COMPOSE_SERVER_DOMAIN=project-database.itkdev.dk diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml new file mode 100644 index 0000000..6908667 --- /dev/null +++ b/.github/workflows/changelog.yaml @@ -0,0 +1,27 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/changelog.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### Changelog +### +### Checks that changelog has been updated + +name: Changelog + +on: + pull_request: + +jobs: + changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 2 + + - name: Git fetch + run: git fetch + + - name: Check that changelog has been updated. + run: git diff --exit-code origin/${{ github.base_ref }} -- CHANGELOG.md && exit 1 || exit 0 diff --git a/.github/workflows/composer.yaml b/.github/workflows/composer.yaml new file mode 100644 index 0000000..7e1ff00 --- /dev/null +++ b/.github/workflows/composer.yaml @@ -0,0 +1,79 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/composer.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### Composer +### +### Validates composer.json and checks that it's normalized. +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can be +### run inside the `phpfpm` service. +### 2. [ergebnis/composer-normalize](https://github.com/ergebnis/composer-normalize) +### is a dev requirement in `composer.json`: +### +### ``` shell +### docker compose run --rm phpfpm composer require --dev ergebnis/composer-normalize +### ``` +### +### Normalize `composer.json` by running +### +### ``` shell +### docker compose run --rm phpfpm composer normalize +### ``` + +name: Composer + +env: + COMPOSE_USER: runner + +on: + pull_request: + paths: &paths + - "composer.json" + - "composer.lock" + - "docker-compose.yml" + push: + branches: + - main + - develop + paths: *paths + +jobs: + composer-validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm phpfpm composer validate --strict + + composer-normalized: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm phpfpm composer install + docker compose run --rm phpfpm composer normalize --dry-run + + composer-audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm phpfpm composer audit --locked diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml new file mode 100644 index 0000000..ce1d1e4 --- /dev/null +++ b/.github/workflows/markdown.yaml @@ -0,0 +1,45 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/markdown.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### Markdown +### +### Lints Markdown files (`**/*.md`) in the project. +### +### [markdownlint-cli configuration +### files](https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#configuration), +### `.markdownlint.jsonc` and `.markdownlintignore`, control what is actually +### linted and how. +### +### #### Assumptions +### +### 1. A docker compose service named `markdownlint` for running `markdownlint` +### (from +### [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli)) +### exists. + +name: Markdown + +on: + pull_request: + paths: &paths + - "**/*.md" + push: + branches: + - main + - develop + paths: *paths + +jobs: + markdown-lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm markdownlint markdownlint '**/*.md' diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml new file mode 100644 index 0000000..7366a30 --- /dev/null +++ b/.github/workflows/php.yaml @@ -0,0 +1,65 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/drupal/php.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### Drupal PHP +### +### Checks that PHP code adheres to the [Drupal coding +### standards](https://www.drupal.org/docs/develop/standards). +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can be +### run inside the `phpfpm` service. +### 2. [drupal/coder](https://www.drupal.org/project/coder) is a dev requirement +### in `composer.json`: +### +### ``` shell +### docker compose run --rm phpfpm composer require --dev drupal/coder +### ``` +### +### Clean up and check code by running +### +### ``` shell +### docker compose run --rm phpfpm vendor/bin/phpcbf +### docker compose run --rm phpfpm vendor/bin/phpcs +### ``` +### +### > [!NOTE] +### > The template adds `.phpcs.xml.dist` as [a configuration file for +### > PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Advanced-Usage#using-a-default-configuration-file) +### > and this makes it possible to override the actual configuration used in a +### > project by adding a more important configuration file, e.g. `.phpcs.xml`. + +name: PHP + +env: + COMPOSE_USER: runner + +on: + pull_request: + paths: &paths + - "**/*.php" + - "composer.json" + - "composer.lock" + - "docker-compose.yml" + push: + branches: + - main + - develop + paths: *paths + +jobs: + coding-standards: + name: PHP - Check Coding Standards + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm phpfpm composer install + docker compose run --rm phpfpm vendor/bin/phpcs diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml new file mode 100644 index 0000000..88dceba --- /dev/null +++ b/.github/workflows/site.yaml @@ -0,0 +1,153 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/drupal/site.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### Drupal +### +### Checks that site can be installed and can be updated (from base branch on +### pull request). +### +### #### Assumptions +### +### 1. A docker compose service named `phpfpm` can be run and `composer` can be +### run inside the `phpfpm` service. +### 2. The docker setup contains a database container and other the dependent +### services and the default settings match connection credentials for these +### services. +### 3. The Drupal site can be installed from existing config. + +name: Drupal + +env: + COMPOSE_USER: runner + +on: + pull_request: + push: + branches: + - main + - develop + +jobs: + install-site: + name: Check that site can be installed + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Create docker network + run: | + docker network create frontend + + - name: Start docker and install dependencies + run: | + docker compose pull + docker compose up --detach + + # Important: Use --no-interaction to make https://getcomposer.org/doc/06-config.md#discard-changes have effect. + docker compose exec phpfpm composer install --no-interaction + + - name: Install site + run: | + # Add some local settings. + cat > web/sites/default/settings.local.php <<'EOF' + web/sites/default/settings.local.php <<'EOF' + + + + + + The coding standard. + + web/modules/custom/ + web/themes/custom/ + + + node_modules + vendor + web/*/custom/*/build/ + *.css + *.js + + + + + + + + + + + + + + + + + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..328caff --- /dev/null +++ b/.prettierignore @@ -0,0 +1,15 @@ +# Drupal-managed configuration (owned by config import/export, not Prettier). +/config/sync/ + +# Drupal scaffold files (owned by drupal/core-composer-scaffold). +/web/sites/default/default.services.yml +/web/sites/development.services.yml + +# Composer- and Drupal-managed code. +/vendor/ +/web/core/ +/web/libraries/ +/web/modules/contrib/ +/web/profiles/contrib/ +/web/themes/contrib/ +/web/sites/*/files/ diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..018e628 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,11 @@ +# This file is copied from config/drupal/yaml/.prettierrc.yaml in https://github.com/itk-dev/devops_itkdev-docker. +# Feel free to edit the file, but consider making a pull request if you find a general issue with the file. + +# https://prettier.io/docs/configuration +overrides: + # https://taskfile.dev/docs/styleguide + - files: + - "Taskfile.{yml,yaml}" + options: + tabWidth: 2 + singleQuote: true diff --git a/.twig-cs-fixer.dist.php b/.twig-cs-fixer.dist.php new file mode 100644 index 0000000..0a0f295 --- /dev/null +++ b/.twig-cs-fixer.dist.php @@ -0,0 +1,16 @@ +in(__DIR__); +// … that are not ignored by VCS +$finder->ignoreVCSIgnored(true); + +$config = new TwigCsFixer\Config\Config(); +$config->setFinder($finder); + +return $config; diff --git a/CHANGELOG.md b/CHANGELOG.md index 0548343..467e398 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,5 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +* [#14](https://github.com/itk-dev/project-database/pull/14) + Aligned the development setup with the itk-dev D11 Docker template * [#13](https://github.com/itk-dev/project-database/pull/13) Upgrade from D9 to D11 diff --git a/README.md b/README.md index 96dd6e4..1307591 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,23 @@ A drupal backend that exposes projects created with an API. ### Production -@TODO +Deploy using the server Docker Compose override: + +```sh +docker compose --file docker-compose.yml --file docker-compose.server.yml up --detach +``` + +Set `COMPOSE_SERVER_DOMAIN` in `.env` (or `.env.local`) to the production domain. + +This project follows the itk-dev [`drupal-11` Docker +template](https://github.com/itk-dev/devops_itkdev-docker) and runs on PHP 8.4. ### Development Setup Docker environment: ```sh -docker-compose up -d +docker compose up --detach ``` Setup local site configuration: @@ -25,34 +34,22 @@ cp web/sites/default/_docker.settings.local.php web/sites/default/docker.setting Install php packages: ```sh -docker-compose exec phpfpm composer install +docker compose exec phpfpm composer install ``` Install site: ```sh -docker-compose exec phpfpm vendor/bin/drush site-install minimal --existing-config --yes +docker compose exec phpfpm vendor/bin/drush site:install minimal --existing-config --yes ``` -Sign in as admin: +Sign in as admin (the site uri is provided to Drush via `DRUSH_OPTIONS_URI`): ```sh -docker-compose exec phpfpm vendor/bin/drush --uri=http://$(docker-compose port nginx 80) user:login +docker compose exec phpfpm vendor/bin/drush user:login ``` -#### Using Symfony Local Web Server - -See [Symfony Local Web -Server](https://symfony.com/doc/current/setup/symfony_server.html) for details. - -```sh -docker-compose up -d -symfony composer install -symfony php vendor/bin/drush site-install minimal --existing-config --yes -symfony local:server:start --daemon -# Update the uri to the actual address of the running web server. -symfony php vendor/bin/drush --uri=https://127.0.0.1:8000 user:login -``` +The site is served through Traefik at . ## Api documentation diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..e20cf74 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,40 @@ +# https://taskfile.dev + +version: '3' + +dotenv: ['.env.local', '.env'] + +vars: + DOCKER_COMPOSE: '{{.CONTAINER_COMPOSE | default "docker compose"}}' + PHP: '{{.DOCKER_COMPOSE}} exec phpfpm' + COMPOSER: '{{.PHP}} composer' + DRUSH: '{{.PHP}} vendor/bin/drush' + +tasks: + install: + desc: 'Install the site for local development' + cmds: + - '{{.DOCKER_COMPOSE}} up --detach' + - cp -n web/sites/default/_docker.settings.local.php web/sites/default/docker.settings.local.php + - '{{.COMPOSER}} install' + - '{{.DRUSH}} site:install minimal --existing-config --yes' + - '{{.DRUSH}} user:login' + + coding-standards:check: + desc: 'Check coding standards (Composer, PHP, Twig, YAML, Markdown)' + cmds: + - '{{.COMPOSER}} normalize --dry-run' + - '{{.PHP}} vendor/bin/phpcs' + - '{{.PHP}} vendor/bin/twig-cs-fixer lint' + - '{{.DOCKER_COMPOSE}} run --rm prettier "**/*.{yml,yaml}" --check' + - '{{.DOCKER_COMPOSE}} run --rm markdownlint markdownlint "**/*.md"' + + coding-standards:apply: + desc: 'Apply coding standards (Composer, PHP, Twig, YAML, Markdown)' + cmds: + - '{{.COMPOSER}} normalize' + - cmd: '{{.PHP}} vendor/bin/phpcbf' + ignore_error: true + - '{{.PHP}} vendor/bin/twig-cs-fixer lint --fix' + - '{{.DOCKER_COMPOSE}} run --rm prettier "**/*.{yml,yaml}" --write' + - '{{.DOCKER_COMPOSE}} run --rm markdownlint markdownlint --fix "**/*.md"' diff --git a/composer.json b/composer.json index e228b2c..b97731c 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,13 @@ { "name": "drupal/recommended-project", "description": "Project template for Drupal projects with a relocated document root", - "type": "project", "license": "GPL-2.0-or-later", + "type": "project", "homepage": "https://www.drupal.org/project/drupal", "support": { - "docs": "https://www.drupal.org/docs/user_guide/en/index.html", - "chat": "https://www.drupal.org/node/314178" + "chat": "https://www.drupal.org/node/314178", + "docs": "https://www.drupal.org/docs/user_guide/en/index.html" }, - "repositories": [ - { - "type": "composer", - "url": "https://packages.drupal.org/8" - } - ], "require": { "composer/installers": "^1.9", "cweagans/composer-patches": "^1.6", @@ -29,35 +23,64 @@ "drupal/views_data_export": "^1.10", "drush/drush": "^13" }, + "require-dev": { + "drupal/coder": "^9.0", + "ergebnis/composer-normalize": "^2.52", + "vincentlanglet/twig-cs-fixer": "^4.0" + }, "conflict": { "drupal/drupal": "*" }, + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + } + ], "minimum-stability": "dev", "prefer-stable": true, "config": { - "sort-packages": true, - "platform": { - "php": "8.3.0" - }, "allow-plugins": { "composer/installers": true, "cweagans/composer-patches": true, + "dealerdirect/phpcodesniffer-composer-installer": true, "drupal/core-composer-scaffold": true, - "drupal/core-project-message": true - } + "drupal/core-project-message": true, + "ergebnis/composer-normalize": true + }, + "platform": { + "php": "8.4.0" + }, + "sort-packages": true }, "extra": { + "drupal-core-project-message": { + "include-keys": [ + "homepage", + "support" + ], + "post-create-project-cmd-message": [ + " ", + " Congratulations, you’ve installed the Drupal codebase ", + " from the drupal/recommended-project template! ", + " ", + "", + "Next steps:", + " * Install the site: https://www.drupal.org/docs/8/install", + " * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html", + " * Get support: https://www.drupal.org/support", + " * Get involved with the Drupal community:", + " https://www.drupal.org/getting-involved", + " * Remove the plugin that prints this message:", + " composer remove drupal/core-project-message" + ] + }, "drupal-scaffold": { "locations": { "web-root": "web/" } }, "enable-patching": true, - "patches": { - "drupal/openapi_jsonapi": { - "Only show enabled endpoints": "patches/only_show_enabled_endpoints.patch" - } - }, "installer-paths": { "web/core": [ "type:drupal-core" @@ -84,26 +107,10 @@ "type:drupal-custom-theme" ] }, - "drupal-core-project-message": { - "include-keys": [ - "homepage", - "support" - ], - "post-create-project-cmd-message": [ - " ", - " Congratulations, you’ve installed the Drupal codebase ", - " from the drupal/recommended-project template! ", - " ", - "", - "Next steps:", - " * Install the site: https://www.drupal.org/docs/8/install", - " * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html", - " * Get support: https://www.drupal.org/support", - " * Get involved with the Drupal community:", - " https://www.drupal.org/getting-involved", - " * Remove the plugin that prints this message:", - " composer remove drupal/core-project-message" - ] + "patches": { + "drupal/openapi_jsonapi": { + "Only show enabled endpoints": "patches/only_show_enabled_endpoints.patch" + } } } } diff --git a/composer.lock b/composer.lock index 9320b3c..f8328bc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "96d315fc358917ae1f2eb21ace9cb971", + "content-hash": "e4a08e23e775a6e46586d8eeea7db1c9", "packages": [ { "name": "asm89/stack-cors", @@ -7314,7 +7314,1066 @@ "time": "2026-05-30T17:09:26+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.2", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "^2.2", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2026-05-06T08:26:05+00:00" + }, + { + "name": "drupal/coder", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/pfrenssen/coder.git", + "reference": "9fcf1a15e81256774699173fbbdd262163af35bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pfrenssen/coder/zipball/9fcf1a15e81256774699173fbbdd262163af35bb", + "reference": "9fcf1a15e81256774699173fbbdd262163af35bb", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.2", + "ext-mbstring": "*", + "php": ">=7.4", + "sirbrillig/phpcs-variable-analysis": "^2.13", + "slevomat/coding-standard": "^8.25.1", + "squizlabs/php_codesniffer": "^4.0.1", + "symfony/yaml": ">=3.4.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.7.12", + "phpunit/phpunit": "^9.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Drupal\\": "coder_sniffer/Drupal/", + "DrupalPractice\\": "coder_sniffer/DrupalPractice/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "Coder is a library to review Drupal code.", + "homepage": "https://www.drupal.org/project/coder", + "keywords": [ + "code review", + "phpcs", + "standards" + ], + "support": { + "issues": "https://www.drupal.org/project/issues/coder", + "source": "https://www.drupal.org/project/coder" + }, + "time": "2026-03-13T17:11:34+00:00" + }, + { + "name": "ergebnis/composer-normalize", + "version": "2.52.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/composer-normalize.git", + "reference": "988f83f5e51a42cdd2337e5fcd935432f8dfa33c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/988f83f5e51a42cdd2337e5fcd935432f8dfa33c", + "reference": "988f83f5e51a42cdd2337e5fcd935432f8dfa33c", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0.0", + "ergebnis/json": "^1.4.0", + "ergebnis/json-normalizer": "^4.9.0", + "ergebnis/json-printer": "^3.7.0", + "ext-json": "*", + "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", + "localheinz/diff": "^1.3.0", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "composer/composer": "^2.9.8", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.62.1", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.18.1", + "fakerphp/faker": "^1.24.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.54", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.11", + "phpunit/phpunit": "^9.6.33", + "rector/rector": "^2.4.3", + "symfony/filesystem": "^5.4.41" + }, + "type": "composer-plugin", + "extra": { + "class": "Ergebnis\\Composer\\Normalize\\NormalizePlugin", + "branch-alias": { + "dev-main": "2.52-dev" + }, + "plugin-optional": true, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Composer\\Normalize\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a composer plugin for normalizing composer.json.", + "homepage": "https://github.com/ergebnis/composer-normalize", + "keywords": [ + "composer", + "normalize", + "normalizer", + "plugin" + ], + "support": { + "issues": "https://github.com/ergebnis/composer-normalize/issues", + "security": "https://github.com/ergebnis/composer-normalize/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/composer-normalize" + }, + "time": "2026-05-15T15:39:24+00:00" + }, + { + "name": "ergebnis/json", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json.git", + "reference": "7b56d2b5d9e897e75b43e2e753075a0904c921b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json/zipball/7b56d2b5d9e897e75b43e2e753075a0904c921b1", + "reference": "7b56d2b5d9e897e75b43e2e753075a0904c921b1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.44.0", + "ergebnis/data-provider": "^3.3.0", + "ergebnis/license": "^2.5.0", + "ergebnis/php-cs-fixer-config": "^6.37.0", + "ergebnis/phpstan-rules": "^2.11.0", + "ergebnis/phpunit-slow-test-detector": "^2.16.1", + "fakerphp/faker": "^1.24.0", + "infection/infection": "~0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "phpunit/phpunit": "^9.6.24", + "rector/rector": "^2.1.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.7-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a Json value object for representing a valid JSON string.", + "homepage": "https://github.com/ergebnis/json", + "keywords": [ + "json" + ], + "support": { + "issues": "https://github.com/ergebnis/json/issues", + "security": "https://github.com/ergebnis/json/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/json" + }, + "time": "2025-09-06T09:08:45+00:00" + }, + { + "name": "ergebnis/json-normalizer", + "version": "4.10.1", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json-normalizer.git", + "reference": "77961faf2c651c3f05977b53c6c68e8434febf62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json-normalizer/zipball/77961faf2c651c3f05977b53c6c68e8434febf62", + "reference": "77961faf2c651c3f05977b53c6c68e8434febf62", + "shasum": "" + }, + "require": { + "ergebnis/json": "^1.2.0", + "ergebnis/json-pointer": "^3.4.0", + "ergebnis/json-printer": "^3.5.0", + "ergebnis/json-schema-validator": "^4.2.0", + "ext-json": "*", + "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "composer/semver": "^3.4.3", + "ergebnis/composer-normalize": "^2.44.0", + "ergebnis/data-provider": "^3.3.0", + "ergebnis/license": "^2.5.0", + "ergebnis/php-cs-fixer-config": "^6.37.0", + "ergebnis/phpunit-slow-test-detector": "^2.16.1", + "fakerphp/faker": "^1.24.0", + "infection/infection": "~0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.10", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.1", + "phpunit/phpunit": "^9.6.19", + "rector/rector": "^1.2.10" + }, + "suggest": { + "composer/semver": "If you want to use ComposerJsonNormalizer or VersionConstraintNormalizer" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.11-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\Normalizer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides generic and vendor-specific normalizers for normalizing JSON documents.", + "homepage": "https://github.com/ergebnis/json-normalizer", + "keywords": [ + "json", + "normalizer" + ], + "support": { + "issues": "https://github.com/ergebnis/json-normalizer/issues", + "security": "https://github.com/ergebnis/json-normalizer/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/json-normalizer" + }, + "time": "2025-09-06T09:18:13+00:00" + }, + { + "name": "ergebnis/json-pointer", + "version": "3.8.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json-pointer.git", + "reference": "b58c3c468a7ff109fdf9a255f17de29ecbe5276c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json-pointer/zipball/b58c3c468a7ff109fdf9a255f17de29ecbe5276c", + "reference": "b58c3c468a7ff109fdf9a255f17de29ecbe5276c", + "shasum": "" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.50.0", + "ergebnis/data-provider": "^3.6.0", + "ergebnis/license": "^2.7.0", + "ergebnis/php-cs-fixer-config": "^6.60.2", + "ergebnis/phpstan-rules": "^2.13.1", + "ergebnis/phpunit-slow-test-detector": "^2.24.0", + "ergebnis/rector-rules": "^1.16.0", + "fakerphp/faker": "^1.24.1", + "infection/infection": "~0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.46", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.16", + "phpstan/phpstan-strict-rules": "^2.0.10", + "phpunit/phpunit": "^9.6.34", + "rector/rector": "^2.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.8-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\Pointer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides an abstraction of a JSON pointer.", + "homepage": "https://github.com/ergebnis/json-pointer", + "keywords": [ + "RFC6901", + "json", + "pointer" + ], + "support": { + "issues": "https://github.com/ergebnis/json-pointer/issues", + "security": "https://github.com/ergebnis/json-pointer/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/json-pointer" + }, + "time": "2026-04-07T14:52:13+00:00" + }, + { + "name": "ergebnis/json-printer", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json-printer.git", + "reference": "211d73fc7ec6daf98568ee6ed6e6d133dee8503e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json-printer/zipball/211d73fc7ec6daf98568ee6ed6e6d133dee8503e", + "reference": "211d73fc7ec6daf98568ee6ed6e6d133dee8503e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.44.0", + "ergebnis/data-provider": "^3.3.0", + "ergebnis/license": "^2.5.0", + "ergebnis/php-cs-fixer-config": "^6.37.0", + "ergebnis/phpunit-slow-test-detector": "^2.16.1", + "fakerphp/faker": "^1.24.0", + "infection/infection": "~0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.10", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.1", + "phpstan/phpstan-strict-rules": "^1.6.1", + "phpunit/phpunit": "^9.6.21", + "rector/rector": "^1.2.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.9-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\Printer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a JSON printer, allowing for flexible indentation.", + "homepage": "https://github.com/ergebnis/json-printer", + "keywords": [ + "formatter", + "json", + "printer" + ], + "support": { + "issues": "https://github.com/ergebnis/json-printer/issues", + "security": "https://github.com/ergebnis/json-printer/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/json-printer" + }, + "time": "2025-09-06T09:59:26+00:00" + }, + { + "name": "ergebnis/json-schema-validator", + "version": "4.5.1", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json-schema-validator.git", + "reference": "b739527a480a9e3651360ad351ea77e7e9019df2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json-schema-validator/zipball/b739527a480a9e3651360ad351ea77e7e9019df2", + "reference": "b739527a480a9e3651360ad351ea77e7e9019df2", + "shasum": "" + }, + "require": { + "ergebnis/json": "^1.2.0", + "ergebnis/json-pointer": "^3.4.0", + "ext-json": "*", + "justinrainbow/json-schema": "^5.2.12 || ^6.0.0", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.44.0", + "ergebnis/data-provider": "^3.3.0", + "ergebnis/license": "^2.5.0", + "ergebnis/php-cs-fixer-config": "^6.37.0", + "ergebnis/phpunit-slow-test-detector": "^2.16.1", + "fakerphp/faker": "^1.24.0", + "infection/infection": "~0.26.6", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.10", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.1", + "phpunit/phpunit": "^9.6.20", + "rector/rector": "^1.2.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.6-dev" + }, + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\SchemaValidator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com" + } + ], + "description": "Provides a JSON schema validator, building on top of justinrainbow/json-schema.", + "homepage": "https://github.com/ergebnis/json-schema-validator", + "keywords": [ + "json", + "schema", + "validator" + ], + "support": { + "issues": "https://github.com/ergebnis/json-schema-validator/issues", + "security": "https://github.com/ergebnis/json-schema-validator/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/json-schema-validator" + }, + "time": "2025-09-06T11:37:35+00:00" + }, + { + "name": "localheinz/diff", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/localheinz/diff.git", + "reference": "33bd840935970cda6691c23fc7d94ae764c0734c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/localheinz/diff/zipball/33bd840935970cda6691c23fc7d94ae764c0734c", + "reference": "33bd840935970cda6691c23fc7d94ae764c0734c", + "shasum": "" + }, + "require": { + "php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.0 || ^8.5.23", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Fork of sebastian/diff for use with ergebnis/composer-normalize", + "homepage": "https://github.com/localheinz/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/localheinz/diff/issues", + "source": "https://github.com/localheinz/diff/tree/1.3.0" + }, + "time": "2025-08-30T09:44:18+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + }, + "time": "2026-01-25T14:56:51+00:00" + }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "a15e970b8a0bf64cfa5e86d941f5e6b08855f369" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/a15e970b8a0bf64cfa5e86d941f5e6b08855f369", + "reference": "a15e970b8a0bf64cfa5e86d941f5e6b08855f369", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.7 || ^4.0.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpstan/phpstan": "^1.7 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2025-09-30T22:22:48+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.29.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "81fce13c4ef4b53a03e5cfa6ce36afc191c1598e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/81fce13c4ef4b53a03e5cfa6ce36afc191c1598e", + "reference": "81fce13c4ef4b53a03e5cfa6ce36afc191c1598e", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.2.1", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.3.2", + "squizlabs/php_codesniffer": "^4.0.1" + }, + "require-dev": { + "phing/phing": "3.0.1|3.1.2", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.54", + "phpstan/phpstan-deprecation-rules": "2.0.4", + "phpstan/phpstan-phpunit": "2.0.16", + "phpstan/phpstan-strict-rules": "2.0.11", + "phpunit/phpunit": "9.6.34|10.5.63|11.4.4|11.5.55|12.5.24" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.29.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2026-05-07T05:48:08+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "0525c73950de35ded110cffafb9892946d7771b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5", + "reference": "0525c73950de35ded110cffafb9892946d7771b5", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=7.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-10T16:43:36+00:00" + }, + { + "name": "vincentlanglet/twig-cs-fixer", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/VincentLanglet/Twig-CS-Fixer.git", + "reference": "10e0133faf33218ea3380432f3a757ba50e9e17d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/VincentLanglet/Twig-CS-Fixer/zipball/10e0133faf33218ea3380432f3a757ba50e9e17d", + "reference": "10e0133faf33218ea3380432f3a757ba50e9e17d", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "ext-ctype": "*", + "php": ">=8.1", + "symfony/console": "^5.4.9 || ^6.4 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/string": "^5.4.42 || ^6.4.10 || ~7.0.10 || ^7.1.3 || ^8.0", + "twig/twig": "^3.15", + "webmozart/assert": "^1.10 || ^2.0" + }, + "require-dev": { + "composer/semver": "^3.2.0", + "dereuromark/composer-prefer-lowest": "^0.1.10", + "ergebnis/composer-normalize": "^2.29", + "friendsofphp/php-cs-fixer": "^3.13.0", + "infection/infection": "^0.26.16 || ^0.32.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-symfony": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + "phpunit/phpunit": "^9.5.26 || ^11.5.18 || ^12.1.3", + "rector/rector": "^2.0.0", + "shipmonk/composer-dependency-analyser": "^1.6", + "symfony/process": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/twig-bridge": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/ux-twig-component": "^2.2.0", + "twig/cache-extra": "^3.2" + }, + "bin": [ + "bin/twig-cs-fixer" + ], + "type": "coding-standard", + "autoload": { + "psr-4": { + "TwigCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Vincent Langlet" + } + ], + "description": "A tool to automatically fix Twig code style", + "homepage": "https://github.com/VincentLanglet/Twig-CS-Fixer", + "support": { + "issues": "https://github.com/VincentLanglet/Twig-CS-Fixer/issues", + "source": "https://github.com/VincentLanglet/Twig-CS-Fixer/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/VincentLanglet", + "type": "github" + } + ], + "time": "2026-06-15T14:41:51+00:00" + }, + { + "name": "webmozart/assert", + "version": "2.4.1", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/2ccb7c2e821038c03a3e6e1700c570c158c55f70", + "reference": "2ccb7c2e821038c03a3e6e1700c570c158c55f70", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^8.2" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "type": "library", + "extra": { + "psalm": { + "pluginClass": "Webmozart\\Assert\\PsalmPlugin" + }, + "branch-alias": { + "dev-master": "2.0-dev", + "dev-feature/2-0": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/2.4.1" + }, + "time": "2026-06-15T15:31:57+00:00" + } + ], "aliases": [], "minimum-stability": "dev", "stability-flags": { @@ -7325,7 +8384,7 @@ "platform": {}, "platform-dev": {}, "platform-overrides": { - "php": "8.3.0" + "php": "8.4.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/config/sync/block.block.projectDatabase_breadcrumbs.yml b/config/sync/block.block.project_database_breadcrumbs.yml similarity index 82% rename from config/sync/block.block.projectDatabase_breadcrumbs.yml rename to config/sync/block.block.project_database_breadcrumbs.yml index eeef269..5ec6659 100644 --- a/config/sync/block.block.projectDatabase_breadcrumbs.yml +++ b/config/sync/block.block.project_database_breadcrumbs.yml @@ -5,11 +5,11 @@ dependencies: module: - system theme: - - projectDatabase + - project_database _core: default_config_hash: b6mUaCq5YPapRUABXRHfNTT6fxWIj5lgf0Mg4HaRJ_I -id: projectDatabase_breadcrumbs -theme: projectDatabase +id: project_database_breadcrumbs +theme: project_database region: breadcrumb weight: 0 provider: null diff --git a/config/sync/block.block.projectDatabase_content.yml b/config/sync/block.block.project_database_content.yml similarity index 83% rename from config/sync/block.block.projectDatabase_content.yml rename to config/sync/block.block.project_database_content.yml index 5cba0ab..a65e9b5 100644 --- a/config/sync/block.block.projectDatabase_content.yml +++ b/config/sync/block.block.project_database_content.yml @@ -5,11 +5,11 @@ dependencies: module: - system theme: - - projectDatabase + - project_database _core: default_config_hash: QTwkfDaGeBUk6aerktJBDXso4fCsqLTQOuWKXE1xMPU -id: projectDatabase_content -theme: projectDatabase +id: project_database_content +theme: project_database region: content weight: 0 provider: null diff --git a/config/sync/block.block.projectDatabase_local_actions.yml b/config/sync/block.block.project_database_local_actions.yml similarity index 81% rename from config/sync/block.block.projectDatabase_local_actions.yml rename to config/sync/block.block.project_database_local_actions.yml index 0e5b1d2..8492003 100644 --- a/config/sync/block.block.projectDatabase_local_actions.yml +++ b/config/sync/block.block.project_database_local_actions.yml @@ -3,11 +3,11 @@ langcode: da status: true dependencies: theme: - - projectDatabase + - project_database _core: default_config_hash: osZQ9lL2jTdH5am4LJiZ29RaivhzOf6vCpoRy6FZwIE -id: projectDatabase_local_actions -theme: projectDatabase +id: project_database_local_actions +theme: project_database region: content weight: -10 provider: null diff --git a/config/sync/block.block.projectDatabase_messages.yml b/config/sync/block.block.project_database_messages.yml similarity index 83% rename from config/sync/block.block.projectDatabase_messages.yml rename to config/sync/block.block.project_database_messages.yml index 686e282..b7ec3a9 100644 --- a/config/sync/block.block.projectDatabase_messages.yml +++ b/config/sync/block.block.project_database_messages.yml @@ -5,11 +5,11 @@ dependencies: module: - system theme: - - projectDatabase + - project_database _core: default_config_hash: iIy-YIc9d9s1isAtTIKWDBKd6kd2r6LxoYz_-hkLJco -id: projectDatabase_messages -theme: projectDatabase +id: project_database_messages +theme: project_database region: highlighted weight: 0 provider: null diff --git a/config/sync/block.block.projectDatabase_page_title.yml b/config/sync/block.block.project_database_page_title.yml similarity index 81% rename from config/sync/block.block.projectDatabase_page_title.yml rename to config/sync/block.block.project_database_page_title.yml index dceaa4d..1a7e842 100644 --- a/config/sync/block.block.projectDatabase_page_title.yml +++ b/config/sync/block.block.project_database_page_title.yml @@ -3,11 +3,11 @@ langcode: da status: true dependencies: theme: - - projectDatabase + - project_database _core: default_config_hash: gfXKmThltk6eewwrjAEaxVPxzPEVHV1UfNjjOUQ5A7g -id: projectDatabase_page_title -theme: projectDatabase +id: project_database_page_title +theme: project_database region: header weight: -30 provider: null diff --git a/config/sync/block.block.projectDatabase_primary_local_tasks.yml b/config/sync/block.block.project_database_primary_local_tasks.yml similarity index 81% rename from config/sync/block.block.projectDatabase_primary_local_tasks.yml rename to config/sync/block.block.project_database_primary_local_tasks.yml index e757265..5cc2828 100644 --- a/config/sync/block.block.projectDatabase_primary_local_tasks.yml +++ b/config/sync/block.block.project_database_primary_local_tasks.yml @@ -3,11 +3,11 @@ langcode: da status: true dependencies: theme: - - projectDatabase + - project_database _core: default_config_hash: 7cvXIzw8NabmQCWMPqBz0mvIQZzXUZB3OeOTa5eqbCo -id: projectDatabase_primary_local_tasks -theme: projectDatabase +id: project_database_primary_local_tasks +theme: project_database region: header weight: 0 provider: null diff --git a/config/sync/block.block.projectDatabase_secondary_local_tasks.yml b/config/sync/block.block.project_database_secondary_local_tasks.yml similarity index 81% rename from config/sync/block.block.projectDatabase_secondary_local_tasks.yml rename to config/sync/block.block.project_database_secondary_local_tasks.yml index c90fd6a..27ae9e8 100644 --- a/config/sync/block.block.projectDatabase_secondary_local_tasks.yml +++ b/config/sync/block.block.project_database_secondary_local_tasks.yml @@ -3,11 +3,11 @@ langcode: da status: true dependencies: theme: - - projectDatabase + - project_database _core: default_config_hash: D_hUB_AW2IvKbVo3lVG-B2KfTsX6xJ-CxfOcRYUnL3E -id: projectDatabase_secondary_local_tasks -theme: projectDatabase +id: project_database_secondary_local_tasks +theme: project_database region: sidebar_first weight: 0 provider: null diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index a4ac39c..e8951b0 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -53,5 +53,5 @@ module: theme: stark: 0 claro: 0 - projectDatabase: 0 + project_database: 0 profile: minimal diff --git a/config/sync/system.theme.yml b/config/sync/system.theme.yml index b4067dc..ffa914d 100644 --- a/config/sync/system.theme.yml +++ b/config/sync/system.theme.yml @@ -2,4 +2,4 @@ _core: default_config_hash: 6lQ55NXM9ysybMQ6NzJj4dtiQ1dAkOYxdDompa-r_kk langcode: da admin: '' -default: projectDatabase +default: project_database diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..71a88b4 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,27 @@ +# itk-version: 3.2.4 +services: + phpfpm: + environment: + - PHP_SENDMAIL_PATH=/usr/sbin/sendmail -S mail:1025 + + nginx: + labels: + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}.middlewares=ITKBasicAuth@file" + + mail: + image: axllent/mailpit + restart: unless-stopped + networks: + - app + - frontend + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}-http.rule=Host(`mail.${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}-http.entrypoints=web" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}.rule=Host(`mail.${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}.entrypoints=websecure" + - "traefik.http.services.mail_${COMPOSE_PROJECT_NAME:?}.loadbalancer.server.port=8025" + - "traefik.http.routers.mail_${COMPOSE_PROJECT_NAME:?}.middlewares=ITKMailhogAuth@file" diff --git a/docker-compose.redirect.yml b/docker-compose.redirect.yml new file mode 100644 index 0000000..2e7ac33 --- /dev/null +++ b/docker-compose.redirect.yml @@ -0,0 +1,15 @@ +# itk-version: 3.2.4 +services: + nginx: + labels: + # Add www before domain and set redirect to non-www + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}-http.rule=Host(`www.${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}-http.entrypoints=web" + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}-http.middlewares=redirect-to-https,non_www" + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}.rule=Host(`www.${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}.entrypoints=websecure" + - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME:?}.middlewares=non_www" + + - traefik.http.middlewares.non_www.redirectregex.regex=^(http|https)?://(?:www\.)?(.+) + - traefik.http.middlewares.non_www.redirectregex.replacement=https://$${2:?} + - traefik.http.middlewares.non_www.redirectregex.permanent=true diff --git a/docker-compose.server.yml b/docker-compose.server.yml new file mode 100644 index 0000000..c9e464c --- /dev/null +++ b/docker-compose.server.yml @@ -0,0 +1,64 @@ +# itk-version: 3.2.4 +networks: + frontend: + external: true + app: + driver: bridge + internal: false + +services: + phpfpm: + image: itkdev/php8.4-fpm:alpine + restart: unless-stopped + networks: + - app + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + - PHP_MAX_EXECUTION_TIME=30 + - PHP_MEMORY_LIMIT=128M + # Let drush know the site uri (makes using --uri redundant) + - DRUSH_OPTIONS_URI=https://${COMPOSE_SERVER_DOMAIN:?} + depends_on: + - memcached + volumes: + - .:/app + + nginx: + image: nginxinc/nginx-unprivileged:alpine + restart: unless-stopped + networks: + - app + - frontend + depends_on: + - phpfpm + volumes: + - ./.docker/templates:/etc/nginx/templates:ro + - ./.docker/nginx.conf:/etc/nginx/nginx.conf:ro + - .:/app + environment: + NGINX_FPM_SERVICE: ${COMPOSE_PROJECT_NAME:?}-phpfpm-1:9000 + NGINX_CRON_METRICS: ${COMPOSE_PROJECT_NAME:?}-phpfpm-1:9746 + NGINX_WEB_ROOT: /app/web + NGINX_PORT: 8080 + NGINX_MAX_BODY_SIZE: 5M + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-http.rule=Host(`${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-http.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}.rule=Host(`${COMPOSE_SERVER_DOMAIN:?}`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}.entrypoints=websecure" + # Cron-metrics protection. + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-metrics.rule=Host(`${COMPOSE_SERVER_DOMAIN:?}`) && PathPrefix(`/cron-metrics`) " + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-metrics.middlewares=ITKMetricsAuth@file" + + memcached: + image: memcached:alpine + restart: unless-stopped + networks: + - app + environment: + - MEMCACHED_CACHE_SIZE=64 diff --git a/docker-compose.yml b/docker-compose.yml index a1af8ea..230ab5a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,4 @@ -version: "3" - +# itk-version: 3.2.4 networks: frontend: external: true @@ -13,70 +12,116 @@ services: networks: - app ports: - - '3306' + - "3306" + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + start_period: 10s + interval: 10s + timeout: 5s + retries: 3 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_USER=db - MYSQL_PASSWORD=db - MYSQL_DATABASE=db #- ENCRYPT=1 # Uncomment to enable database encryption. - # @see https://symfony.com/doc/current/setup/symfony_server.html#docker-integration - labels: - com.symfony.server.service-prefix: 'DATABASE' phpfpm: - image: itkdev/php8.3-fpm:latest + image: itkdev/php8.4-fpm:latest + user: ${COMPOSE_USER:-deploy} networks: - app + extra_hosts: + - "host.docker.internal:host-gateway" environment: - - PHP_XDEBUG=${PHP_XDEBUG:-0} - - PHP_XDEBUG_REMOTE_AUTOSTART=${PHP_XDEBUG_REMOTE_AUTOSTART:-0} - - PHP_XDEBUG_REMOTE_CONNECT_BACK=${PHP_XDEBUG_REMOTE_CONNECT_BACK:-0} + - PHP_XDEBUG_MODE=${PHP_XDEBUG_MODE:-off} - PHP_MAX_EXECUTION_TIME=30 - PHP_MEMORY_LIMIT=256M - # - PHP_MAIL=1 # Uncomment to enable mailhog. - - DOCKER_HOST_DOMAIN=${COMPOSE_DOMAIN} + # Depending on the setup, you may have to remove --read-envelope-from from msmtp (cf. https://marlam.de/msmtp/msmtp.html) or use SMTP to send mail + - PHP_SENDMAIL_PATH=/usr/bin/msmtp --host=mail --port=1025 --read-recipients --read-envelope-from + - DOCKER_HOST_DOMAIN=${COMPOSE_DOMAIN:?} + - PHP_IDE_CONFIG=serverName=localhost + # Let drush know the site uri (makes using --uri redundant) + - DRUSH_OPTIONS_URI=http://${COMPOSE_DOMAIN:?} depends_on: - - mariadb + mariadb: + condition: service_healthy + memcached: + condition: service_healthy volumes: - - .:/app:delegated - - drush-cache:/root/.drush + - .:/app nginx: - image: nginx:latest + image: nginxinc/nginx-unprivileged:alpine networks: - app - frontend depends_on: - phpfpm - - memcached ports: - - '80' + - "8080" volumes: - - ${PWD}/.docker/vhost.conf:/etc/nginx/conf.d/default.conf:ro - - ./:/app:delegated + - ./.docker/templates:/etc/nginx/templates:ro + - .:/app + environment: + NGINX_FPM_SERVICE: ${COMPOSE_PROJECT_NAME:?}-phpfpm-1:9000 + NGINX_CRON_METRICS: ${COMPOSE_PROJECT_NAME:?}-phpfpm-1:9746 + NGINX_WEB_ROOT: /app/web + NGINX_PORT: 8080 + NGINX_MAX_BODY_SIZE: 5M labels: - "traefik.enable=true" - "traefik.docker.network=frontend" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`${COMPOSE_DOMAIN}`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}.rule=Host(`${COMPOSE_DOMAIN:?}`)" + # HTTPS config - enable redirect from :80 to :443 + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + # Cron-metrics protection. + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-metrics.rule=Host(`${COMPOSE_DOMAIN:?}`) && PathPrefix(`/cron-metrics`) " + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}-metrics.middlewares=ITKMetricsAuth@file" memcached: - image: 'memcached:latest' + image: memcached:alpine networks: - app ports: - - '11211' + - "11211" + healthcheck: + test: echo "version" | nc -vn -w 1 127.0.0.1 11211 + interval: 10s + retries: 60 environment: - MEMCACHED_CACHE_SIZE=64 - mailhog: - image: mailhog/mailhog + mail: + image: axllent/mailpit networks: - app + - frontend ports: - "1025" - "8025" + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}mail.rule=Host(`mail-${COMPOSE_DOMAIN:?}`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME:?}mail.loadbalancer.server.port=8025" -# Drush cache volume to persist cache between runs. -volumes: - drush-cache: + # Code checks tools + markdownlint: + image: itkdev/markdownlint + profiles: + - dev + volumes: + - ./:/md + + prettier: + # Prettier does not (yet, fcf. + # https://github.com/prettier/prettier/issues/15206) have an official + # docker image. + # https://hub.docker.com/r/jauderho/prettier is good candidate (cf. https://hub.docker.com/search?q=prettier&sort=updated_at&order=desc) + image: jauderho/prettier + profiles: + - dev + volumes: + - ./:/work diff --git a/web/themes/custom/projectDatabase/projectDatabase.libraries.yml b/web/modules/custom/.gitkeep similarity index 100% rename from web/themes/custom/projectDatabase/projectDatabase.libraries.yml rename to web/modules/custom/.gitkeep diff --git a/web/sites/default/_docker.settings.local.php b/web/sites/default/_docker.settings.local.php index d92f311..42c9c9f 100644 --- a/web/sites/default/_docker.settings.local.php +++ b/web/sites/default/_docker.settings.local.php @@ -20,19 +20,6 @@ $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null'; $settings['cache']['bins']['page'] = 'cache.backend.null'; -/** - * Define database connection. - */ -$databases['default']['default'] = [ - 'database' => getenv('DATABASE_DATABASE') ?: 'db', - 'username' => getenv('DATABASE_USERNAME') ?: 'db', - 'password' => getenv('DATABASE_PASSWORD') ?: 'db', - 'host' => getenv('DATABASE_HOST') ?: 'mariadb', - 'port' => getenv('DATABASE_PORT') ?: '', - 'driver' => getenv('DATABASE_DRIVER') ?: 'mysql', - 'prefix' => '', -]; - /** * Set hash salt. */ diff --git a/web/sites/default/settings.php b/web/sites/default/settings.php index eb825d9..f8bd4c4 100644 --- a/web/sites/default/settings.php +++ b/web/sites/default/settings.php @@ -767,6 +767,22 @@ * Keep this code block at the end of this file to take full effect. */ +/** + * Database connection. + * + * Defaults match the Docker development database; override per environment + * with the DATABASE_* environment variables. + */ +$databases['default']['default'] = [ + 'database' => getenv('DATABASE_DATABASE') ?: 'db', + 'username' => getenv('DATABASE_USERNAME') ?: 'db', + 'password' => getenv('DATABASE_PASSWORD') ?: 'db', + 'host' => getenv('DATABASE_HOST') ?: 'mariadb', + 'port' => getenv('DATABASE_PORT') ?: '', + 'driver' => getenv('DATABASE_DRIVER') ?: 'mysql', + 'prefix' => '', +]; + if (file_exists($app_root . '/' . $site_path . '/docker.settings.local.php')) { include $app_root . '/' . $site_path . '/docker.settings.local.php'; } diff --git a/web/themes/custom/projectDatabase/projectDatabase.info.yml b/web/themes/custom/projectDatabase/projectDatabase.info.yml deleted file mode 100644 index 9f8450c..0000000 --- a/web/themes/custom/projectDatabase/projectDatabase.info.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: projectDatabase -type: theme -description: A base theme using Drupal 9.0.0's core markup and CSS. -package: Core -version: VERSION -base theme: claro -core_version_requirement: ^8 || ^9 \ No newline at end of file diff --git a/web/themes/custom/projectDatabase/projectDatabase.theme b/web/themes/custom/projectDatabase/projectDatabase.theme deleted file mode 100644 index 2ba0688..0000000 --- a/web/themes/custom/projectDatabase/projectDatabase.theme +++ /dev/null @@ -1,11 +0,0 @@ -getRequestUri(); - } -} \ No newline at end of file diff --git a/web/themes/custom/project_database/project_database.info.yml b/web/themes/custom/project_database/project_database.info.yml new file mode 100644 index 0000000..87256df --- /dev/null +++ b/web/themes/custom/project_database/project_database.info.yml @@ -0,0 +1,7 @@ +name: "Project database" +type: theme +description: "Custom theme for the Project database site, based on Claro." +package: Custom +version: VERSION +base theme: claro +core_version_requirement: ^10 || ^11 diff --git a/web/themes/custom/project_database/project_database.libraries.yml b/web/themes/custom/project_database/project_database.libraries.yml new file mode 100644 index 0000000..e69de29 diff --git a/web/themes/custom/project_database/project_database.theme b/web/themes/custom/project_database/project_database.theme new file mode 100644 index 0000000..4937da5 --- /dev/null +++ b/web/themes/custom/project_database/project_database.theme @@ -0,0 +1,17 @@ +getRequestUri(); + } +} diff --git a/web/themes/custom/projectDatabase/templates/views/views-view.html.twig b/web/themes/custom/project_database/templates/views/views-view.html.twig similarity index 95% rename from web/themes/custom/projectDatabase/templates/views/views-view.html.twig rename to web/themes/custom/project_database/templates/views/views-view.html.twig index 2d13c50..289bbbf 100644 --- a/web/themes/custom/projectDatabase/templates/views/views-view.html.twig +++ b/web/themes/custom/project_database/templates/views/views-view.html.twig @@ -60,9 +60,8 @@ {{ attachment_before }} {% endif %} - {{ 'Export csv'|t }} - - + {{ 'Export csv'|t }} + {% if rows %}
{{ rows }}