├── .app.env.sample ├── .docker ├── examples │ ├── badlint │ │ ├── Dockerfile │ │ └── Dockerfile1 │ ├── multistage-binary │ │ └── Dockerfile │ ├── multistage-nginx │ │ └── Dockerfile │ └── traefik-for-several-projects │ │ ├── docker-compose.traefik.yml │ │ ├── project1 │ │ └── docker-compose.yml │ │ └── project2 │ │ └── docker-compose.yml ├── php │ ├── Dockerfile │ ├── Dockerfile0 │ ├── Dockerfile1 │ ├── Dockerfile2 │ ├── Dockerfile3 │ └── config │ │ ├── dev.ini │ │ └── prod.ini └── traefik │ ├── certs │ └── .gitkeep │ └── configuration │ └── certificates.yaml ├── .dockerignore ├── .editorconfig ├── .env.sample ├── .gitignore ├── .rr.yaml ├── .styleci.yml ├── LICENSE ├── Makefile ├── README.md ├── app.php ├── app ├── .DS_Store ├── config │ ├── cache.php │ ├── cycle.php │ ├── database.php │ ├── distribution.php │ ├── grpc.php │ ├── mailer.php │ ├── migration.php │ ├── monolog.php │ ├── queue.php │ ├── scaffolder.php │ ├── session.php │ ├── storage.php │ └── views │ │ └── stempler.php ├── locale │ └── ru │ │ └── messages.en.php ├── migrations │ └── .gitignore ├── o.txt ├── src │ ├── Api │ │ ├── Cli │ │ │ └── Command │ │ │ │ ├── DoNothing.php │ │ │ │ ├── Mail.php │ │ │ │ └── Pdf.php │ │ ├── Job │ │ │ └── Ping.php │ │ ├── Rpc │ │ │ └── .gitignore │ │ └── Web │ │ │ ├── Controller │ │ │ └── HomeController.php │ │ │ └── routes.php │ ├── Application │ │ ├── Bootloader │ │ │ ├── ExceptionHandlerBootloader.php │ │ │ ├── LoggingBootloader.php │ │ │ └── RoutesBootloader.php │ │ ├── Kernel.php │ │ ├── Middleware │ │ │ └── LocaleSelector.php │ │ ├── Service │ │ │ ├── ErrorHandler │ │ │ │ ├── Handler.php │ │ │ │ └── ViewRenderer.php │ │ │ └── Pdf.php │ │ └── helpers.php │ └── Module │ │ └── EmptyModule │ │ ├── Api │ │ └── EmptyService.php │ │ ├── Application │ │ └── Bootloader.php │ │ ├── Internal │ │ └── EmptyService.php │ │ └── Test │ │ └── EmptyServiceTest.php ├── test.php └── views │ ├── embed │ └── links.dark.php │ ├── exception │ ├── 403.dark.php │ ├── 404.dark.php │ ├── 500.dark.php │ └── error.dark.php │ ├── home.dark.php │ ├── layout │ └── base.dark.php │ └── template.dark.php ├── composer.json ├── composer.lock ├── deptrac.yaml ├── docker-compose.0.yml ├── docker-compose.1.yml ├── docker-compose.2.yml ├── docker-compose.3.yml ├── docker-compose.improved.yml ├── docker-compose.local.0.yml ├── docker-compose.local.1.yml ├── docker-compose.local.2.yml ├── docker-compose.local.3.yml ├── docker-compose.local.yml ├── docker-compose.yml ├── phpunit.xml ├── psalm.xml ├── public ├── favicon.ico ├── images │ ├── 403.svg │ ├── 404.svg │ ├── 500.svg │ └── logo.svg └── styles │ └── welcome.css └── tests ├── App └── TestKernel.php ├── Feature ├── Controller │ └── HomeControllerTest.php └── Job │ └── PingTest.php ├── TestCase.php └── Unit └── DemoTest.php /.app.env.sample: -------------------------------------------------------------------------------- 1 | # Environment (prod or local) 2 | APP_ENV=local 3 | 4 | # Debug mode set to TRUE disables view caching and enables higher verbosity. 5 | DEBUG=true 6 | 7 | # Set to an application specific value, used to encrypt/decrypt cookies etc. 8 | ENCRYPTER_KEY=def000003f47c1bb39cf6d8b96a4ab6198df982d06e9123e2de36933bae0d603cd3cec838fdd31fc7c768a43872b72c920dac5365fb631d6cfd51e500d812372b7c9f70a 9 | 10 | # Set to TRUE to disable confirmation in `migrate` commands. 11 | SAFE_MIGRATIONS=true 12 | 13 | # Queue 14 | QUEUE_CONNECTION=sync 15 | 16 | # Monolog 17 | MONOLOG_DEFAULT_CHANNEL=default 18 | # DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY 19 | MONOLOG_DEFAULT_LEVEL=DEBUG 20 | 21 | # Cache 22 | CACHE_STORAGE=local 23 | 24 | # Session 25 | SESSION_LIFETIME=86400 26 | SESSION_COOKIE=sid 27 | 28 | # Mailer 29 | MAILER_DSN=smtp://mailhog:1025 30 | MAILER_PIPELINE=local 31 | MAILER_FROM="Alex Novikov " 32 | 33 | # Storage 34 | STORAGE_DEFAULT=default 35 | 36 | # Cycle Bridge 37 | CYCLE_SCHEMA_CACHE=true 38 | CYCLE_SCHEMA_WARMUP=false 39 | S3_REGION=us-east1 40 | S3_BUCKET=podlodka 41 | S3_PREFIX=uploads 42 | S3_ENDPOINT=http://minio:9000 43 | 44 | PDF_ENDPOINT=http://gotenberg:3000 45 | 46 | # change to debug if want to test xdebug 47 | #XDEBUG_MODE=debug 48 | XDEBUG_MODE=off 49 | PHP_IDE_CONFIG=serverName=podlodka 50 | -------------------------------------------------------------------------------- /.docker/examples/badlint/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.1 as builder 2 | 3 | COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer 4 | COPY ./composer.* /var/www 5 | COPY ./auth.json /var/www 6 | RUN composer install --no-autoloader --no-suggest --no-scripts 7 | 8 | FROM php:8.1 9 | 10 | COPY --from=builder /var/www/vendor ./ 11 | COPY ./app . -------------------------------------------------------------------------------- /.docker/examples/badlint/Dockerfile1: -------------------------------------------------------------------------------- 1 | FROM alpine:3.9 2 | 3 | EXPOSE 9000 4 | 5 | COPY /ssh /root/.ssh 6 | RUN chmod 600 /root/.ssh/id_rsa && mkdir -p /var/www/site.com 7 | WORKDIR /var/www/site.com 8 | 9 | # ensure www-data user exists 10 | RUN set -x \ 11 | && addgroup -g 1000 -S www-data \ 12 | && adduser -u 1000 -D -S -G www-data www-data 13 | 14 | # make sure you can use HTTPS 15 | RUN apk add --update --no-cache ca-certificates vim nano git unzip curl bash parallel 16 | 17 | # Install all package 18 | RUN apk add --update --no-cache \ 19 | php7 php7-common php7-fpm php7-dev php7-xdebug php7-imagick \ 20 | php7-mbstring php7-json php7-ctype php7-phar php7-intl \ 21 | php7-bcmath php7-calendar php7-curl php7-dba php7-pgsql \ 22 | php7-exif php7-fileinfo php7-ftp php7-gd php7-gettext php7-iconv php7-imap \ 23 | php7-ldap php7-sockets php7-tokenizer php7-soap \ 24 | php7-opcache php7-openssl php7-tidy php7-xml php7-simplexml \ 25 | php7-pdo php7-pdo_mysql php7-pdo_pgsql php7-pdo_sqlite php7-sqlite3 \ 26 | php7-xmlreader php7-xmlwriter php7-xsl php7-zip php7-zlib php7-session \ 27 | autoconf file g++ gcc libc-dev make pkgconf re2c php7-dev php7-pear \ 28 | yaml-dev pcre-dev zlib-dev cyrus-sasl-dev 29 | 30 | ENV PHP_INI_DIR /etc/php7 31 | 32 | # Install additional extension 33 | RUN apk add --update --no-cache \ 34 | linux-headers 35 | 36 | RUN phpize -v \ 37 | #hot fix of pecl 38 | && sed -i 's|$PHP -C -n -q |$PHP -C -q |' /usr/bin/pecl \ 39 | && pecl install grpc protobuf \ 40 | && echo "extension=grpc" > $PHP_INI_DIR/conf.d/20_grpc.ini \ 41 | && echo "extension=protobuf" > $PHP_INI_DIR/conf.d/20_protobuf.ini 42 | 43 | # Cleaning 44 | #RUN apk del autoconf file g++ gcc libc-dev make pkgconf re2c \ 45 | # yaml-dev pcre-dev zlib-dev libmemcached-dev cyrus-sasl-dev \ 46 | 47 | RUN rm -rf /var/cache/apk/* /var/tmp/* /tmp/* \ 48 | && ln -snf /usr/bin/php7 /usr/bin/php 49 | 50 | ARG TIMEZONE=UTC 51 | 52 | # Set timezone 53 | RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && echo ${TIMEZONE} > /etc/timezone \ 54 | && printf '[PHP]\ndate.timezone = "%s"\n', ${TIMEZONE} > $PHP_INI_DIR/conf.d/tzone.ini \ 55 | && date 56 | COPY www.conf $PHP_INI_DIR/php-fpm.d/www.conf 57 | 58 | # Install composer 59 | RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer 60 | 61 | ## Set xDebug 62 | ARG XDEBUG_STATE=Off 63 | ARG XDEBUG_PORT=9005 64 | 65 | RUN echo "zend_extension=xdebug.so" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 66 | && echo "xdebug.remote_enable=$XDEBUG_STATE" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 67 | && echo 'xdebug.remote_autostart=Off' >> $PHP_INI_DIR/conf.d/xdebug.ini \ 68 | && echo 'xdebug.idekey=PHPSTORM' >> $PHP_INI_DIR/conf.d/xdebug.ini \ 69 | && echo 'xdebug.remote_host=host.docker.internal' >> $PHP_INI_DIR/conf.d/xdebug.ini \ 70 | && echo 'xdebug.remote_handler=dbgp' >> $PHP_INI_DIR/conf.d/xdebug.ini \ 71 | && echo "xdebug.remote_port=$XDEBUG_PORT" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 72 | && echo "xdebug.profiler_enable=Off" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 73 | && echo "xdebug.profiler_enable_trigger=$XDEBUG_STATE" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 74 | && echo "xdebug.profiler_enable_trigger_value=prof" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 75 | && echo "xdebug.profiler_output_dir=/var/www/site.com/logs/php/profiler" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 76 | && echo "xdebug.auto_trace=Off" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 77 | && echo "xdebug.trace_enable_trigger=$XDEBUG_STATE" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 78 | && echo "xdebug.trace_enable_trigger_value=trace" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 79 | && echo "xdebug.trace_output_dir=/var/www/site.com/logs/php/tracer" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 80 | && echo "xdebug.collect_assignments=Off" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 81 | && echo "xdebug.trace_format=On" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 82 | && echo "xdebug.collect_params=1" >> $PHP_INI_DIR/conf.d/xdebug.ini \ 83 | ## Disable xDebug for none local builds 84 | && sh -c "if [[ $XDEBUG_STATE = 'Off' ]] ; then sed -i '1s/^/;/' $PHP_INI_DIR/conf.d/xdebug.ini ; fi" 85 | 86 | CMD ["php-fpm7"] 87 | -------------------------------------------------------------------------------- /.docker/examples/multistage-binary/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.13-alpine3.12 as builder 2 | 3 | COPY ./go.mod go.mod 4 | RUN go mod download 5 | 6 | COPY ./main.go . 7 | RUN go build -v -o rr main.go 8 | 9 | FROM php:8.2-cli-alpine3.17 10 | 11 | COPY --from=builder /var/www/aim/rr ./ 12 | -------------------------------------------------------------------------------- /.docker/examples/multistage-nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | # Container to build frontend 2 | FROM node:16-alpine3.16 as builder 3 | 4 | RUN apk update \ 5 | && apk add --no-cache \ 6 | nss \ 7 | curl \ 8 | libcurl \ 9 | yarn \ 10 | git \ 11 | openssh-client \ 12 | wget \ 13 | && rm -rf /var/lib/apt/lists/* 14 | 15 | WORKDIR /var/www 16 | 17 | COPY ./package.json /var/www 18 | COPY ./yarn.lock /var/www 19 | 20 | RUN yarn install --silent 21 | 22 | COPY ./ /var/www 23 | RUN yarn build 24 | 25 | FROM nginx:1.23-alpine as fe-server 26 | 27 | COPY --from=builder /var/www/build /usr/share/nginx/html 28 | COPY ./docker/nginx/server.conf /etc/nginx/conf.d/default.conf 29 | COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf 30 | 31 | EXPOSE 11211 32 | -------------------------------------------------------------------------------- /.docker/examples/traefik-for-several-projects/docker-compose.traefik.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | reverse-proxy: 5 | image: traefik:v2.6 6 | command: 7 | - "--accesslog" 8 | - "--api.insecure=true" 9 | - "--providers.docker=true" 10 | - "--providers.docker.exposedbydefault=false" 11 | - "--entrypoints.web.address=:80" 12 | - "--entrypoints.websecure.address=:443" 13 | - "--providers.file.directory=/configuration/" 14 | - "--providers.file.watch=true" 15 | ports: 16 | - "80:80" 17 | - "443:443" 18 | - "8082:8080" 19 | volumes: 20 | - /var/run/docker.sock:/var/run/docker.sock 21 | - ./.docker/traefik/configuration:/configuration/ 22 | - ./.docker/traefik/certs:/etc/certs:ro 23 | -------------------------------------------------------------------------------- /.docker/examples/traefik-for-several-projects/project1/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | minio: 5 | labels: 6 | - "traefik.enable=true" 7 | - "traefik.http.routers.minio-http.entrypoints=web" 8 | - "traefik.http.routers.minio-http.rule=Host(`s3.podlodka.localhost`)" 9 | - "traefik.http.routers.minio-http.middlewares=minio-https" 10 | - "traefik.http.services.minio.loadbalancer.server.port=9000" 11 | - "traefik.http.middlewares.minio-https.redirectscheme.scheme=https" 12 | - "traefik.http.routers.minio.entrypoints=websecure" 13 | - "traefik.http.routers.minio.rule=Host(`s3.podlodka.localhost`)" 14 | - "traefik.http.routers.minio.tls=true" 15 | -------------------------------------------------------------------------------- /.docker/examples/traefik-for-several-projects/project2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | 5 | mailhog: 6 | image: "mailhog/mailhog" 7 | labels: 8 | - "traefik.enable=true" 9 | - "traefik.http.routers.mailhog-http.entrypoints=web" 10 | - "traefik.http.routers.mailhog-http.rule=Host(`mail.podlodka.localhost`)" 11 | - "traefik.http.routers.mailhog-http.middlewares=mailhog-https" 12 | - "traefik.http.services.mailhog.loadbalancer.server.port=8025" 13 | - "traefik.http.middlewares.mailhog-https.redirectscheme.scheme=https" 14 | - "traefik.http.routers.mailhog.entrypoints=websecure" 15 | - "traefik.http.routers.mailhog.rule=Host(`mail.podlodka.localhost`)" 16 | - "traefik.http.routers.mailhog.tls=true" 17 | -------------------------------------------------------------------------------- /.docker/php/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | FROM php:8.2-cli-alpine3.17 as app_php 3 | 4 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 5 | apk update && \ 6 | install-php-extensions opcache zip xsl dom exif intl pcntl bcmath sockets && \ 7 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} && \ 8 | wget -q "https://github.com/aptible/supercronic/releases/download/v0.2.1/supercronic-linux-arm64" \ 9 | -O /usr/bin/supercronic \ 10 | && chmod +x /usr/bin/supercronic \ 11 | && mkdir /etc/supercronic \ 12 | && echo '*/1 * * * * php /app/app.php cron-task foo --times=20' > /etc/supercronic/podlodka 13 | 14 | WORKDIR /app 15 | 16 | # Host system user id, default 1000, but can be passed on buildtime 17 | ARG UID=1000 18 | ARG GID=1000 19 | # 20 | ## Add user so we don't need --no-sandbox. 21 | RUN addgroup -g ${GID} -S podlodka && adduser --uid ${UID} --ingroup podlodka -S -g podlodka podlodka && \ 22 | mkdir -p /home/podlodka/Downloads /app \ 23 | && chown -R podlodka:podlodka /home/podlodka \ 24 | && chown -R podlodka:podlodka /app 25 | 26 | USER podlodka 27 | 28 | ENV COMPOSER_HOME="/tmp/composer" 29 | 30 | COPY --chown=podlodka:podlodka --from=composer:2.3 /usr/bin/composer /usr/bin/composer 31 | COPY --chown=podlodka:podlodka ./composer.* . 32 | 33 | RUN composer config --no-plugins allow-plugins.spiral/composer-publish-plugin false && \ 34 | composer install --no-cache --no-ansi --no-autoloader --no-scripts --no-dev 35 | 36 | COPY --chown=podlodka:podlodka --from=spiralscout/roadrunner:latest /usr/bin/rr /app 37 | 38 | COPY --chown=podlodka:podlodka ./ . 39 | 40 | RUN set -x \ 41 | && composer dump-autoload -n --optimize \ 42 | && chmod -R 777 ${COMPOSER_HOME}/cache \ 43 | && php app.php configure 44 | 45 | 46 | FROM app_php as app_php_dev 47 | USER root 48 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 49 | install-php-extensions xdebug && \ 50 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} 51 | 52 | COPY .docker/php/config/dev.ini /usr/local/etc/php/conf.d/ 53 | 54 | USER podlodka 55 | 56 | 57 | FROM app_php as app_php_prod 58 | USER root 59 | COPY .docker/php/config/prod.ini /usr/local/etc/php/conf.d/ 60 | USER podlodka 61 | -------------------------------------------------------------------------------- /.docker/php/Dockerfile0: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | FROM php:8.2-cli-alpine3.17 3 | 4 | COPY --from=mlocati/php-extension-installer:latest --link /usr/bin/install-php-extensions /usr/local/bin/ 5 | RUN install-php-extensions opcache zip xsl dom exif intl pcntl sockets && \ 6 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} 7 | 8 | WORKDIR /app 9 | 10 | ENV COMPOSER_HOME="/tmp/composer" 11 | 12 | COPY --from=composer:2.3 /usr/bin/composer /usr/bin/composer 13 | COPY ./composer.* . 14 | 15 | RUN composer config --no-plugins allow-plugins.spiral/composer-publish-plugin false && \ 16 | composer install --no-cache --no-ansi --no-autoloader --no-scripts --no-dev 17 | 18 | COPY --from=spiralscout/roadrunner:latest /usr/bin/rr /app 19 | 20 | COPY ./ . 21 | # check .dockerignore! 22 | 23 | RUN set -x \ 24 | && composer dump-autoload -n --optimize \ 25 | && chmod -R 777 ${COMPOSER_HOME}/cache \ 26 | && php app.php configure 27 | -------------------------------------------------------------------------------- /.docker/php/Dockerfile1: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | FROM php:8.2-cli-alpine3.17 3 | 4 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 5 | apk update && \ 6 | install-php-extensions opcache zip xsl dom exif intl pcntl bcmath sockets && \ 7 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} && \ 8 | wget -q "https://github.com/aptible/supercronic/releases/download/v0.2.1/supercronic-linux-arm64" \ 9 | -O /usr/bin/supercronic \ 10 | && chmod +x /usr/bin/supercronic \ 11 | && mkdir /etc/supercronic \ 12 | && echo '*/1 * * * * php /app/app.php cron-task foo --times=20' > /etc/supercronic/podlodka 13 | 14 | WORKDIR /app 15 | 16 | # Host system user id, default 1000, should can be passed on buildtime 17 | ARG UID=1000 18 | ARG GID=1000 19 | # 20 | ## Add user so we don't need --no-sandbox. 21 | RUN addgroup -g ${GID} -S podlodka && adduser --uid ${UID} --ingroup podlodka -S -g podlodka podlodka && \ 22 | mkdir -p /home/podlodka/Downloads /app \ 23 | && chown -R podlodka:podlodka /home/podlodka \ 24 | && chown -R podlodka:podlodka /app 25 | 26 | USER podlodka 27 | 28 | ENV COMPOSER_HOME="/tmp/composer" 29 | 30 | COPY --chown=podlodka:podlodka --from=composer:2.3 /usr/bin/composer /usr/bin/composer 31 | COPY --chown=podlodka:podlodka ./composer.* . 32 | 33 | RUN composer config --no-plugins allow-plugins.spiral/composer-publish-plugin false && \ 34 | composer install --no-cache --no-ansi --no-autoloader --no-scripts --no-dev 35 | 36 | COPY --chown=podlodka:podlodka --from=spiralscout/roadrunner:latest /usr/bin/rr /app 37 | 38 | # why so many extra steps with COPY? 39 | COPY --chown=podlodka:podlodka ./ . 40 | 41 | RUN set -x \ 42 | && composer dump-autoload -n --optimize \ 43 | && chmod -R 777 ${COMPOSER_HOME}/cache \ 44 | && php app.php configure 45 | -------------------------------------------------------------------------------- /.docker/php/Dockerfile2: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | FROM php:8.2-cli-alpine3.17 as app_php 3 | 4 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 5 | apk update && \ 6 | install-php-extensions opcache zip xsl dom exif intl pcntl bcmath sockets && \ 7 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} && \ 8 | wget -q "https://github.com/aptible/supercronic/releases/download/v0.2.1/supercronic-linux-arm64" \ 9 | -O /usr/bin/supercronic \ 10 | && chmod +x /usr/bin/supercronic \ 11 | && mkdir /etc/supercronic \ 12 | && echo '*/1 * * * * php /app/app.php cron-task foo --times=20' > /etc/supercronic/podlodka 13 | 14 | WORKDIR /app 15 | 16 | ARG UID=1000 17 | ARG GID=1000 18 | 19 | 20 | RUN addgroup -g ${GID} -S podlodka && adduser --uid ${UID} --ingroup podlodka -S -g podlodka podlodka && \ 21 | mkdir -p /home/podlodka/Downloads /app \ 22 | && chown -R podlodka:podlodka /home/podlodka \ 23 | && chown -R podlodka:podlodka /app 24 | 25 | USER podlodka 26 | 27 | ENV COMPOSER_HOME="/tmp/composer" 28 | 29 | COPY --chown=podlodka:podlodka --from=composer:2.3 /usr/bin/composer /usr/bin/composer 30 | COPY --chown=podlodka:podlodka ./composer.* . 31 | 32 | RUN composer config --no-plugins allow-plugins.spiral/composer-publish-plugin false && \ 33 | composer install --no-cache --no-ansi --no-autoloader --no-scripts --no-dev 34 | 35 | COPY --chown=podlodka:podlodka --from=spiralscout/roadrunner:latest /usr/bin/rr /app 36 | 37 | COPY --chown=podlodka:podlodka ./ . 38 | 39 | RUN set -x \ 40 | && composer dump-autoload -n --optimize \ 41 | && chmod -R 777 ${COMPOSER_HOME}/cache \ 42 | && php app.php configure 43 | 44 | 45 | FROM app_php as app_php_dev 46 | USER root 47 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 48 | install-php-extensions xdebug && \ 49 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} 50 | 51 | COPY .docker/php/config/dev.ini /usr/local/etc/php/conf.d/ 52 | 53 | USER podlodka 54 | -------------------------------------------------------------------------------- /.docker/php/Dockerfile3: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | FROM php:8.2-cli-alpine3.17 as app_php 3 | 4 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 5 | apk update && \ 6 | install-php-extensions opcache zip xsl dom exif intl pcntl bcmath sockets && \ 7 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} && \ 8 | wget -q "https://github.com/aptible/supercronic/releases/download/v0.2.1/supercronic-linux-arm64" \ 9 | -O /usr/bin/supercronic \ 10 | && chmod +x /usr/bin/supercronic \ 11 | && mkdir /etc/supercronic \ 12 | && echo '*/1 * * * * php /app/app.php cron-task foo --times=20' > /etc/supercronic/podlodka 13 | 14 | WORKDIR /app 15 | 16 | ARG UID=1000 17 | ARG GID=1000 18 | 19 | RUN addgroup -g ${GID} -S podlodka && adduser --uid ${UID} --ingroup podlodka -S -g podlodka podlodka && \ 20 | mkdir -p /home/podlodka/Downloads /app \ 21 | && chown -R podlodka:podlodka /home/podlodka \ 22 | && chown -R podlodka:podlodka /app 23 | 24 | USER podlodka 25 | 26 | ENV COMPOSER_HOME="/tmp/composer" 27 | 28 | COPY --chown=podlodka:podlodka --from=composer:2.3 /usr/bin/composer /usr/bin/composer 29 | COPY --chown=podlodka:podlodka ./composer.* . 30 | 31 | RUN composer config --no-plugins allow-plugins.spiral/composer-publish-plugin false && \ 32 | composer install --no-cache --no-ansi --no-autoloader --no-scripts --no-dev 33 | 34 | COPY --chown=podlodka:podlodka --from=spiralscout/roadrunner:latest /usr/bin/rr /app 35 | 36 | COPY --chown=podlodka:podlodka ./ . 37 | 38 | RUN set -x \ 39 | && composer dump-autoload -n --optimize \ 40 | && chmod -R 777 ${COMPOSER_HOME}/cache \ 41 | && php app.php configure 42 | 43 | 44 | FROM app_php as app_php_dev 45 | USER root 46 | RUN --mount=type=bind,from=mlocati/php-extension-installer:1.5,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \ 47 | install-php-extensions xdebug && \ 48 | apk del --no-cache ${PHPIZE_DEPS} ${BUILD_DEPENDS} 49 | 50 | COPY .docker/php/config/dev.ini /usr/local/etc/php/conf.d/ 51 | 52 | USER podlodka 53 | 54 | 55 | FROM app_php as app_php_prod 56 | USER root 57 | COPY .docker/php/config/prod.ini /usr/local/etc/php/conf.d/ 58 | USER podlodka 59 | -------------------------------------------------------------------------------- /.docker/php/config/dev.ini: -------------------------------------------------------------------------------- 1 | [xdebug] 2 | ; to enable xdebug just set XDEBUG_MODE: debug in .env 3 | xdebug.client_host=host.docker.internal 4 | xdebug.start_with_request=yes 5 | -------------------------------------------------------------------------------- /.docker/php/config/prod.ini: -------------------------------------------------------------------------------- 1 | opcache.enable=1 2 | opcache.enable_cli=1 3 | -------------------------------------------------------------------------------- /.docker/traefik/certs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexndr-novikov/podlodka-php-crew-2/3c7f30ee682ea1bac6fb12c27c0ac36928b97f34/.docker/traefik/certs/.gitkeep -------------------------------------------------------------------------------- /.docker/traefik/configuration/certificates.yaml: -------------------------------------------------------------------------------- 1 | tls: 2 | certificates: 3 | - certFile: /etc/certs/local-cert.pem 4 | keyFile: /etc/certs/local-key.pem -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ## Ignore all 2 | * 3 | 4 | ## Except 5 | !/app 6 | !/public 7 | !app.php 8 | !composer.json 9 | !composer.lock 10 | !.rr.yaml 11 | !.docker/php/config/* 12 | 13 | # Ignore unnecessary files inside allowed directories 14 | # This should go after the allowed directories 15 | **/*~ 16 | **/*.log 17 | **/.DS_Store 18 | **/Thumbs.db 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.yml] 12 | indent_size = 2 13 | 14 | [*.yaml] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | COMPOSE_FILE=docker-compose.yml:docker-compose.local.yml 2 | # COMPOSE_FILE=docker-compose.yml 3 | COMPOSE_PROJECT_NAME=CREW 4 | 5 | # minio 6 | AWS_KEY=adminadmin 7 | AWS_SECRET=adminadmin 8 | # postgres 9 | DB_HOST=postgres 10 | POSTGRES_DB=podlodka 11 | POSTGRES_USER=crew 12 | POSTGRES_PASSWORD=iddqd 13 | # postlivecoding 14 | PHP_IMAGE=repo.io/podlodka 15 | PHP_TAG=0.0.1 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | .DS_Store 4 | runtime 5 | rr* 6 | spiral* 7 | .env 8 | .app.env 9 | .phpunit.result.cache 10 | .deptrac.cache 11 | .docker/traefik/certs/local-cert.pem 12 | .docker/traefik/certs/local-key.pem 13 | -------------------------------------------------------------------------------- /.rr.yaml: -------------------------------------------------------------------------------- 1 | version: '2.7' 2 | 3 | rpc: 4 | listen: tcp://127.0.0.1:6001 5 | 6 | server: 7 | command: "php app.php" 8 | relay: pipes 9 | env: 10 | - XDEBUG_SESSION: 1 11 | 12 | http: 13 | address: 0.0.0.0:8090 14 | middleware: [ "gzip", "static" ] 15 | static: 16 | dir: "public" 17 | forbid: [ ".php", ".htaccess" ] 18 | pool: 19 | num_workers: 1 20 | supervisor: 21 | max_worker_memory: 100 22 | 23 | jobs: 24 | consume: [ ] 25 | pool: 26 | num_workers: 2 27 | supervisor: 28 | max_worker_memory: 100 29 | 30 | kv: 31 | local: 32 | driver: memory 33 | config: 34 | interval: 60 35 | redis: 36 | driver: redis 37 | config: 38 | addrs: 39 | - localhost:6379 40 | status: 41 | # Host and port to listen on (eg.: `127.0.0.1:2114`). Use the following URL: http://127.0.0.1:2114/health?plugin=http 42 | # Multiple plugins must be separated using "&" - http://127.0.0.1:2114/health?plugin=http&plugin=rpc where "http" and 43 | # "rpc" are active (connected) plugins. 44 | # 45 | # This option is required. 46 | address: 127.0.0.1:8082 47 | 48 | # Response status code if a requested plugin not ready to handle requests 49 | # Valid for both /health and /ready endpoints 50 | # 51 | # Default: 503 52 | unavailable_status_code: 503 53 | 54 | #grpc: 55 | # listen: "tcp://0.0.0.0:9001" 56 | # proto: 57 | # - "first.proto" 58 | 59 | metrics: 60 | address: localhost:2112 61 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | risky: false 2 | preset: psr12 3 | enabled: 4 | # Risky Fixers 5 | # - declare_strict_types 6 | # - void_return 7 | - ordered_class_elements 8 | - linebreak_after_opening_tag 9 | - single_quote 10 | - no_blank_lines_after_phpdoc 11 | - unary_operator_spaces 12 | - no_useless_else 13 | - no_useless_return 14 | - trailing_comma_in_multiline_array 15 | finder: 16 | exclude: 17 | - "tests" 18 | - "public" 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Spiral Scout 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make 2 | SHELL = /bin/bash 3 | 4 | init: 5 | cp .env.sample .env && cp .app.env.sample .app.env && make tls && docker-compose -f docker-compose.yml up -d --build && docker-compose cp cron:/app/vendor . && make up 6 | tls: 7 | mkcert -cert-file .docker/traefik/certs/local-cert.pem -key-file .docker/traefik/certs/local-key.pem "podlodka.localhost" "*.podlodka.localhost" && mkcert -install 8 | up: 9 | docker-compose up -d 10 | down: 11 | docker-compose down --volumes 12 | build: 13 | docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) -f .docker/php/Dockerfile . 14 | lint: 15 | docker run --rm -i hadolint/hadolint < .docker/php/Dockerfile 16 | blint1: 17 | docker run --rm -i hadolint/hadolint < .docker/examples/badlint/Dockerfile 18 | blint2: 19 | docker run --rm -i hadolint/hadolint < .docker/examples/badlint/Dockerfile1 20 | dive: 21 | dive crew-cron:latest 22 | trivy: 23 | trivy image crew-cron:latest 24 | mail: 25 | docker-compose exec cron php app.php mail Name 26 | pdf: 27 | docker-compose exec cron php app.php pdf https://wikipedia.org 28 | target1: 29 | docker build --target=app_php --tag=crew:0.0.1 -f .docker/php/Dockerfile . 30 | target2: 31 | docker build --target=app_php_dev --tag=crew:0.0.1 -f .docker/php/Dockerfile . 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Podlodka PHP Crew #2 Livecoding Example: "Just Dockerize it!" 2 | 3 | ## Launching the Example 4 | 5 | 1) Install Docker (tested on Docker version 20.10.22 and Docker Compose version v2.15.1). 6 | 2) Ensure that ports 80, 443, and 5432 are not already allocated (Traefik requires them in the current configuration). 7 | 2) Install [mkcert](https://github.com/FiloSottile/mkcert) 8 | 3) Run `make init`. This will: 9 | - copy `.env` and `.env.app` from samples 10 | - generate certificates 11 | - run Docker with the `docker-compose.yml` configuration (without volumes) 12 | - copy the `vendor` directory from the running PHP container to the host 13 | - run Docker with both the `docker-compose.yml` and `docker-compose.local.yml` configurations (with volumes) 14 | 4) Visit [http://localhost:8082/](http://localhost:8082/) to view the Traefik admin dashboard. 15 | 5) Visit [https://podlodka.localhost/](https://podlodka.localhost/) to view the application. 16 | 6) Visit [https://mail.podlodka.localhost/](https://mail.podlodka.localhost/) to view the Mailhog admin. 17 | 7) Visit [https://s3.podlodka.localhost/](https://s3.podlodka.localhost/) to view the Minio admin (use `AWS_KEY` and `AWS_SECRET` from `.env` as credentials) 18 | 8) Create a `podlodka` bucket in Minio if you plan to test the code later. 19 | 20 | #### To test linting with Hadolint, run: 21 | ```bash 22 | make lint 23 | make blint1 24 | make blint2 25 | ``` 26 | 27 | 28 | #### To test security, run: 29 | ```bash 30 | make trivy 31 | ``` 32 | 33 | 34 | #### To check image layers, run: 35 | ```bash 36 | make dive 37 | ``` 38 | 39 | 40 | #### To test mail sending, run: 41 | ```bash 42 | make mail 43 | ``` 44 | 45 | 46 | #### To test PDF generation + S3 combo (don't forget to create the podlodka bucket first in Minio), run: 47 | ```bash 48 | make pdf 49 | ``` 50 | 51 | #### To turn off the local setup, run: 52 | ```bash 53 | make down 54 | ``` 55 | -------------------------------------------------------------------------------- /app.php: -------------------------------------------------------------------------------- 1 | __DIR__], 23 | exceptionHandler: Handler::class, 24 | )->run(); 25 | 26 | if ($app === null) { 27 | exit(255); 28 | } 29 | 30 | $code = (int)$app->serve(); 31 | exit($code); 32 | -------------------------------------------------------------------------------- /app/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexndr-novikov/podlodka-php-crew-2/3c7f30ee682ea1bac6fb12c27c0ac36928b97f34/app/.DS_Store -------------------------------------------------------------------------------- /app/config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_STORAGE', 'local'), 14 | 15 | /** 16 | * Aliases, if you want to use domain specific storages. 17 | */ 18 | 'aliases' => [ 19 | 'user-data' => 'localMemory', 20 | ], 21 | 22 | /** 23 | * Here you may define all of the cache "storages" for your application as well as their types. 24 | */ 25 | 'storages' => [ 26 | 27 | 'local' => [ 28 | // Alias for ArrayStorage type 29 | 'type' => 'array', 30 | ], 31 | 32 | 'localMemory' => [ 33 | 'type' => ArrayStorage::class, 34 | ], 35 | 36 | 'file' => [ 37 | // Alias for FileStorage type 38 | 'type' => 'file', 39 | 'path' => directory('runtime') . 'cache', 40 | ], 41 | 42 | 'redis' => [ 43 | 'type' => 'roadrunner', 44 | 'driver' => 'redis', 45 | ], 46 | 47 | 'rr-local' => [ 48 | 'type' => 'roadrunner', 49 | 'driver' => 'local', 50 | ], 51 | 52 | ], 53 | 54 | /** 55 | * Aliases for storage types 56 | */ 57 | 'typeAliases' => [ 58 | 'array' => ArrayStorage::class, 59 | 'file' => FileStorage::class, 60 | ], 61 | ]; 62 | -------------------------------------------------------------------------------- /app/config/cycle.php: -------------------------------------------------------------------------------- 1 | [ 10 | /** 11 | * true (Default) - Schema will be stored in a cache after compilation. 12 | * It won't be changed after entity modification. Use `php app.php cycle` to update schema. 13 | * 14 | * false - Schema won't be stored in a cache after compilation. 15 | * It will be automatically changed after entity modification. (Development mode) 16 | */ 17 | 'cache' => env('CYCLE_SCHEMA_CACHE', true), 18 | 19 | /** 20 | * The CycleORM provides the ability to manage default settings for 21 | * every schema with not defined segments 22 | */ 23 | 'defaults' => [ 24 | // SchemaInterface::MAPPER => \Cycle\ORM\Mapper\Mapper::class, 25 | // SchemaInterface::REPOSITORY => \Cycle\ORM\Select\Repository::class, 26 | // SchemaInterface::SCOPE => null, 27 | // SchemaInterface::TYPECAST_HANDLER => [ 28 | // \Cycle\ORM\Parser\Typecast::class 29 | // ], 30 | ], 31 | 32 | 'collections' => [ 33 | 'default' => 'doctrine', 34 | 'factories' => [ 35 | 'array' => new ArrayCollectionFactory(), 36 | 'doctrine' => new DoctrineCollectionFactory(), 37 | ], 38 | ], 39 | 40 | /** 41 | * Schema generators (Optional) 42 | * null (default) - Will be used schema generators defined in bootloaders 43 | */ 44 | 'generators' => null, 45 | 46 | // 'generators' => [ 47 | // \Cycle\Annotated\Embeddings::class, 48 | // \Cycle\Annotated\Entities::class, 49 | // \Cycle\Annotated\MergeColumns::class, 50 | // \Cycle\Schema\Generator\ResetTables::class, 51 | // \Cycle\Schema\Generator\GenerateRelations::class, 52 | // \Cycle\Schema\Generator\ValidateEntities::class, 53 | // \Cycle\Schema\Generator\RenderTables::class, 54 | // \Cycle\Schema\Generator\RenderRelations::class, 55 | // \Cycle\Annotated\TableInheritance::class, 56 | // \Cycle\Annotated\MergeIndexes::class 57 | // \Cycle\Schema\Generator\GenerateTypecast::class, 58 | // ], 59 | ], 60 | 61 | 'warmup' => env('CYCLE_SCHEMA_WARMUP', false), 62 | 63 | /** 64 | * Custom relation types for entities 65 | */ 66 | 'customRelations' => [ 67 | // \Cycle\ORM\Relation::EMBEDDED => [ 68 | // \Cycle\ORM\Config\RelationConfig::LOADER => \Cycle\ORM\Select\Loader\EmbeddedLoader::class, 69 | // \Cycle\ORM\Config\RelationConfig::RELATION => \Cycle\ORM\Relation\Embedded::class, 70 | // ] 71 | ], 72 | ]; 73 | -------------------------------------------------------------------------------- /app/config/database.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'default' => null, 10 | 'drivers' => [ 11 | 'runtime' => 'stdout', 12 | 'postgresql' => 'stdout', 13 | ], 14 | ], 15 | 16 | /** 17 | * Default database connection 18 | */ 19 | 'default' => 'default', 20 | 21 | /** 22 | * The Spiral/Database module provides support to manage multiple databases 23 | * in one application, use read/write connections and logically separate 24 | * multiple databases within one connection using prefixes. 25 | * 26 | * To register a new database simply add a new one into 27 | * "databases" section below. 28 | */ 29 | 'databases' => [ 30 | 'default' => [ 31 | 'driver' => 'postgresql', 32 | ], 33 | ], 34 | 35 | /** 36 | * Each database instance must have an associated connection object. 37 | * Connections used to provide low-level functionality and wrap different 38 | * database drivers. To register a new connection you have to specify 39 | * the driver class and its connection options. 40 | */ 41 | 'drivers' => [ 42 | 'runtime' => new Config\SQLiteDriverConfig( 43 | connection: new Config\SQLite\MemoryConnectionConfig(), 44 | queryCache: true 45 | ), 46 | 'postgresql' => new Config\Postgres\TcpConnectionConfig( 47 | env('DB_NAME', ""), 48 | env('DB_HOST', ""), 49 | 5432, 50 | env('DB_USER', ""), 51 | env('DB_PASSWORD', ""), 52 | ) 53 | // ... 54 | ], 55 | ]; 56 | -------------------------------------------------------------------------------- /app/config/distribution.php: -------------------------------------------------------------------------------- 1 | [ 5 | // ... 6 | 'default' => [ 7 | // 8 | // Required key of resolver type. 9 | // For S3, it must contain the "s3" string value. 10 | // 11 | 'type' => 's3', 12 | 13 | // 14 | // Required string key of S3 region like "eu-north-1". 15 | // 16 | // Region can be found on "Amazon S3" page here: 17 | // - https://s3.console.aws.amazon.com/s3/home 18 | // 19 | 'region' => env('S3_REGION'), 20 | 21 | // 22 | // Optional key of S3 API version. 23 | // 24 | 'version' => env('S3_VERSION', 'latest'), 25 | 26 | // 27 | // Required key of S3 bucket. 28 | // 29 | // Bucket name can be found on "Amazon S3" page here: 30 | // - https://s3.console.aws.amazon.com/s3/home 31 | // 32 | 'bucket' => env('S3_BUCKET'), 33 | 34 | // 35 | // Required key of S3 credentials key like "AAAABBBBCCCCDDDDEEEE". 36 | // 37 | // Credentials key can be found on "Security Credentials" page here: 38 | // - https://console.aws.amazon.com/iam/home#/security_credentials 39 | // 40 | 'key' => env('S3_KEY'), 41 | 42 | // 43 | // Required key of S3 credentials private key. 44 | // This must be a private key string value or a path to a private key file. 45 | // 46 | // Identifier can be also found on "Security Credentials" page here: 47 | // - https://console.aws.amazon.com/iam/home#/security_credentials 48 | // 49 | 'secret' => env('S3_SECRET'), 50 | 51 | // 52 | // Optional key of S3 credentials token. 53 | // 54 | 'token' => env('S3_TOKEN', null), 55 | 56 | // 57 | // Optional key of S3 credentials expiration time. 58 | // 59 | 'expires' => env('S3_EXPIRES', null), 60 | 61 | // 62 | // Optional key of S3 API endpoint URI. 63 | // 64 | // 'endpoint' => env('S3_ENDPOINT', null), 65 | 'endpoint' => "https://s3.podlodka.localhost", 66 | 67 | // 68 | // Optional key of S3 API file prefixes. 69 | // This must contain string like "path/to/directory". 70 | // 71 | // In this case, this prefix will be added for each file when 72 | // generating url. 73 | // 74 | 'prefix' => env('S3_PREFIX'), 75 | 76 | // 77 | // Optional additional S3 options. 78 | // For example, option "use_path_style_endpoint" is required to work 79 | // with a Minio S3 Server. 80 | // 81 | // Note: This "options" section is available since framework >= 2.8.6 82 | // 83 | 'options' => [ 84 | 'use_path_style_endpoint' => true, 85 | ] 86 | ], 87 | ] 88 | ]; 89 | -------------------------------------------------------------------------------- /app/config/grpc.php: -------------------------------------------------------------------------------- 1 | directory('root') . '/app', 11 | 12 | /** 13 | * Base namespace for generated proto files. 14 | * Default: null 15 | */ 16 | // 'namespace' => '\GRPC', 17 | 18 | /** 19 | * Root path for all proto files in which imports will be searched. 20 | * Default: null 21 | */ 22 | // 'servicesBasePath' => directory('root') . '/proto', 23 | 24 | /** 25 | * Path to protoc-gen-php-grpc library. 26 | * You can download the binary here: https://github.com/roadrunner-server/roadrunner/releases 27 | * Default: null 28 | */ 29 | // 'binaryPath' => directory('root').'/bin/protoc-gen-php-grpc', 30 | 31 | /** 32 | * Paths to proto files, that should be compiled into PHP by "grpc:generate" console command. 33 | */ 34 | 'services' => [ 35 | // directory('root').'proto/echo.proto', 36 | ], 37 | ]; 38 | -------------------------------------------------------------------------------- /app/config/mailer.php: -------------------------------------------------------------------------------- 1 | env('MAILER_DSN', 'smtp://user:pass@mailhog:25'), 11 | 12 | /** 13 | * Global "From" Address 14 | */ 15 | 'from' => env('MAILER_FROM', 'Spiral '), 16 | 17 | /** 18 | * A queue connection in that any email messages will be pushed. 19 | */ 20 | 'queueConnection' => env('MAILER_QUEUE_CONNECTION'), 21 | 'queue' => env('MAILER_QUEUE', 'local'), 22 | ]; 23 | -------------------------------------------------------------------------------- /app/config/migration.php: -------------------------------------------------------------------------------- 1 | directory('app') . 'migrations/', 10 | 11 | /** 12 | * Table name to store information about migrations status (per database) 13 | */ 14 | 'table' => 'migrations', 15 | 16 | /** 17 | * When set to true no confirmation will be requested on migration run. 18 | */ 19 | 'safe' => env('APP_ENV') === 'local', 20 | ]; 21 | -------------------------------------------------------------------------------- /app/config/monolog.php: -------------------------------------------------------------------------------- 1 | env('MONOLOG_DEFAULT_CHANNEL', 'default'), 15 | 16 | /** 17 | * Monolog supports the logging levels described by RFC 5424. 18 | * 19 | * @see https://github.com/Seldaek/monolog/blob/main/doc/01-usage.md#log-levels 20 | */ 21 | 'globalLevel' => Logger::toMonologLevel(env('MONOLOG_DEFAULT_LEVEL', Logger::DEBUG)), 22 | 23 | /** 24 | * @see https://github.com/Seldaek/monolog/blob/main/doc/02-handlers-formatters-processors.md#handlers 25 | */ 26 | 'handlers' => [ 27 | 'default' => [ 28 | [ 29 | 'class' => 'log.rotate', 30 | 'options' => [ 31 | 'filename' => directory('runtime') . 'logs/app.log', 32 | 'level' => Logger::DEBUG, 33 | ], 34 | ], 35 | ], 36 | 'stderr' => [ 37 | ErrorLogHandler::class, 38 | ], 39 | 'stdout' => [ 40 | [ 41 | 'class' => SyslogHandler::class, 42 | 'options' => [ 43 | 'ident' => 'app', 44 | 'facility' => LOG_USER, 45 | ], 46 | ], 47 | ], 48 | ], 49 | 50 | /** 51 | * Processors allows adding extra data for all records. 52 | * 53 | * @see https://github.com/Seldaek/monolog/blob/main/doc/02-handlers-formatters-processors.md#processors 54 | */ 55 | 'processors' => [ 56 | 'default' => [ 57 | // ... 58 | ], 59 | 'stdout' => [ 60 | [ 61 | 'class' => PsrLogMessageProcessor::class, 62 | 'options' => [ 63 | 'dateFormat' => 'Y-m-d\TH:i:s.uP', 64 | ], 65 | ], 66 | ], 67 | ], 68 | ]; 69 | -------------------------------------------------------------------------------- /app/config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'sync'), 17 | 18 | /** 19 | * Aliases for queue connections, if you want to use domain specific queues 20 | */ 21 | 'aliases' => [ 22 | // 'mail-queue' => 'roadrunner', 23 | // 'rating-queue' => 'sync', 24 | ], 25 | 26 | /** 27 | * Queue connections 28 | * Drivers: "sync", "roadrunner" 29 | */ 30 | 'connections' => [ 31 | 'sync' => [ 32 | // Job will be handled immediately without queueing 33 | 'driver' => 'sync', 34 | ], 35 | 'roadrunner' => [ 36 | 'driver' => 'roadrunner', 37 | 'default' => 'memory', 38 | 'pipelines' => [ 39 | 'memory' => [ 40 | 'connector' => new MemoryCreateInfo('local'), 41 | // Run consumer for this pipeline on startup (by default) 42 | // You can pause consumer for this pipeline via console command 43 | // php app.php queue:pause local 44 | 'consume' => true, 45 | ], 46 | // 'amqp' => [ 47 | // 'connector' => new AMQPCreateInfo('bus', ...), 48 | // // Don't consume jobs for this pipeline on start 49 | // // You can run consumer for this pipeline via console command 50 | // // php app.php queue:resume local 51 | // 'consume' => false 52 | // ], 53 | // 54 | // 'beanstalk' => [ 55 | // 'connector' => new BeanstalkCreateInfo('bus', ...), 56 | // ], 57 | // 58 | // 'sqs' => [ 59 | // 'connector' => new SQSCreateInfo('amazon', ...), 60 | // ], 61 | ], 62 | ], 63 | ], 64 | 65 | 'driverAliases' => [ 66 | 'sync' => SyncDriver::class, 67 | 'roadrunner' => Queue::class, 68 | ], 69 | 70 | 'registry' => [ 71 | 'handlers' => [], 72 | ], 73 | ]; 74 | -------------------------------------------------------------------------------- /app/config/scaffolder.php: -------------------------------------------------------------------------------- 1 | 'App', 10 | ]; 11 | -------------------------------------------------------------------------------- /app/config/session.php: -------------------------------------------------------------------------------- 1 | (int)env('SESSION_LIFETIME', 86400), 10 | 'cookie' => env('SESSION_COOKIE', 'sid'), 11 | 'secure' => true, 12 | 'sameSite' => null, 13 | 'handler' => new Autowire( 14 | FileHandler::class, 15 | [ 16 | 'directory' => directory('runtime') . 'session', 17 | 'lifetime' => (int)env('SESSION_LIFETIME', 86400), 18 | ] 19 | ), 20 | ]; 21 | -------------------------------------------------------------------------------- /app/config/storage.php: -------------------------------------------------------------------------------- 1 | [ 4 | 's3' => [ 5 | // 6 | // Server type name. For a S3 server, this value must be a string 7 | // value "s3" or "s3-async". 8 | // 9 | 'adapter' => 's3', 10 | 11 | // 12 | // Required string key of S3 region like "eu-north-1". 13 | // 14 | // Region can be found on "Amazon S3" page here: 15 | // - https://s3.console.aws.amazon.com/s3/home 16 | // 17 | 'region' => env('S3_REGION'), 18 | 19 | // 20 | // Optional key of S3 API version. 21 | // 22 | 'version' => env('S3_VERSION', 'latest'), 23 | 24 | // 25 | // Required key of S3 bucket. 26 | // 27 | // Bucket name can be found on "Amazon S3" page here: 28 | // - https://s3.console.aws.amazon.com/s3/home 29 | // 30 | 'bucket' => env('S3_BUCKET'), 31 | 32 | // 33 | // Required key of S3 credentials key like "AAAABBBBCCCCDDDDEEEE". 34 | // 35 | // Credentials key can be found on "Security Credentials" page here: 36 | // - https://console.aws.amazon.com/iam/home#/security_credentials 37 | // 38 | 'key' => env('S3_KEY'), 39 | 40 | // 41 | // Required key of S3 credentials private key. 42 | // This must be a private key string value or a path to a private key file. 43 | // 44 | // Identifier can be also found on "Security Credentials" page here: 45 | // - https://console.aws.amazon.com/iam/home#/security_credentials 46 | // 47 | 'secret' => env('S3_SECRET'), 48 | 49 | // 50 | // Optional key of S3 credentials token. 51 | // 52 | 'token' => env('S3_TOKEN', null), 53 | 54 | // 55 | // Optional key of S3 credentials expiration time. 56 | // 57 | 'expires' => env('S3_EXPIRES', null), 58 | 59 | // 60 | // Optional key of S3 files visibility. Visibility is "public" 61 | // by default. 62 | // 63 | 'visibility' => env('S3_VISIBILITY', 'public'), 64 | 65 | // 66 | // For buckets that use S3 servers, you can add a directory 67 | // prefix. 68 | // 69 | 'prefix' => '', 70 | 71 | // 72 | // Optional key of S3 API endpoint URI. This value is required when 73 | // using a server other than Amazon. 74 | // 75 | 'endpoint' => env('S3_ENDPOINT', null), 76 | 77 | // 78 | // Optional additional S3 options. 79 | // For example, option "use_path_style_endpoint" is required to work 80 | // with a Minio S3 Server. 81 | // 82 | // Note: This "options" section is available since framework >= 2.8.5 83 | // See also https://github.com/spiral/framework/issues/416 84 | // 85 | 'options' => [ 86 | 'use_path_style_endpoint' => true, 87 | ] 88 | ], 89 | ], 90 | 91 | 'buckets' => [ 92 | 'podlodka' => [ 93 | // 94 | // Relation to an existing S3 server. Note that all further bucket 95 | // options are applicable only for this (i.e. s3 or s3-async) server 96 | // type. 97 | // 98 | 'server' => 's3', 99 | 100 | // 101 | // The visibility value for a specific bucket type. Although you can 102 | // specify server-wide visibility, you can also override this value 103 | // for a specific bucket type. 104 | // 105 | 'visibility' => env('S3_VISIBILITY', 'public'), 106 | 107 | // 108 | // In case you want to use another bucket using the main 109 | // server settings, you can redefine it by specifying the 110 | // appropriate configuration key. 111 | // 112 | 'bucket' => env('S3_BUCKET', null), 113 | 114 | // 115 | // If the new bucket is in a different region, you can also 116 | // override this value. 117 | // 118 | 'region' => env('S3_REGION', null), 119 | 120 | // 121 | // A similar thing can be done with the directory prefix in cases 122 | // where a particular bucket must refer to some other root directory. 123 | // 124 | 'prefix' => env('S3_PREFIX', null), 125 | ] 126 | ] 127 | ]; 128 | -------------------------------------------------------------------------------- /app/config/views/stempler.php: -------------------------------------------------------------------------------- 1 | [ 13 | // available Blade-style directives 14 | Directive\PHPDirective::class, 15 | Directive\RouteDirective::class, 16 | Directive\LoopDirective::class, 17 | Directive\JsonDirective::class, 18 | Directive\ConditionalDirective::class, 19 | Directive\ContainerDirective::class, 20 | ], 21 | 'processors' => [ 22 | // cache depended source processors (i.e. LocaleProcessor) 23 | Processor\ContextProcessor::class, 24 | ], 25 | 'visitors' => [ 26 | Builder::STAGE_PREPARE => [ 27 | // visitors to be invoked before transformations 28 | Visitor\DefineBlocks::class, 29 | Visitor\DefineAttributes::class, 30 | Visitor\DefineHidden::class, 31 | ], 32 | Builder::STAGE_TRANSFORM => [ 33 | // visitors to be invoked during transformations 34 | ], 35 | Builder::STAGE_FINALIZE => [ 36 | // visitors to be invoked on after the transformations is over 37 | Visitor\DefineStacks::class, 38 | Finalizer\StackCollector::class, 39 | ], 40 | Builder::STAGE_COMPILE => [ 41 | // visitors to be invoked on compilation stage 42 | ], 43 | ], 44 | ]; 45 | -------------------------------------------------------------------------------- /app/locale/ru/messages.en.php: -------------------------------------------------------------------------------- 1 | 'GitHub', 7 | 'Exception' => 'Страница ошибки', 8 | 'Create Queue Task' => 'Создать фоновую задачу', 9 | 'Application Metrics' => 'Prometheus метрики', 10 | 'Website and Documentation' => 'Документация', 11 | 'Welcome To Spiral' => 'Добро пожаловать', 12 | 'Welcome to Spiral Framework' => 'Вас приветствует Spiral Framework', 13 | 'This view file is located in' => 'Данный шаблон находится в файле', 14 | 'and rendered by' => 'и вызван контроллером', 15 | 'Access Forbidden' => 'Доступ запрещен', 16 | 'Page not found' => 'Страница не найдена', 17 | 'Something went wrong' => 'Что-то пошло не так', 18 | 'Error code' => 'Код ошибки', 19 | ]; 20 | -------------------------------------------------------------------------------- /app/migrations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexndr-novikov/podlodka-php-crew-2/3c7f30ee682ea1bac6fb12c27c0ac36928b97f34/app/migrations/.gitignore -------------------------------------------------------------------------------- /app/o.txt: -------------------------------------------------------------------------------- 1 | phpinfo() 2 | PHP Version => 8.2.3 3 | 4 | System => Linux 40d66087d6bd 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 5 | Build Date => Feb 14 2023 21:12:02 6 | Build System => Linux 60816e673574 5.10.0-19-cloud-arm64 #1 SMP Debian 5.10.149-1 (2022-10-17) aarch64 GNU/Linux 7 | Configure Command => './configure' '--build=aarch64-linux-musl' '--with-config-file-path=/usr/local/etc/php' '--with-config-file-scan-dir=/usr/local/etc/php/conf.d' '--enable-option-checking=fatal' '--with-mhash' '--with-pic' '--enable-ftp' '--enable-mbstring' '--enable-mysqlnd' '--with-password-argon2' '--with-sodium=shared' '--with-pdo-sqlite=/usr' '--with-sqlite3=/usr' '--with-curl' '--with-iconv=/usr' '--with-openssl' '--with-readline' '--with-zlib' '--enable-phpdbg' '--enable-phpdbg-readline' '--with-pear' 'build_alias=aarch64-linux-musl' 8 | Server API => Command Line Interface 9 | Virtual Directory Support => disabled 10 | Configuration File (php.ini) Path => /usr/local/etc/php 11 | Loaded Configuration File => (none) 12 | Scan this dir for additional .ini files => /usr/local/etc/php/conf.d 13 | Additional .ini files parsed => /usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini, 14 | /usr/local/etc/php/conf.d/docker-php-ext-exif.ini, 15 | /usr/local/etc/php/conf.d/docker-php-ext-intl.ini, 16 | /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini, 17 | /usr/local/etc/php/conf.d/docker-php-ext-pcntl.ini, 18 | /usr/local/etc/php/conf.d/docker-php-ext-sockets.ini, 19 | /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini, 20 | /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini, 21 | /usr/local/etc/php/conf.d/docker-php-ext-xsl.ini, 22 | /usr/local/etc/php/conf.d/docker-php-ext-zip.ini 23 | 24 | PHP API => 20220829 25 | PHP Extension => 20220829 26 | Zend Extension => 420220829 27 | Zend Extension Build => API420220829,NTS 28 | PHP Extension Build => API20220829,NTS 29 | Debug Build => no 30 | Thread Safety => disabled 31 | Zend Signal Handling => enabled 32 | Zend Memory Manager => enabled 33 | Zend Multibyte Support => provided by mbstring 34 | IPv6 Support => enabled 35 | DTrace Support => disabled 36 | 37 | Registered PHP Streams => https, ftps, compress.zlib, php, file, glob, data, http, ftp, phar, zip 38 | Registered Stream Socket Transports => tcp, udp, unix, udg, ssl, tls, tlsv1.0, tlsv1.1, tlsv1.2, tlsv1.3 39 | Registered Stream Filters => zlib.*, convert.iconv.*, string.rot13, string.toupper, string.tolower, convert.*, consumed, dechunk 40 | 41 | This program makes use of the Zend Scripting Language Engine: 42 | Zend Engine v4.2.3, Copyright (c) Zend Technologies 43 | with Zend OPcache v8.2.3, Copyright (c), by Zend Technologies 44 | with Xdebug v3.2.0, Copyright (c) 2002-2022, by Derick Rethans 45 | 46 | 47 | _______________________________________________________________________ 48 | 49 | 50 | Configuration 51 | 52 | bcmath 53 | 54 | BCMath support => enabled 55 | 56 | Directive => Local Value => Master Value 57 | bcmath.scale => 0 => 0 58 | 59 | Core 60 | 61 | PHP Version => 8.2.3 62 | 63 | Directive => Local Value => Master Value 64 | allow_url_fopen => On => On 65 | allow_url_include => Off => Off 66 | arg_separator.input => & => & 67 | arg_separator.output => & => & 68 | auto_append_file => no value => no value 69 | auto_globals_jit => On => On 70 | auto_prepend_file => no value => no value 71 | browscap => no value => no value 72 | default_charset => UTF-8 => UTF-8 73 | default_mimetype => text/html => text/html 74 | disable_classes => no value => no value 75 | disable_functions => no value => no value 76 | display_errors => STDOUT => STDOUT 77 | display_startup_errors => On => On 78 | doc_root => no value => no value 79 | docref_ext => no value => no value 80 | docref_root => no value => no value 81 | enable_dl => On => On 82 | enable_post_data_reading => On => On 83 | error_append_string => no value => no value 84 | error_log => no value => no value 85 | error_log_mode => 0644 => 0644 86 | error_prepend_string => no value => no value 87 | error_reporting => no value => no value 88 | expose_php => On => On 89 | extension_dir => /usr/local/lib/php/extensions/no-debug-non-zts-20220829 => /usr/local/lib/php/extensions/no-debug-non-zts-20220829 90 | fiber.stack_size => no value => no value 91 | file_uploads => On => On 92 | hard_timeout => 2 => 2 93 | highlight.comment => #FF8000 => #FF8000 94 | highlight.default => #0000BB => #0000BB 95 | highlight.html => #000000 => #000000 96 | highlight.keyword => #007700 => #007700 97 | highlight.string => #DD0000 => #DD0000 98 | html_errors => Off => Off 99 | ignore_repeated_errors => Off => Off 100 | ignore_repeated_source => Off => Off 101 | ignore_user_abort => Off => Off 102 | implicit_flush => On => On 103 | include_path => .:/usr/local/lib/php => .:/usr/local/lib/php 104 | input_encoding => no value => no value 105 | internal_encoding => no value => no value 106 | log_errors => Off => Off 107 | mail.add_x_header => Off => Off 108 | mail.force_extra_parameters => no value => no value 109 | mail.log => no value => no value 110 | max_execution_time => 0 => 0 111 | max_file_uploads => 20 => 20 112 | max_input_nesting_level => 64 => 64 113 | max_input_time => -1 => -1 114 | max_input_vars => 1000 => 1000 115 | max_multipart_body_parts => -1 => -1 116 | memory_limit => 128M => 128M 117 | open_basedir => no value => no value 118 | output_buffering => 0 => 0 119 | output_encoding => no value => no value 120 | output_handler => no value => no value 121 | post_max_size => 8M => 8M 122 | precision => 14 => 14 123 | realpath_cache_size => 4096K => 4096K 124 | realpath_cache_ttl => 120 => 120 125 | register_argc_argv => On => On 126 | report_memleaks => On => On 127 | report_zend_debug => Off => Off 128 | request_order => no value => no value 129 | sendmail_from => no value => no value 130 | sendmail_path => /usr/sbin/sendmail -t -i => /usr/sbin/sendmail -t -i 131 | serialize_precision => -1 => -1 132 | short_open_tag => On => On 133 | SMTP => localhost => localhost 134 | smtp_port => 25 => 25 135 | sys_temp_dir => no value => no value 136 | syslog.facility => LOG_USER => LOG_USER 137 | syslog.filter => no-ctrl => no-ctrl 138 | syslog.ident => php => php 139 | unserialize_callback_func => no value => no value 140 | upload_max_filesize => 2M => 2M 141 | upload_tmp_dir => no value => no value 142 | user_dir => no value => no value 143 | user_ini.cache_ttl => 300 => 300 144 | user_ini.filename => .user.ini => .user.ini 145 | variables_order => EGPCS => EGPCS 146 | xmlrpc_error_number => 0 => 0 147 | xmlrpc_errors => Off => Off 148 | zend.assertions => 1 => 1 149 | zend.detect_unicode => On => On 150 | zend.enable_gc => On => On 151 | zend.exception_ignore_args => Off => Off 152 | zend.exception_string_param_max_len => 15 => 15 153 | zend.multibyte => Off => Off 154 | zend.script_encoding => no value => no value 155 | zend.signal_check => Off => Off 156 | 157 | ctype 158 | 159 | ctype functions => enabled 160 | 161 | curl 162 | 163 | cURL support => enabled 164 | cURL Information => 7.87.0 165 | Age => 10 166 | Features 167 | AsynchDNS => Yes 168 | CharConv => No 169 | Debug => No 170 | GSS-Negotiate => No 171 | IDN => No 172 | IPv6 => Yes 173 | krb4 => No 174 | Largefile => Yes 175 | libz => Yes 176 | NTLM => Yes 177 | NTLMWB => Yes 178 | SPNEGO => No 179 | SSL => Yes 180 | SSPI => No 181 | TLS-SRP => Yes 182 | HTTP2 => Yes 183 | GSSAPI => No 184 | KERBEROS5 => No 185 | UNIX_SOCKETS => Yes 186 | PSL => No 187 | HTTPS_PROXY => Yes 188 | MULTI_SSL => No 189 | BROTLI => Yes 190 | ALTSVC => Yes 191 | HTTP3 => No 192 | UNICODE => No 193 | ZSTD => No 194 | HSTS => Yes 195 | GSASL => No 196 | Protocols => dict, file, ftp, ftps, gopher, gophers, http, https, imap, imaps, mqtt, pop3, pop3s, rtsp, smb, smbs, smtp, smtps, telnet, tftp, ws, wss 197 | Host => aarch64-alpine-linux-musl 198 | SSL Version => OpenSSL/3.0.8 199 | ZLib Version => 1.2.13 200 | 201 | Directive => Local Value => Master Value 202 | curl.cainfo => no value => no value 203 | 204 | date 205 | 206 | date/time support => enabled 207 | timelib version => 2022.03 208 | "Olson" Timezone Database Version => 2022.7 209 | Timezone Database => internal 210 | Default timezone => UTC 211 | 212 | Directive => Local Value => Master Value 213 | date.default_latitude => 31.7667 => 31.7667 214 | date.default_longitude => 35.2333 => 35.2333 215 | date.sunrise_zenith => 90.833333 => 90.833333 216 | date.sunset_zenith => 90.833333 => 90.833333 217 | date.timezone => UTC => UTC 218 | 219 | dom 220 | 221 | DOM/XML => enabled 222 | DOM/XML API Version => 20031129 223 | libxml Version => 2.10.3 224 | HTML Support => enabled 225 | XPath Support => enabled 226 | XPointer Support => enabled 227 | Schema Support => enabled 228 | RelaxNG Support => enabled 229 | 230 | exif 231 | 232 | EXIF Support => enabled 233 | Supported EXIF Version => 0220 234 | Supported filetypes => JPEG, TIFF 235 | Multibyte decoding support using mbstring => enabled 236 | Extended EXIF tag formats => Canon, Casio, Fujifilm, Nikon, Olympus, Samsung, Panasonic, DJI, Sony, Pentax, Minolta, Sigma, Foveon, Kyocera, Ricoh, AGFA, Epson 237 | 238 | Directive => Local Value => Master Value 239 | exif.decode_jis_intel => JIS => JIS 240 | exif.decode_jis_motorola => JIS => JIS 241 | exif.decode_unicode_intel => UCS-2LE => UCS-2LE 242 | exif.decode_unicode_motorola => UCS-2BE => UCS-2BE 243 | exif.encode_jis => no value => no value 244 | exif.encode_unicode => ISO-8859-15 => ISO-8859-15 245 | 246 | fileinfo 247 | 248 | fileinfo support => enabled 249 | libmagic => 540 250 | 251 | filter 252 | 253 | Input Validation and Filtering => enabled 254 | 255 | Directive => Local Value => Master Value 256 | filter.default => unsafe_raw => unsafe_raw 257 | filter.default_flags => no value => no value 258 | 259 | ftp 260 | 261 | FTP support => enabled 262 | FTPS support => enabled 263 | 264 | hash 265 | 266 | hash support => enabled 267 | Hashing Engines => md2 md4 md5 sha1 sha224 sha256 sha384 sha512/224 sha512/256 sha512 sha3-224 sha3-256 sha3-384 sha3-512 ripemd128 ripemd160 ripemd256 ripemd320 whirlpool tiger128,3 tiger160,3 tiger192,3 tiger128,4 tiger160,4 tiger192,4 snefru snefru256 gost gost-crypto adler32 crc32 crc32b crc32c fnv132 fnv1a32 fnv164 fnv1a64 joaat murmur3a murmur3c murmur3f xxh32 xxh64 xxh3 xxh128 haval128,3 haval160,3 haval192,3 haval224,3 haval256,3 haval128,4 haval160,4 haval192,4 haval224,4 haval256,4 haval128,5 haval160,5 haval192,5 haval224,5 haval256,5 268 | 269 | MHASH support => Enabled 270 | MHASH API Version => Emulated Support 271 | 272 | iconv 273 | 274 | iconv support => enabled 275 | iconv implementation => libiconv 276 | iconv library version => 1.17 277 | 278 | Directive => Local Value => Master Value 279 | iconv.input_encoding => no value => no value 280 | iconv.internal_encoding => no value => no value 281 | iconv.output_encoding => no value => no value 282 | 283 | intl 284 | 285 | Internationalization support => enabled 286 | ICU version => 72.1 287 | ICU Data version => 72.1 288 | ICU Unicode version => 15.0 289 | 290 | Directive => Local Value => Master Value 291 | intl.default_locale => no value => no value 292 | intl.error_level => 0 => 0 293 | intl.use_exceptions => Off => Off 294 | 295 | json 296 | 297 | json support => enabled 298 | 299 | libxml 300 | 301 | libXML support => active 302 | libXML Compiled Version => 2.10.3 303 | libXML Loaded Version => 21003 304 | libXML streams => enabled 305 | 306 | mbstring 307 | 308 | Multibyte Support => enabled 309 | Multibyte string engine => libmbfl 310 | HTTP input encoding translation => disabled 311 | libmbfl version => 1.3.2 312 | 313 | mbstring extension makes use of "streamable kanji code filter and converter", which is distributed under the GNU Lesser General Public License version 2.1. 314 | 315 | Multibyte (japanese) regex support => enabled 316 | Multibyte regex (oniguruma) version => 6.9.8 317 | 318 | Directive => Local Value => Master Value 319 | mbstring.detect_order => no value => no value 320 | mbstring.encoding_translation => Off => Off 321 | mbstring.http_input => no value => no value 322 | mbstring.http_output => no value => no value 323 | mbstring.http_output_conv_mimetypes => ^(text/|application/xhtml\+xml) => ^(text/|application/xhtml\+xml) 324 | mbstring.internal_encoding => no value => no value 325 | mbstring.language => neutral => neutral 326 | mbstring.regex_retry_limit => 1000000 => 1000000 327 | mbstring.regex_stack_limit => 100000 => 100000 328 | mbstring.strict_detection => Off => Off 329 | mbstring.substitute_character => no value => no value 330 | 331 | mysqlnd 332 | 333 | mysqlnd => enabled 334 | Version => mysqlnd 8.2.3 335 | Compression => supported 336 | core SSL => supported 337 | extended SSL => supported 338 | Command buffer size => 4096 339 | Read buffer size => 32768 340 | Read timeout => 86400 341 | Collecting statistics => Yes 342 | Collecting memory statistics => No 343 | Tracing => n/a 344 | Loaded plugins => mysqlnd,debug_trace,auth_plugin_mysql_native_password,auth_plugin_mysql_clear_password,auth_plugin_caching_sha2_password,auth_plugin_sha256_password 345 | API Extensions => 346 | 347 | openssl 348 | 349 | OpenSSL support => enabled 350 | OpenSSL Library Version => OpenSSL 3.0.8 7 Feb 2023 351 | OpenSSL Header Version => OpenSSL 3.0.8 7 Feb 2023 352 | Openssl default config => /etc/ssl/openssl.cnf 353 | 354 | Directive => Local Value => Master Value 355 | openssl.cafile => no value => no value 356 | openssl.capath => no value => no value 357 | 358 | pcntl 359 | 360 | pcntl support => enabled 361 | 362 | pcre 363 | 364 | PCRE (Perl Compatible Regular Expressions) Support => enabled 365 | PCRE Library Version => 10.40 2022-04-14 366 | PCRE Unicode Version => 14.0.0 367 | PCRE JIT Support => enabled 368 | PCRE JIT Target => ARM-64 64bit (little endian + unaligned) 369 | 370 | Directive => Local Value => Master Value 371 | pcre.backtrack_limit => 1000000 => 1000000 372 | pcre.jit => On => On 373 | pcre.recursion_limit => 100000 => 100000 374 | 375 | PDO 376 | 377 | PDO support => enabled 378 | PDO drivers => sqlite 379 | 380 | pdo_sqlite 381 | 382 | PDO Driver for SQLite 3.x => enabled 383 | SQLite Library => 3.40.1 384 | 385 | Phar 386 | 387 | Phar: PHP Archive support => enabled 388 | Phar API version => 1.1.1 389 | Phar-based phar archives => enabled 390 | Tar-based phar archives => enabled 391 | ZIP-based phar archives => enabled 392 | gzip compression => enabled 393 | bzip2 compression => disabled (install ext/bz2) 394 | Native OpenSSL support => enabled 395 | 396 | 397 | Phar based on pear/PHP_Archive, original concept by Davey Shafik. 398 | Phar fully realized by Gregory Beaver and Marcus Boerger. 399 | Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle. 400 | Directive => Local Value => Master Value 401 | phar.cache_list => no value => no value 402 | phar.readonly => On => On 403 | phar.require_hash => On => On 404 | 405 | posix 406 | 407 | POSIX support => enabled 408 | 409 | random 410 | 411 | Version => 8.2.3 412 | 413 | readline 414 | 415 | Readline Support => enabled 416 | Readline library => 8.2 417 | 418 | Directive => Local Value => Master Value 419 | cli.pager => no value => no value 420 | cli.prompt => \b \> => \b \> 421 | 422 | Reflection 423 | 424 | Reflection => enabled 425 | 426 | session 427 | 428 | Session Support => enabled 429 | Registered save handlers => files user 430 | Registered serializer handlers => php_serialize php php_binary 431 | 432 | Directive => Local Value => Master Value 433 | session.auto_start => Off => Off 434 | session.cache_expire => 180 => 180 435 | session.cache_limiter => nocache => nocache 436 | session.cookie_domain => no value => no value 437 | session.cookie_httponly => Off => Off 438 | session.cookie_lifetime => 0 => 0 439 | session.cookie_path => / => / 440 | session.cookie_samesite => no value => no value 441 | session.cookie_secure => Off => Off 442 | session.gc_divisor => 100 => 100 443 | session.gc_maxlifetime => 1440 => 1440 444 | session.gc_probability => 1 => 1 445 | session.lazy_write => On => On 446 | session.name => PHPSESSID => PHPSESSID 447 | session.referer_check => no value => no value 448 | session.save_handler => files => files 449 | session.save_path => no value => no value 450 | session.serialize_handler => php => php 451 | session.sid_bits_per_character => 4 => 4 452 | session.sid_length => 32 => 32 453 | session.upload_progress.cleanup => On => On 454 | session.upload_progress.enabled => On => On 455 | session.upload_progress.freq => 1% => 1% 456 | session.upload_progress.min_freq => 1 => 1 457 | session.upload_progress.name => PHP_SESSION_UPLOAD_PROGRESS => PHP_SESSION_UPLOAD_PROGRESS 458 | session.upload_progress.prefix => upload_progress_ => upload_progress_ 459 | session.use_cookies => On => On 460 | session.use_only_cookies => On => On 461 | session.use_strict_mode => Off => Off 462 | session.use_trans_sid => Off => Off 463 | 464 | SimpleXML 465 | 466 | SimpleXML support => enabled 467 | Schema support => enabled 468 | 469 | sockets 470 | 471 | Sockets Support => enabled 472 | 473 | sodium 474 | 475 | sodium support => enabled 476 | libsodium headers version => 1.0.18 477 | libsodium library version => 1.0.18 478 | 479 | SPL 480 | 481 | SPL support => enabled 482 | Interfaces => OuterIterator, RecursiveIterator, SeekableIterator, SplObserver, SplSubject 483 | Classes => AppendIterator, ArrayIterator, ArrayObject, BadFunctionCallException, BadMethodCallException, CachingIterator, CallbackFilterIterator, DirectoryIterator, DomainException, EmptyIterator, FilesystemIterator, FilterIterator, GlobIterator, InfiniteIterator, InvalidArgumentException, IteratorIterator, LengthException, LimitIterator, LogicException, MultipleIterator, NoRewindIterator, OutOfBoundsException, OutOfRangeException, OverflowException, ParentIterator, RangeException, RecursiveArrayIterator, RecursiveCachingIterator, RecursiveCallbackFilterIterator, RecursiveDirectoryIterator, RecursiveFilterIterator, RecursiveIteratorIterator, RecursiveRegexIterator, RecursiveTreeIterator, RegexIterator, RuntimeException, SplDoublyLinkedList, SplFileInfo, SplFileObject, SplFixedArray, SplHeap, SplMinHeap, SplMaxHeap, SplObjectStorage, SplPriorityQueue, SplQueue, SplStack, SplTempFileObject, UnderflowException, UnexpectedValueException 484 | 485 | sqlite3 486 | 487 | SQLite3 support => enabled 488 | SQLite Library => 3.40.1 489 | 490 | Directive => Local Value => Master Value 491 | sqlite3.defensive => On => On 492 | sqlite3.extension_dir => no value => no value 493 | 494 | standard 495 | 496 | Dynamic Library Support => enabled 497 | Path to sendmail => /usr/sbin/sendmail -t -i 498 | 499 | Directive => Local Value => Master Value 500 | assert.active => On => On 501 | assert.bail => Off => Off 502 | assert.callback => no value => no value 503 | assert.exception => On => On 504 | assert.warning => On => On 505 | auto_detect_line_endings => Off => Off 506 | default_socket_timeout => 60 => 60 507 | from => no value => no value 508 | session.trans_sid_hosts => no value => no value 509 | session.trans_sid_tags => a=href,area=href,frame=src,form= => a=href,area=href,frame=src,form= 510 | unserialize_max_depth => 4096 => 4096 511 | url_rewriter.hosts => no value => no value 512 | url_rewriter.tags => form= => form= 513 | user_agent => no value => no value 514 | 515 | tokenizer 516 | 517 | Tokenizer Support => enabled 518 | 519 | xdebug 520 | 521 | __ __ _ _ 522 | \ \ / / | | | | 523 |  \ V / __| | ___| |__ _ _ __ _ 524 |  > < / _` |/ _ \ '_ \| | | |/ _` | 525 |  / . \ (_| | __/ |_) | |_| | (_| | 526 | /_/ \_\__,_|\___|_.__/ \__,_|\__, | 527 |  __/ | 528 |  |___/ 529 | 530 | Version => 3.2.0 531 | Support Xdebug on Patreon, GitHub, or as a business: https://xdebug.org/support 532 | 533 | Enabled Features (through 'XDEBUG_MODE' env variable) 534 | Feature => Enabled/Disabled 535 | Development Helpers => ✘ disabled 536 | Coverage => ✘ disabled 537 | GC Stats => ✘ disabled 538 | Profiler => ✘ disabled 539 | Step Debugger => ✔ enabled 540 | Tracing => ✘ disabled 541 | 542 | Optional Features 543 | Compressed File Support => no 544 | Clock Source => clock_gettime 545 | 'xdebug://gateway' pseudo-host support => yes 546 | 'xdebug://nameserver' pseudo-host support => no 547 | Systemd Private Temp Directory => not enabled 548 | 549 | Debugger => enabled 550 | IDE Key => 551 | 552 | Directive => Local Value => Master Value 553 | xdebug.auto_trace => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 554 | xdebug.cli_color => 0 => 0 555 | xdebug.client_discovery_header => HTTP_X_FORWARDED_FOR,REMOTE_ADDR => HTTP_X_FORWARDED_FOR,REMOTE_ADDR 556 | xdebug.client_host => localhost => localhost 557 | xdebug.client_port => 9003 => 9003 558 | xdebug.cloud_id => no value => no value 559 | xdebug.collect_assignments => Off => Off 560 | xdebug.collect_includes => (setting removed in Xdebug 3) => (setting removed in Xdebug 3) 561 | xdebug.collect_params => (setting removed in Xdebug 3) => (setting removed in Xdebug 3) 562 | xdebug.collect_return => Off => Off 563 | xdebug.collect_vars => (setting removed in Xdebug 3) => (setting removed in Xdebug 3) 564 | xdebug.connect_timeout_ms => 200 => 200 565 | xdebug.coverage_enable => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 566 | xdebug.default_enable => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 567 | xdebug.discover_client_host => Off => Off 568 | xdebug.dump.COOKIE => no value => no value 569 | xdebug.dump.ENV => no value => no value 570 | xdebug.dump.FILES => no value => no value 571 | xdebug.dump.GET => no value => no value 572 | xdebug.dump.POST => no value => no value 573 | xdebug.dump.REQUEST => no value => no value 574 | xdebug.dump.SERVER => no value => no value 575 | xdebug.dump.SESSION => no value => no value 576 | xdebug.dump_globals => On => On 577 | xdebug.dump_once => On => On 578 | xdebug.dump_undefined => Off => Off 579 | xdebug.file_link_format => no value => no value 580 | xdebug.filename_format => no value => no value 581 | xdebug.force_display_errors => Off => Off 582 | xdebug.force_error_reporting => 0 => 0 583 | xdebug.gc_stats_enable => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 584 | xdebug.gc_stats_output_dir => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 585 | xdebug.gc_stats_output_name => gcstats.%p => gcstats.%p 586 | xdebug.halt_level => 0 => 0 587 | xdebug.idekey => no value => no value 588 | xdebug.log => no value => no value 589 | xdebug.log_level => 7 => 7 590 | xdebug.max_nesting_level => 256 => 256 591 | xdebug.max_stack_frames => -1 => -1 592 | xdebug.mode => develop => develop 593 | xdebug.output_dir => /tmp => /tmp 594 | xdebug.overload_var_dump => (setting removed in Xdebug 3) => (setting removed in Xdebug 3) 595 | xdebug.profiler_append => Off => Off 596 | xdebug.profiler_enable => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 597 | xdebug.profiler_enable_trigger => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 598 | xdebug.profiler_enable_trigger_value => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 599 | xdebug.profiler_output_dir => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 600 | xdebug.profiler_output_name => cachegrind.out.%p => cachegrind.out.%p 601 | xdebug.remote_autostart => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 602 | xdebug.remote_connect_back => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 603 | xdebug.remote_enable => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 604 | xdebug.remote_host => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 605 | xdebug.remote_log => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 606 | xdebug.remote_log_level => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 607 | xdebug.remote_mode => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 608 | xdebug.remote_port => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 609 | xdebug.remote_timeout => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 610 | xdebug.scream => Off => Off 611 | xdebug.show_error_trace => Off => Off 612 | xdebug.show_exception_trace => Off => Off 613 | xdebug.show_local_vars => Off => Off 614 | xdebug.show_mem_delta => (setting removed in Xdebug 3) => (setting removed in Xdebug 3) 615 | xdebug.start_upon_error => default => default 616 | xdebug.start_with_request => default => default 617 | xdebug.trace_enable_trigger => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 618 | xdebug.trace_enable_trigger_value => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 619 | xdebug.trace_format => 0 => 0 620 | xdebug.trace_options => 0 => 0 621 | xdebug.trace_output_dir => (setting renamed in Xdebug 3) => (setting renamed in Xdebug 3) 622 | xdebug.trace_output_name => trace.%c => trace.%c 623 | xdebug.trigger_value => no value => no value 624 | xdebug.use_compression => 0 => 0 625 | xdebug.var_display_max_children => 128 => 128 626 | xdebug.var_display_max_data => 512 => 512 627 | xdebug.var_display_max_depth => 3 => 3 628 | 629 | xml 630 | 631 | XML Support => active 632 | XML Namespace Support => active 633 | libxml2 Version => 2.10.3 634 | 635 | xmlreader 636 | 637 | XMLReader => enabled 638 | 639 | xmlwriter 640 | 641 | XMLWriter => enabled 642 | 643 | xsl 644 | 645 | XSL => enabled 646 | libxslt Version => 1.1.37 647 | libxslt compiled against libxml Version => 2.10.3 648 | EXSLT => enabled 649 | libexslt Version => 0.8.20 650 | 651 | Zend OPcache 652 | 653 | Opcode Caching => Disabled 654 | Optimization => Disabled 655 | SHM Cache => Enabled 656 | File Cache => Disabled 657 | JIT => On 658 | Startup Failed => Opcode Caching is disabled for CLI 659 | 660 | Directive => Local Value => Master Value 661 | opcache.blacklist_filename => no value => no value 662 | opcache.consistency_checks => 0 => 0 663 | opcache.dups_fix => Off => Off 664 | opcache.enable => On => On 665 | opcache.enable_cli => Off => Off 666 | opcache.enable_file_override => Off => Off 667 | opcache.error_log => no value => no value 668 | opcache.file_cache => no value => no value 669 | opcache.file_cache_consistency_checks => On => On 670 | opcache.file_cache_only => Off => Off 671 | opcache.file_update_protection => 2 => 2 672 | opcache.force_restart_timeout => 180 => 180 673 | opcache.huge_code_pages => Off => Off 674 | opcache.interned_strings_buffer => 8 => 8 675 | opcache.jit => tracing => tracing 676 | opcache.jit_bisect_limit => 0 => 0 677 | opcache.jit_blacklist_root_trace => 16 => 16 678 | opcache.jit_blacklist_side_trace => 8 => 8 679 | opcache.jit_buffer_size => 0 => 0 680 | opcache.jit_debug => 0 => 0 681 | opcache.jit_hot_func => 127 => 127 682 | opcache.jit_hot_loop => 64 => 64 683 | opcache.jit_hot_return => 8 => 8 684 | opcache.jit_hot_side_exit => 8 => 8 685 | opcache.jit_max_exit_counters => 8192 => 8192 686 | opcache.jit_max_loop_unrolls => 8 => 8 687 | opcache.jit_max_polymorphic_calls => 2 => 2 688 | opcache.jit_max_recursive_calls => 2 => 2 689 | opcache.jit_max_recursive_returns => 2 => 2 690 | opcache.jit_max_root_traces => 1024 => 1024 691 | opcache.jit_max_side_traces => 128 => 128 692 | opcache.jit_prof_threshold => 0.005 => 0.005 693 | opcache.lockfile_path => /tmp => /tmp 694 | opcache.log_verbosity_level => 1 => 1 695 | opcache.max_accelerated_files => 10000 => 10000 696 | opcache.max_file_size => 0 => 0 697 | opcache.max_wasted_percentage => 5 => 5 698 | opcache.memory_consumption => 128 => 128 699 | opcache.opt_debug_level => 0 => 0 700 | opcache.optimization_level => 0 => 0x7FFEBFFF 701 | opcache.preferred_memory_model => no value => no value 702 | opcache.preload => no value => no value 703 | opcache.preload_user => no value => no value 704 | opcache.protect_memory => Off => Off 705 | opcache.record_warnings => Off => Off 706 | opcache.restrict_api => no value => no value 707 | opcache.revalidate_freq => 2 => 2 708 | opcache.revalidate_path => Off => Off 709 | opcache.save_comments => On => On 710 | opcache.use_cwd => On => On 711 | opcache.validate_permission => Off => Off 712 | opcache.validate_root => Off => Off 713 | opcache.validate_timestamps => On => On 714 | 715 | zip 716 | 717 | Zip => enabled 718 | Zip version => 1.21.1 719 | Libzip version => 1.9.2 720 | BZIP2 compression => Yes 721 | XZ compression => Yes 722 | ZSTD compression => Yes 723 | AES-128 encryption => Yes 724 | AES-192 encryption => Yes 725 | AES-256 encryption => Yes 726 | 727 | zlib 728 | 729 | ZLib Support => enabled 730 | Stream Wrapper => compress.zlib:// 731 | Stream Filter => zlib.inflate, zlib.deflate 732 | Compiled Version => 1.2.13 733 | Linked Version => 1.2.13 734 | 735 | Directive => Local Value => Master Value 736 | zlib.output_compression => Off => Off 737 | zlib.output_compression_level => -1 => -1 738 | zlib.output_handler => no value => no value 739 | 740 | Additional Modules 741 | 742 | Module Name 743 | 744 | Environment 745 | 746 | Variable => Value 747 | HOSTNAME => 40d66087d6bd 748 | CYCLE_SCHEMA_WARMUP => false 749 | DEBUG => true 750 | PHP_INI_DIR => /usr/local/etc/php 751 | SHLVL => 1 752 | HOME => /home/podlodka 753 | OLDPWD => /app 754 | MONOLOG_DEFAULT_LEVEL => DEBUG 755 | DB_NAME => podlodka 756 | MAILER_DSN => smtp://mailhog:1025 757 | MAILER_FROM => Alex Novikov 758 | PHP_IDE_CONFIG => serverName=podlodka 759 | PHP_LDFLAGS => -Wl,-O1 -pie 760 | PHP_CFLAGS => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 761 | CACHE_STORAGE => local 762 | PHP_VERSION => 8.2.3 763 | COMPOSER_HOME => /tmp/composer 764 | S3_BUCKET => podlodka 765 | GPG_KEYS => 39B641343D8C104B2B146DC3F9C39DC0B9698544 E60913E4DF209907D8E30D96659A97C9CF2A795A 1198C0117593497A5EC5C199286AF1F9897469DC 766 | PHP_CPPFLAGS => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 767 | PHP_ASC_URL => https://www.php.net/distributions/php-8.2.3.tar.xz.asc 768 | STORAGE_DEFAULT => default 769 | PHP_URL => https://www.php.net/distributions/php-8.2.3.tar.xz 770 | TERM => xterm 771 | PDF_ENDPOINT => http://gotenberg:3000 772 | SAFE_MIGRATIONS => true 773 | MONOLOG_DEFAULT_CHANNEL => default 774 | S3_REGION => us-east1 775 | XDEBUG_MODE => debug 776 | PATH => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 777 | S3_ENDPOINT => http://minio:9000 778 | S3_SECRET => adminadmin 779 | CYCLE_SCHEMA_CACHE => true 780 | ENCRYPTER_KEY => def000003f47c1bb39cf6d8b96a4ab6198df982d06e9123e2de36933bae0d603cd3cec838fdd31fc7c768a43872b72c920dac5365fb631d6cfd51e500d812372b7c9f70a 781 | MAILER_PIPELINE => local 782 | SESSION_LIFETIME => 86400 783 | S3_PREFIX => uploads 784 | APP_ENV => local 785 | DB_PASSWORD => iddqd 786 | PHPIZE_DEPS => autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c 787 | PWD => /app/app 788 | SESSION_COOKIE => sid 789 | PHP_SHA256 => b9b566686e351125d67568a33291650eb8dfa26614d205d70d82e6e92613d457 790 | S3_KEY => adminadmin 791 | QUEUE_CONNECTION => sync 792 | DB_HOST => postgres 793 | DB_USER => crew 794 | 795 | PHP Variables 796 | 797 | Variable => Value 798 | $_SERVER['HOSTNAME'] => 40d66087d6bd 799 | $_SERVER['CYCLE_SCHEMA_WARMUP'] => false 800 | $_SERVER['DEBUG'] => true 801 | $_SERVER['PHP_INI_DIR'] => /usr/local/etc/php 802 | $_SERVER['SHLVL'] => 1 803 | $_SERVER['HOME'] => /home/podlodka 804 | $_SERVER['OLDPWD'] => /app 805 | $_SERVER['MONOLOG_DEFAULT_LEVEL'] => DEBUG 806 | $_SERVER['DB_NAME'] => podlodka 807 | $_SERVER['MAILER_DSN'] => smtp://mailhog:1025 808 | $_SERVER['MAILER_FROM'] => Alex Novikov 809 | $_SERVER['PHP_IDE_CONFIG'] => serverName=podlodka 810 | $_SERVER['PHP_LDFLAGS'] => -Wl,-O1 -pie 811 | $_SERVER['PHP_CFLAGS'] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 812 | $_SERVER['CACHE_STORAGE'] => local 813 | $_SERVER['PHP_VERSION'] => 8.2.3 814 | $_SERVER['COMPOSER_HOME'] => /tmp/composer 815 | $_SERVER['S3_BUCKET'] => podlodka 816 | $_SERVER['GPG_KEYS'] => 39B641343D8C104B2B146DC3F9C39DC0B9698544 E60913E4DF209907D8E30D96659A97C9CF2A795A 1198C0117593497A5EC5C199286AF1F9897469DC 817 | $_SERVER['PHP_CPPFLAGS'] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 818 | $_SERVER['PHP_ASC_URL'] => https://www.php.net/distributions/php-8.2.3.tar.xz.asc 819 | $_SERVER['STORAGE_DEFAULT'] => default 820 | $_SERVER['PHP_URL'] => https://www.php.net/distributions/php-8.2.3.tar.xz 821 | $_SERVER['TERM'] => xterm 822 | $_SERVER['PDF_ENDPOINT'] => http://gotenberg:3000 823 | $_SERVER['SAFE_MIGRATIONS'] => true 824 | $_SERVER['MONOLOG_DEFAULT_CHANNEL'] => default 825 | $_SERVER['S3_REGION'] => us-east1 826 | $_SERVER['XDEBUG_MODE'] => debug 827 | $_SERVER['PATH'] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 828 | $_SERVER['S3_ENDPOINT'] => http://minio:9000 829 | $_SERVER['S3_SECRET'] => adminadmin 830 | $_SERVER['CYCLE_SCHEMA_CACHE'] => true 831 | $_SERVER['ENCRYPTER_KEY'] => def000003f47c1bb39cf6d8b96a4ab6198df982d06e9123e2de36933bae0d603cd3cec838fdd31fc7c768a43872b72c920dac5365fb631d6cfd51e500d812372b7c9f70a 832 | $_SERVER['MAILER_PIPELINE'] => local 833 | $_SERVER['SESSION_LIFETIME'] => 86400 834 | $_SERVER['S3_PREFIX'] => uploads 835 | $_SERVER['APP_ENV'] => local 836 | $_SERVER['DB_PASSWORD'] => iddqd 837 | $_SERVER['PHPIZE_DEPS'] => autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c 838 | $_SERVER['PWD'] => /app/app 839 | $_SERVER['SESSION_COOKIE'] => sid 840 | $_SERVER['PHP_SHA256'] => b9b566686e351125d67568a33291650eb8dfa26614d205d70d82e6e92613d457 841 | $_SERVER['S3_KEY'] => adminadmin 842 | $_SERVER['QUEUE_CONNECTION'] => sync 843 | $_SERVER['DB_HOST'] => postgres 844 | $_SERVER['DB_USER'] => crew 845 | $_SERVER['PHP_SELF'] => test.php 846 | $_SERVER['SCRIPT_NAME'] => test.php 847 | $_SERVER['SCRIPT_FILENAME'] => test.php 848 | $_SERVER['PATH_TRANSLATED'] => test.php 849 | $_SERVER['DOCUMENT_ROOT'] => 850 | $_SERVER['REQUEST_TIME_FLOAT'] => 1677342849.8248 851 | $_SERVER['REQUEST_TIME'] => 1677342849 852 | $_SERVER['argv'] => Array 853 | ( 854 | [0] => test.php 855 | ) 856 | 857 | $_SERVER['argc'] => 1 858 | $_ENV['HOSTNAME'] => 40d66087d6bd 859 | $_ENV['CYCLE_SCHEMA_WARMUP'] => false 860 | $_ENV['DEBUG'] => true 861 | $_ENV['PHP_INI_DIR'] => /usr/local/etc/php 862 | $_ENV['SHLVL'] => 1 863 | $_ENV['HOME'] => /home/podlodka 864 | $_ENV['OLDPWD'] => /app 865 | $_ENV['MONOLOG_DEFAULT_LEVEL'] => DEBUG 866 | $_ENV['DB_NAME'] => podlodka 867 | $_ENV['MAILER_DSN'] => smtp://mailhog:1025 868 | $_ENV['MAILER_FROM'] => Alex Novikov 869 | $_ENV['PHP_IDE_CONFIG'] => serverName=podlodka 870 | $_ENV['PHP_LDFLAGS'] => -Wl,-O1 -pie 871 | $_ENV['PHP_CFLAGS'] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 872 | $_ENV['CACHE_STORAGE'] => local 873 | $_ENV['PHP_VERSION'] => 8.2.3 874 | $_ENV['COMPOSER_HOME'] => /tmp/composer 875 | $_ENV['S3_BUCKET'] => podlodka 876 | $_ENV['GPG_KEYS'] => 39B641343D8C104B2B146DC3F9C39DC0B9698544 E60913E4DF209907D8E30D96659A97C9CF2A795A 1198C0117593497A5EC5C199286AF1F9897469DC 877 | $_ENV['PHP_CPPFLAGS'] => -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 878 | $_ENV['PHP_ASC_URL'] => https://www.php.net/distributions/php-8.2.3.tar.xz.asc 879 | $_ENV['STORAGE_DEFAULT'] => default 880 | $_ENV['PHP_URL'] => https://www.php.net/distributions/php-8.2.3.tar.xz 881 | $_ENV['TERM'] => xterm 882 | $_ENV['PDF_ENDPOINT'] => http://gotenberg:3000 883 | $_ENV['SAFE_MIGRATIONS'] => true 884 | $_ENV['MONOLOG_DEFAULT_CHANNEL'] => default 885 | $_ENV['S3_REGION'] => us-east1 886 | $_ENV['XDEBUG_MODE'] => debug 887 | $_ENV['PATH'] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 888 | $_ENV['S3_ENDPOINT'] => http://minio:9000 889 | $_ENV['S3_SECRET'] => adminadmin 890 | $_ENV['CYCLE_SCHEMA_CACHE'] => true 891 | $_ENV['ENCRYPTER_KEY'] => def000003f47c1bb39cf6d8b96a4ab6198df982d06e9123e2de36933bae0d603cd3cec838fdd31fc7c768a43872b72c920dac5365fb631d6cfd51e500d812372b7c9f70a 892 | $_ENV['MAILER_PIPELINE'] => local 893 | $_ENV['SESSION_LIFETIME'] => 86400 894 | $_ENV['S3_PREFIX'] => uploads 895 | $_ENV['APP_ENV'] => local 896 | $_ENV['DB_PASSWORD'] => iddqd 897 | $_ENV['PHPIZE_DEPS'] => autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c 898 | $_ENV['PWD'] => /app/app 899 | $_ENV['SESSION_COOKIE'] => sid 900 | $_ENV['PHP_SHA256'] => b9b566686e351125d67568a33291650eb8dfa26614d205d70d82e6e92613d457 901 | $_ENV['S3_KEY'] => adminadmin 902 | $_ENV['QUEUE_CONNECTION'] => sync 903 | $_ENV['DB_HOST'] => postgres 904 | $_ENV['DB_USER'] => crew 905 | 906 | 907 | _______________________________________________________________________ 908 | 909 | PHP Credits 910 | 911 | PHP Group 912 | Thies C. Arntzen, Stig Bakken, Shane Caraveo, Andi Gutmans, Rasmus Lerdorf, Sam Ruby, Sascha Schumann, Zeev Suraski, Jim Winstead, Andrei Zmievski 913 | 914 | Language Design & Concept 915 | Andi Gutmans, Rasmus Lerdorf, Zeev Suraski, Marcus Boerger 916 | 917 | PHP Authors 918 | Contribution => Authors 919 | Zend Scripting Language Engine => Andi Gutmans, Zeev Suraski, Stanislav Malyshev, Marcus Boerger, Dmitry Stogov, Xinchen Hui, Nikita Popov 920 | Extension Module API => Andi Gutmans, Zeev Suraski, Andrei Zmievski 921 | UNIX Build and Modularization => Stig Bakken, Sascha Schumann, Jani Taskinen, Peter Kokot 922 | Windows Support => Shane Caraveo, Zeev Suraski, Wez Furlong, Pierre-Alain Joye, Anatol Belski, Kalle Sommer Nielsen 923 | Server API (SAPI) Abstraction Layer => Andi Gutmans, Shane Caraveo, Zeev Suraski 924 | Streams Abstraction Layer => Wez Furlong, Sara Golemon 925 | PHP Data Objects Layer => Wez Furlong, Marcus Boerger, Sterling Hughes, George Schlossnagle, Ilia Alshanetsky 926 | Output Handler => Zeev Suraski, Thies C. Arntzen, Marcus Boerger, Michael Wallner 927 | Consistent 64 bit support => Anthony Ferrara, Anatol Belski 928 | 929 | SAPI Modules 930 | Contribution => Authors 931 | Apache 2.0 Handler => Ian Holsman, Justin Erenkrantz (based on Apache 2.0 Filter code) 932 | CGI / FastCGI => Rasmus Lerdorf, Stig Bakken, Shane Caraveo, Dmitry Stogov 933 | CLI => Edin Kadribasic, Marcus Boerger, Johannes Schlueter, Moriyoshi Koizumi, Xinchen Hui 934 | Embed => Edin Kadribasic 935 | FastCGI Process Manager => Andrei Nigmatulin, dreamcat4, Antony Dovgal, Jerome Loyet 936 | litespeed => George Wang 937 | phpdbg => Felipe Pena, Joe Watkins, Bob Weinand 938 | 939 | Module Authors 940 | Module => Authors 941 | BC Math => Andi Gutmans 942 | Bzip2 => Sterling Hughes 943 | Calendar => Shane Caraveo, Colin Viebrock, Hartmut Holzgraefe, Wez Furlong 944 | COM and .Net => Wez Furlong 945 | ctype => Hartmut Holzgraefe 946 | cURL => Sterling Hughes 947 | Date/Time Support => Derick Rethans 948 | DB-LIB (MS SQL, Sybase) => Wez Furlong, Frank M. Kromann, Adam Baratz 949 | DBA => Sascha Schumann, Marcus Boerger 950 | DOM => Christian Stocker, Rob Richards, Marcus Boerger 951 | enchant => Pierre-Alain Joye, Ilia Alshanetsky 952 | EXIF => Rasmus Lerdorf, Marcus Boerger 953 | FFI => Dmitry Stogov 954 | fileinfo => Ilia Alshanetsky, Pierre Alain Joye, Scott MacVicar, Derick Rethans, Anatol Belski 955 | Firebird driver for PDO => Ard Biesheuvel 956 | FTP => Stefan Esser, Andrew Skalski 957 | GD imaging => Rasmus Lerdorf, Stig Bakken, Jim Winstead, Jouni Ahto, Ilia Alshanetsky, Pierre-Alain Joye, Marcus Boerger, Mark Randall 958 | GetText => Alex Plotnick 959 | GNU GMP support => Stanislav Malyshev 960 | Iconv => Rui Hirokawa, Stig Bakken, Moriyoshi Koizumi 961 | IMAP => Rex Logan, Mark Musone, Brian Wang, Kaj-Michael Lang, Antoni Pamies Olive, Rasmus Lerdorf, Andrew Skalski, Chuck Hagenbuch, Daniel R Kalowsky 962 | Input Filter => Rasmus Lerdorf, Derick Rethans, Pierre-Alain Joye, Ilia Alshanetsky 963 | Internationalization => Ed Batutis, Vladimir Iordanov, Dmitry Lakhtyuk, Stanislav Malyshev, Vadim Savchuk, Kirti Velankar 964 | JSON => Jakub Zelenka, Omar Kilani, Scott MacVicar 965 | LDAP => Amitay Isaacs, Eric Warnke, Rasmus Lerdorf, Gerrit Thomson, Stig Venaas 966 | LIBXML => Christian Stocker, Rob Richards, Marcus Boerger, Wez Furlong, Shane Caraveo 967 | Multibyte String Functions => Tsukada Takuya, Rui Hirokawa 968 | MySQL driver for PDO => George Schlossnagle, Wez Furlong, Ilia Alshanetsky, Johannes Schlueter 969 | MySQLi => Zak Greant, Georg Richter, Andrey Hristov, Ulf Wendel 970 | MySQLnd => Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlüter 971 | OCI8 => Stig Bakken, Thies C. Arntzen, Andy Sautins, David Benson, Maxim Maletsky, Harald Radi, Antony Dovgal, Andi Gutmans, Wez Furlong, Christopher Jones, Oracle Corporation 972 | ODBC driver for PDO => Wez Furlong 973 | ODBC => Stig Bakken, Andreas Karajannis, Frank M. Kromann, Daniel R. Kalowsky 974 | Opcache => Andi Gutmans, Zeev Suraski, Stanislav Malyshev, Dmitry Stogov, Xinchen Hui 975 | OpenSSL => Stig Venaas, Wez Furlong, Sascha Kettler, Scott MacVicar, Eliot Lear 976 | Oracle (OCI) driver for PDO => Wez Furlong 977 | pcntl => Jason Greene, Arnaud Le Blanc 978 | Perl Compatible Regexps => Andrei Zmievski 979 | PHP Archive => Gregory Beaver, Marcus Boerger 980 | PHP Data Objects => Wez Furlong, Marcus Boerger, Sterling Hughes, George Schlossnagle, Ilia Alshanetsky 981 | PHP hash => Sara Golemon, Rasmus Lerdorf, Stefan Esser, Michael Wallner, Scott MacVicar 982 | Posix => Kristian Koehntopp 983 | PostgreSQL driver for PDO => Edin Kadribasic, Ilia Alshanetsky 984 | PostgreSQL => Jouni Ahto, Zeev Suraski, Yasuo Ohgaki, Chris Kings-Lynne 985 | Pspell => Vlad Krupin 986 | random => Go Kudo, Tim Düsterhus, Guilliam Xavier, Christoph M. Becker, Jakub Zelenka, Bob Weinand, Máté Kocsis, and Original RNG implementators 987 | Readline => Thies C. Arntzen 988 | Reflection => Marcus Boerger, Timm Friebe, George Schlossnagle, Andrei Zmievski, Johannes Schlueter 989 | Sessions => Sascha Schumann, Andrei Zmievski 990 | Shared Memory Operations => Slava Poliakov, Ilia Alshanetsky 991 | SimpleXML => Sterling Hughes, Marcus Boerger, Rob Richards 992 | SNMP => Rasmus Lerdorf, Harrie Hazewinkel, Mike Jackson, Steven Lawrance, Johann Hanne, Boris Lytochkin 993 | SOAP => Brad Lafountain, Shane Caraveo, Dmitry Stogov 994 | Sockets => Chris Vandomelen, Sterling Hughes, Daniel Beulshausen, Jason Greene 995 | Sodium => Frank Denis 996 | SPL => Marcus Boerger, Etienne Kneuss 997 | SQLite 3.x driver for PDO => Wez Furlong 998 | SQLite3 => Scott MacVicar, Ilia Alshanetsky, Brad Dewar 999 | System V Message based IPC => Wez Furlong 1000 | System V Semaphores => Tom May 1001 | System V Shared Memory => Christian Cartus 1002 | tidy => John Coggeshall, Ilia Alshanetsky 1003 | tokenizer => Andrei Zmievski, Johannes Schlueter 1004 | XML => Stig Bakken, Thies C. Arntzen, Sterling Hughes 1005 | XMLReader => Rob Richards 1006 | XMLWriter => Rob Richards, Pierre-Alain Joye 1007 | XSL => Christian Stocker, Rob Richards 1008 | Zip => Pierre-Alain Joye, Remi Collet 1009 | Zlib => Rasmus Lerdorf, Stefan Roehrich, Zeev Suraski, Jade Nicoletti, Michael Wallner 1010 | 1011 | PHP Documentation 1012 | Authors => Mehdi Achour, Friedhelm Betz, Antony Dovgal, Nuno Lopes, Hannes Magnusson, Philip Olson, Georg Richter, Damien Seguy, Jakub Vrana, Adam Harvey 1013 | Editor => Peter Cowburn 1014 | User Note Maintainers => Daniel P. Brown, Thiago Henrique Pojda 1015 | Other Contributors => Previously active authors, editors and other contributors are listed in the manual. 1016 | 1017 | PHP Quality Assurance Team 1018 | Ilia Alshanetsky, Joerg Behrens, Antony Dovgal, Stefan Esser, Moriyoshi Koizumi, Magnus Maatta, Sebastian Nohn, Derick Rethans, Melvyn Sopacua, Pierre-Alain Joye, Dmitry Stogov, Felipe Pena, David Soria Parra, Stanislav Malyshev, Julien Pauli, Stephen Zarkos, Anatol Belski, Remi Collet, Ferenc Kovacs 1019 | 1020 | Websites and Infrastructure team 1021 | PHP Websites Team => Rasmus Lerdorf, Hannes Magnusson, Philip Olson, Lukas Kahwe Smith, Pierre-Alain Joye, Kalle Sommer Nielsen, Peter Cowburn, Adam Harvey, Ferenc Kovacs, Levi Morrison 1022 | Event Maintainers => Damien Seguy, Daniel P. Brown 1023 | Network Infrastructure => Daniel P. Brown 1024 | Windows Infrastructure => Alex Schoenmaker 1025 | 1026 | PHP License 1027 | This program is free software; you can redistribute it and/or modify 1028 | it under the terms of the PHP License as published by the PHP Group 1029 | and included in the distribution in the file: LICENSE 1030 | 1031 | This program is distributed in the hope that it will be useful, 1032 | but WITHOUT ANY WARRANTY; without even the implied warranty of 1033 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1034 | 1035 | If you did not receive a copy of the PHP license, or have any 1036 | questions about PHP licensing, please contact license@php.net. 1037 | -------------------------------------------------------------------------------- /app/src/Api/Cli/Command/DoNothing.php: -------------------------------------------------------------------------------- 1 | info(\sprintf('I did %s %s times!', $this->argument('name'), $this->option('times'))); 28 | 29 | return self::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/Api/Cli/Command/Mail.php: -------------------------------------------------------------------------------- 1 | send(new Message( 29 | 'template.dark.php', 30 | 'test@gmail.com', 31 | [ 32 | 'name' => $this->argument('name'), 33 | ] 34 | )); 35 | $this->writeln("https://mail.podlodka.localhost"); 36 | 37 | return self::SUCCESS; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/Api/Cli/Command/Pdf.php: -------------------------------------------------------------------------------- 1 | writeln($pdf->gen($this->argument('url'))); 28 | return self::SUCCESS; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/Api/Job/Ping.php: -------------------------------------------------------------------------------- 1 | push(PingJob::class, ["value"=>"my value"]); 11 | */ 12 | class Ping extends JobHandler 13 | { 14 | public function invoke(array $payload): void 15 | { 16 | // do something 17 | echo $payload['value']; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/Api/Rpc/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexndr-novikov/podlodka-php-crew-2/3c7f30ee682ea1bac6fb12c27c0ac36928b97f34/app/src/Api/Rpc/.gitignore -------------------------------------------------------------------------------- /app/src/Api/Web/Controller/HomeController.php: -------------------------------------------------------------------------------- 1 | views->render('home.dark.php'); 28 | } 29 | 30 | /** 31 | * Example of exception page. 32 | */ 33 | public function exception(): never 34 | { 35 | throw new Exception('This is a test exception.'); 36 | } 37 | 38 | public function ping(): string 39 | { 40 | $jobID = $this->queue->push(Ping::class, [ 41 | 'value' => 'hello world', 42 | ]); 43 | 44 | return sprintf('Job ID: %s', $jobID); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/Api/Web/routes.php: -------------------------------------------------------------------------------- 1 | add('home', '/')->controller(HomeController::class); 20 | }; 21 | -------------------------------------------------------------------------------- /app/src/Application/Bootloader/ExceptionHandlerBootloader.php: -------------------------------------------------------------------------------- 1 | EnvSuppressErrors::class, 25 | RendererInterface::class => ViewRenderer::class, 26 | ]; 27 | 28 | public function init(AbstractKernel $kernel): void 29 | { 30 | $kernel->running(static function (ExceptionHandler $handler): void { 31 | $handler->addRenderer(new JsonRenderer()); 32 | }); 33 | } 34 | 35 | public function boot( 36 | ExceptionHandlerInterface $handler, 37 | LoggerReporter $logger, 38 | FileReporter $files, 39 | ): void { 40 | \assert($handler instanceof Handler); 41 | $handler->addReporter($logger); 42 | $handler->addReporter($files); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/Application/Bootloader/LoggingBootloader.php: -------------------------------------------------------------------------------- 1 | addHandler( 19 | channel: ErrorHandlerMiddleware::class, 20 | handler: $monolog->logRotate( 21 | directory('runtime') . 'logs/http.log' 22 | ) 23 | ); 24 | 25 | // app level errors 26 | $monolog->addHandler( 27 | channel: MonologConfig::DEFAULT_CHANNEL, 28 | handler: $monolog->logRotate( 29 | filename: directory('runtime') . 'logs/error.log', 30 | level: Logger::ERROR, 31 | maxFiles: 25, 32 | bubble: false 33 | ) 34 | ); 35 | 36 | // debug and info messages via global LoggerInterface 37 | $monolog->addHandler( 38 | channel: MonologConfig::DEFAULT_CHANNEL, 39 | handler: $monolog->logRotate( 40 | filename: directory('runtime') . 'logs/debug.log' 41 | ) 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/Application/Bootloader/RoutesBootloader.php: -------------------------------------------------------------------------------- 1 | [ 39 | CookiesMiddleware::class, 40 | SessionMiddleware::class, 41 | CsrfMiddleware::class, 42 | // new Autowire(AuthTransportMiddleware::class, ['transportName' => 'cookie']) 43 | ], 44 | 'api' => [ 45 | // new Autowire(AuthTransportMiddleware::class, ['transportName' => 'header']) 46 | ], 47 | ]; 48 | } 49 | 50 | protected function defineRoutes(RoutingConfigurator $routes): void 51 | { 52 | $routes->import($this->dirs->get('app') . 'src/Api/Web/routes.php')->group('web'); 53 | 54 | $routes->default('/[[/]]') 55 | ->namespaced('App\\Api\\Web\\Controller') 56 | ->defaults([ 57 | 'controller' => 'home', 58 | 'action' => 'index', 59 | ]) 60 | ->middleware([ 61 | // SomeMiddleware::class, 62 | ]); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/Application/Kernel.php: -------------------------------------------------------------------------------- 1 | availableLocales = $this->translator->getCatalogueManager()->getLocales(); 22 | } 23 | 24 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 25 | { 26 | $defaultLocale = $this->translator->getLocale(); 27 | 28 | try { 29 | foreach ($this->fetchLocales($request) as $locale) { 30 | if ($locale !== '' && \in_array($locale, $this->availableLocales, true)) { 31 | $this->translator->setLocale($locale); 32 | break; 33 | } 34 | } 35 | 36 | return $handler->handle($request); 37 | } finally { 38 | // restore 39 | $this->translator->setLocale($defaultLocale); 40 | } 41 | } 42 | 43 | public function fetchLocales(ServerRequestInterface $request): \Generator 44 | { 45 | $header = $request->getHeaderLine('accept-language'); 46 | foreach (\explode(',', $header) as $value) { 47 | $pos = \strpos($value, ';'); 48 | if ($pos!== false) { 49 | yield \substr($value, 0, $pos); 50 | } 51 | 52 | yield $value; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/Application/Service/ErrorHandler/Handler.php: -------------------------------------------------------------------------------- 1 | addRenderer(new ConsoleRenderer()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/Application/Service/ErrorHandler/ViewRenderer.php: -------------------------------------------------------------------------------- 1 | getHeaderLine('Accept'))->getAll(); 29 | if ($acceptItems && $acceptItems[0]->getValue() === 'application/json') { 30 | return $this->renderJson($code, $exception); 31 | } 32 | 33 | return $this->renderView($code, $exception); 34 | } 35 | 36 | private function renderJson(int $code, \Throwable $exception): ResponseInterface 37 | { 38 | $response = $this->responseFactory->createResponse($code); 39 | 40 | $response = $response->withHeader('Content-Type', 'application/json; charset=UTF-8'); 41 | $response->getBody()->write(\json_encode(['status' => $code, 'error' => $exception->getMessage()])); 42 | 43 | return $response; 44 | } 45 | 46 | private function renderView(int $code, \Throwable $exception): ResponseInterface 47 | { 48 | $response = $this->responseFactory->createResponse($code); 49 | 50 | try { 51 | $view = $this->views->get(\sprintf(self::VIEW, $code)); 52 | } catch (ViewException) { 53 | $view = $this->views->get(self::GENERAL_VIEW); 54 | } 55 | 56 | $content = $view->render(['code' => $code, 'exception' => $exception]); 57 | $response->getBody()->write($content); 58 | 59 | return $response; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/Application/Service/Pdf.php: -------------------------------------------------------------------------------- 1 | storage = $storage; 18 | $this->resolver = $resolver; 19 | } 20 | 21 | public function gen(string $url): string 22 | { 23 | $request = Gotenberg::chromium(env('PDF_ENDPOINT')) 24 | ->url($url); 25 | 26 | $filename = Gotenberg::save($request, '/tmp'); 27 | $this->storage->bucket('podlodka')->write($filename, file_get_contents("/tmp/$filename")); 28 | $url = $this->resolver->resolve($filename, new \DateTime(datetime: '+10 sec')); 29 | return (string)$url; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/Application/helpers.php: -------------------------------------------------------------------------------- 1 | addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); 31 | 32 | // Set new handler and store previous one 33 | $prevent = VarDumper::setHandler(static fn ($value) => $dumper->dump($cloner->cloneVar($value))); 34 | $result = VarDumper::dump($value); 35 | 36 | foreach ($values as $v) { 37 | VarDumper::dump($v); 38 | } 39 | 40 | // Reset handler 41 | VarDumper::setHandler($prevent); 42 | 43 | if ($previous) { 44 | $_SERVER['VAR_DUMPER_FORMAT'] = $previous; 45 | } 46 | 47 | return $result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/Module/EmptyModule/Api/EmptyService.php: -------------------------------------------------------------------------------- 1 | Internal\EmptyService::class, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/Module/EmptyModule/Internal/EmptyService.php: -------------------------------------------------------------------------------- 1 | createEmptyService()->doNothing(); 23 | 24 | $this->assertTrue(true); 25 | } 26 | 27 | private function createEmptyService(): EmptyServiceInterface 28 | { 29 | return new EmptyService(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/test.php: -------------------------------------------------------------------------------- 1 | [[GitHub]] 2 | | [[Exception]] 3 | | [[Create Queue Task]] 4 | | [[Application Metrics]] 5 | | [[Website and Documentation]] 6 | -------------------------------------------------------------------------------- /app/views/exception/403.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | Error 403 12 |

[[Access Forbidden]]

13 | 14 | 15 | 16 |
17 | [[This view file is located in]] app/views/exception/403.dark.php. 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /app/views/exception/404.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | Framework Logotype 12 |

[[Page not found]]

13 | 14 | 15 | 16 |
17 | [[This view file is located in]] app/views/exception/404.dark.php. 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /app/views/exception/500.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | Error 500 12 |

[[Something went wrong]]

13 | 14 | 15 | 16 |
17 | [[This view file is located in]] app/views/exception/500.dark.php. 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /app/views/exception/error.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | Framework Logotype 12 |

[[Something went wrong]]. [[Error code]]: {{ $code }}

13 | 14 | 15 | 16 |
17 | [[This view file is located in]] app/views/exception/error.dark.php. 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /app/views/home.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | Framework Logotype 12 |

[[Welcome to Spiral Framework]]

13 | 14 | 15 | 16 |
17 | [[This view file is located in]] app/views/home.dark.php [[and rendered by]] Controller\HomeController. 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /app/views/layout/base.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ${title} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ${context} 14 | -------------------------------------------------------------------------------- /app/views/template.dark.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

Hey, {{ $name }}!

7 |

You nailed it! Here's your reward:

8 |

9 |
10 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spiral/app", 3 | "type": "project", 4 | "license": "MIT", 5 | "description": "Spiral Skeleton Application", 6 | "homepage": "https://spiral.dev", 7 | "support": { 8 | "issues": "https://github.com/spiral/app/issues", 9 | "source": "https://github.com/spiral/app" 10 | }, 11 | "require": { 12 | "php": "^8.2", 13 | "ext-mbstring": "*", 14 | "doctrine/collections": "^1.8", 15 | "gotenberg/gotenberg-php": "^1.1", 16 | "league/flysystem-async-aws-s3": "^2.0", 17 | "league/flysystem-aws-s3-v3": "^2.0", 18 | "spiral/cycle-bridge": "^2.1", 19 | "spiral/framework": "^3.2", 20 | "spiral/nyholm-bridge": "^1.3", 21 | "spiral/roadrunner-bridge": "^2.1", 22 | "spiral/sapi-bridge": "^1.0.1" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^9.5", 26 | "qossmic/deptrac-shim": "^1.0", 27 | "spiral/testing": "^2.2", 28 | "symfony/var-dumper": "^6.1", 29 | "vimeo/psalm": "dev-master" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "App\\": "app/src" 34 | }, 35 | "files": [ 36 | "app/src/Application/helpers.php" 37 | ] 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Tests\\": "tests" 42 | } 43 | }, 44 | "extra": { 45 | "publish-cmd": "php app.php publish" 46 | }, 47 | "config": { 48 | "sort-packages": true, 49 | "allow-plugins": { 50 | "spiral/composer-publish-plugin": true, 51 | "php-http/discovery": true 52 | } 53 | }, 54 | "scripts": { 55 | "post-create-project-cmd": [ 56 | "php -r \"copy('.env.sample', '.env');\"", 57 | "php app.php encrypt:key -m .env", 58 | "php app.php configure -vv", 59 | "rr get-binary" 60 | ], 61 | "psalm:config": "psalm", 62 | "deptrack": [ 63 | "deptrac analyze --report-uncovered" 64 | ] 65 | }, 66 | "minimum-stability": "dev", 67 | "prefer-stable": true 68 | } 69 | -------------------------------------------------------------------------------- /deptrac.yaml: -------------------------------------------------------------------------------- 1 | # deptrac.yaml 2 | deptrac: 3 | paths: 4 | - ./app/src 5 | exclude_files: 6 | - '#test/.*#' 7 | - '#app/src/module/.*/test/.*#' 8 | layers: 9 | # App 10 | - name: Application 11 | collectors: 12 | - type: bool 13 | must: 14 | - type: className 15 | value: App\\Application\\.* 16 | must_not: 17 | - type: layer 18 | layer: AppBootloader 19 | - type: layer 20 | layer: AppKernel 21 | - name: AppKernel 22 | collectors: 23 | - type: className 24 | value: App\\Application\\Kernel 25 | - name: AppBootloader 26 | collectors: 27 | - type: className 28 | value: App\\Application\\Bootloader\\.* 29 | # - name: AppTest 30 | # collectors: 31 | # - type: className 32 | # value: Tests\\.* 33 | 34 | # Api 35 | - name: Controller 36 | collectors: 37 | - type: className 38 | value: App\\Api\\.* 39 | 40 | # Modules 41 | - name: ModuleContract 42 | collectors: 43 | - type: className 44 | value: App\\Module\\[a-z_][a-z0-9_]*\\Api\\.* 45 | - name: ModuleInternal 46 | collectors: 47 | - type: className 48 | value: App\\Module\\[a-z_][a-z0-9_]*\\Internal\\.* 49 | - name: ModuleApplication 50 | collectors: 51 | - type: bool 52 | must: 53 | - type: className 54 | value: App\\Module\\[a-z_][a-z0-9_]*\\Application\\.* 55 | must_not: 56 | - type: layer 57 | layer: ModuleBootloader 58 | - name: ModuleBootloader 59 | collectors: 60 | - type: className 61 | value: App\\Module\\.*Bootloader.* 62 | # - name: ModuleTest 63 | # collectors: 64 | # - type: className 65 | # value: App\\Module\\[a-z_][a-z0-9_]*\\Tests?\\.* 66 | 67 | # Vendor 68 | - name: VendorBootloader 69 | collectors: 70 | - type: bool 71 | must: 72 | - type: className 73 | value: .*Bootloader.* 74 | must_not: 75 | - type: className 76 | value: App\\.* 77 | - name: VendorDev 78 | collectors: 79 | - type: className 80 | value: PhpUnit\\.* 81 | - type: className 82 | value: Spiral\\Testing\\.* 83 | - name: Vendor 84 | collectors: 85 | - type: bool 86 | must: 87 | - type: className 88 | value: .+\\.+ 89 | must_not: 90 | - type: className 91 | value: App\\.* 92 | - type: layer 93 | layer: VendorDev 94 | - type: layer 95 | layer: SpiralKernel 96 | - type: layer 97 | layer: SpiralPrototype 98 | - name: SpiralKernel 99 | collectors: 100 | - type: className 101 | value: Spiral\\Framework\\Kernel 102 | - name: SpiralPrototype 103 | collectors: 104 | - type: className 105 | value: Spiral\\Prototype\\.* 106 | 107 | ruleset: 108 | AppKernel: 109 | - AppBootloader 110 | - ModuleBootloader 111 | - VendorBootloader 112 | - SpiralKernel 113 | AppBootloader: 114 | - VendorBootloader 115 | - Application 116 | - Vendor 117 | Application: 118 | - ModuleApplication 119 | - Vendor 120 | 121 | Controller: 122 | - ModuleContract 123 | - SpiralPrototype 124 | # todo add more details 125 | - Vendor 126 | 127 | ModuleContract: 128 | - ModuleContract 129 | ModuleInternal: 130 | - ModuleContract 131 | ModuleApplication: 132 | - ModuleContract 133 | - ModuleInternal 134 | ModuleBootloader: 135 | - AppBootloader 136 | - VendorBootloader 137 | - ModuleContract 138 | - ModuleInternal 139 | # ModuleTest: 140 | # - ModuleInternal 141 | # - ModuleContract 142 | # - VendorDev 143 | 144 | # AppTest: 145 | # - Application 146 | # - AppBootloader 147 | # - AppKernel 148 | # - Controller 149 | # - ModuleContract 150 | # - ModuleInternal 151 | # - ModuleApplication 152 | # - VendorDev 153 | -------------------------------------------------------------------------------- /docker-compose.0.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | depends_on: 6 | - postgres 7 | - gotenberg 8 | - redis 9 | - minio 10 | ports: 11 | - "8090:8090" 12 | build: 13 | dockerfile: .docker/php/Dockerfile 14 | context: ./ 15 | target: app_php 16 | command: "/app/rr serve -c .rr.yaml" 17 | 18 | cron: 19 | depends_on: 20 | - postgres 21 | - gotenberg 22 | - redis 23 | - minio 24 | build: 25 | dockerfile: .docker/php/Dockerfile 26 | context: ./ 27 | target: app_php 28 | command: supercronic /etc/supercronic/podlodka 29 | 30 | postgres: 31 | image: postgres:15.2-alpine3.17 32 | 33 | gotenberg: 34 | image: thecodingmachine/gotenberg:7.8 35 | 36 | redis: 37 | image: redis:7-alpine 38 | 39 | minio: 40 | image: minio/minio:RELEASE.2021-06-09T18-51-39Z 41 | -------------------------------------------------------------------------------- /docker-compose.1.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | # possible since 3.4 4 | x-php: 5 | &php 6 | build: 7 | dockerfile: .docker/php/Dockerfile 8 | context: ./ 9 | target: app_php 10 | depends_on: 11 | postgres: 12 | condition: service_healthy 13 | minio: 14 | condition: service_healthy 15 | gotenberg: 16 | condition: service_healthy 17 | redis: 18 | condition: service_healthy 19 | 20 | services: 21 | application: 22 | <<: *php 23 | command: "/app/rr serve -c .rr.yaml" 24 | 25 | cron: 26 | <<: *php 27 | command: supercronic /etc/supercronic/podlodka 28 | 29 | postgres: 30 | image: postgres:15.2-alpine3.17 31 | 32 | gotenberg: 33 | image: thecodingmachine/gotenberg:7.8 34 | 35 | redis: 36 | image: redis:7-alpine 37 | 38 | minio: 39 | image: minio/minio:RELEASE.2021-06-09T18-51-39Z 40 | -------------------------------------------------------------------------------- /docker-compose.2.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | # possible since 3.4 4 | x-php: 5 | &php 6 | build: 7 | dockerfile: .docker/php/Dockerfile 8 | context: ./ 9 | target: app_php 10 | env_file: 11 | - .app.env 12 | depends_on: 13 | postgres: 14 | condition: service_healthy 15 | minio: 16 | condition: service_healthy 17 | gotenberg: 18 | condition: service_healthy 19 | redis: 20 | condition: service_healthy 21 | 22 | services: 23 | application: 24 | <<: *php 25 | command: "/app/rr serve -c .rr.yaml" 26 | healthcheck: 27 | test: [ 'CMD-SHELL', 'wget --spider -q "http://127.0.0.1:8082/health?plugin=http&plugin=rpc"' ] 28 | interval: 2s 29 | timeout: 2s 30 | 31 | cron: 32 | <<: *php 33 | container_name: cron 34 | command: supercronic /etc/supercronic/podlodka 35 | 36 | postgres: 37 | image: postgres:15.2-alpine3.17 38 | healthcheck: 39 | test: pg_isready -d $$POSTGRES_DB -U $$POSTGRES_USER 40 | interval: 2s 41 | timeout: 5s 42 | start_period: 2s 43 | 44 | gotenberg: 45 | image: thecodingmachine/gotenberg:7.8 46 | healthcheck: 47 | test: curl --fail http://127.0.0.1:3000/health || exit 1 48 | interval: 5s 49 | timeout: 30s 50 | retries: 3 51 | start_period: 2s 52 | 53 | redis: 54 | image: redis:7-alpine 55 | healthcheck: 56 | test: [ 'CMD', 'redis-cli', 'ping' ] 57 | interval: 500ms 58 | timeout: 1s 59 | 60 | minio: 61 | image: minio/minio:RELEASE.2021-06-09T18-51-39Z 62 | command: [ "minio", "server", "/home/shared" ] 63 | healthcheck: 64 | test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ] 65 | interval: 5s 66 | timeout: 20s 67 | retries: 3 68 | -------------------------------------------------------------------------------- /docker-compose.3.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | # possible since 3.4 4 | x-php: 5 | &php 6 | build: 7 | dockerfile: .docker/php/Dockerfile 8 | context: ./ 9 | target: app_php 10 | environment: 11 | DB_HOST: ${DB_HOST:?provide db host to .env} 12 | DB_NAME: ${POSTGRES_DB:?provide db name to .env} 13 | DB_USER: ${POSTGRES_USER:?provide db user to .env} 14 | S3_KEY: ${AWS_KEY:?Provide access key to env} 15 | S3_SECRET: ${AWS_SECRET:?Provide secret key to env} 16 | DB_PASSWORD: ${POSTGRES_PASSWORD:?provide db password to .env} 17 | env_file: 18 | - .app.env 19 | depends_on: 20 | postgres: 21 | condition: service_healthy 22 | minio: 23 | condition: service_healthy 24 | gotenberg: 25 | condition: service_healthy 26 | redis: 27 | condition: service_healthy 28 | 29 | services: 30 | application: 31 | <<: *php 32 | command: "/app/rr serve -c .rr.yaml" 33 | healthcheck: 34 | test: [ 'CMD-SHELL', 'wget --spider -q "http://127.0.0.1:8082/health?plugin=http&plugin=rpc"' ] 35 | interval: 2s 36 | timeout: 2s 37 | 38 | cron: 39 | <<: *php 40 | container_name: cron 41 | command: supercronic /etc/supercronic/podlodka 42 | 43 | postgres: 44 | image: postgres:15.2-alpine3.17 45 | environment: 46 | POSTGRES_DB: ${POSTGRES_DB:?provide db name to .env} 47 | POSTGRES_USER: ${POSTGRES_USER:?provide db user to .env} 48 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?provide db password to .env} 49 | healthcheck: 50 | test: pg_isready -d $$POSTGRES_DB -U $$POSTGRES_USER 51 | interval: 2s 52 | timeout: 5s 53 | start_period: 2s 54 | 55 | gotenberg: 56 | image: thecodingmachine/gotenberg:7.8 57 | healthcheck: 58 | test: curl --fail http://127.0.0.1:3000/health || exit 1 59 | interval: 5s 60 | timeout: 30s 61 | retries: 3 62 | start_period: 2s 63 | 64 | redis: 65 | image: redis:7-alpine 66 | healthcheck: 67 | test: [ 'CMD', 'redis-cli', 'ping' ] 68 | interval: 500ms 69 | timeout: 1s 70 | 71 | minio: 72 | image: minio/minio:RELEASE.2021-06-09T18-51-39Z 73 | command: [ "minio", "server", "/home/shared" ] 74 | healthcheck: 75 | test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ] 76 | interval: 5s 77 | timeout: 20s 78 | retries: 3 79 | environment: 80 | MINIO_ACCESS_KEY: ${AWS_KEY:?Provide access key to env} 81 | MINIO_SECRET_KEY: ${AWS_SECRET:?Provide secret key to env} 82 | -------------------------------------------------------------------------------- /docker-compose.improved.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | php: 5 | image: ${PHP_IMAGE}:${PHP_TAG} 6 | volumes: 7 | - ./app:/app/app 8 | -------------------------------------------------------------------------------- /docker-compose.local.0.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | build: 6 | target: app_php_dev 7 | expose: 8 | - 9000 9 | volumes: 10 | - ./app:/app/app 11 | - ./vendor:/app/vendor 12 | - ./runtime:/app/runtime 13 | 14 | cron: 15 | build: 16 | target: app_php_dev 17 | volumes: 18 | - ./app:/app/app 19 | - ./vendor:/app/vendor 20 | - ./runtime:/app/runtime 21 | 22 | -------------------------------------------------------------------------------- /docker-compose.local.1.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | build: 6 | target: app_php_dev 7 | expose: 8 | - 9000 9 | volumes: 10 | - ./app:/app/app 11 | - ./vendor:/app/vendor 12 | - ./runtime:/app/runtime 13 | 14 | cron: 15 | build: 16 | target: app_php_dev 17 | volumes: 18 | - ./app:/app/app 19 | - ./vendor:/app/vendor 20 | - ./runtime:/app/runtime 21 | 22 | reverse-proxy: 23 | image: traefik:v2.6 24 | command: 25 | - "--accesslog" 26 | - "--api.insecure=true" 27 | - "--providers.docker=true" 28 | - "--providers.docker.exposedbydefault=false" 29 | - "--entrypoints.web.address=:80" 30 | - "--entrypoints.websecure.address=:443" 31 | - "--providers.file.directory=/configuration/" 32 | - "--providers.file.watch=true" 33 | ports: 34 | - "80:80" 35 | - "443:443" 36 | - "8082:8080" 37 | volumes: 38 | - /var/run/docker.sock:/var/run/docker.sock 39 | - ./.docker/traefik/configuration:/configuration/ 40 | - ./.docker/traefik/certs:/etc/certs:ro 41 | -------------------------------------------------------------------------------- /docker-compose.local.2.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | build: 6 | target: app_php_dev 7 | expose: 8 | - 9000 9 | volumes: 10 | - ./app:/app/app 11 | - ./vendor:/app/vendor 12 | - ./runtime:/app/runtime 13 | labels: 14 | - "traefik.enable=true" 15 | - "traefik.http.routers.application-http.entrypoints=web" 16 | - "traefik.http.routers.application-http.rule=Host(`podlodka.localhost`)" 17 | - "traefik.http.routers.application-http.middlewares=application" 18 | - "traefik.http.services.application.loadbalancer.server.port=8090" 19 | - "traefik.http.middlewares.application.redirectscheme.scheme=https" 20 | - "traefik.http.routers.application.entrypoints=websecure" 21 | - "traefik.http.routers.application.rule=Host(`podlodka.localhost`)" 22 | - "traefik.http.routers.application.tls=true" 23 | 24 | cron: 25 | build: 26 | target: app_php_dev 27 | volumes: 28 | - ./app:/app/app 29 | - ./vendor:/app/vendor 30 | - ./runtime:/app/runtime 31 | 32 | minio: 33 | labels: 34 | - "traefik.enable=true" 35 | - "traefik.http.routers.minio-http.entrypoints=web" 36 | - "traefik.http.routers.minio-http.rule=Host(`s3.podlodka.localhost`)" 37 | - "traefik.http.routers.minio-http.middlewares=minio-https" 38 | - "traefik.http.services.minio.loadbalancer.server.port=9000" 39 | - "traefik.http.middlewares.minio-https.redirectscheme.scheme=https" 40 | - "traefik.http.routers.minio.entrypoints=websecure" 41 | - "traefik.http.routers.minio.rule=Host(`s3.podlodka.localhost`)" 42 | - "traefik.http.routers.minio.tls=true" 43 | 44 | mailhog: 45 | image: "mailhog/mailhog" 46 | labels: 47 | - "traefik.enable=true" 48 | - "traefik.http.routers.mailhog-http.entrypoints=web" 49 | - "traefik.http.routers.mailhog-http.rule=Host(`mail.podlodka.localhost`)" 50 | - "traefik.http.routers.mailhog-http.middlewares=mailhog-https" 51 | - "traefik.http.services.mailhog.loadbalancer.server.port=8025" 52 | - "traefik.http.middlewares.mailhog-https.redirectscheme.scheme=https" 53 | - "traefik.http.routers.mailhog.entrypoints=websecure" 54 | - "traefik.http.routers.mailhog.rule=Host(`mail.podlodka.localhost`)" 55 | - "traefik.http.routers.mailhog.tls=true" 56 | 57 | 58 | reverse-proxy: 59 | image: traefik:v2.6 60 | command: 61 | - "--accesslog" 62 | - "--api.insecure=true" 63 | - "--providers.docker=true" 64 | - "--providers.docker.exposedbydefault=false" 65 | - "--entrypoints.web.address=:80" 66 | - "--entrypoints.websecure.address=:443" 67 | - "--providers.file.directory=/configuration/" 68 | - "--providers.file.watch=true" 69 | ports: 70 | - "80:80" 71 | - "443:443" 72 | - "8082:8080" 73 | volumes: 74 | - /var/run/docker.sock:/var/run/docker.sock 75 | - ./.docker/traefik/configuration:/configuration/ 76 | - ./.docker/traefik/certs:/etc/certs:ro 77 | -------------------------------------------------------------------------------- /docker-compose.local.3.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | build: 6 | target: app_php_dev 7 | expose: 8 | - 9000 9 | volumes: 10 | - ./app:/app/app 11 | - ./vendor:/app/vendor 12 | - ./runtime:/app/runtime 13 | labels: 14 | - "traefik.enable=true" 15 | - "traefik.http.routers.application-http.entrypoints=web" 16 | - "traefik.http.routers.application-http.rule=Host(`podlodka.localhost`)" 17 | - "traefik.http.routers.application-http.middlewares=application" 18 | - "traefik.http.services.application.loadbalancer.server.port=8090" 19 | - "traefik.http.middlewares.application.redirectscheme.scheme=https" 20 | - "traefik.http.routers.application.entrypoints=websecure" 21 | - "traefik.http.routers.application.rule=Host(`podlodka.localhost`)" 22 | - "traefik.http.routers.application.tls=true" 23 | cron: 24 | build: 25 | target: app_php_dev 26 | volumes: 27 | - ./app:/app/app 28 | - ./vendor:/app/vendor 29 | - ./runtime:/app/runtime 30 | 31 | minio: 32 | labels: 33 | - "traefik.enable=true" 34 | - "traefik.http.routers.minio-http.entrypoints=web" 35 | - "traefik.http.routers.minio-http.rule=Host(`s3.podlodka.localhost`)" 36 | - "traefik.http.routers.minio-http.middlewares=minio-https" 37 | - "traefik.http.services.minio.loadbalancer.server.port=9000" 38 | - "traefik.http.middlewares.minio-https.redirectscheme.scheme=https" 39 | - "traefik.http.routers.minio.entrypoints=websecure" 40 | - "traefik.http.routers.minio.rule=Host(`s3.podlodka.localhost`)" 41 | - "traefik.http.routers.minio.tls=true" 42 | 43 | mailhog: 44 | image: "mailhog/mailhog" 45 | labels: 46 | - "traefik.enable=true" 47 | - "traefik.http.routers.mailhog-http.entrypoints=web" 48 | - "traefik.http.routers.mailhog-http.rule=Host(`mail.podlodka.localhost`)" 49 | - "traefik.http.routers.mailhog-http.middlewares=mailhog-https" 50 | - "traefik.http.services.mailhog.loadbalancer.server.port=8025" 51 | - "traefik.http.middlewares.mailhog-https.redirectscheme.scheme=https" 52 | - "traefik.http.routers.mailhog.entrypoints=websecure" 53 | - "traefik.http.routers.mailhog.rule=Host(`mail.podlodka.localhost`)" 54 | - "traefik.http.routers.mailhog.tls=true" 55 | 56 | postgres: 57 | labels: 58 | - "traefik.enable=true" 59 | - "traefik.tcp.routers.db.entrypoints=postgres" 60 | - "traefik.tcp.routers.db.rule=HostSNI(`*`)" 61 | - "traefik.tcp.routers.db.tls=false" 62 | - "traefik.tcp.services.db.loadBalancer.server.port=5432" 63 | - "traefik.tcp.routers.db.service=db" 64 | 65 | 66 | reverse-proxy: 67 | image: traefik:v2.6 68 | command: 69 | - "--accesslog" 70 | - "--api.insecure=true" 71 | - "--providers.docker=true" 72 | - "--providers.docker.exposedbydefault=false" 73 | - "--entrypoints.web.address=:80" 74 | - "--entrypoints.websecure.address=:443" 75 | - "--entrypoints.postgres.address=:5432" 76 | - "--providers.file.directory=/configuration/" 77 | - "--providers.file.watch=true" 78 | ports: 79 | - "80:80" 80 | - "443:443" 81 | - "8082:8080" 82 | - "5432:5432" 83 | volumes: 84 | - /var/run/docker.sock:/var/run/docker.sock 85 | - ./.docker/traefik/configuration:/configuration/ 86 | - ./.docker/traefik/certs:/etc/certs:ro 87 | -------------------------------------------------------------------------------- /docker-compose.local.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | application: 5 | build: 6 | target: app_php_dev 7 | volumes: 8 | - ./app:/app/app 9 | - ./vendor:/app/vendor 10 | - ./runtime:/app/runtime 11 | labels: 12 | - "traefik.enable=true" 13 | - "traefik.http.routers.application-http.entrypoints=web" 14 | - "traefik.http.routers.application-http.rule=Host(`podlodka.localhost`)" 15 | - "traefik.http.routers.application-http.middlewares=application" 16 | - "traefik.http.services.application.loadbalancer.server.port=8090" 17 | - "traefik.http.middlewares.application.redirectscheme.scheme=https" 18 | - "traefik.http.routers.application.entrypoints=websecure" 19 | - "traefik.http.routers.application.rule=Host(`podlodka.localhost`)" 20 | - "traefik.http.routers.application.tls=true" 21 | cron: 22 | build: 23 | target: app_php_dev 24 | volumes: 25 | - ./app:/app/app 26 | - ./vendor:/app/vendor 27 | - ./runtime:/app/runtime 28 | 29 | minio: 30 | labels: 31 | - "traefik.enable=true" 32 | - "traefik.http.routers.minio-http.entrypoints=web" 33 | - "traefik.http.routers.minio-http.rule=Host(`s3.podlodka.localhost`)" 34 | - "traefik.http.routers.minio-http.middlewares=minio-https" 35 | - "traefik.http.services.minio.loadbalancer.server.port=9000" 36 | - "traefik.http.middlewares.minio-https.redirectscheme.scheme=https" 37 | - "traefik.http.routers.minio.entrypoints=websecure" 38 | - "traefik.http.routers.minio.rule=Host(`s3.podlodka.localhost`)" 39 | - "traefik.http.routers.minio.tls=true" 40 | 41 | mailhog: 42 | image: "mailhog/mailhog" 43 | labels: 44 | - "traefik.enable=true" 45 | - "traefik.http.routers.mailhog-http.entrypoints=web" 46 | - "traefik.http.routers.mailhog-http.rule=Host(`mail.podlodka.localhost`)" 47 | - "traefik.http.routers.mailhog-http.middlewares=mailhog-https" 48 | - "traefik.http.services.mailhog.loadbalancer.server.port=8025" 49 | - "traefik.http.middlewares.mailhog-https.redirectscheme.scheme=https" 50 | - "traefik.http.routers.mailhog.entrypoints=websecure" 51 | - "traefik.http.routers.mailhog.rule=Host(`mail.podlodka.localhost`)" 52 | - "traefik.http.routers.mailhog.tls=true" 53 | 54 | postgres: 55 | labels: 56 | - "traefik.enable=true" 57 | - "traefik.tcp.routers.db.entrypoints=postgres" 58 | - "traefik.tcp.routers.db.rule=HostSNI(`*`)" 59 | - "traefik.tcp.routers.db.tls=false" 60 | - "traefik.tcp.services.db.loadBalancer.server.port=5432" 61 | - "traefik.tcp.routers.db.service=db" 62 | 63 | 64 | reverse-proxy: 65 | image: traefik:v2.6 66 | command: 67 | - "--accesslog" 68 | - "--api.insecure=true" 69 | - "--providers.docker=true" 70 | - "--providers.docker.exposedbydefault=false" 71 | - "--entrypoints.web.address=:80" 72 | - "--entrypoints.websecure.address=:443" 73 | - "--entrypoints.postgres.address=:5432" 74 | - "--providers.file.directory=/configuration/" 75 | - "--providers.file.watch=true" 76 | ports: 77 | - "80:80" 78 | - "443:443" 79 | - "8082:8080" 80 | - "5432:5432" 81 | volumes: 82 | - /var/run/docker.sock:/var/run/docker.sock 83 | - ./.docker/traefik/configuration:/configuration/ 84 | - ./.docker/traefik/certs:/etc/certs:ro 85 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | # possible since 3.4 4 | x-php: 5 | &php 6 | build: 7 | dockerfile: .docker/php/Dockerfile 8 | context: ./ 9 | target: app_php 10 | environment: 11 | DB_HOST: ${DB_HOST:?provide db host to .env} 12 | DB_NAME: ${POSTGRES_DB:?provide db name to .env} 13 | DB_USER: ${POSTGRES_USER:?provide db user to .env} 14 | S3_KEY: ${AWS_KEY:?Provide access key to env} 15 | S3_SECRET: ${AWS_SECRET:?Provide secret key to env} 16 | DB_PASSWORD: ${POSTGRES_PASSWORD:?provide db password to .env} 17 | env_file: 18 | - .app.env 19 | depends_on: 20 | postgres: 21 | condition: service_healthy 22 | minio: 23 | condition: service_healthy 24 | gotenberg: 25 | condition: service_healthy 26 | redis: 27 | condition: service_healthy 28 | 29 | services: 30 | application: 31 | <<: *php 32 | command: "/app/rr serve -c .rr.yaml" 33 | ports: 34 | - "8090:8090" 35 | healthcheck: 36 | test: [ 'CMD-SHELL', 'wget --spider -q "http://127.0.0.1:8082/health?plugin=http&plugin=rpc"' ] 37 | interval: 2s 38 | timeout: 2s 39 | 40 | cron: 41 | <<: *php 42 | container_name: cron 43 | command: supercronic /etc/supercronic/podlodka 44 | 45 | postgres: 46 | image: postgres:15.2-alpine3.17 47 | environment: 48 | POSTGRES_DB: ${POSTGRES_DB:?provide db name to .env} 49 | POSTGRES_USER: ${POSTGRES_USER:?provide db user to .env} 50 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?provide db password to .env} 51 | healthcheck: 52 | test: pg_isready -d $$POSTGRES_DB -U $$POSTGRES_USER 53 | interval: 2s 54 | timeout: 5s 55 | start_period: 2s 56 | 57 | gotenberg: 58 | image: thecodingmachine/gotenberg:7.8 59 | healthcheck: 60 | test: curl --fail http://127.0.0.1:3000/health || exit 1 61 | interval: 5s 62 | timeout: 30s 63 | retries: 3 64 | start_period: 2s 65 | 66 | redis: 67 | image: redis:7-alpine 68 | healthcheck: 69 | test: [ 'CMD', 'redis-cli', 'ping' ] 70 | interval: 500ms 71 | timeout: 1s 72 | 73 | minio: 74 | image: minio/minio:RELEASE.2021-06-09T18-51-39Z 75 | command: [ "minio", "server", "/home/shared" ] 76 | healthcheck: 77 | test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ] 78 | interval: 5s 79 | timeout: 20s 80 | retries: 3 81 | environment: 82 | MINIO_ACCESS_KEY: ${AWS_KEY:?Provide access key to .env} 83 | MINIO_SECRET_KEY: ${AWS_SECRET:?Provide secret key to .env} 84 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | app/src 20 | 21 | 22 | 23 | 24 | tests/Unit 25 | 26 | 27 | tests/Feature 28 | 29 | 30 | app/src/Module/*/Test 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexndr-novikov/podlodka-php-crew-2/3c7f30ee682ea1bac6fb12c27c0ac36928b97f34/public/favicon.ico -------------------------------------------------------------------------------- /public/images/403.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/images/404.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/images/500.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/styles/welcome.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 90%; 3 | } 4 | 5 | body { 6 | height: 100%; 7 | min-height: 100%; 8 | margin: 0; 9 | color: #595a59; 10 | font-family: "Helvetica", sans-serif; 11 | font-weight: lighter; 12 | font-size: 14px; 13 | } 14 | 15 | .wrapper { 16 | position: relative; 17 | top: 10%; 18 | transform: translate(50%, -40%); 19 | -webkit-transform: translate(50%, 40%); 20 | text-align: center; 21 | width: 50%; 22 | } 23 | 24 | a { 25 | color: #5fa4ea; 26 | } -------------------------------------------------------------------------------- /tests/App/TestKernel.php: -------------------------------------------------------------------------------- 1 | fakeHttp() 15 | ->get('/') 16 | ->assertOk() 17 | ->assertBodyContains('Welcome to Spiral Framework'); 18 | } 19 | 20 | public function testDefaultActionWithRuLocale(): void 21 | { 22 | $this 23 | ->fakeHttp() 24 | ->withHeader('accept-language', 'ru') 25 | ->get('/') 26 | ->assertOk() 27 | ->assertBodyContains('Вас приветствует Spiral Framework'); 28 | } 29 | 30 | public function testInteractWithConsole(): void 31 | { 32 | $output = $this->runCommand('views:reset'); 33 | 34 | $this->assertStringContainsString('cache', $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/Feature/Job/PingTest.php: -------------------------------------------------------------------------------- 1 | connection = $this->fakeQueue()->getConnection(); 20 | } 21 | 22 | public function testJobPushed(): void 23 | { 24 | $this->connection->push(Ping::class, ['value' => 'hello world']); 25 | 26 | $this->connection->assertPushed(Ping::class, fn (array $data) => 27 | $data['handler'] instanceof Ping && $data['payload']['value'] === 'hello world' 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | beforeBooting(static function (ConfiguratorInterface $config): void { 21 | if (! $config->exists('session')) { 22 | return; 23 | } 24 | 25 | $config->modify('session', new Set('handler', null)); 26 | }); 27 | 28 | parent::setUp(); 29 | 30 | $this->getContainer()->get(TranslatorInterface::class)->setLocale('en'); 31 | } 32 | 33 | public function createAppInstance(Container $container = new Container()): TestableKernelInterface 34 | { 35 | return TestKernel::create( 36 | directories: $this->defineDirectories( 37 | $this->rootDirectory() 38 | ), 39 | exceptionHandler: Handler::class, 40 | container: $container 41 | ); 42 | } 43 | 44 | protected function tearDown(): void 45 | { 46 | // Uncomment this line if you want to clean up runtime directory. 47 | // $this->cleanUpRuntimeDirectory(); 48 | } 49 | 50 | public function rootDirectory(): string 51 | { 52 | return __DIR__.'/..'; 53 | } 54 | 55 | public function defineDirectories(string $root): array 56 | { 57 | return [ 58 | 'root' => $root, 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/Unit/DemoTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($expected); 17 | $this->assertFalse($actual); 18 | } 19 | } 20 | --------------------------------------------------------------------------------