diff --git a/.ddev/.env.web b/.ddev/.env.web new file mode 100644 index 0000000..2d2b404 --- /dev/null +++ b/.ddev/.env.web @@ -0,0 +1 @@ +DRUPAL_CORE="^11.4.10" diff --git a/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml new file mode 100644 index 0000000..2208155 --- /dev/null +++ b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml @@ -0,0 +1,19 @@ +name: ddev-drupal-contrib +repository: ddev/ddev-drupal-contrib +version: 1.2.2 +install_date: "2026-10-21T11:52:46+02:00" +project_files: + - commands/host/core-version + - commands/web/eslint + - commands/web/expand-composer-json + - commands/web/nightwatch + - commands/web/phpcbf + - commands/web/phpcs + - commands/web/phpstan + - commands/web/phpunit + - commands/web/poser + - commands/web/stylelint + - commands/web/symlink-project + - config.contrib.yaml +global_files: [] +removal_actions: [] diff --git a/.ddev/commands/host/core-version b/.ddev/commands/host/core-version new file mode 100755 index 0000000..e3e0122 --- /dev/null +++ b/.ddev/commands/host/core-version @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Switch the core version and rebuild. +## Usage: core-version [version] +## Example: "ddev core-version ^11" or "ddev core-version ~11.1.0" + +set -eu -o pipefail + +# Handle default values. +DRUPAL_CORE=${1:-default} +if [ "$DRUPAL_CORE" == "default" ]; then + DRUPAL_CORE="" +fi + +# Set/clear the env. +ddev dotenv set .ddev/.env.web --drupal-core "${DRUPAL_CORE}" + +# Restart and rebuild. +ddev restart +ddev poser diff --git a/.ddev/commands/web/eslint b/.ddev/commands/web/eslint new file mode 100755 index 0000000..6be295c --- /dev/null +++ b/.ddev/commands/web/eslint @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run eslint inside the web container +## Usage: eslint [flags] [args] +## Example: "ddev eslint" +## ExecRaw: true + +set -eu -o pipefail + +if "$DDEV_DOCROOT/core/node_modules/.bin/eslint" --version >/dev/null ; then + # Configure prettier + test -e .prettierrc.json || ln -s $DDEV_DOCROOT/core/.prettierrc.json . + test -e .prettierignore || echo '*.yml' > .prettierignore + # Change directory to the project root folder + cd "$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_}" || exit + "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/eslint" --config="../../../core/.eslintrc.passing.json" --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core --ext=.js,.yml . "$@" +else + echo "eslint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'" + exit 1 +fi diff --git a/.ddev/commands/web/expand-composer-json b/.ddev/commands/web/expand-composer-json new file mode 100755 index 0000000..393cc07 --- /dev/null +++ b/.ddev/commands/web/expand-composer-json @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Add Drupal core and other needed dependencies. +## Usage: expand-composer-json [flags] [PROJECT_NAME] +## Example: "ddev expand-composer-json ctools" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +# Set the default core version. +export DRUPAL_CORE=${DRUPAL_CORE:-^11} + +export _WEB_ROOT=$DDEV_DOCROOT +cd "$DDEV_COMPOSER_ROOT" || exit +curl -fsSL -O https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/scripts/expand_composer_json.php +_ddev_drupal_contrib_empty_composer=false +if [[ ! -f composer.json ]]; then + echo "{}" > composer.json + _ddev_drupal_contrib_empty_composer=true +fi +php expand_composer_json.php "$DDEV_SITENAME" +rm -f expand_composer_json.php +if [ "$_ddev_drupal_contrib_empty_composer" = true ]; then + rm -f composer.json +fi diff --git a/.ddev/commands/web/nightwatch b/.ddev/commands/web/nightwatch new file mode 100755 index 0000000..06b2ea2 --- /dev/null +++ b/.ddev/commands/web/nightwatch @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run nightwatch inside the web container +## Usage: nightwatch [flags] [args] +## Example: "ddev nightwatch" +## ExecRaw: true + +set -eu -o pipefail + +yarn --cwd "$DDEV_DOCROOT/core" test:nightwatch "$DDEV_APPROOT/$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/" "$@" diff --git a/.ddev/commands/web/phpcbf b/.ddev/commands/web/phpcbf new file mode 100755 index 0000000..a42a5b9 --- /dev/null +++ b/.ddev/commands/web/phpcbf @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpcbf inside the web container +## Usage: phpcbf [flags] [args] +## Example: "ddev phpcbf" or "ddev phpcbf -n" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpcbf >/dev/null; then + echo "phpcbf is not available. You may need to 'ddev composer install'" + exit 1 +fi +test -e phpcs.xml.dist || curl -fsSL -O https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist +phpcbf -s --report-full --report-summary --report-source $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH --ignore=*/.ddev/* "$@" diff --git a/.ddev/commands/web/phpcs b/.ddev/commands/web/phpcs new file mode 100755 index 0000000..b4d19af --- /dev/null +++ b/.ddev/commands/web/phpcs @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpcs inside the web container +## Usage: phpcs [flags] [args] +## Example: "ddev phpcs" or "ddev phpcs -n" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpcs >/dev/null; then + echo "phpcs is not available. You may need to 'ddev composer install'" + exit 1 +fi +test -e phpcs.xml.dist || curl -fsSL -O https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist +phpcs -s --report-full --report-summary --report-source $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH --ignore=*/.ddev/* "$@" diff --git a/.ddev/commands/web/phpstan b/.ddev/commands/web/phpstan new file mode 100755 index 0000000..1619b93 --- /dev/null +++ b/.ddev/commands/web/phpstan @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpstan inside the web container +## Usage: phpstan [flags] [args] +## Example: "ddev phpstan" or "ddev phpstan -n" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +if ! command -v phpstan >/dev/null; then + echo "phpstan is not available. You may need to 'ddev poser'" + exit 1 +fi +# PHPStan discovers phpstan.neon.dist and phpstan.dist.neon on its own, so only scaffold when neither exists. +if [ -e phpstan.neon ] || { [ ! -e phpstan.neon.dist ] && [ ! -e phpstan.dist.neon ]; }; then + test -e phpstan.neon || curl -fsSL -O https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpstan.neon + # See https://git.drupalcode.org/project/gitlab_templates/-/commit/a107b7f1f79af12e0b09f70be47b68e3f69b4504 + sed -i 's/BASELINE_PLACEHOLDER/phpstan-baseline.neon/g' phpstan.neon + # Add an empty baseline file to ensure it exists. + test -e phpstan-baseline.neon || touch phpstan-baseline.neon +fi + +EXTENSION_DIRECTORY=$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_} +cd "$EXTENSION_DIRECTORY" || exit 1 +# Ensure PHPStan configuration is symlinked from project root. +ln -s $DDEV_DOCROOT/phpstan.neon 2>/dev/null || true +ln -s $DDEV_DOCROOT/phpstan-baseline.neon 2>/dev/null || true +phpstan analyze . "$@" diff --git a/.ddev/commands/web/phpunit b/.ddev/commands/web/phpunit new file mode 100755 index 0000000..b967304 --- /dev/null +++ b/.ddev/commands/web/phpunit @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpunit inside the web container +## Usage: phpunit [flags] [args] +## Example: "ddev phpunit" or "ddev phpunit --stop-on-failure" +## Example: "ddev phpunit web/modules/custom/mymodule/tests/src/Unit/MyTest.php" +## Example: "ddev phpunit --filter testMyFunction" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpunit >/dev/null; then + echo "phpunit is not available. You may need to 'ddev composer install'" + exit 1 +fi + +# CHECK for local config. +if [ -f "phpunit.xml" ]; then + # Defer to local config + phpunit "$@" +else + # Check if we are running a specific test or test folder. + if [ $# -gt 0 ] && [ -e "$1" ]; then + TEST_PATH="$1" + shift + phpunit --bootstrap $PWD/$DDEV_DOCROOT/core/tests/bootstrap.php "$TEST_PATH" "$@" + else + # Run all custom module tests. + phpunit --bootstrap $PWD/$DDEV_DOCROOT/core/tests/bootstrap.php $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH "$@" + fi +fi diff --git a/.ddev/commands/web/poser b/.ddev/commands/web/poser new file mode 100755 index 0000000..b6c30bb --- /dev/null +++ b/.ddev/commands/web/poser @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Expand composer.json and run composer update. +## Usage: poser [flags] [args] +## Example: "ddev poser" or "ddev poser --prefer-source" or "ddev poser --prefer-lowest --prefer-stable" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +export COMPOSER=composer.contrib.json +.ddev/commands/web/expand-composer-json +composer update "$@" +# The -f flag suppresses errors if lock file does not exist. +rm -f composer.contrib.json composer.contrib.lock +touch $DDEV_DOCROOT/core/.env diff --git a/.ddev/commands/web/stylelint b/.ddev/commands/web/stylelint new file mode 100755 index 0000000..521d3bc --- /dev/null +++ b/.ddev/commands/web/stylelint @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run stylelint inside the web container +## Usage: stylelint [flags] [args] +## Example: "ddev stylelint" +## ExecRaw: true + +set -eu -o pipefail + +if "$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --version >/dev/null ; then + # Configure prettier + test -e .prettierrc.json || ln -s $DDEV_DOCROOT/core/.prettierrc.json . + # Change directory to the project root folder + cd "$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_}" || exit + "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --color --config "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/.stylelintrc.json" "./**/*.css" "$@" +else + echo "stylelint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'" + exit 1 +fi diff --git a/.ddev/commands/web/symlink-project b/.ddev/commands/web/symlink-project new file mode 100755 index 0000000..fa27806 --- /dev/null +++ b/.ddev/commands/web/symlink-project @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Symlink project files into the configured location (defaults to `web/modules/custom/[PROJECT_NAME]`) +## Usage: symlink-project [flags] [args] +## Example: "ddev symlink-project" +## ExecRaw: true + +set -eu -o pipefail + +export _WEB_ROOT=$DDEV_DOCROOT +cd "$DDEV_COMPOSER_ROOT" || exit +curl -fsSL -O https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/scripts/symlink_project.php + +if [ -z "${PROJECT_FILES-}" ]; then + # Suppress a warning. + PROJECT_FILES=$(ls -A --ignore="web" --ignore="vendor" --ignore="symlink_project.php" --ignore=".ddev" --ignore=".idea" --ignore=".claude") + export PROJECT_FILES +fi + +# Symlink name using underscores. +# @see https://www.drupal.org/docs/develop/creating-modules/naming-and-placing-your-drupal-module +# DRUPAL_PROJECT_FOLDER is used by the symlink-project script in gitlab_templates +export DRUPAL_PROJECT_FOLDER=${DDEV_DOCROOT}/${DRUPAL_PROJECTS_PATH}/${DDEV_SITENAME//-/_} +php symlink_project.php +rm -f symlink_project.php + +# Ignore generated Drupal paths, unless the project already manages its own .gitignore. +if [ ! -e .gitignore ]; then + printf "/vendor/\n/web/\n" > .gitignore +fi diff --git a/.ddev/config.contrib.yaml b/.ddev/config.contrib.yaml new file mode 100644 index 0000000..344b786 --- /dev/null +++ b/.ddev/config.contrib.yaml @@ -0,0 +1,24 @@ +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## To customize this configuration, see: +## https://ddev.readthedocs.io/en/stable/users/extend/customization-extendibility/ +web_environment: + # To change the Drupal core version, see the README: + # https://github.com/ddev/ddev-drupal-contrib/blob/main/README.md#changing-the-drupal-core-version + # https://git.drupalcode.org/project/gitlab_templates/-/blob/1.9.6/scripts/expand_composer_json.php?ref_type=tags#L15 + - IGNORE_PROJECT_DRUPAL_CORE_VERSION=1 + # To change the location of your project code, see the README: + # https://github.com/ddev/ddev-drupal-contrib/blob/main/README.md#changing-the-symlink-location + - DRUPAL_PROJECTS_PATH=modules/custom + - SIMPLETEST_DB=mysql://db:db@db/db + - SIMPLETEST_BASE_URL=http://web + - BROWSERTEST_OUTPUT_DIRECTORY=/tmp + - BROWSERTEST_OUTPUT_BASE_URL=${DDEV_PRIMARY_URL} +hooks: + post-start: + - exec-host: | + if [[ -f vendor/autoload.php ]]; then + ddev symlink-project + else + exit 0 + fi diff --git a/.ddev/config.yaml b/.ddev/config.yaml new file mode 100644 index 0000000..1635ade --- /dev/null +++ b/.ddev/config.yaml @@ -0,0 +1,308 @@ +name: os2forms-rest-api +type: drupal11 +docroot: web +php_version: "8.4" +webserver_type: nginx-fpm +xdebug_enabled: false +additional_hostnames: [] +additional_fqdns: [] +database: + type: mariadb + version: "11.8" +use_dns_when_possible: true +composer_version: "2" +web_environment: [] +nodejs_version: "24" +corepack_enable: true + +# Key features of DDEV's config.yaml: + +# name: # Name of the project, automatically provides +# http://projectname.ddev.site and https://projectname.ddev.site +# If the name is omitted, the project will take the name of the enclosing directory, +# which is useful if you want to have a copy of the project side by side with this one. + +# type: # asterios, backdrop, cakephp, codeigniter, craftcms, drupal, drupal6, drupal7, drupal8, drupal9, drupal10, drupal11, drupal12, generic, joomla, laravel, magento, magento2, maho, modx, php, shopware6, silverstripe, symfony, typo3, wordpress, wp-bedrock +# See https://docs.ddev.com/en/stable/users/quickstart/ for more +# information on the different project types + +# docroot: # Relative path to the directory containing index.php. + +# php_version: "8.4" # PHP version to use, "5.6" through "8.5" + +# You can explicitly specify the webimage but this +# is not recommended, as the images are often closely tied to DDEV's behavior, +# so this can break upgrades. + +# webimage: +# It’s unusual to change this option, and we don’t recommend it without Docker experience and a good reason. +# Typically, this means additions to the existing web image using a .ddev/web-build/Dockerfile.* + +# database: +# type: # mysql, mariadb, postgres +# version: # database version, like "10.11" or "8.0" +# MariaDB versions can be 5.5-10.8, 10.11, 11.4, 11.8, 12.3 +# MySQL versions can be 5.5-8.0, 8.4, 9.7 +# PostgreSQL versions can be 9-18 + +# You can explicitly specify the dbimage but this +# is not recommended, as the images are often closely tied to DDEV's behavior, +# so this can break upgrades. + +# dbimage: +# It’s unusual to change this option, and we don’t recommend it without Docker experience and a good reason. +# Typically, this means additions to the existing db image using a .ddev/db-build/Dockerfile.* + +# router_http_port: # Port to be used for http (defaults to global configuration, usually 80) +# router_https_port: # Port for https (defaults to global configuration, usually 443) + +# xdebug_enabled: false # Set to true to enable Xdebug and "ddev start" or "ddev restart" +# Note that for most people the commands +# "ddev xdebug" to enable Xdebug and "ddev xdebug off" to disable it work better, +# as leaving Xdebug enabled all the time is a big performance hit. + +# xhgui_http_port: "8143" +# xhgui_https_port: "8142" +# The XHGui ports can be changed from the default 8143 and 8142 +# Very rarely used + +# host_xhgui_port: "8142" +# Can be used to change the host binding port of the XHGui +# application. Rarely used; only when port conflict and +# bind_all_ports is used (normally with router disabled) + +# xhprof_mode: [prepend|xhgui|global] +# Default is "xhgui" + +# webserver_type: nginx-fpm, apache-fpm, generic + +# timezone: Europe/Berlin +# If timezone is unset, DDEV will attempt to derive it from the host system timezone +# using the $TZ environment variable or the /etc/localtime symlink. +# This is the timezone used in the containers and by PHP; +# it can be set to any valid timezone, +# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +# For example Europe/Dublin or MST7MDT + +# composer_root: +# Relative path to the Composer root directory from the project root. This is +# the directory which contains the composer.json and where all Composer related +# commands are executed. + +# composer_version: "2" +# You can set it to "" or "2" (default) for Composer v2 +# to use the latest major version available at the time your container is built. +# It is also possible to use any other Composer version channel. This includes: +# - 2.2 (latest Composer LTS version) +# - stable +# - preview +# - snapshot +# Alternatively, an explicit Composer version may be specified, for example "2.2.18". +# To reinstall Composer after the image was built, run "ddev utility rebuild". + +# nodejs_root: +# Relative path to the directory containing the Node.js version file from the +# project root. Only used with "nodejs_version: auto" or "nodejs_version: engine". + +# nodejs_version: "24" +# change from the default system Node.js version to any other version. +# See https://docs.ddev.com/en/stable/users/configuration/config/#nodejs_version for more information +# and https://www.npmjs.com/package/n#specifying-nodejs-versions for the full documentation. + +# corepack_enable: false +# Change to 'true' to 'corepack enable' and gain access to latest versions of yarn/pnpm + +# additional_hostnames: +# - somename +# - someothername +# would provide http and https URLs for "somename.ddev.site" +# and "someothername.ddev.site". + +# additional_fqdns: +# - example.com +# - sub1.example.com +# would provide http and https URLs for "example.com" and "sub1.example.com" +# Please take care with this because it can cause great confusion. + +# upload_dirs: "custom/upload/dir" +# +# upload_dirs: +# - custom/upload/dir +# - ../private +# +# would set the destination paths for ddev import-files to /custom/upload/dir +# When Mutagen is enabled this path is bind-mounted so that all the files +# in the upload_dirs don't have to be synced into Mutagen. + +# disable_upload_dirs_warning: false +# If true, turns off the normal warning that says +# "You have Mutagen enabled and your 'php' project type doesn't have upload_dirs set" + +# ddev_version_constraint: "" +# Example: +# ddev_version_constraint: ">= 1.24.8" +# This will enforce that the running ddev version is within this constraint. +# See https://github.com/Masterminds/semver#checking-version-constraints for +# supported constraint formats + +# working_dir: +# web: /var/www/html +# db: /home +# would set the default working directory for the web and db services. +# These values specify the destination directory for ddev ssh and the +# directory in which commands passed into ddev exec are run. + +# omit_containers: [db, ddev-ssh-agent] +# Currently only these containers are supported. Some containers can also be +# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit +# the "db" container, several standard features of DDEV that access the +# database container will be unusable. In the global configuration it is also +# possible to omit ddev-router, but not here. + +# performance_mode: "global" +# DDEV offers performance optimization strategies to improve the filesystem +# performance depending on your host system. Should be configured globally. +# +# If set, will override the global config. Possible values are: +# - "global": uses the value from the global config. +# - "none": disables performance optimization for this project. +# - "mutagen": enables Mutagen for this project. +# +# See https://docs.ddev.com/en/stable/users/install/performance/#mutagen + +# fail_on_hook_fail: False +# Decide whether 'ddev start' should be interrupted by a failing hook + +# host_https_port: "59002" +# The host port binding for https can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_webserver_port: "59001" +# The host port binding for the ddev-webserver can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_db_port: "59002" +# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic +# unless explicitly specified. + +# mailpit_http_port: "8025" +# mailpit_https_port: "8026" +# The Mailpit ports can be changed from the default 8025 and 8026 + +# host_mailpit_port: "8025" +# The mailpit port is not normally bound on the host at all, instead being routed +# through ddev-router, but it can be bound directly to localhost if specified here. + +# webimage_extra_packages: ['php${DDEV_PHP_VERSION}-tidy', 'php${DDEV_PHP_VERSION}-yac'] +# Extra Debian packages that are needed in the webimage can be added here + +# dbimage_extra_packages: [netcat, telnet, sudo] +# Extra Debian packages that are needed in the dbimage can be added here + +# use_dns_when_possible: true +# If the host has internet access and the domain configured can +# successfully be looked up, DNS will be used for hostname resolution +# instead of editing /etc/hosts +# Defaults to true + +# project_tld: ddev.site +# The top-level domain used for project URLs +# The default "ddev.site" allows DNS lookup via a wildcard + +# share_default_provider: ngrok +# The default share provider to use for "ddev share" +# Defaults to global configuration, usually "ngrok" +# Can be "ngrok" or "cloudflared" or the name of a custom provider from .ddev/share-providers/ + +# share_provider_args: --basic-auth username:pass1234 +# Provide extra flags to the share provider script +# See https://docs.ddev.com/en/stable/users/configuration/config/#share_provider_args + +# disable_settings_management: false +# If true, DDEV will not create CMS-specific settings files like +# Drupal's settings.php/settings.ddev.php or TYPO3's additional.php +# In this case the user must provide all such settings. + +# You can inject environment variables into the web container with: +# web_environment: +# - SOMEENV=somevalue +# - SOMEOTHERENV=someothervalue + +# no_project_mount: false +# (Experimental) If true, DDEV will not mount the project into the web container; +# the user is responsible for mounting it manually or via a script. +# This is to enable experimentation with alternate file mounting strategies. +# For advanced users only! + +# bind_all_interfaces: false +# If true, host ports will be bound on all network interfaces, +# not the localhost interface only. This means that ports +# will be available on the local network if the host firewall +# allows it. + +# default_container_timeout: 120 +# The default time that DDEV waits for all containers to become ready can be increased from +# the default 120. This helps in importing huge databases, for example. + +#web_extra_exposed_ports: +#- name: nodejs +# container_port: 3000 +# http_port: 2999 +# https_port: 3000 +#- name: something +# container_port: 4000 +# https_port: 4000 +# http_port: 3999 +# Allows a set of extra ports to be exposed via ddev-router +# Fill in all three fields even if you don’t intend to use the https_port! +# If you don’t add https_port, then it defaults to 0 and ddev-router will fail to start. +# +# The port behavior on the ddev-webserver must be arranged separately, for example +# using web_extra_daemons. +# For example, with a web app on port 3000 inside the container, this config would +# expose that web app on https://.ddev.site:9999 and http://.ddev.site:9998 +# web_extra_exposed_ports: +# - name: myapp +# container_port: 3000 +# http_port: 9998 +# https_port: 9999 + +#web_extra_daemons: +#- name: "http-1" +# command: "/var/www/html/node_modules/.bin/http-server -p 3000" +# directory: /var/www/html +#- name: "http-2" +# command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000" +# directory: /var/www/html + +# override_config: false +# By default, config.*.yaml files are *merged* into the configuration +# But this means that some things can't be overridden +# For example, if you have 'use_dns_when_possible: true' you can't override it with a merge +# and you can't erase existing hooks or all environment variables. +# However, with "override_config: true" in a particular config.*.yaml file, +# 'use_dns_when_possible: false' can override the existing values, and +# hooks: +# post-start: [] +# or +# web_environment: [] +# or +# additional_hostnames: [] +# can have their intended effect. 'override_config' affects only behavior of the +# config.*.yaml file it exists in. + +# Many DDEV commands can be extended to run tasks before or after the +# DDEV command is executed, for example "post-start", "post-import-db", +# "pre-composer", "post-composer" +# See https://docs.ddev.com/en/stable/users/extend/custom-commands/ for more +# information on the commands that can be extended and the tasks you can define +# for them. Example: +#hooks: +# post-import-db: +# - exec: drush sql:sanitize +# - exec: drush updatedb +# - exec: drush cache:rebuild diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 6908667..54b9acb 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 2 @@ -24,4 +24,6 @@ jobs: 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 + env: + BASE_REF: ${{ github.base_ref }} + run: git diff --exit-code "origin/$BASE_REF" -- CHANGELOG.md && exit 1 || exit 0 diff --git a/.github/workflows/composer.yaml b/.github/workflows/composer.yaml deleted file mode 100644 index 65fd01f..0000000 --- a/.github/workflows/composer.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# 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 - # https://getcomposer.org/doc/03-cli.md#composer-auth - COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"} }' - -on: - pull_request: - paths: &paths - - "composer.json" - - "compose.yaml" - 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 - - - &composer_install - name: Composer install - run: | - # Create a temporary composer file to install https://github.com/mglaman/composer-drupal-lenient before the real install needs it. - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm composer init --no-interaction - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true - docker compose run --rm --env COMPOSER_AUTH --env COMPOSER=composer.lenient.json phpfpm composer require mglaman/composer-drupal-lenient:^1 - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm rm composer.lenient.* - # The real install. - docker compose run --rm --env COMPOSER_AUTH phpfpm composer install --no-blocking - - - run: | - 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 - - - *composer_install - - - run: | - docker compose run --rm phpfpm composer audit diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml index ce1d1e4..ac0fc21 100644 --- a/.github/workflows/markdown.yaml +++ b/.github/workflows/markdown.yaml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Create docker network run: | diff --git a/.github/workflows/module.yaml b/.github/workflows/module.yaml new file mode 100644 index 0000000..6a76615 --- /dev/null +++ b/.github/workflows/module.yaml @@ -0,0 +1,55 @@ +name: Module + +env: + COMPOSE_USER: runner + # https://getcomposer.org/doc/03-cli.md#composer-auth + COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"} }' + +on: + pull_request: + push: + branches: + - main + - develop + +jobs: + php: + name: PHP + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: go-task/setup-task@v2 + # https://github.com/ddev/github-action-setup-ddev + - uses: ddev/github-action-setup-ddev@v1 + with: + autostart: false + + - name: Start DDEV + # https://github.com/ddev/ddev-drupal-contrib + run: | + ddev start + # We still need drupal lenient. + ddev exec -- COMPOSER=composer.lenient.json composer init --no-interaction + ddev exec -- COMPOSER=composer.lenient.json composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true + ddev exec -- COMPOSER=composer.lenient.json composer require mglaman/composer-drupal-lenient:^1.0 + rm -f composer.lenient.* + ddev poser --no-interaction --no-security-blocking + ddev symlink-project + + - name: Composer - validate + run: ddev composer validate --strict + + - name: Composer - normalize + run: ddev composer normalize --dry-run + + - name: PHP coding standards + run: ddev phpcs + + - name: Code analysis + run: ddev phpstan + + - name: Rector + run: ddev php vendor/bin/rector --dry-run + + - name: Composer - audit + run: ddev composer audit diff --git a/.github/workflows/php.yaml b/.github/workflows/php.yaml deleted file mode 100644 index 6361b71..0000000 --- a/.github/workflows/php.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# Do not edit this file! Make a pull request on changing -# github/workflows/drupal-module/php.yaml in -# https://github.com/itk-dev/devops_itkdev-docker if need be. - -### ### Drupal module 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 - # https://getcomposer.org/doc/03-cli.md#composer-auth - COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"} }' - -on: - pull_request: - paths: &paths - - "**/*.php" - - "composer.json" - - "compose.yaml" - 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 - - - &composer_install - name: Composer install - run: | - # Create a temporary composer file to install https://github.com/mglaman/composer-drupal-lenient before the real install needs it. - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm composer init --no-interaction - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true - docker compose run --rm --env COMPOSER_AUTH --env COMPOSER=composer.lenient.json phpfpm composer require mglaman/composer-drupal-lenient:^1 - docker compose run --rm --env COMPOSER=composer.lenient.json phpfpm rm composer.lenient.* - # The real install. - docker compose run --rm --env COMPOSER_AUTH phpfpm composer install --no-blocking - - - run: | - docker compose run --rm phpfpm vendor/bin/phpcs diff --git a/.github/workflows/yaml.yaml b/.github/workflows/yaml.yaml new file mode 100644 index 0000000..c54cf8e --- /dev/null +++ b/.github/workflows/yaml.yaml @@ -0,0 +1,45 @@ +# Do not edit this file! Make a pull request on changing +# github/workflows/yaml.yaml in +# https://github.com/itk-dev/devops_itkdev-docker if need be. + +### ### YAML +### +### Validates YAML files. +### +### #### Assumptions +### +### 1. A docker compose service named `prettier` for running +### [Prettier](https://prettier.io/) exists. +### +### #### Symfony YAML +### +### Symfony's YAML config files use 4 spaces for indentation and single quotes. +### Therefore we use a [Prettier configuration +### file](https://prettier.io/docs/configuration), `.prettierrc.yaml`, to make +### Prettier format YAML files in the `config/` folder like Symfony expects. + +name: YAML + +on: + pull_request: + paths: &paths + - "**/*.yml" + - "**/*.yaml" + push: + branches: + - main + - develop + paths: *paths + +jobs: + yaml-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Create docker network + run: | + docker network create frontend + + - run: | + docker compose run --rm prettier --no-editorconfig '**/*.{yml,yaml}' --check diff --git a/.gitignore b/.gitignore index 3a9875b..f44d567 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ /vendor/ composer.lock +/.gitattributes + +# DDEV stuff +/web/ +/recipes/ +/.editorconfig \ No newline at end of file diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc index a28c580..0253096 100644 --- a/.markdownlint.jsonc +++ b/.markdownlint.jsonc @@ -1,3 +1,7 @@ +// This file is copied from config/markdown/.markdownlint.jsonc 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. + +// markdownlint-cli configuration file (cf. https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#configuration) { "default": true, // https://github.com/DavidAnson/markdownlint/blob/main/doc/md013.md @@ -9,5 +13,10 @@ // https://github.com/DavidAnson/markdownlint/blob/main/doc/md024.md "no-duplicate-heading": { "siblings_only": true + }, + // https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections#creating-a-collapsed-section + // https://github.com/DavidAnson/markdownlint/blob/main/doc/md033.md + "no-inline-html": { + "allowed_elements": ["details", "summary"] } } diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000..747414b --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1,17 @@ +# This file is copied from config/drupal-module-ddev/markdown/.markdownlintignore 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://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#ignoring-files +vendor/ +node_modules/ +LICENSE.md +# Python +.venv/ +# Drupal +web/*.md +web/core/ +web/libraries/ +web/*/contrib/ +# DDEV stuff +/web/ +/recipes/ diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 0000000..ed57053 --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,33 @@ + + + + + + The coding standard. + + . + + + node_modules + vendor + *.css + *.js + + web + + + + + + + + + + + + + + + + + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..fc24e0c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +# This file is copied from config/drupal-module-ddev/prettier/.prettierignore 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. + +# Ignore all Drupal config since it is nearly all autogenerated by config-export +config/ +# Ignore all ddev files +.ddev/ diff --git a/CHANGELOG.md b/CHANGELOG.md index fa195c7..4ae66dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ about writing changes to this log. ## [Unreleased] +## [2.5.0] + +* Drupal 11 compatibility. + ## [2.4.0] * Upgraded to `"drupal/webform_rest": "^4.2"` @@ -63,7 +67,8 @@ about writing changes to this log. * Release 1.0.0 -[Unreleased]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.4.0...HEAD +[Unreleased]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.5.0...HEAD +[2.5.0]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.4.0...2.5.0 [2.4.0]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.3.0...2.4.0 [2.3.0]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.2.1...2.3.0 [2.2.1]: https://github.com/OS2Forms/os2forms_rest_api/compare/2.2.0...2.2.1 diff --git a/README.md b/README.md index 879d2f5..a7db608 100644 --- a/README.md +++ b/README.md @@ -232,3 +232,29 @@ In order to add linked data, we apply a patch, Webform REST module and implement an event subscriber, [WebformSubmissionDataEventSubscriber](src/EventSubscriber/WebformSubmissionDataEventSubscriber.php), to add the linked data. + +## Development + +We use [DDEV Drupal Contrib](https://github.com/ddev/ddev-drupal-contrib) for development[^1]. + +[^1]: The DDEV environment has been created by running + + ```shell + ddev config --project-type=drupal11 --docroot=Drupal + ddev add-on get ddev/ddev-drupal-contrib + ddev start + ddev poser --no-interaction + ddev symlink-project + # Detect expected Drupal and PHP versions. + ddev config --update + ``` + + (cf. ) + +Start the show by running + +```shell +task ddev:start +``` + +Run `task` to see other useful development tasks. diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..55ce8bf --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,130 @@ +# https://taskfile.dev + +version: "3" + +tasks: + default: + cmd: task --list-all + silent: true + + ddev: + desc: "Run DDEV command" + cmd: ddev {{.TASK_ARGS}} {{.CLI_ARGS}} + internal: true + + coding-standards:apply: + desc: "Apply coding standards" + cmds: + - task: coding-standards:composer:apply + - task: coding-standards:markdown:apply + - task: coding-standards:php:apply + - task: coding-standards:yaml:apply + + coding-standards:check: + desc: "Check coding standards" + cmds: + - task: coding-standards:composer:check + - task: coding-standards:markdown:check + - task: coding-standards:php:check + - task: coding-standards:yaml:check + + coding-standards:composer:apply: + desc: "Apply coding standards for composer" + cmds: + - task: ddev + vars: + TASK_ARGS: composer normalize + + coding-standards:composer:check: + - task: coding-standards:composer:apply + - task: ddev + vars: + TASK_ARGS: composer normalize --dry-run + - task: ddev + vars: + TASK_ARGS: composer validate + + coding-standards:markdown:apply: + desc: "Apply coding standards for Markdown" + cmds: + # Cf. .github/workflows/markdown.yaml + - docker compose run --rm markdownlint markdownlint '**/*.md' --fix + + coding-standards:markdown:check: + desc: "Apply and check coding standards for Markdown" + cmds: + - task: coding-standards:markdown:apply + # Cf. .github/workflows/markdown.yaml + - docker compose run --rm markdownlint markdownlint '**/*.md' + + coding-standards:php:apply: + desc: "Apply coding standards for PHP" + cmds: + # Cf. .github/workflows/php.yaml + - task: ddev + vars: + TASK_ARGS: phpcbf + + coding-standards:php:check: + desc: "Apply and check coding standards for PHP" + cmds: + - task: coding-standards:php:apply + # Cf. .github/workflows/php.yaml + - task: ddev + vars: + TASK_ARGS: phpcs + + coding-standards:yaml:apply: + desc: "Apply coding standards for YAML" + cmds: + # Cf. .github/workflows/yaml.yaml + - docker compose run --rm prettier '**/*.{yml,yaml}' --write + + coding-standards:yaml:check: + desc: "Apply coding standards for YAML" + cmds: + - task: coding-standards:yaml:apply + # Cf. .github/workflows/yaml.yaml + - docker compose run --rm prettier '**/*.{yml,yaml}' --check + + code-analysis: + desc: "Run static code analysis" + cmds: + - task: code-analysis:rector + - task: code-analysis:phpstan + + code-analysis:phpstan: + desc: "Run PHPStan" + cmds: + - task: ddev + vars: + TASK_ARGS: phpstan + + code-analysis:rector: + desc: "Run rector" + cmds: + - task: ddev + vars: + TASK_ARGS: php vendor/bin/rector + + ddev:start: + desc: Start DDEV setup (https://github.com/ddev/ddev-drupal-contrib) + # https://github.com/ddev/ddev-drupal-contrib + cmds: + - ddev start + - task: composer:install:lenient + # @todo Remove --no-security-blocking when possible. + - ddev poser --no-interaction --no-security-blocking + - ddev symlink-project + + composer:install:lenient: + cmds: + # Create a temporary composer file to install https://github.com/mglaman/composer-drupal-lenient before the real install needs it. + - for: + - init --no-interaction + - config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true + - require mglaman/composer-drupal-lenient:^1.0 + cmd: ddev exec -- COMPOSER=composer.lenient.json composer {{.ITEM}} + # Clean up + - rm -f composer.lenient.* + internal: true diff --git a/compose.override.yaml b/compose.override.yaml deleted file mode 100644 index e81a3bd..0000000 --- a/compose.override.yaml +++ /dev/null @@ -1,4 +0,0 @@ -services: - phpfpm: - # OS2Forms is not yet ready for PHP 8.4 (!) - image: itkdev/php8.3-fpm:latest diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index bbec743..0000000 --- a/compose.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# itk-version: 3.2.4 - -services: - phpfpm: - image: itkdev/php8.4-fpm:latest - user: ${COMPOSE_USER:-deploy} - volumes: - - .:/app-os2forms_get_organized - working_dir: /app-os2forms_get_organized - environment: - # https://getcomposer.org/doc/03-cli.md#composer-no-security-blocking - # @see https://github.com/OS2Forms/os2forms/issues/245 - COMPOSER_NO_SECURITY_BLOCKING: 1 - - # Code checks tools - markdownlint: - image: itkdev/markdownlint - profiles: - - dev - volumes: - - ./:/md - - prettier: - # Prettier does not (yet, cf. - # 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/composer.json b/composer.json index 7ebbe0e..0712674 100644 --- a/composer.json +++ b/composer.json @@ -13,14 +13,14 @@ "cweagans/composer-patches": "^1.7", "drupal/key_auth": "^2.0", "drupal/webform_rest": "^4.2", - "os2forms/os2forms": "^4.0 || ^5.0" + "os2forms/os2forms": "^5.0 || ^6.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", "drupal/coder": "^8.3", "ergebnis/composer-normalize": "^2", - "mglaman/drupal-check": "^1.4", - "mglaman/phpstan-drupal": "~1.2.0" + "mglaman/phpstan-drupal": "^2.0", + "palantirnet/drupal-rector": "^1.0" }, "repositories": [ { @@ -34,10 +34,12 @@ "allow-plugins": { "cweagans/composer-patches": true, "dealerdirect/phpcodesniffer-composer-installer": true, + "drupal/core-composer-scaffold": true, "ergebnis/composer-normalize": true, "mglaman/composer-drupal-lenient": true, "simplesamlphp/composer-module-installer": true, "simplesamlphp/composer-xmlprovider-installer": true, + "symfony/runtime": true, "zaporylie/composer-drupal-optimizations": true }, "sort-packages": true @@ -45,7 +47,10 @@ "extra": { "drupal-lenient": { "allowed-list": [ - "drupal/webform_node_element" + "drupal/coc_forms_auto_export", + "drupal/webform_node_element", + "drupal/events_logging", + "drupal/switch_page_theme" ] }, "enable-patching": true, @@ -54,25 +59,5 @@ "Added ability to modify response data sent from Webform Submission endpoint": "https://raw.githubusercontent.com/OS2Forms/os2forms_rest_api/2.4.0/patches/webform_rest_submission.patch" } } - }, - "scripts": { - "code-analysis": [ - "@code-analysis/drupal-check" - ], - "code-analysis/drupal-check": [ - "vendor/bin/drupal-check --deprecations --analysis --exclude-dir=vendor *.* src" - ], - "coding-standards-apply": [ - "@coding-standards-apply/phpcs" - ], - "coding-standards-apply/phpcs": [ - "vendor/bin/phpcbf --standard=phpcs.xml.dist" - ], - "coding-standards-check": [ - "@coding-standards-check/phpcs" - ], - "coding-standards-check/phpcs": [ - "vendor/bin/phpcs --standard=phpcs.xml.dist" - ] } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..da941b7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +# itk-version: 3.2.4 + +services: + # Code checks tools + markdownlint: + image: itkdev/markdownlint + profiles: + - dev + volumes: + - ./:/md + + prettier: + # Prettier does not (yet, cf. + # 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/os2forms_rest_api.info.yml b/os2forms_rest_api.info.yml index fac4fe1..c459e64 100644 --- a/os2forms_rest_api.info.yml +++ b/os2forms_rest_api.info.yml @@ -1,8 +1,8 @@ -name: 'OS2Forms REST API' +name: "OS2Forms REST API" type: module -description: 'OS2Forms REST API' +description: "OS2Forms REST API" package: OS2Forms -core_version_requirement: ^9 || ^10 +core_version_requirement: ^10 || ^11 dependencies: - drupal:key_auth - drupal:webform diff --git a/os2forms_rest_api.services.yml b/os2forms_rest_api.services.yml index 561e8c8..f3e50a5 100644 --- a/os2forms_rest_api.services.yml +++ b/os2forms_rest_api.services.yml @@ -1,32 +1,37 @@ services: logger.channel.os2forms_rest_api: parent: logger.channel_base - arguments: [ 'os2forms_rest_api' ] + arguments: ["os2forms_rest_api"] Drupal\os2forms_rest_api\WebformHelper: arguments: - - '@entity_type.manager' - - '@current_user' + - "@entity_type.manager" + - "@current_user" Drupal\os2forms_rest_api\EventSubscriber\WebformAccessEventSubscriber: arguments: - - '@current_route_match' - - '@current_user' + - "@current_route_match" + - "@current_user" - '@Drupal\os2forms_rest_api\WebformHelper' tags: - - { name: 'event_subscriber' } + - { name: "event_subscriber" } Drupal\os2forms_rest_api\EventSubscriber\WebformSubmissionDataEventSubscriber: arguments: - - '@entity_type.manager' - - '@logger.channel.os2forms_rest_api' + - "@entity_type.manager" + - "@logger.channel.os2forms_rest_api" tags: - - { name: 'event_subscriber' } + - { name: "event_subscriber" } # Overwrite, adding global tag # @see https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/altering-existing-services-providing-dynamic-services key_auth.authentication.key_auth: class: Drupal\key_auth\Authentication\Provider\KeyAuth - arguments: [ '@key_auth' ] + arguments: ["@key_auth"] tags: - - { name: authentication_provider, provider_id: 'key_auth', priority: 200, global: true } + - { + name: authentication_provider, + provider_id: "key_auth", + priority: 200, + global: true, + } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 0f9161d..3f54e21 100755 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -1,23 +1,35 @@ + + + The coding standard. . - vendor/ + + vendor + rector.php + + web - + - + + + + + + + + src/Settings/ - - diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..e69de29 diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..a5f3385 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + level: 6 + paths: + - src + +# Local Variables: +# mode: yaml +# End: diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..5263437 --- /dev/null +++ b/rector.php @@ -0,0 +1,20 @@ +withPaths([ + __DIR__ . '/src', + ]) + ->withSets([ + Drupal11SetList::DRUPAL_114, + ]) + ->withPhpSets(php83: TRUE) + ->withTypeCoverageLevel(0); diff --git a/src/EventSubscriber/WebformAccessEventSubscriber.php b/src/EventSubscriber/WebformAccessEventSubscriber.php index 6039d27..d14c26e 100644 --- a/src/EventSubscriber/WebformAccessEventSubscriber.php +++ b/src/EventSubscriber/WebformAccessEventSubscriber.php @@ -15,34 +15,24 @@ * Webform access event subscriber. */ class WebformAccessEventSubscriber implements EventSubscriberInterface { - /** - * The route match. - * - * @var \Drupal\Core\Routing\RouteMatchInterface - */ - private RouteMatchInterface $routeMatch; - - /** - * The current user. - * - * @var \Drupal\Core\Session\AccountProxyInterface - */ - private AccountProxyInterface $currentUser; - - /** - * The webform helper. - * - * @var \Drupal\os2forms_rest_api\WebformHelper - */ - private WebformHelper $webformHelper; - /** * Constructor. */ - public function __construct(RouteMatchInterface $routeMatch, AccountProxyInterface $currentUser, WebformHelper $webformHelper) { - $this->routeMatch = $routeMatch; - $this->currentUser = $currentUser; - $this->webformHelper = $webformHelper; + public function __construct( + /** + * The route match. + */ + private readonly RouteMatchInterface $routeMatch, + /** + * The current user. + */ + private readonly AccountProxyInterface $currentUser, + /** + * The webform helper. + */ + private readonly WebformHelper $webformHelper + ) + { } /** @@ -81,7 +71,7 @@ public function onRequest(KernelEvent $event): void { $submissionUuid = (string) $content['submission_uuid']; } } - catch (\JsonException $exception) { + catch (\JsonException) { // Invalid JSON body. We cannot get webform id from request body. } } diff --git a/src/EventSubscriber/WebformSubmissionDataEventSubscriber.php b/src/EventSubscriber/WebformSubmissionDataEventSubscriber.php index 291602b..c80a78d 100644 --- a/src/EventSubscriber/WebformSubmissionDataEventSubscriber.php +++ b/src/EventSubscriber/WebformSubmissionDataEventSubscriber.php @@ -19,17 +19,10 @@ class WebformSubmissionDataEventSubscriber implements EventSubscriberInterface { use LoggerAwareTrait; - /** - * Entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - private EntityTypeManagerInterface $entityTypeManager; - /** * Map from entity type to webform element types. */ - private const LINKED_ELEMENT_TYPES = [ + private const array LINKED_ELEMENT_TYPES = [ 'file' => [ 'webform_image_file', 'webform_document_file', @@ -42,8 +35,10 @@ class WebformSubmissionDataEventSubscriber implements EventSubscriberInterface { /** * Constructor. */ - public function __construct(EntityTypeManagerInterface $entityTypeManager, LoggerInterface $logger) { - $this->entityTypeManager = $entityTypeManager; + public function __construct(/** + * Entity type manager. + */ + private EntityTypeManagerInterface $entityTypeManager, LoggerInterface $logger) { $this->setLogger($logger); } diff --git a/src/Plugin/rest/resource/WebformAllFormSubmissions.php b/src/Plugin/rest/resource/WebformAllFormSubmissions.php index 31eb341..d021d16 100644 --- a/src/Plugin/rest/resource/WebformAllFormSubmissions.php +++ b/src/Plugin/rest/resource/WebformAllFormSubmissions.php @@ -24,7 +24,7 @@ class WebformAllFormSubmissions extends ResourceBase { /** * Allowed DateTime query parameters and their operation. */ - private const ALLOWED_DATETIME_QUERY_PARAMS = [ + private const array ALLOWED_DATETIME_QUERY_PARAMS = [ 'starttime' => '>=', 'endtime' => '<=', ]; @@ -34,21 +34,21 @@ class WebformAllFormSubmissions extends ResourceBase { * * @var \Symfony\Component\HttpFoundation\Request */ - private $currentRequest; + protected $currentRequest; /** * The webform helper. * * @var \Drupal\os2forms_rest_api\WebformHelper */ - private $webformHelper; + protected $webformHelper; /** * The database connection. * * @var \Drupal\Core\Database\Connection */ - private $database; + protected $database; /** * {@inheritdoc} @@ -126,7 +126,7 @@ public function get(string $webform_id): ModifiedResourceResponse { $query .= sprintf(' AND created %s %s', $operator, $dateTime->getTimestamp()); $result[$param] = $value; } - catch (\Exception $e) { + catch (\Exception) { $errors = [ 'error' => [ 'message' => $this->t('Invalid :param: :value', [':param' => $param, ':value' => $value]), @@ -158,7 +158,7 @@ public function get(string $webform_id): ModifiedResourceResponse { $submissions ?: [] ); } - catch (\Exception $e) { + catch (\Exception) { $errors = [ 'error' => [ 'message' => $this->t('Could not generate submission URLs'), diff --git a/src/WebformHelper.php b/src/WebformHelper.php index b99305f..6b8fec6 100644 --- a/src/WebformHelper.php +++ b/src/WebformHelper.php @@ -9,7 +9,6 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Url; use Drupal\webform\WebformInterface; -use Drupal\webform\WebformSubmissionInterface; /** * Webform helper for helping with webforms. @@ -17,26 +16,20 @@ class WebformHelper { use StringTranslationTrait; - /** - * The entity type manager. - * - * @var \Drupal\Core\Entity\EntityTypeManagerInterface - */ - private EntityTypeManagerInterface $entityTypeManager; - - /** - * The current user manager. - * - * @var \Drupal\Core\Session\AccountProxyInterface - */ - private AccountProxyInterface $currentUser; - /** * Constructor. */ - public function __construct(EntityTypeManagerInterface $entityTypeManager, AccountProxyInterface $currentUser) { - $this->entityTypeManager = $entityTypeManager; - $this->currentUser = $currentUser; + public function __construct( + /** + * The entity type manager. + */ + private EntityTypeManagerInterface $entityTypeManager, + /** + * The current user manager. + */ + private AccountProxyInterface $currentUser + ) + { } /** @@ -86,26 +79,22 @@ public function webformThirdPartySettingsFormAlter(array &$form, FormStateInterf 'rest.webform_rest_submission.GET', ]; - $requireUuid = static function ($route) { - return in_array( - $route, - [ - 'rest.webform_rest_submission.GET', - 'rest.webform_rest_submission.PATCH', - ], - TRUE - ); - }; + $requireUuid = (static fn($route) => in_array( + $route, + [ + 'rest.webform_rest_submission.GET', + 'rest.webform_rest_submission.PATCH', + ], + TRUE + )); $form['third_party_settings']['os2forms']['os2forms_rest_api']['api_info']['endpoints']['links']['#prefix'] = '
    '; $form['third_party_settings']['os2forms']['os2forms_rest_api']['api_info']['endpoints']['links']['#suffix'] = '
'; foreach ($routes as $route) { - $parameters = []; - - if ('rest.webform_rest_submit.POST' !== $route) { - $parameters['webform_id'] = $webform->id(); - } + $parameters = [ + 'webform_id' => $webform->id(), + ]; $uuidPlaceholder = '{uuid}'; if ($requireUuid($route)) { $parameters['uuid'] = $uuidPlaceholder; @@ -146,11 +135,9 @@ public function webformThirdPartySettingsFormAlter(array &$form, FormStateInterf $form['third_party_settings']['os2forms']['os2forms_rest_api']['api_info']['endpoints_test']['links']['#suffix'] = ''; foreach ($routes as $route) { - $parameters = []; - - if ('rest.webform_rest_submit.POST' !== $route) { - $parameters['webform_id'] = $webform->id(); - } + $parameters = [ + 'webform_id' => $webform->id(), + ]; $uuidPlaceholder = '{uuid}'; if ($requireUuid($route)) { $parameters['uuid'] = $uuidPlaceholder; @@ -193,7 +180,6 @@ public function getWebform(string $webformId, ?string $submissionUuid = NULL): ? return NULL; } - assert($submission instanceof WebformSubmissionInterface); $webform = $submission->getWebform(); if ($webformId !== $webform->id()) { return NULL; @@ -239,7 +225,6 @@ public function hasWebformAccess(WebformInterface $webform, $user): bool { // AccountInterface::id() should return an `int` but actually returns a // `string`. $userId = (int) ($user instanceof AccountInterface ? $user->id() : $user); - assert(is_int($userId)); $allowedUsers = $this->getAllowedUsers($webform);