diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 000000000..597803b57 --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,60 @@ +# syntax=docker/dockerfile:1 + +FROM pimcore/pimcore:php8.4-v4 AS base +RUN set -eux; \ + apt-get update -y; \ + apt-get install -y --no-install-recommends autoconf make g++ unixodbc-dev cron procps iputils-ping vim supervisor netcat-traditional default-mysql-client; \ + rm -rf /var/lib/apt/lists/*; \ + usermod -u 1000 www-data; \ + groupmod -g 1000 www-data; +# We copy in the composer files and download dependencies, then in a separate set of statements below copy in the full +# source directory and run a full composer install. This will take advantage of Docker-build caching when the composer +# dependencies do not change. +COPY --chown=www-data:www-data /composer.* /var/www/html +COPY /.docker/composer-install-dependencies.sh /composer-install-dependencies.sh +RUN /composer-install-dependencies.sh +COPY /.docker/secrets-to-env-vars.sh /etc/profile.d/secrets-to-env-vars.sh +COPY --chown=www-data:www-data / /var/www/html +RUN --mount=type=secret,id=kernel-secret,uid=1000 \ + # These three secrets are deliberately mounted as env vars rather than files as required by Pimcore + --mount=type=secret,id=pimcore-product-key,env=PIMCORE_PRODUCT_KEY,uid=1000 \ + --mount=type=secret,id=pimcore-instance-identifier,env=PIMCORE_INSTANCE_IDENTIFIER,uid=1000 \ + --mount=type=secret,id=pimcore-encryption-secret,env=PIMCORE_ENCRYPTION_SECRET,uid=1000 \ + set -eux; \ + cd /var/www/html; \ + runuser -u www-data -- php /usr/local/bin/composer install; \ + runuser -u www-data -- /var/www/html/bin/console pimcore:build:classes; \ + runuser -u www-data -- /var/www/html/bin/console cache:warmup + +FROM base AS init +COPY ./.docker/init/install-bundles.sh /install-bundles.sh +COPY /.docker/init/init.sh /init.sh +CMD [ "/init.sh" ] + +FROM base AS php +RUN set -eux; \ + apt-get update -y; \ + apt-get install -y --no-install-recommends nginx wget; \ + rm -rf /var/lib/apt/lists/*; +COPY /.docker/php/php.ini /usr/local/etc/php/conf.d/docker-pimcore-php.ini +COPY /.docker/php/nginx.conf /etc/nginx/sites-available/default +COPY /.docker/php/supervisord.conf /etc/supervisor/supervisord.conf +COPY ./.docker/php/start-php.sh /start-php.sh +CMD [ "/start-php.sh" ] + +FROM base AS supervisord +COPY --from=pimcore/pimcore:php8.4-supervisord-v4 /var/run /var/run +COPY --from=pimcore/pimcore:php8.4-supervisord-v4 /usr/sbin/cron /usr/sbin/cron +COPY --from=pimcore/pimcore:php8.4-supervisord-v4 /etc/supervisor/supervisord.conf /etc/supervisor/supervisord.conf +COPY /.docker/supervisord/supervisord.conf /etc/supervisor/conf.d/pimcore.conf +COPY ./.docker/supervisord/start-supervisord.sh /start-supervisord.sh +CMD [ "/start-supervisord.sh" ] + +FROM base AS php-debug +COPY --from=pimcore/pimcore:php8.4-debug-v4 /usr/local/bin/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN pecl install xdebug; \ + docker-php-ext-enable xdebug; +ENV PHP_IDE_CONFIG=serverName=localhost +COPY /.docker/php-debug/xdebug.conf /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +COPY /.docker/php-debug/start-php-debug.sh /start-php-debug.sh +CMD [ "/start-php-debug.sh" ] diff --git a/.docker/composer-install-dependencies.sh b/.docker/composer-install-dependencies.sh new file mode 100755 index 000000000..d00845c7c --- /dev/null +++ b/.docker/composer-install-dependencies.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +echo Configuring Composer... +mkdir -p /var/www/.cache/composer && chown -R www-data:www-data /var/www/.cache/composer +mkdir -p /var/www/.config/composer && chown -R www-data:www-data /var/www/.config/composer +echo Installing Composer packages... +cd /var/www/html && runuser -u www-data -- php -d memory_limit=-1 -d xdebug.remote_enable=0 /usr/local/bin/composer install --prefer-dist --no-scripts \ No newline at end of file diff --git a/.docker/init/init.local.sh b/.docker/init/init.local.sh new file mode 100755 index 000000000..bcaf51d5b --- /dev/null +++ b/.docker/init/init.local.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +source /etc/profile.d/secrets-to-env-vars.sh + +/composer-install-dependencies.sh + +if [ "$(mysql -h "$DATABASE_HOST" -u "$DATABASE_USER" -p"$DATABASE_PASSWORD" \ + -sse "select count(*) from information_schema.tables where table_schema='pimcore' and table_name='assets';")" -ne 0 ] +then + # Only run cache clear if the database is seeded. If it is not, trying to clear the cache will cause errors. + # init.sh will handle seeding it + runuser -u www-data -- bin/console cache:clear +fi + +/init.sh diff --git a/.docker/init/init.sh b/.docker/init/init.sh new file mode 100755 index 000000000..b37bf381e --- /dev/null +++ b/.docker/init/init.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +set -e + +source /etc/profile.d/secrets-to-env-vars.sh + +if [ "$(mysql -h "$DATABASE_HOST" -u "$DATABASE_USER" -p"$DATABASE_PASSWORD" \ + -sse "select count(*) from information_schema.tables where table_schema='pimcore' and table_name='assets';")" -eq 0 ] \ + && [ "$PIMCORE_INSTALL" = "true" ] +then + echo "Database is empty and PIMCORE_INSTALL is set to true, so calling pimcore-install..." + PIMCORE_INSTALL_ENCRYPTION_SECRET=$PIMCORE_ENCRYPTION_SECRET \ + PIMCORE_INSTALL_INSTANCE_IDENTIFIER=$PIMCORE_INSTANCE_IDENTIFIER \ + PIMCORE_INSTALL_PRODUCT_KEY=$PIMCORE_PRODUCT_KEY \ + runuser -u www-data -- vendor/bin/pimcore-install --skip-database-config --no-interaction +fi + +echo Installing bundles... +/install-bundles.sh + +echo Running migration... +runuser -u www-data -- /var/www/html/bin/console doctrine:migrations:migrate -n + +echo Rebuilding classes... +runuser -u www-data -- /var/www/html/bin/console pimcore:deployment:classes-rebuild -c -d -n --force + +echo Creating folders... +runuser -u www-data -- /var/www/html/bin/console torq:folder-creator + +echo Generating roles... +runuser -u www-data -- /var/www/html/bin/console torq:generate-roles + +echo Clearing Pimcore cache... +runuser -u www-data -- /var/www/html/bin/console pimcore:cache:clear + +echo Generating quantity values... +runuser -u www-data -- /var/www/html/bin/console definition:import:units config/quantityvalues.json --override diff --git a/.docker/init/install-bundles.sh b/.docker/init/install-bundles.sh new file mode 100755 index 000000000..6638293f0 --- /dev/null +++ b/.docker/init/install-bundles.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +BUNDLES=$( + bin/console pimcore:bundle:list --json | \ + php -r ' + $bundles = json_decode(stream_get_contents(STDIN), true); + $toInstall = []; + foreach($bundles as $b) { + if ($b["Enabled"] == true && + $b["Installed"] == false && + $b["Installable"] == true) { + $toInstall[] = $b["Bundle"]; + } + } + echo implode(" ", $toInstall); + ' +) + +if [ -z "${BUNDLES}" ]; then + echo "No bundles to install" +else + for BUNDLE in ${BUNDLES}; do + echo "Installing bundle: ${BUNDLE}" + runuser -u www-data -- /var/www/html/bin/console pimcore:bundle:install "${BUNDLE}" --no-interaction --no-cache-clear + done + + echo "Manually clearing cache..." + runuser -u www-data -- /var/www/html/bin/console cache:clear --no-interaction +fi \ No newline at end of file diff --git a/.docker/messenger.yaml b/.docker/messenger.yaml deleted file mode 100644 index 6895228ac..000000000 --- a/.docker/messenger.yaml +++ /dev/null @@ -1,8 +0,0 @@ -framework: - messenger: - transports: - pimcore_core: 'amqp://rabbitmq:5672/%2f/pimcore_core' - pimcore_maintenance: 'amqp://rabbitmq:5672/%2f/pimcore_maintenance' - pimcore_scheduled_tasks: 'amqp://rabbitmq:5672/%2f/pimcore_scheduled_tasks' - pimcore_image_optimize: 'amqp://rabbitmq:5672/%2f/pimcore_image_optimize' - pimcore_asset_update: 'amqp://rabbitmq:5672/%2f/pimcore_asset_update' diff --git a/.docker/php-debug/nginx-debug.conf b/.docker/php-debug/nginx-debug.conf new file mode 100644 index 000000000..8f3c4fa53 --- /dev/null +++ b/.docker/php-debug/nginx-debug.conf @@ -0,0 +1,184 @@ + +# mime types are already covered in nginx.conf +#include mime.types; + +upstream php-pimcore10 { + server php:9000; +} + +upstream php-pimcore10-debug { + server php-debug:9000; +} + +map $args $static_page_root { + default /var/tmp/pages; + "~*(^|&)pimcore_editmode=true(&|$)" /var/nonexistent; + "~*(^|&)pimcore_preview=true(&|$)" /var/nonexistent; + "~*(^|&)pimcore_version=[^&]+(&|$)" /var/nonexistent; +} + +map $uri $static_page_uri { + default $uri; + "/" /%home; +} + +server { + listen [::]:80 default_server; + listen 80 default_server; + + #server_name pimcore.localhost; + + root /var/www/html/public; + index index.php; + + # Filesize depending on your data + client_max_body_size 100m; + + # It is recommended to seclude logs per virtual host + #access_log /var/log/access.log; + #error_log /var/log/error.log error; + + # Protected Assets + # + ### 1. Option - Restricting access to certain assets completely + # + # location ~ ^/protected/.* { + # return 403; + # } + # location ~ ^/var/.*/protected(.*) { + # return 403; + # } + # + # location ~ ^/cache-buster\-[\d]+/protected(.*) { + # return 403; + # } + # + ### 2. Option - Checking permissions before delivery + # + # rewrite ^(/protected/.*) /index.php$is_args$args last; + # + # rewrite ^(/cache-buster-(?:\d+)/protected(?:.*)) /index.php$is_args$args last; + # + # location ~ ^/var/.*/protected(.*) { + # return 403; + # } + # + # location ~ ^/cache-buster\-[\d]+/protected(.*) { + # return 403; + # } + + # Pimcore Head-Link Cache-Busting + rewrite ^/cache-buster-(?:\d+)/(.*) /$1 last; + + # Stay secure + # + # a) don't allow PHP in folders allowing file uploads + location ~* /var/assets/.*\.php(/|$) { + return 404; + } + + # b) Prevent clients from accessing hidden files (starting with a dot) + # Access to `/.well-known/` is allowed. + # https://www.mnot.net/blog/2010/04/07/well-known + # https://tools.ietf.org/html/rfc5785 + location ~* /\.(?!well-known/) { + deny all; + log_not_found off; + access_log off; + } + + # c) Prevent clients from accessing to backup/config/source files + location ~* (?:\.(?:bak|conf(ig)?|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ { + deny all; + } + + # Some Admin Modules need this: + # Server Info, Opcache + location ~* ^/admin/external { + rewrite .* /index.php$is_args$args last; + } + + # Thumbnails + location ~* .*/(image|video)-thumb__\d+__.* { + try_files /var/tmp/thumbnails$uri /index.php; + expires 2w; + access_log off; + add_header Cache-Control "public"; + } + + # Assets + # Still use a whitelist approach to prevent each and every missing asset to go through the PHP Engine. + location ~* ^(?!/admin|/asset/webdav|/studio/api)(.+?)\.((?:css|js)(?:\.map)?|jpe?g|gif|png|svgz?|eps|exe|gz|json|zip|mp\d|m4a|ogg|ogv|webp|webm|pdf|csv|docx?|xlsx?|pptx?)$ { + try_files /var/assets$uri $uri =404; + expires 2w; + access_log off; + log_not_found off; + add_header Cache-Control "public"; + } + + location / { + error_page 404 /meta/404; + try_files $static_page_root$static_page_uri.html $uri /index.php$is_args$args; + } + + # Use this location when the installer has to be run + # location ~ /(index|install)\.php(/|$) { + # + # Use this after initial install is done: + location ~ ^/index\.php(/|$) { + send_timeout 1800; + fastcgi_read_timeout 1800; + # regex to split $uri to $fastcgi_script_name and $fastcgi_path_info + fastcgi_split_path_info ^(.+\.php)(/.+)$; + # Check that the PHP script exists before passing it + #try_files $fastcgi_script_name =404; + # include fastcgi.conf if needed + include fastcgi_params; + # Bypass the fact that try_files resets $fastcgi_path_info + # see: http://trac.nginx.org/nginx/ticket/321 + set $path_info $fastcgi_path_info; + fastcgi_param PATH_INFO $path_info; + + # Activate these, if using Symlinks and opcache + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + + # Mitigate https://httpoxy.org/ vulnerabilities + fastcgi_param HTTP_PROXY ""; + + # If Xdebug session is requested, pass it to the Xdebug enabled container + if ($http_cookie ~* "XDEBUG_SESSION") { + fastcgi_pass php-pimcore10-debug; + } + + fastcgi_pass php-pimcore10; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/index.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + # PHP-FPM Status and Ping + location /fpm- { + access_log off; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + location /fpm-status { + allow 127.0.0.1; + # add additional IP's or Ranges + deny all; + fastcgi_pass php-pimcore10; + } + location /fpm-ping { + fastcgi_pass php-pimcore10; + } + } + # nginx Status + # see: https://nginx.org/en/docs/http/ngx_http_stub_status_module.html + location /nginx-status { + allow 127.0.0.1; + deny all; + access_log off; + stub_status; + } +} diff --git a/.docker/php-debug/start-php-debug.sh b/.docker/php-debug/start-php-debug.sh new file mode 100755 index 000000000..ae6fc0081 --- /dev/null +++ b/.docker/php-debug/start-php-debug.sh @@ -0,0 +1,3 @@ +#!/bin/bash +source /etc/profile.d/secrets-to-env-vars.sh +exec "/usr/local/bin/entrypoint.sh" php-fpm \ No newline at end of file diff --git a/.docker/php-debug/xdebug.conf b/.docker/php-debug/xdebug.conf new file mode 100644 index 000000000..94ba158c5 --- /dev/null +++ b/.docker/php-debug/xdebug.conf @@ -0,0 +1,13 @@ +zend_extension=xdebug + +[xdebug] +xdebug.mode=debug,develop,profile +xdebug.output_dir = /var/www/html/var/log/xdebug.log +xdebug.client_host=host.docker.internal +xdebug.client_port=9003 +xdebug.cli_color=1 +xdebug.start_with_request=trigger +xdebug.log_level=3 +xdebug.log=/var/www/html/var/log/xdebug.log +xdebug.discover_client_host=1 +xdebug.max_nesting_level=256 diff --git a/.docker/nginx.conf b/.docker/php/nginx.conf similarity index 96% rename from .docker/nginx.conf rename to .docker/php/nginx.conf index 98cbb8b3e..4c7598956 100644 --- a/.docker/nginx.conf +++ b/.docker/php/nginx.conf @@ -2,10 +2,6 @@ # mime types are already covered in nginx.conf #include mime.types; -upstream php-pimcore10 { - server php:9000; -} - map $args $static_page_root { default /var/tmp/pages; "~*(^|&)pimcore_editmode=true(&|$)" /var/nonexistent; @@ -53,6 +49,8 @@ server { # # rewrite ^(/protected/.*) /index.php$is_args$args last; # + # rewrite ^(/cache-buster-(?:\d+)/protected(?:.*)) /index.php$is_args$args last; + # # location ~ ^/var/.*/protected(.*) { # return 403; # } @@ -140,7 +138,7 @@ server { # Mitigate https://httpoxy.org/ vulnerabilities fastcgi_param HTTP_PROXY ""; - fastcgi_pass php-pimcore10; + fastcgi_pass 127.0.0.1:9000; # Prevents URIs that include the front controller. This will 404: # http://domain.tld/index.php/some-path # Remove the internal directive to allow URIs like this @@ -156,10 +154,10 @@ server { allow 127.0.0.1; # add additional IP's or Ranges deny all; - fastcgi_pass php-pimcore10; + fastcgi_pass 127.0.0.1:9000; } location /fpm-ping { - fastcgi_pass php-pimcore10; + fastcgi_pass 127.0.0.1:9000; } } # nginx Status diff --git a/.docker/php/php.ini b/.docker/php/php.ini new file mode 100644 index 000000000..5bc3e1e97 --- /dev/null +++ b/.docker/php/php.ini @@ -0,0 +1,2 @@ +session.save_handler=redis +session.save_path="tcp://${REDIS_HOST}:6379?database=${REDIS_SESSION_DB}" \ No newline at end of file diff --git a/.docker/php/start-php.sh b/.docker/php/start-php.sh new file mode 100755 index 000000000..9e63247bb --- /dev/null +++ b/.docker/php/start-php.sh @@ -0,0 +1,3 @@ +#!/bin/bash +source /etc/profile.d/secrets-to-env-vars.sh +exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf \ No newline at end of file diff --git a/.docker/php/supervisord.conf b/.docker/php/supervisord.conf new file mode 100644 index 000000000..a2de158c4 --- /dev/null +++ b/.docker/php/supervisord.conf @@ -0,0 +1,25 @@ +[supervisord] +nodaemon=true +logfile=/dev/null +logfile_maxbytes=0 +user=root + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +autostart=true +autorestart=true +startretries=5 +numprocs=1 +startsecs=0 +process_name=%(program_name)s_%(process_num)02d +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:php-fpm] +command=php-fpm +autostart=true +autorestart=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true \ No newline at end of file diff --git a/.docker/secrets-to-env-vars.sh b/.docker/secrets-to-env-vars.sh new file mode 100755 index 000000000..9829ad47b --- /dev/null +++ b/.docker/secrets-to-env-vars.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Certain secrets cause problems with Pimcore when used as files - this script converts them to env vars, and then containers can source this script at startup. +# IMPORTANT: Only use this for secrets that must be converted to env vars. For all other secrets, continue to use them as files. +export PIMCORE_ENCRYPTION_SECRET=$(cat /run/secrets/pimcore-encryption-secret 2>/dev/null || echo "") +export PIMCORE_INSTANCE_IDENTIFIER=$(cat /run/secrets/pimcore-instance-identifier 2>/dev/null || echo "") +export PIMCORE_PRODUCT_KEY=$(cat /run/secrets/pimcore-product-key 2>/dev/null || echo "") \ No newline at end of file diff --git a/.docker/supervisord.conf b/.docker/supervisord.conf deleted file mode 100644 index 4edb00234..000000000 --- a/.docker/supervisord.conf +++ /dev/null @@ -1,33 +0,0 @@ - -# Important Notice: this configuration is not optimized for production use! - -[program:messenger-consume] -command=php /var/www/html/bin/console messenger:consume pimcore_core pimcore_maintenance pimcore_scheduled_tasks pimcore_image_optimize --memory-limit=250M --time-limit=3600 -numprocs=1 -startsecs=0 -autostart=true -autorestart=true -process_name=%(program_name)s_%(process_num)02d -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -redirect_stderr=true - -[program:consume-asset-update] -command=php /var/www/html/bin/console messenger:consume pimcore_asset_update --memory-limit=250M --time-limit=3600 -numprocs=1 -startsecs=0 -autostart=true -autorestart=true -process_name=%(program_name)s_%(process_num)02d -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -redirect_stderr=true - - -[program:maintenance] -command=bash -c 'sleep 3600 && exec php /var/www/html/bin/console pimcore:maintenance' -autostart=true -autorestart=true -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -redirect_stderr=true diff --git a/.docker/supervisord/start-supervisord.sh b/.docker/supervisord/start-supervisord.sh new file mode 100755 index 000000000..1b7ff17da --- /dev/null +++ b/.docker/supervisord/start-supervisord.sh @@ -0,0 +1,3 @@ +#!/bin/bash +source /etc/profile.d/secrets-to-env-vars.sh +exec /usr/bin/supervisord -c /etc/supervisor/conf.d/pimcore.conf \ No newline at end of file diff --git a/.docker/supervisord/supervisord.conf b/.docker/supervisord/supervisord.conf new file mode 100644 index 000000000..dfb2b65af --- /dev/null +++ b/.docker/supervisord/supervisord.conf @@ -0,0 +1,62 @@ +[supervisord] +nodaemon=true +logfile=/dev/null +logfile_maxbytes=0 +user=root + +[program:messenger-consume-search-backend] +user=www-data +command=php /var/www/html/bin/console messenger:consume pimcore_search_backend_message --memory-limit=250M --time-limit=3600 +numprocs=1 # Increase if queue is getting backed up +startsecs=0 +autostart=true +autorestart=true +process_name=%(program_name)s_%(process_num)02d +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:messenger-consume-maintenance] +user=www-data +command=php /var/www/html/bin/console messenger:consume pimcore_maintenance --memory-limit=250M --time-limit=3600 +numprocs=1 +startsecs=0 +autostart=true +autorestart=true +process_name=%(program_name)s_%(process_num)02d +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:messenger-consume-others] +user=www-data +command=php /var/www/html/bin/console messenger:consume pimcore_core pimcore_scheduled_tasks pimcore_image_optimize pimcore_asset_update --memory-limit=250M --time-limit=3600 +numprocs=1 +startsecs=0 +autostart=true +autorestart=true +process_name=%(program_name)s_%(process_num)02d +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:maintenance] +user=www-data +command=bash -c 'php /var/www/html/bin/console pimcore:maintenance && sleep 3600' +autostart=true +autorestart=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true + +[program:messenger-consume-data-import] +user=www-data +command=php /var/www/html/bin/console messenger:consume pimcore_data_import --memory-limit=128M --time-limit=360 --limit=128 +numprocs=1 # To increase worker count for parallel processes, update the following in the config.yaml: pimcore_data_importer.messenger_queue_processing.worker_count_parallel +startsecs=0 +autostart=true +autorestart=true +process_name=%(program_name)s_%(process_num)02d +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +redirect_stderr=true diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..457590c59 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,23 @@ +.github +cache +config/local/*.yaml +public/var +public/bundles +var/application-logger +var/assets +var/cache +var/email +var/installer +var/log +var/versions +vendor +.editorconfig +.gitattributes +.git +docker-compose.yaml +gpl-3.0.txt +README.md +SECURITY.md +supervisord.log +supervisord.pid +.secrets diff --git a/.env b/.env index cfb0cde15..8965e9a04 100644 --- a/.env +++ b/.env @@ -21,3 +21,38 @@ PIMCORE_DEV_MODE=false #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 #TRUSTED_HOSTS='^(localhost|example\.com)$' ###< symfony/framework-bundle ### + +# TODO added this to get rid of deprecation warnings when running bin/console commands, but is it correct? +SYMFONY_DOTENV_VARS=APP_ENV,APP_DEBUG + +APP_NAME=torq-pimcore-skeleton +WEB_PORT_EXTERNAL=8400 +DATABASE_HOST=db +DATABASE_PORT=3306 +DATABASE_PORT_EXTERNAL=3400 +DATABASE_NAME=pimcore +DATABASE_USER=pimcore +DATABASE_PASSWORD=pimcore +DATABASE_SERVER_VERSION=10.11.7-MariaDB-1:10.11.7+maria~ubu2204 +SMTP_PORT_EXTERNAL=5400 +SMTP_DOMAIN=${APP_NAME}-smtp +PIMCORE_INSTALL=true +PIMCORE_INSTALL_MYSQL_HOST_SOCKET=${DATABASE_HOST} +PIMCORE_INSTALL_MYSQL_PORT=${DATABASE_PORT} +PIMCORE_INSTALL_MYSQL_USERNAME=${DATABASE_USER} +PIMCORE_INSTALL_MYSQL_PASSWORD=${DATABASE_PASSWORD} +PIMCORE_INSTALL_MYSQL_DATABASE=${DATABASE_NAME} +PIMCORE_INSTALL_ADMIN_USERNAME=admin +PIMCORE_INSTALL_ADMIN_PASSWORD=pimcore +MYSQL_ROOT_PASSWORD=ROOT +MYSQL_DATABASE=${DATABASE_NAME} +MYSQL_USER=${DATABASE_USER} +MYSQL_PASSWORD=${DATABASE_PASSWORD} +MYSQL_PORT=${DATABASE_PORT} +REDIS_HOST=redis +REDIS_DB=12 +REDIS_SESSION_DB=14 +DEFAULT_DOMAIN_NAME=http://localhost/ + + + diff --git a/.github/ISSUE_TEMPLATE/Bug-Report.yml b/.github/ISSUE_TEMPLATE/Bug-Report.yml deleted file mode 100644 index 109825463..000000000 --- a/.github/ISSUE_TEMPLATE/Bug-Report.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Bug Report -description: File a bug report -title: "[Bug]: " -labels: [Bug] -body: - - type: markdown - attributes: - value: | - ## Important notice - As an open core project we love to work together with our community to improve and develop our products. - It's also important for us to make clear that **we're not working for you or your company**, - but we enjoy to work together to solve existing bugs. - So we would love to see PRs with bugfixes, discuss them and we are happy to merge them when they are ready. - For details see also our [contributing guidelines](https://github.com/pimcore/pimcore/blob/10.x/CONTRIBUTING.md). - - Bug reports that do not meet the conditions listed below will be closed/deleted without comment. - - - Bug was verified on the latest supported version. - - This is not a security issue -> see [our security policy](https://github.com/pimcore/pimcore/security/policy) instead. - - You are not able to provide a pull request that fixes the issue. - - There's no existing ticket for the same issue. - - - type: textarea - attributes: - label: Expected behavior - validations: - required: true - - type: textarea - attributes: - label: Actual behavior - validations: - required: true - - type: textarea - attributes: - label: Steps to reproduce - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/Feature-Request.yml b/.github/ISSUE_TEMPLATE/Feature-Request.yml deleted file mode 100644 index bb8e2047a..000000000 --- a/.github/ISSUE_TEMPLATE/Feature-Request.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Feature Request -description: Request or propose a new feature -title: "[Feature]: " -labels: ["New Feature"] -body: - - type: markdown - attributes: - value: | - ## Important notice - As an open core project we love to work together with our community to improve and develop our products. - It's also important for us to make clear that **we're not working for you or your company**, - but we enjoy to work together to improve or add new features to the product. - So we are always ready to discuss features and improvements with our community. - Especially for bigger topics, please [start a discussion](https://github.com/pimcore/pimcore/discussions) first to aviod unnecessary efforts. - - As soon as a topic is more specific, feel free to create issues for it or even better provide a corresponding PR as we love to - review and merge contributions. - - Feature requests that do not meet the conditions listed below will be closed/deleted without comment. - - There's no existing ticket for the same topic - - This is already a specific ready-to-work-on feature request - - - type: textarea - attributes: - label: Feature description - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/Improvement.yml b/.github/ISSUE_TEMPLATE/Improvement.yml deleted file mode 100644 index 7a771af80..000000000 --- a/.github/ISSUE_TEMPLATE/Improvement.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Improvement -description: Request or propose an improvement -title: "[Improvement]: " -labels: ["Improvement"] -body: - - type: markdown - attributes: - value: | - ## Important notice - As an open core project we love to work together with our community to improve and develop our products. - It's also important for us to make clear that **we're not working for you or your company**, - but we enjoy to work together to improve or add new features to the product. - So we are always ready to discuss features and improvements with our community. - Especially for bigger topics, please [start a discussion](https://github.com/pimcore/pimcore/discussions) first to aviod unnecessary efforts. - - As soon as a topic is more specific, feel free to create issues for it or even better provide a corresponding PR as we love to - review and merge contributions. - - Feature requests that do not meet the conditions listed below will be closed/deleted without comment. - - There's no existing ticket for the same topic - - This is already a specific ready-to-work-on feature request - - - type: textarea - attributes: - label: Improvement description - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 9af4f9ce0..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: We are hiring! - url: https://pimcore.com/en/careers?utm_source=github&utm_medium=issue-template-skeleton&utm_campaign=careers - about: Enjoy working with Pimcore? Join us on our mission! - - name: Community Support - url: https://github.com/pimcore/pimcore/discussions - about: Please ask and answer questions here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..e0dc08c12 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: CI + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ci__${{ github.ref }} + cancel-in-progress: true + +jobs: + ci: + name: Build Docker images + uses: TorqIT/pimcore-github-actions-workflows/.github/workflows/ci-docker.yml@v7 + permissions: + contents: read + actions: read + with: + RUN_UNIT_TESTS: true + secrets: + BUILD_TIME_SECRETS: > + { + "pimcore-product-key": "${{ secrets.PIMCORE_PRODUCT_KEY }}", + "pimcore-instance-identifier": "${{ secrets.PIMCORE_INSTANCE_IDENTIFIER }}", + "pimcore-encryption-secret": "${{ secrets.PIMCORE_ENCRYPTION_SECRET }}" + } diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml deleted file mode 100644 index 72f832234..000000000 --- a/.github/workflows/cla.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: CLA check -on: - issue_comment: - types: [created] - pull_request_target: - types: [opened, closed, synchronize] -jobs: - cla-workflow: - uses: pimcore/workflows-collection-public/.github/workflows/reusable-cla-check.yaml@v1.3.0 - if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - secrets: - CLA_ACTION_ACCESS_TOKEN: ${{ secrets.CLA_ACTION_ACCESS_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/new-php-cs-fixer.yaml b/.github/workflows/new-php-cs-fixer.yaml deleted file mode 100644 index 91256e7c5..000000000 --- a/.github/workflows/new-php-cs-fixer.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: "PHP-CS-Fixer" - -on: - workflow_dispatch: - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "*_actions" - - "feature-*" - -permissions: - contents: write - -jobs: - php-style: - uses: pimcore/workflows-collection-public/.github/workflows/reusable-php-cs-fixer.yaml@fix-failed-workflow - with: - head_ref: ${{ github.head_ref || github.ref_name }} - repository: ${{ github.repository }} - config_file: ".php-cs-fixer.dist.php" - secrets: - PHP_CS_FIXER_GITHUB_TOKEN: ${{ secrets.PHP_CS_FIXER_GITHUB_TOKEN }} diff --git a/.github/workflows/php-cs-fixer.yaml.bak b/.github/workflows/php-cs-fixer.yaml.bak deleted file mode 100644 index 6d19d4f94..000000000 --- a/.github/workflows/php-cs-fixer.yaml.bak +++ /dev/null @@ -1,35 +0,0 @@ -name: "PHP-CS-Fixer" - -on: - pull_request_target: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "feature-*" - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "*_actions" - - "feature-*" - -permissions: - contents: read - -jobs: - php-cs-fixer: - permissions: - contents: write # for stefanzweifel/git-auto-commit-action to push code in repo - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga:latest - - - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply php-cs-fixer changes diff --git a/.github/workflows/pimcore-skeleton.yml b/.github/workflows/pimcore-skeleton.yml deleted file mode 100644 index c00a615ba..000000000 --- a/.github/workflows/pimcore-skeleton.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Test Pimcore Skeleton - -on: - pull_request: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - push: - branches: - - "[0-9]+.[0-9]+" - - "[0-9]+.x" - - "*_actions" - -jobs: - test-pimcore-skeleton: - if: github.repository == 'pimcore/skeleton' - runs-on: ubuntu-latest - steps: - # Check out the repo in a sub-dir to see if it can serve as - # teplate for `composer create-project` - # See: https://github.com/actions/checkout#usage - - uses: actions/checkout@v2 - with: - path: 'skeleton' - - - name: Pull latest pimcore image - run: | - # Echo commands and terminate on first error - set -ex - - # Pull latest build of pimcore's image - docker pull docker.io/pimcore/pimcore:php8.3-latest - - - name: Create project from skeleton in latest pimcore environment - run: | - # Echo commands and terminate on first error - set -ex - - # Try creating a new project with composer using contents of this repo as the package. - # We execute composer within docker container to suttisfy platform requirements. - # The value of ยด"url":` must match checkout path in the first step. - # - # See: https://getcomposer.org/doc/03-cli.md#create-project - # See: https://getcomposer.org/doc/05-repositories.md#path - docker run \ - --volume=${{ github.workspace }}/:/test/ \ - --workdir=/test/ \ - --user=$(id -u):$(id -g) \ - docker.io/pimcore/pimcore:php8.3-latest \ - composer create-project \ - pimcore/skeleton:@dev \ - --repository='{"type": "path", "url": "./skeleton"}' \ - sample-project - - - name: Smoke-test compose file - run: | - # Echo commands and terminate on first error - set -ex - - # Check (lint) the compose file - docker compose version - cd sample-project/ - docker compose config -q - - - name: Test pimcore installation - env: - PIMCORE_INSTANCE_IDENTIFIER: ${{ secrets.PIMCORE_CI_INSTANCE_IDENTIFIER }} - PIMCORE_ENCRYPTION_SECRET: ${{ secrets.PIMCORE_CI_ENCRYPTION_SECRET }} - PIMCORE_PRODUCT_KEY: ${{ secrets.PIMCORE_CI_PRODUCT_KEY }} - run: | - # Echo commands and terminate on first error - set -ex - - cd sample-project/ - - # Set up docker-compose.yaml to use current user's uid:gid, just like README.md suggests. - sed -i "s|#user: '1000:1000'|user: '$(id -u):$(id -g)'|g" docker-compose.yaml - - # Start containers - docker compose pull --quiet - docker compose up -d - - # Run pimcore installation. - docker compose exec -T \ - -e PIMCORE_INSTALL_ADMIN_USERNAME=pimcore \ - -e PIMCORE_INSTALL_ADMIN_PASSWORD=pimcore \ - -e PIMCORE_INSTALL_ENCRYPTION_SECRET=${PIMCORE_ENCRYPTION_SECRET} \ - -e PIMCORE_INSTALL_INSTANCE_IDENTIFIER=${PIMCORE_INSTANCE_IDENTIFIER} \ - -e PIMCORE_INSTALL_PRODUCT_KEY=${PIMCORE_PRODUCT_KEY} \ - -- \ - php vendor/bin/pimcore-install -n - - - name: Run codeception tests - env: - PIMCORE_INSTANCE_IDENTIFIER: ${{ secrets.PIMCORE_CI_INSTANCE_IDENTIFIER }} - PIMCORE_ENCRYPTION_SECRET: ${{ secrets.PIMCORE_CI_ENCRYPTION_SECRET }} - PIMCORE_PRODUCT_KEY: ${{ secrets.PIMCORE_CI_PRODUCT_KEY }} - run: | - # Echo commands and terminate on first error - set -ex - - cd sample-project/ - - # Set up and execute codeception tests, just like README.md suggests. - docker compose run --user=root --rm test-php chown -R $(id -u):$(id -g) var/ public/var/ - docker compose run --rm -T \ - -e PIMCORE_INSTALL_ADMIN_USERNAME=pimcore \ - -e PIMCORE_INSTALL_ADMIN_PASSWORD=pimcore \ - -e PIMCORE_INSTALL_ENCRYPTION_SECRET=${PIMCORE_ENCRYPTION_SECRET} \ - -e PIMCORE_INSTALL_INSTANCE_IDENTIFIER=${PIMCORE_INSTANCE_IDENTIFIER} \ - -e PIMCORE_INSTALL_PRODUCT_KEY=${PIMCORE_PRODUCT_KEY} \ - test-php vendor/bin/pimcore-install -n - docker compose run --rm -T test-php vendor/bin/codecept run -vv diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index 553c3b572..000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Handle stale issues - -on: - workflow_dispatch: - schedule: - - cron: '37 7 * * *' - -jobs: - call-stale-workflow: - uses: pimcore/workflows-collection-public/.github/workflows/stale.yml@v1.1.0 diff --git a/.github/workflows/sync-changes-scheduled.yaml b/.github/workflows/sync-changes-scheduled.yaml deleted file mode 100644 index 002ac9320..000000000 --- a/.github/workflows/sync-changes-scheduled.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: Sync changes scheduled from skeleton to paas-skeleton -on: - workflow_dispatch: - schedule: - - cron: '30 21 * * *' - -jobs: - sync-branches: - uses: pimcore/workflows-collection-public/.github/workflows/reusable-sync-changes.yaml@main - if: github.repository == 'pimcore/skeleton' - strategy: - fail-fast: false - matrix: - ref: [{'base': '2025.x', 'destination': '2025.x'}] - with: - base_ref: ${{ matrix.ref.base }} - ref_name: ${{ matrix.ref.destination }} - target_repo: 'paas-skeleton' - auto_merge: true - secrets: - SYNC_TOKEN: ${{ secrets.SYNC_TOKEN }} - GIT_NAME: ${{ secrets.GIT_NAME }} - GIT_EMAIL: ${{ secrets.GIT_EMAIL }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8e92a919a..2e5503b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,9 +12,10 @@ /.env.local /.env.local.php /.env.*.local -!/config/local -/config/local/* -!config/local/.gitkeep + +# Difference from pimcore/skeleton - we allow committing of files in the config/local directory so that developer's +# can share them, but use .dockerignore to ensure they are not built into the Docker images. When developers run +# the Docker Compose locally, they can then simply mount the directory into the running containers. /var/* !/var/.gitkeep @@ -39,6 +40,7 @@ # composer /vendor/ +/cache/ # PhpStorm / IDEA .idea @@ -47,3 +49,15 @@ nbproject # temp .temp + +supervisord.pid +supervisord.log +.htaccess + +# .secrets +/.secrets/* +!/.secrets/.gitkeep + +# Pimcore installation files +/config/local/product_registration.yaml +/var/config/needs-install.lock \ No newline at end of file diff --git a/.secrets/.gitkeep b/.secrets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..f9896fad2 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + "recommendations": [ + "ms-vscode-remote.remote-wsl", + "ms-azuretools.vscode-docker", + "xdebug.php-debug", + "bmewburn.vscode-intelephense-client", + "ethansk.restore-terminals", + "ms-azuretools.vscode-bicep", + "esbenp.prettier-vscode", + "editorconfig.editorconfig" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..03a80bd2c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,34 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/html": "${workspaceRoot}" + }, + "xdebugSettings": { + "max_children": 128 + }, + "hostname": "0.0.0.0" + }, + { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 0, + "runtimeArgs": ["-dxdebug.start_with_request=yes"], + "env": { + "XDEBUG_MODE": "debug,develop", + "XDEBUG_CONFIG": "client_port=${port}" + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..e8b676aaa --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "[php]": { + "editor.defaultFormatter": "bmewburn.vscode-intelephense-client" + }, + "intelephense.format.braces": "per" +} diff --git a/README.md b/README.md index 15c172f3c..e68119635 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,40 @@ -# Pimcore Project Skeleton +# Pimcore Project Skeleton (Torq IT fork) -This skeleton should be used by experienced Pimcore developers for starting a new project from the ground up. -If you are new to Pimcore, it's better to start with our demo package, listed below ๐Ÿ˜‰ +Forked from https://github.com/pimcore/skeleton. -## Getting started -```bash -COMPOSER_MEMORY_LIMIT=-1 composer create-project pimcore/skeleton my-project -cd ./my-project -./vendor/bin/pimcore-install -``` +## Setup -- Point your virtual host to `my-project/public` -- [Only for Apache] Create `my-project/public/.htaccess` according to https://pimcore.com/docs/platform/Pimcore/Installation_and_Upgrade/System_Setup_and_Hosting/Apache_Configuration/ -- Open https://your-host/admin in your browser -- Done! ๐Ÿ˜Ž +### Prerequisites: -## Docker +- A Linux based system (or Windows Subsystem for Linux (WSL) if you are on Windows - see https://learn.microsoft.com/en-us/windows/wsl/install for more information) +- Docker Desktop (https://www.docker.com/products/docker-desktop/) -You can also use Docker to set up a new Pimcore Installation. -You don't need to have a PHP environment with composer installed. +### Setup instructions -### Prerequisites +1. Clone the repository +1. Update the `origin` remote to point to your client-specific repository: `git remote set-url origin ` +1. Update the name of your main branch, e.g. `git branch -m main` +1. Update the `name` property in `composer.json` to match your project's name +1. Update the `.env` property `APP_NAME` to match your project's name +1. Update the `.env.` properties ending in `_EXTERNAL` with unused port values (i.e. those that don't conflict with other apps you may be running) +1. Under the `.secrets` directory: + 1. Create a file called `kernel-secret` and add a random 32-character string to it. + 1. Create a file called `pimcore-product-key` and add your Pimcore product key to it. + 1. Create a file called `pimcore-instance-identifier` and add your Pimcore instance ID to it. + 1. Create a file called `pimcore-encryption-secret` and add an encryption secret to it generated using https://github.com/defuse/php-encryption. + 1. Do NOT commit any of the files in this directory to your repository (they should already be gitignored). +1. Run `docker compose up -d` to build the Docker images and run the containers +1. By default, go to `localhost:8400` in your browser to access the Pimcore admin (port is controlled by the `WEB_EXTERNAL_PORT` environment variable). Use username `admin` and password `pimcore` to log in. -* Your user must be allowed to run docker commands (directly or via sudo). -* You must have docker compose installed. -* Your user must be allowed to change file permissions (directly or via sudo). +## Getting updates -### Follow these steps -1. Initialize the skeleton project using the `pimcore/pimcore` image -``docker run -u `id -u`:`id -g` --rm -v `pwd`:/var/www/html pimcore/pimcore:php8.3-latest composer create-project pimcore/skeleton my-project`` +We recommend forking this repository and using it as an upstream remote in order to get the latest updates and improvements. To do that, run the following commands: -2. Go to your new project -`cd my-project/` +1. If using SSH for Git, run `git remote add upstream git@github.com:TorqIT/pimcore-skeleton.git`; otherwise, run `git remote add upstream https://github.com/TorqIT/pimcore-skeleton.git` +1. To fetch and merge updates from the skeleton, run `git fetch upstream`, then `git merge upstream/2025.x`. -3. Part of the new project is a docker compose file - * Run `sed -i "s|#user: '1000:1000'|user: '$(id -u):$(id -g)'|g" docker-compose.yaml` to set the correct user id and group id. - * Start the needed services with `docker compose up -d` +## Contributing to the skeleton -4. Install pimcore and initialize the DB - `docker compose exec php vendor/bin/pimcore-install` - * When asked for admin user and password: Choose freely - * This can take a while, up to 20 minutes - * If you select to install the SimpleBackendSearchBundle please make sure to add the `pimcore_search_backend_message` to your `.docker/supervisord.conf` file inside value for 'command' like `pimcore_maintenance` already is. - -5. Run codeception tests: - * `docker compose run --user=root --rm test-php chown -R $(id -u):$(id -g) var/ public/var/` - * `docker compose run --rm test-php vendor/bin/pimcore-install -n` - * `docker compose run --rm test-php vendor/bin/codecept run -vv` - -6. :heavy_check_mark: DONE - You can now visit your pimcore instance: - * The frontend: - * The admin interface, using the credentials you have chosen above: - - -## Pimcore Platform Version -By default, Pimcore Platform Version is added as a dependency which ensures installation of compatible and in combination -with each other tested versions of additional Pimcore modules. More information about the Platform Version can be found in the -[Platform Version docs](https://github.com/pimcore/platform-version). - -It might be necessary to update a specific Pimcore module to a version that is not included in the Platform Version. -In that case, you need to remove the `platform-version` dependency from your `composer.json` and update the module to -the desired version. -Be aware that this might lead to a theoretically compatible but untested combination of Pimcore modules. - -## Other demo/skeleton packages -- [Pimcore Basic Demo](https://github.com/pimcore/demo) +1. Clone the repository +1. Get the secrets from your password manager (should be named "Pimcore skeleton secrets"), download the ZIP, extract and add the contents to your local repository's `.secrets` folder +1. Create a branch for your work and open a Pull Request diff --git a/composer.json b/composer.json index 66f445a5f..78fe4bb1d 100644 --- a/composer.json +++ b/composer.json @@ -14,13 +14,21 @@ "minimum-stability": "dev", "require": { "php": "~8.3.0 || ~8.4.0", - "pimcore/pimcore": "^12.3", - "pimcore/platform-version": "2025.x-dev", + "pimcore/pimcore": "*", + "pimcore/platform-version": "2025.4", "pimcore/admin-ui-classic-bundle": "*", "pimcore/quill-bundle": "*", + "pimcore/perspective-editor": "*", + "pimcore/data-hub": "*", + "pimcore/data-importer": "*", + "symfony/dotenv": "^6.4.12 || ^7.2", + "symfony/runtime": "^6.4.12 || ^7.3", "symfony/amqp-messenger": "^6.2 || ^7.2", - "symfony/dotenv": "^6.2 || ^7.2", - "symfony/runtime": "^6.2 || ^7.3" + "torqit/pimcore-folder-creator-bundle": ">=4.0.1 <5.0", + "torqit/pimcore-role-creator-bundle": "^5.0", + "coreshop/messenger-bundle": "^5.0", + "torqit/pimcore-object-layout-grid-bundle": ">=2.0.1 <3.0", + "basilicom/pimcore-path-formatter-bundle": "^3.0" }, "require-dev": { "codeception/codeception": "^5.0.3", diff --git a/config/config.yaml b/config/config.yaml index 7b65fba1d..6483db697 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,8 +1,70 @@ imports: - { resource: 'local/' } + - { resource: 'database.yaml' } +pimcore_data_hub: + config_location: + data_hub: + write_target: + type: "settings-store" + +pimcore_data_importer: + messenger_queue_processing: + activated: true + worker_count_lifetime: 60 + worker_count_parallel: 4 # Increase this to add more parallel workers + worker_item_count: 50 pimcore: + product_registration: + product_key: '%env(PIMCORE_PRODUCT_KEY)%' + instance_identifier: '%env(PIMCORE_INSTANCE_IDENTIFIER)%' + encryption: + secret: '%env(PIMCORE_ENCRYPTION_SECRET)%' + # config_location: + # image_thumbnails: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/image-thumbnails' + # video_thumbnails: + # write_target: + # type: 'disabled' + # document_types: + # write_target: + # type: 'disabled' + # predefined_properties: + # write_target: + # type: 'settings-store' + # predefined_asset_metadata: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/predefined_asset_metadata' + # perspectives: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/perspectives' + # custom_views: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/custom_views' + # object_custom_layouts: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/object_custom_layouts' + # select_options: + # write_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/object_custom_layouts' + # read_target: + # type: 'symfony-config' + # options: + # directory: '/var/www/html/var/config/object_custom_layouts' # IMPORTANT Notice! # Following there are only some examples listed, for a full list of possible options, please run the following command: @@ -100,6 +162,26 @@ pimcore: #### SYMFONY OVERRIDES framework: + router: + default_uri: "%env(DEFAULT_DOMAIN_NAME)%" + profiler: + enabled: false + trusted_proxies: "127.0.0.1,REMOTE_ADDR" + trusted_headers: + [ + "x-forwarded-for", + "x-forwarded-host", + "x-forwarded-proto", + "x-forwarded-port", + "x-forwarded-prefix", + ] + + session: + # ... + cookie_samesite: null + cookie_lifetime: 86400 + gc_maxlifetime: 86400 + # WHEN RUNNING PIMCORE AND OTHER APPLICATIONS ON SAME DOMAIN, SET SESSION COOKIE NAME TO PROVIDE COLLISION # session: # name: "PIMCORE_SESSION_ID" @@ -109,13 +191,13 @@ framework: # json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' #### USE CUSTOM CACHE POOL -# cache: -# pools: -# pimcore.cache.pool: -# public: true -# default_lifetime: 31536000 # 1 year -# adapter: cache.adapter.redis_tag_aware -# provider: 'redis://localhost' # Redis DNS, see: https://symfony.com/doc/current/components/cache/adapters/redis_adapter.html#configure-the-connection + cache: + pools: + pimcore.cache.pool: + public: true + default_lifetime: 31536000 # 1 year + adapter: cache.adapter.redis_tag_aware + provider: "redis://%env(REDIS_HOST)%:6379/%env(REDIS_DB)%" # Redis DNS, see: https://symfony.com/doc/current/components/cache/adapters/redis_adapter.html#configure-the-connection #### USE SESSION HANDLER CONFIGURED IN php.ini # session: diff --git a/config/database.yaml b/config/database.yaml new file mode 100644 index 000000000..7ef57f28a --- /dev/null +++ b/config/database.yaml @@ -0,0 +1,15 @@ +doctrine: + dbal: + connections: + default: + host: "%env(DATABASE_HOST)%" + port: "%env(string:DATABASE_PORT)%" + user: "%env(DATABASE_USER)%" + password: "%env(DATABASE_PASSWORD)%" + dbname: "%env(DATABASE_NAME)%" + mapping_types: + enum: string + bit: boolean + server_version: "%env(DATABASE_SERVER_VERSION)%" + options: + 1001: true diff --git a/config/folders.yaml b/config/folders.yaml new file mode 100644 index 000000000..c63779bed --- /dev/null +++ b/config/folders.yaml @@ -0,0 +1 @@ +system_folders: diff --git a/config/packages/dev/config.yaml b/config/packages/dev/config.yaml index d77183c87..b8f7616ce 100644 --- a/config/packages/dev/config.yaml +++ b/config/packages/dev/config.yaml @@ -1,2 +1,13 @@ imports: - { resource: ../../config.yaml } + +pimcore_data_hub: + config_location: + data_hub: + write_target: + type: "symfony-config" + +framework: + mailer: + transports: + main: "smtp://%env(SMTP_DOMAIN)%:25" diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml new file mode 100644 index 000000000..ab73c82de --- /dev/null +++ b/config/packages/monolog.yaml @@ -0,0 +1,12 @@ +monolog: + handlers: + main: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%-debug.log" + level: debug + channels: ['!event', '!doctrine', '!cache'] + error: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%-error.log" + level: error + channels: [ '!event', '!doctrine', '!cache' ] \ No newline at end of file diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 7c027d121..c4108deb0 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -5,9 +5,9 @@ security: firewalls: dev: - pattern: ^/(_(profiler|wdt)|css|images|js)/ + pattern: ^/(css|images|js)/ security: false - + # Pimcore WebDAV HTTP basic // DO NOT CHANGE! pimcore_webdav: pattern: ^/asset/webdav diff --git a/config/quantityvalues.json b/config/quantityvalues.json new file mode 100644 index 000000000..0d4f101c7 --- /dev/null +++ b/config/quantityvalues.json @@ -0,0 +1,2 @@ +[ +] diff --git a/config/roles.yaml b/config/roles.yaml new file mode 100644 index 000000000..7a7e2c87d --- /dev/null +++ b/config/roles.yaml @@ -0,0 +1 @@ +system_roles: diff --git a/config/services.yaml b/config/services.yaml index 4427875bc..c33ec1a01 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,5 +1,18 @@ parameters: - secret: ThisTokenIsNotSoSecretChangeItImmediately + env(KERNEL_SECRET_FILE): '/run/secrets/kernel-secret' + secret: '%env(file:KERNEL_SECRET_FILE)%' + + # These are default values for connecting to the database/Redis cache that the Docker build sometimes requires to be set. + # Once the app is actually running, they will be replaced with actual values. + env(DATABASE_HOST): '' + env(DATABASE_PORT): 0 + env(DATABASE_NAME): '' + env(DATABASE_USER): '' + env(DATABASE_PASSWORD): '' + env(DATABASE_SERVER_VERSION): '0.0.0' + env(REDIS_DB): "0" + env(REDIS_SESSION_DB): "0" + env(REDIS_HOST): 'redis://redis' # customize the full path to external executables # normally they are auto-detected by `which program` or auto-discovered in the configured path in @@ -73,3 +86,20 @@ services: # App\EventListener\TestListener: # tags: # - { name: kernel.event_listener, event: pimcore.dataobject.preUpdate, method: onObjectPreUpdate } + + App\EventListener\AdminFileLoaderEventListener: + tags: + - { + name: kernel.event_listener, + event: pimcore.bundle_manager.paths.js, + method: addJSFiles, + } + - { + name: kernel.event_listener, + event: pimcore.bundle_manager.paths.css, + method: addCSSFiles, + } + + App\ExpressionLanguage\BasicExpressionProvider: + tags: + - { name: 'pimcore.calculated_value.expression_language_provider' } \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 5c8f6f515..0fde41787 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,24 +1,22 @@ services: redis: + container_name: ${APP_NAME}-redis image: redis:alpine - command: [ redis-server, --maxmemory 128mb, --maxmemory-policy volatile-lru, --save "" ] - - rabbitmq: - image: rabbitmq:alpine - volumes: - - pimcore-rabbitmq:/var/lib/rabbitmq/ + command: [ redis-server, --maxmemory 128mb, --maxmemory-policy volatile-lru, --save "" ] db: + container_name: ${APP_NAME}-db image: mariadb:10.11 working_dir: /application - command: [ mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_520_ci, --innodb-file-per-table=1 ] + command: [ mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_520_ci, --innodb-file-per-table=1, --local-infile=1 ] volumes: - pimcore-database:/var/lib/mysql environment: - - MYSQL_ROOT_PASSWORD=ROOT - - MYSQL_DATABASE=pimcore - - MYSQL_USER=pimcore - - MYSQL_PASSWORD=pimcore + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - MYSQL_PORT=${MYSQL_PORT} healthcheck: # The service is considered healthy when: # - connection to pimcore db can be established, and @@ -28,62 +26,125 @@ services: retries: 6 start_period: 1m timeout: 3s - - nginx: - image: nginx:stable-alpine ports: - - "80:80" - volumes: - - .:/var/www/html:ro - - ./.docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - "${DATABASE_PORT_EXTERNAL}:${MYSQL_PORT}" + + init: + container_name: ${APP_NAME}-init + build: + dockerfile: ./.docker/Dockerfile + target: init + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret depends_on: - - php + db: + condition: service_healthy + env_file: + - .env + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret + volumes: + - .:/var/www/html + - ./.docker/init/init.sh:/init.sh + - ./.docker/init/init.local.sh:/init.local.sh + command: [ "/init.local.sh" ] php: - #user: '1000:1000' # set to your uid:gid - image: pimcore/pimcore:php8.3-debug-latest + container_name: ${APP_NAME}-php + build: + dockerfile: ./.docker/Dockerfile + target: php + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret + env_file: + - .env + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret + depends_on: + init: + condition: service_completed_successfully + ports: + - "${WEB_PORT_EXTERNAL}:80" + volumes: + - .:/var/www/html + - ./.docker/php-debug/nginx-debug.conf:/etc/nginx/sites-available/default:ro + + php-debug: + container_name: ${APP_NAME}-php-debug + build: + dockerfile: ./.docker/Dockerfile + target: php-debug + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret environment: - COMPOSER_HOME: /var/www/html - PHP_IDE_CONFIG: serverName=localhost - # Feed installer configuration via ENV variables. - # See: https://pimcore.com/docs/pimcore/current/Development_Documentation/Getting_Started/Advanced_Installation_Topics.html#page_Advanced-Installation-Topics - PIMCORE_INSTALL_MYSQL_USERNAME: pimcore - PIMCORE_INSTALL_MYSQL_PASSWORD: pimcore - PIMCORE_INSTALL_MYSQL_PORT: 3306 - PIMCORE_INSTALL_MYSQL_HOST_SOCKET: db - PIMCORE_INSTALL_MYSQL_DATABASE: pimcore + - XDEBUG_CONFIG=remote_enable=1 + - PHP_IDE_CONFIG=serverName=localhost + env_file: + - .env + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret depends_on: - db: - condition: service_healthy + init: + condition: service_completed_successfully volumes: - .:/var/www/html - - ./.docker/messenger.yaml:/var/www/html/config/packages/messenger.yaml:ro supervisord: - #user: '1000:1000' # set to your uid:gid - image: pimcore/pimcore:php8.3-supervisord-latest + container_name: ${APP_NAME}-supervisord + build: + dockerfile: ./.docker/Dockerfile + target: supervisord + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret depends_on: - rabbitmq: - condition: service_started - db: - condition: service_healthy + init: + condition: service_completed_successfully + env_file: + - .env + secrets: + - kernel-secret + - pimcore-product-key + - pimcore-instance-identifier + - pimcore-encryption-secret volumes: - .:/var/www/html - - ./.docker/messenger.yaml:/var/www/html/config/packages/messenger.yaml:ro - - ./.docker/supervisord.conf:/etc/supervisor/conf.d/pimcore.conf:ro + - ./.docker/supervisord/supervisord.conf:/etc/supervisor/conf.d/pimcore.conf:ro # The following two services are used for testing. # We restrict these services to the test profile only, so we don't spin them up with every `docker compose up`. # See: https://docs.docker.com/compose/profiles/ test-db: profiles: [ 'test' ] - extends: db + extends: + service: db volumes: - pimcore-test-database:/var/lib/mysql test-php: profiles: [ 'test' ] - extends: php + extends: + service: php environment: APP_ENV: test PIMCORE_TEST_DB_DSN: ${PIMCORE_TEST_DB_DSN:-mysql://pimcore:pimcore@test-db/pimcore} @@ -97,9 +158,29 @@ services: - pimcore-test-var:/var/www/html/var - pimcore-test-public-var:/var/www/html/public/var + smtp: + container_name: ${APP_NAME}-smtp + image: rnwood/smtp4dev:v3 + ports: + - ${SMTP_PORT_EXTERNAL}:80 + volumes: + - smtp4dev-data:/smtp4dev + environment: + - ServerOptions__HostName=smtp4dev + volumes: pimcore-database: - pimcore-rabbitmq: pimcore-test-database: pimcore-test-var: pimcore-test-public-var: + smtp4dev-data: + +secrets: + kernel-secret: + file: ./.secrets/kernel-secret + pimcore-product-key: + file: ./.secrets/pimcore-product-key + pimcore-instance-identifier: + file: ./.secrets/pimcore-instance-identifier + pimcore-encryption-secret: + file: ./.secrets/pimcore-encryption-secret diff --git a/public/admin/js/sidebar-environment-indicator.js b/public/admin/js/sidebar-environment-indicator.js new file mode 100644 index 000000000..e2b41af29 --- /dev/null +++ b/public/admin/js/sidebar-environment-indicator.js @@ -0,0 +1,9 @@ +document.addEventListener(pimcore.events.pimcoreReady, () => { + Ext.get("pimcore_navigation").insertHtml( + "beforeEnd", + '

' + + (pimcore?.settings?.environment || "").toUpperCase() + + '

' + ); +}); + \ No newline at end of file diff --git a/src/EventListener/AdminFileLoaderEventListener.php b/src/EventListener/AdminFileLoaderEventListener.php new file mode 100644 index 000000000..f2f7ef8d5 --- /dev/null +++ b/src/EventListener/AdminFileLoaderEventListener.php @@ -0,0 +1,30 @@ +setPaths( + array_merge( + $event->getPaths(), + [ + '/admin/js/sidebar-environment-indicator.js', + ] + ) + ); + } + + public function addCSSFiles(PathsEvent $event) + { + $event->setPaths( + array_merge( + $event->getPaths(), + [] + ) + ); + } +} diff --git a/src/ExpressionLanguage/BasicExpressionProvider.php b/src/ExpressionLanguage/BasicExpressionProvider.php new file mode 100644 index 000000000..db2c373d0 --- /dev/null +++ b/src/ExpressionLanguage/BasicExpressionProvider.php @@ -0,0 +1,49 @@ +addBundle(new PimcoreAdminBundle(), 60); - } - if (class_exists(PimcoreQuillBundle::class)) { - $collection->addBundle(new PimcoreQuillBundle()); - } + // Official Pimcore bundles + $collection->addBundle(new PimcoreAdminBundle(), 60); + $collection->addBundle(new PimcoreQuillBundle()); + $collection->addBundle(new PimcoreApplicationLoggerBundle()); + $collection->addBundle(new PimcoreCustomReportsBundle()); + $collection->addBundle(new PimcoreGlossaryBundle()); + $collection->addBundle(new PimcoreSeoBundle()); + $collection->addBundle(new PimcoreSimpleBackendSearchBundle()); + $collection->addBundle(new PimcoreStaticRoutesBundle()); + $collection->addBundle(new PimcoreUuidBundle()); + $collection->addBundle(new PimcoreXliffBundle()); + $collection->addBundle(new PimcoreWordExportBundle()); + $collection->addBundle(new PimcoreDataHubBundle()); + $collection->addBundle(new PimcoreDataImporterBundle()); + $collection->addBundle(new PimcorePerspectiveEditorBundle()); + // Custom bundles + $collection->addBundle(new FolderCreatorBundle()); + $collection->addBundle(new RoleCreatorBundle()); + $collection->addBundle(new CoreShopMessengerBundle()); + $collection->addBundle(new ObjectLayoutGridBundle()); + $collection->addBundle(new BasilicomPathFormatterBundle()); } } diff --git a/var/config/perspectives/default.yaml b/var/config/perspectives/default.yaml new file mode 100644 index 000000000..b88cd6ead --- /dev/null +++ b/var/config/perspectives/default.yaml @@ -0,0 +1,159 @@ +pimcore: + perspectives: + definitions: + default: + elementTree: + - + type: objects + position: left + expanded: false + hidden: false + sort: 0 + treeContextMenu: + object: + items: + add: true + addFolder: true + importCsv: true + cut: true + copy: true + paste: true + delete: true + rename: true + reload: true + publish: true + unpublish: true + searchAndMove: true + lock: true + unlock: true + lockAndPropagate: true + unlockAndPropagate: true + changeChildrenSortBy: true + - + type: assets + position: left + expanded: false + hidden: false + sort: 1 + - + type: documents + position: left + expanded: false + hidden: false + sort: 2 + iconCls: pimcore_nav_icon_perspective + icon: null + dashboards: + predefined: + welcome: + positions: + - + - + id: 1 + type: pimcore.layout.portlets.modificationStatistic + config: null + - + id: 2 + type: pimcore.layout.portlets.modifiedAssets + config: null + - + - + id: 3 + type: pimcore.layout.portlets.modifiedObjects + config: null + - + id: 4 + type: pimcore.layout.portlets.modifiedDocuments + config: null + toolbar: + file: + hidden: false + items: + perspectives: true + dashboards: true + openDocument: true + openAsset: true + openObject: true + searchReplace: true + schedule: true + seemode: true + closeAll: true + help: true + about: true + marketing: + hidden: false + items: + reports: true + tagmanagement: true + targeting: true + seo: + hidden: false + items: + documents: true + robots: true + httperrors: true + extras: + hidden: false + items: + glossary: true + redirects: true + translations: true + recyclebin: true + plugins: true + notesEvents: true + applicationlog: true + gdpr_data_extractor: true + emails: true + maintenance: true + systemtools: + hidden: false + items: + requirements: true + settings: + hidden: false + items: + customReports: true + marketingReports: true + documentTypes: true + predefinedProperties: true + predefinedMetadata: true + system: true + appearance: true + website: true + users: + hidden: false + items: + users: true + roles: true + thumbnails: true + objects: + hidden: false + items: + classes: true + fieldcollections: true + objectbricks: true + quantityValue: true + classificationstore: true + bulkExport: true + bulkImport: true + routes: true + cache: + hidden: false + items: + clearAll: true + clearData: true + clearSymfony: true + clearOutput: true + clearTemp: true + adminTranslations: true + tagConfiguration: true + perspectiveEditor: true + search: + hidden: false + items: + quickSearch: true + documents: true + assets: true + objects: true + datahub: + hidden: false diff --git a/var/config/system_settings/system_settings.yaml b/var/config/system_settings/system_settings.yaml new file mode 100644 index 000000000..333260ff4 --- /dev/null +++ b/var/config/system_settings/system_settings.yaml @@ -0,0 +1,28 @@ +pimcore: + general: + domain: '' + redirect_to_maindomain: false + valid_languages: + - en_US + fallback_languages: + en_US: '' + required_languages: + - '' + default_language: en_US + debug_admin_translations: false + documents: + versions: + days: null + steps: null + error_pages: + default: '' + localized: { } + objects: + versions: + days: null + steps: null + assets: + versions: + days: null + steps: null + email: { }