diff --git a/.ddev/addon-metadata/redis/manifest.yaml b/.ddev/addon-metadata/redis/manifest.yaml new file mode 100644 index 00000000..27fe4ac0 --- /dev/null +++ b/.ddev/addon-metadata/redis/manifest.yaml @@ -0,0 +1,38 @@ +name: redis +repository: ddev/ddev-redis +version: v2.2.0 +install_date: "2026-09-08T18:12:40+02:00" +project_files: + - docker-compose.redis.yaml + - redis/scripts/settings.ddev.redis.php + - redis/scripts/setup-drupal-settings.sh + - redis/scripts/setup-redis-optimized-config.sh + - redis/redis.conf + - redis/advanced.conf + - redis/append.conf + - redis/general.conf + - redis/io.conf + - redis/memory.conf + - redis/network.conf + - redis/security.conf + - redis/snapshots.conf + - commands/host/redis-backend + - commands/redis/redis-cli + - commands/redis/redis-flush +global_files: [] +removal_actions: + - | + #ddev-description:Remove redis settings if applicable + files=( + "${DDEV_APPROOT}/${DDEV_DOCROOT}/sites/default/settings.ddev.redis.php" + "${DDEV_APPROOT}/.ddev/docker-compose.redis_extra.yaml" + ) + for file in "${files[@]}"; do + if [ -f "$file" ]; then + if grep -q '#ddev-generated' "$file"; then + rm -f "$file" + else + echo "Unwilling to remove '$file' because it does not have #ddev-generated in it; you can manually delete it if it is safe to delete." + fi + fi + done diff --git a/.ddev/commands/host/redis-backend b/.ddev/commands/host/redis-backend new file mode 100755 index 00000000..fbcaba55 --- /dev/null +++ b/.ddev/commands/host/redis-backend @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +#ddev-generated + +## Description: Use a different key-value store for Redis +## Usage: redis-backend [optimize] +## Example: ddev redis-backend redis-alpine optimize + +REDIS_DOCKER_IMAGE=${1:-} +REDIS_CONFIG=${2:-} +NAME=$REDIS_DOCKER_IMAGE + +function show_help() { + cat < [optimize] + +Choose from predefined aliases, or provide any Redis-compatible Docker image. +Note that not every Docker image can work right away, and you may need to override +the "command:" in the docker-compose.redis_extra.yaml file + +Available aliases: + redis redis:7 + redis-alpine redis:7-alpine + valkey valkey/valkey:8 + valkey-alpine valkey/valkey:8-alpine + +Custom backend: + You can specify any Docker image, e.g.: + ddev redis-backend redis:6 + +Optional: + optimize Apply additional Redis configuration with resource limits + optimized Same as optimize + +Examples: + ddev redis-backend redis-alpine optimize + ddev redis-backend valkey + ddev redis-backend redis:7.2-alpine +EOF + exit 0 +} + +function optimize_config() { + [[ "$REDIS_CONFIG" != "optimized" && "$REDIS_CONFIG" != "optimize" ]] && return + ddev dotenv set .ddev/.env.redis --redis-optimized=true +} + +function change_hostname() { + [[ "${REDIS_HOSTNAME:-}" == "" ]] && return + ddev dotenv set .ddev/.env.redis --redis-hostname="$REDIS_HOSTNAME" +} + +function cleanup() { + rm -f "$DDEV_APPROOT/.ddev/.env.redis" + rm -rf "$DDEV_APPROOT/.ddev/redis/" + rm -f "$DDEV_APPROOT/.ddev/docker-compose.redis.yaml" "$DDEV_APPROOT/.ddev/docker-compose.redis_extra.yaml" + + redis_volume="ddev-$(ddev status -j | docker run -i --rm ddev/ddev-utilities jq -r '.raw.name')_redis" + if docker volume ls -q | grep -qw "$redis_volume"; then + ddev stop + docker volume rm "$redis_volume" + fi +} + +function check_docker_image() { + echo "Pulling ${REDIS_DOCKER_IMAGE}..." + if ! docker pull "$REDIS_DOCKER_IMAGE"; then + echo >&2 "❌ Unable to pull ${REDIS_DOCKER_IMAGE}" + exit 2 + fi +} + +function use_docker_image() { + [[ "$REDIS_DOCKER_IMAGE" != "redis:7" ]] && ddev dotenv set .ddev/.env.redis --redis-docker-image="$REDIS_DOCKER_IMAGE" + REPO=$(ddev add-on list --installed -j 2>/dev/null | docker run -i --rm ddev/ddev-utilities jq -r '.raw[] | select(.Name=="redis") | .Repository // empty' 2>/dev/null) + ddev add-on get "${REPO:-ddev/ddev-redis}" +} + +case "$REDIS_DOCKER_IMAGE" in + redis) + NAME="Redis 7" + REDIS_DOCKER_IMAGE="redis:7" + ;; + redis-alpine) + NAME="Redis 7 Alpine" + REDIS_DOCKER_IMAGE="redis:7-alpine" + ;; + valkey) + NAME="Valkey 8" + REDIS_DOCKER_IMAGE="valkey/valkey:8" + REDIS_HOSTNAME="valkey" + ;; + valkey-alpine) + NAME="Valkey 8 Alpine" + REDIS_DOCKER_IMAGE="valkey/valkey:8-alpine" + REDIS_HOSTNAME="valkey" + ;; + ""|--help|-h) + show_help + ;; + *) + NAME="$REDIS_DOCKER_IMAGE" + # Allow unknown image, nothing to override + ;; +esac + +check_docker_image +cleanup +optimize_config +change_hostname +use_docker_image + +echo +echo "✅ Redis backend: $REDIS_DOCKER_IMAGE" +if [[ "$REDIS_CONFIG" == "optimized" || "$REDIS_CONFIG" == "optimize" ]]; then + echo "⚙️ Redis config: optimized" +else + echo "⚙️ Redis config: default" +fi + +echo +echo "📝 Commit the '.ddev' directory to version control" + +echo +echo "🔄 Redis config available after 'ddev restart'" diff --git a/.ddev/commands/redis/redis-cli b/.ddev/commands/redis/redis-cli new file mode 100755 index 00000000..2800343e --- /dev/null +++ b/.ddev/commands/redis/redis-cli @@ -0,0 +1,13 @@ +#!/usr/bin/env sh + +#ddev-generated +## Description: Run redis-cli inside the Redis container +## Usage: redis-cli [flags] [args] +## Example: "ddev redis-cli KEYS *" or "ddev redis-cli INFO" or "ddev redis-cli --version" +## Aliases: redis + +if [ -f /etc/redis/conf/security.conf ]; then + redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" -a redis --no-auth-warning $@ +else + redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" $@ +fi diff --git a/.ddev/commands/redis/redis-flush b/.ddev/commands/redis/redis-flush new file mode 100755 index 00000000..db90558a --- /dev/null +++ b/.ddev/commands/redis/redis-flush @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +#ddev-generated +## Description: Flush all cache inside the Redis container +## Usage: redis-flush +## Example: "ddev redis-flush" + +if [ -f /etc/redis/conf/security.conf ]; then + redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" -a redis --no-auth-warning FLUSHALL ASYNC +else + redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" FLUSHALL ASYNC +fi diff --git a/.ddev/docker-compose.redis.yaml b/.ddev/docker-compose.redis.yaml new file mode 100644 index 00000000..e9da4c6e --- /dev/null +++ b/.ddev/docker-compose.redis.yaml @@ -0,0 +1,27 @@ +#ddev-generated +services: + redis: + container_name: ddev-${DDEV_SITENAME}-redis + image: ${REDIS_DOCKER_IMAGE:-redis:7} + hostname: ${REDIS_HOSTNAME:-redis} + # These labels ensure this service is discoverable by ddev. + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: ${DDEV_APPROOT} + restart: "no" + expose: + - 6379 + volumes: + - ".:/mnt/ddev_config" + - "ddev-global-cache:/mnt/ddev-global-cache" + - "./redis:/etc/redis/conf" + - "redis:/data" + command: /etc/redis/conf/redis.conf + x-ddev: + describe-url-port: | + Backend: ${REDIS_DOCKER_IMAGE:-redis:7} + describe-info: | + Pass: + +volumes: + redis: diff --git a/.ddev/redis/redis.conf b/.ddev/redis/redis.conf new file mode 100644 index 00000000..937c4e5d --- /dev/null +++ b/.ddev/redis/redis.conf @@ -0,0 +1,13 @@ +# Redis configuration. +# #ddev-generated +# Example configuration files for reference: +# http://download.redis.io/redis-stable/redis.conf +# http://download.redis.io/redis-stable/sentinel.conf + +maxmemory 2048mb +maxmemory-policy allkeys-lfu + +# to disable Redis persistence, remove ddev-generated from this file, +# and uncomment the two lines below: +#appendonly no +#save "" diff --git a/.gitignore b/.gitignore index 524015d1..87163ec7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,6 @@ public/typo3conf/ext/*/ public/typo3conf/ext/ep_events/Resources/Public/ public/typo3conf/ext/ep_theme/Resources/Public/ public/typo3conf/LocalConfiguration.php -public/typo3conf/AdditionalConfiguration.php public/typo3conf/PackageStates.php public/typo3conf/l10n public/typo3temp diff --git a/deploy.php b/deploy.php index b84ece29..a4405adb 100644 --- a/deploy.php +++ b/deploy.php @@ -25,6 +25,7 @@ add('shared_dirs', [ $rsyncOptions = [ 'exclude' => [ '.ddev', + '.claude', '.DS_Store', '.git', '.github', diff --git a/public/typo3conf/AdditionalConfiguration.php b/public/typo3conf/AdditionalConfiguration.php new file mode 100644 index 00000000..74643dd0 --- /dev/null +++ b/public/typo3conf/AdditionalConfiguration.php @@ -0,0 +1,94 @@ + '/run/redis_eptypo3/redis.sock', + 'port' => 0, +]; + +if (getenv('IS_DDEV_PROJECT') == 'true') { + $redisOptions = [ + 'hostname' => 'redis', + 'port' => 6379, + ]; + + $GLOBALS['TYPO3_CONF_VARS'] = array_replace_recursive( + $GLOBALS['TYPO3_CONF_VARS'], + [ + 'DB' => [ + 'Connections' => [ + 'Default' => [ + 'dbname' => 'db', + 'driver' => 'mysqli', + 'host' => 'db', + 'password' => 'db', + 'port' => '3306', + 'user' => 'db', + ], + ], + ], + // This GFX configuration allows processing by installed ImageMagick 6 + 'GFX' => [ + 'processor' => 'ImageMagick', + 'processor_path' => '/usr/bin/', + 'processor_path_lzw' => '/usr/bin/', + ], + // This mail configuration sends all emails to mailpit + 'MAIL' => [ + 'transport' => 'smtp', + 'transport_smtp_encrypt' => false, + 'transport_smtp_server' => 'localhost:1025', + ], + 'SYS' => [ + 'trustedHostsPattern' => '.*.*', + 'devIPmask' => '*', + 'displayErrors' => 1, + ], + ] + ); +} + +$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_pages'] = [ + 'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class, + 'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class, + 'options' => $redisOptions + ['database' => 0], +]; + +$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_hash'] = [ + 'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class, + 'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class, + 'options' => $redisOptions + ['database' => 1], +]; + +$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_rootline'] = [ + 'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class, + 'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class, + 'options' => $redisOptions + ['database' => 1], +]; + +// suppress php deprecation warnings flooding typo3 logs +$GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'] = + $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'] & ~E_DEPRECATED & ~E_USER_DEPRECATED; +/* +$GLOBALS['TYPO3_CONF_VARS']['BE']['cookieSameSite'] = 'lax'; + +$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['oauth2_client'] = [ + 'providers' => [ + 'myep' => [ + 'label' => 'MyEP', + 'iconIdentifier' => 'ep-logo', + 'scopes' => [ + \Waldhacker\Oauth2Client\Service\Oauth2ProviderManager::SCOPE_BACKEND, + ], + 'options' => [ + 'clientId' => '8df8f314ce17e8b716f86f9c24564746', + 'clientSecret' => '7ff2532abc06f2b48438fc2e6e0278c8fdfb0e2de839889f4d5d17fd4a37cfffcca3bb19166331cc6ced462550611b33f08e9a3a993270d8c786a884c7fe935b', + 'urlAuthorize' => 'https://myep-next-booking.ddev.site/authorize', + 'urlAccessToken' => 'https://myep-next-booking.ddev.site/token', + 'urlResourceOwnerDetails' => 'https://myep-next-booking.ddev.site/api/userinfo', + 'scopes' => ['email', 'id', 'roles', 'profile'], + 'scopeSeparator' => ' ', + ], + ], + ], +]; +*/