├── var
└── .gitkeep
├── docker
├── keys
│ └── .gitkeep
├── nginx
│ ├── config
│ │ ├── empty.conf
│ │ ├── https_config.conf
│ │ ├── http_to_https_redirect.conf
│ │ ├── conf.d
│ │ │ ├── default.tpl
│ │ │ └── cors_proxy.tpl
│ │ └── nginx.conf
│ ├── web
│ │ └── index.html
│ ├── Dockerfile
│ └── boot.sh
├── shortcuts
│ ├── php
│ ├── console
│ ├── php_stan
│ ├── psql
│ ├── composer
│ └── run_tests
├── docker-compose.local.yml
├── scripts
│ ├── hooks
│ │ └── pre-commit
│ ├── prepare_jwt_keys
│ └── build
├── docker-compose.test.yml
├── docker-compose.dev.yml
├── docker-compose.prod.yml
├── docker-compose.stage.yml
├── docker-compose.yml
└── php
│ ├── Dockerfile
│ └── config
│ └── www.conf
├── tests
├── Fixtures
│ ├── files
│ │ └── .gitkeep
│ └── ORM
│ │ ├── LoadTestUsersData.php
│ │ └── Fixture.php
├── Support
│ ├── ApiAssertionsTrait.php
│ ├── AnonymousFixture.php
│ ├── ApiTestCase.php
│ ├── FixturesTrait.php
│ └── ApiClientTrait.php
└── Api
│ └── LoginTest.php
├── .dockerignore
├── app
├── config
│ ├── routing.yml
│ ├── security.yml
│ ├── services.yml
│ ├── config_test.yml
│ ├── status_codes.php
│ ├── routing_dev.yml
│ ├── config_prod.yml
│ ├── parameters.yml
│ ├── config_dev.yml
│ └── config.yml
├── Resources
│ └── views
│ │ ├── default
│ │ └── index.html.twig
│ │ └── base.html.twig
├── AppCache.php
├── autoload.php
└── AppKernel.php
├── phpstan.neon
├── src
├── Handler
│ └── Session
│ │ ├── LoginRequest.php
│ │ └── LoginHandler.php
├── Command
│ └── LoadInitialDataCommand.php
├── AppBundle.php
├── Model
│ └── User
│ │ ├── User.php
│ │ └── UserRepository.php
└── Common
│ ├── Doctrine
│ └── MigrationEventSubscriber.php
│ └── Http
│ └── RequestObject.php
├── .gitignore
├── bin
├── wait_for_db
├── healthcheck
└── console
├── .editorconfig
├── README.md
├── .php_cs
├── .env
├── app.php
├── phpunit.xml.dist
└── composer.json
/var/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/keys/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/nginx/config/empty.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/Fixtures/files/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/nginx/web/index.html:
--------------------------------------------------------------------------------
1 |
Web Root!
2 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | docker/*
3 | !docker/php/config
4 | var/*
5 | vendor
6 |
--------------------------------------------------------------------------------
/app/config/routing.yml:
--------------------------------------------------------------------------------
1 | #app:
2 | # resource: "@AppBundle/Controller/"
3 | # type: annotation
4 |
--------------------------------------------------------------------------------
/docker/shortcuts/php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose run --user $(id -u) --no-deps --rm php $@
4 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | includes:
2 | - vendor/finwe/phpstan-faker/extension.neon
3 |
4 | parameters:
5 | ignoreErrors:
6 |
7 |
--------------------------------------------------------------------------------
/docker/shortcuts/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose run --rm --user $(id -u) --no-deps php bin/console $@
4 |
--------------------------------------------------------------------------------
/docker/nginx/config/https_config.conf:
--------------------------------------------------------------------------------
1 | ssl on;
2 | ssl_certificate /certs/domain.crt;
3 | ssl_certificate_key /certs/domain.key;
4 |
--------------------------------------------------------------------------------
/src/Handler/Session/LoginRequest.php:
--------------------------------------------------------------------------------
1 | /dev/null; do
6 | sleep 0.1
7 | echo "Retry to connect to database"
8 | done
9 | HEALTHCHECK
10 |
--------------------------------------------------------------------------------
/app/config/security.yml:
--------------------------------------------------------------------------------
1 | security:
2 | providers:
3 | in_memory:
4 | memory: ~
5 |
6 | firewalls:
7 | dev:
8 | pattern: ^/(_(profiler|wdt|error)|css|images|js)/
9 | security: false
10 |
11 | default:
12 | anonymous: ~
13 |
--------------------------------------------------------------------------------
/src/Model/User/UserRepository.php:
--------------------------------------------------------------------------------
1 | em = $em;
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/app/config/services.yml:
--------------------------------------------------------------------------------
1 | # Learn more about services, parameters and containers at
2 | # http://symfony.com/doc/current/book/service_container.html
3 | parameters:
4 |
5 | services:
6 | App\Common\Doctrine\MigrationEventSubscriber:
7 | tags:
8 | - { name: 'doctrine.event_subscriber', connection: 'default' }
9 |
--------------------------------------------------------------------------------
/app/autoload.php:
--------------------------------------------------------------------------------
1 | 404,
6 | \Doctrine\ORM\OptimisticLockException::class => 409,
7 | ];
8 |
9 | // do not touch
10 | $container->loadFromExtension('fos_rest', ['exception' => ['codes' => $statusCodes]]);
11 |
--------------------------------------------------------------------------------
/docker/docker-compose.test.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | php:
5 | environment:
6 | - SYMFONY_ENV=test
7 | - DB_HOST=database_test
8 |
9 | database_test:
10 | extends:
11 | file: docker-compose.dev.yml
12 | service: database
13 | tmpfs:
14 | - /var/lib/postgresql/data
15 |
--------------------------------------------------------------------------------
/docker/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | front:
5 | environment:
6 | - USE_CORS_PROXY=yes
7 |
8 | database:
9 | image: postgres:9.6
10 | environment:
11 | - POSTGRES_USER=${DB_USER}
12 | - POSTGRES_DB=${DB_NAME}
13 | - POSTGRES_PASSWORD=${DB_PASS}
14 | - PGPASSWORD=${DB_PASS}
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | # PHP should follow the PSR-2 standard
13 | # (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
14 | [*.php]
15 | indent_size = 4
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Project Skeleton
2 | ===================================
3 |
4 | ## Build
5 |
6 | Please follow this section in order to build images with application locally or for CI configuration.
7 |
8 | ### Composer
9 |
10 | In order to speed up composer install operation, just provide value for `COMPOSER_GITHUB_TOKEN` in your build environment.
11 | Then it will be used to download files from github.
12 |
--------------------------------------------------------------------------------
/docker/docker-compose.prod.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 |
5 | front:
6 | ports:
7 | - 80:80
8 | - 443:443
9 | volumes:
10 | - "/certs/domain.crt:/certs/domain.crt:ro"
11 | - "/certs/domain.key:/certs/domain.key:ro"
12 | logging:
13 | driver: syslog
14 | php:
15 | logging:
16 | driver: syslog
17 |
--------------------------------------------------------------------------------
/tests/Support/ApiAssertionsTrait.php:
--------------------------------------------------------------------------------
1 | getStatusCode(), $message);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/config/routing_dev.yml:
--------------------------------------------------------------------------------
1 | _wdt:
2 | resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
3 | prefix: /_wdt
4 |
5 | _profiler:
6 | resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
7 | prefix: /_profiler
8 |
9 | _errors:
10 | resource: "@TwigBundle/Resources/config/routing/errors.xml"
11 | prefix: /_error
12 |
13 | _main:
14 | resource: routing.yml
15 |
--------------------------------------------------------------------------------
/tests/Fixtures/ORM/LoadTestUsersData.php:
--------------------------------------------------------------------------------
1 | setRules(array(
9 | '@Symfony' => true,
10 | 'array_syntax' => ['syntax' => 'short'],
11 | 'ordered_imports' => true
12 | ))
13 | ->setFinder(
14 | Finder::create()->in([
15 | __DIR__.'/src'
16 | ])
17 | )
18 | ;
19 |
--------------------------------------------------------------------------------
/tests/Api/LoginTest.php:
--------------------------------------------------------------------------------
1 | request('POST', '/api/v1/sessions', [
12 | 'email' => 'testuser@example.com',
13 | 'password' => 'password',
14 | ]);
15 |
16 | $this->assertStatusCode(201, $response);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Resources/views/base.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block title %}Welcome!{% endblock %}
6 | {% block stylesheets %}{% endblock %}
7 |
8 |
9 |
10 | {% block body %}{% endblock %}
11 | {% block javascripts %}{% endblock %}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/config/config_prod.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
4 | doctrine:
5 | orm:
6 | metadata_cache_driver: apcu
7 | result_cache_driver: apcu
8 | query_cache_driver: apcu
9 |
10 | monolog:
11 | handlers:
12 | main:
13 | type: fingers_crossed
14 | action_level: error
15 | handler: nested
16 | nested:
17 | type: stream
18 | path: php://stderr
19 | level: debug
20 | console:
21 | type: console
22 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # docker
2 | DOCKER_TAG=master
3 | COMPOSE_PROJECT_NAME=skeleton
4 | REPOSITORY_NAME=skeleton/
5 | REGISTRY_URL=
6 | COMPOSE_FILE=docker/docker-compose.yml:docker/docker-compose.dev.yml:docker/docker-compose.local.yml
7 |
8 | # symfony
9 | SYMFONY_ENV=dev
10 | APP_SECRET=00e88699d0655da97f008286e8d4c30c28bd5b4a
11 |
12 | # database
13 | DB_HOST=database
14 | DB_NAME=skeleton_db
15 | DB_USER=skeleton
16 | DB_PASS=skeleton
17 |
18 | # volumes
19 | FRONTEND_HOME=./nginx/web
20 | JWT_PRIVATE_KEY_PATH=./keys/jwt_private.pem
21 | JWT_PUBLIC_KEY_PATH=./keys/jwt_public.pem
22 |
--------------------------------------------------------------------------------
/docker/docker-compose.stage.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | front:
5 | environment:
6 | - USE_CORS_PROXY=yes
7 | ports:
8 | - 80:80
9 | - 443:443
10 | volumes:
11 | - "/certs/domain.crt:/certs/domain.crt:ro"
12 | - "/certs/domain.key:/certs/domain.key:ro"
13 |
14 |
15 | php:
16 | environment:
17 | - RELOAD_DATA
18 |
19 | database:
20 | ports:
21 | # QA wants to work with database on server
22 | - 0.0.0.0:5432:5432
23 |
--------------------------------------------------------------------------------
/docker/scripts/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | dir=$(dirname "${BASH_SOURCE[0]}")
6 |
7 | workflow/shortcuts/composer install --ignore-platform-reqs --optimize-autoloader
8 |
9 | export COMPOSE_FILE=docker/docker-compose.yml:docker/docker-compose.prod.yml
10 | docker-compose build --force-rm
11 | # Spooky bash hack for getting all images built by docker-compose
12 | images=$(docker-compose config | grep -o 'image:\s*registry.*' | cut -d" " -f2)
13 | for image in $images; do
14 | echo "pushing image: $image"
15 | docker push $image
16 | done
17 |
--------------------------------------------------------------------------------
/tests/Support/AnonymousFixture.php:
--------------------------------------------------------------------------------
1 | fn = $fn;
19 | }
20 |
21 | public function load(ObjectManager $manager)
22 | {
23 | call_user_func($this->fn, $manager);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/config/parameters.yml:
--------------------------------------------------------------------------------
1 | # This file is a "template" of what your parameters.yml file should look like
2 | # Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production.
3 | # http://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
4 | parameters:
5 | mailer_transport: smtp
6 | mailer_host: 127.0.0.1
7 | mailer_user: ~
8 | mailer_password: ~
9 |
10 | # A secret key that's used to generate certain security-related tokens
11 | secret: '%env(APP_SECRET)%'
12 |
--------------------------------------------------------------------------------
/tests/Fixtures/ORM/Fixture.php:
--------------------------------------------------------------------------------
1 | faker = Factory::create();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/bin/healthcheck:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | # This scripts awaits for backend to be successfully deployed
6 | # And fails by timeout
7 | # Usage: deploy_health.sh hostname [timeout]
8 | #
9 | # Example:
10 | # deploy_health.sh futureworld.docker
11 | #
12 | # Or with timeout
13 | # deploy_health.sh futureworld.docker 30
14 |
15 | host=$1
16 | timeout_value=${2:-240}
17 |
18 | timeout $timeout_value bash <load(__DIR__.'/.env');
14 | //$kernel = new AppCache($kernel);
15 |
16 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
17 | //Request::enableHttpMethodParameterOverride();
18 | $request = Request::createFromGlobals();
19 | $response = $kernel->handle($request);
20 | $response->send();
21 | $kernel->terminate($request, $response);
22 |
--------------------------------------------------------------------------------
/docker/nginx/config/conf.d/default.tpl:
--------------------------------------------------------------------------------
1 | include ${HTTP_TO_HTTPS_REDIRECT};
2 |
3 | server {
4 | listen ${NGINX_LISTEN_PORT};
5 |
6 | include ${SSL_CONFIG};
7 |
8 | root /srv;
9 |
10 | client_max_body_size 20M;
11 |
12 | gzip on;
13 | gzip_comp_level 2;
14 | gzip_min_length 1000;
15 | gzip_proxied expired no-cache no-store private auth;
16 | gzip_types text/plain application/x-javascript application/javascript text/xml text/css application/xml;
17 |
18 |
19 | location ~* ^/(_profiler|_wdt|api)/.* {
20 | fastcgi_pass php:9000;
21 | include fastcgi_params;
22 | fastcgi_param SCRIPT_FILENAME /app/app.php;
23 | fastcgi_param SCRIPT_NAME app.php;
24 | }
25 |
26 | location / {
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/docker/nginx/config/nginx.conf:
--------------------------------------------------------------------------------
1 | user nginx;
2 | worker_processes auto;
3 |
4 | error_log /var/log/nginx/error.log warn;
5 | pid /var/run/nginx.pid;
6 |
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 | http {
13 | include /etc/nginx/mime.types;
14 | default_type application/octet-stream;
15 |
16 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
17 | '$status $body_bytes_sent "$http_referer" '
18 | '"$http_user_agent" "$http_x_forwarded_for"';
19 |
20 | access_log /var/log/nginx/access.log main;
21 |
22 | sendfile on;
23 | #tcp_nopush on;
24 |
25 | keepalive_timeout 65;
26 |
27 | client_max_body_size 20M;
28 |
29 | include /etc/nginx/conf.d/*.conf;
30 | }
31 |
--------------------------------------------------------------------------------
/src/Common/Doctrine/MigrationEventSubscriber.php:
--------------------------------------------------------------------------------
1 | getSchema();
25 |
26 | if (! $Schema->hasNamespace('public')) {
27 | $Schema->createNamespace('public');
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Support/ApiTestCase.php:
--------------------------------------------------------------------------------
1 | getKernel()->getContainer();
17 | }
18 |
19 | protected function getKernel(): KernelInterface
20 | {
21 | if (!self::$kernel) {
22 | self::$kernel = self::createKernel();
23 | }
24 | self::$kernel->boot();
25 |
26 | return self::$kernel;
27 | }
28 |
29 | protected function getFileFixturesPath(): string
30 | {
31 | return __DIR__.'/../Fixtures/files';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docker/nginx/boot.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -ef
4 |
5 | conf="/etc/nginx/conf.d"
6 | ssl_cert="/certs/domain.crt"
7 | vars='\$NGINX_LISTEN_PORT \$SSL_CONFIG \$HTTP_TO_HTTPS_REDIRECT'
8 |
9 | if [ -f $ssl_cert ]; then
10 | NGINX_LISTEN_PORT="443 ssl"
11 | SSL_CONFIG="https_config.conf"
12 | HTTP_TO_HTTPS_REDIRECT="http_to_https_redirect.conf"
13 | fi
14 |
15 | export NGINX_LISTEN_PORT=${NGINX_LISTEN_PORT:-80} \
16 | HTTP_TO_HTTPS_REDIRECT=${HTTP_TO_HTTPS_REDIRECT:-empty.conf} \
17 | SSL_CONFIG=${SSL_CONFIG:-empty.conf}
18 |
19 | if [ -n "$USE_CORS_PROXY" ]; then
20 | envsubst "$vars" < "$conf/cors_proxy.tpl" > "$conf/cors_proxy.conf"
21 |
22 | export HTTP_TO_HTTPS_REDIRECT="empty.conf" \
23 | SSL_CONFIG="empty.conf" \
24 | NGINX_LISTEN_PORT=8080
25 | fi
26 |
27 | envsubst "$vars" < "$conf/default.tpl" > "$conf/default.conf"
28 |
29 | nginx -g 'daemon off;'
30 |
--------------------------------------------------------------------------------
/docker/nginx/config/conf.d/cors_proxy.tpl:
--------------------------------------------------------------------------------
1 | include ${HTTP_TO_HTTPS_REDIRECT};
2 |
3 | server {
4 | listen ${NGINX_LISTEN_PORT};
5 |
6 | include ${SSL_CONFIG};
7 |
8 | add_header 'Access-Control-Allow-Origin' '*';
9 | add_header 'Access-Control-Allow-Credentials' 'true';
10 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
11 | add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With,X-Authorization';
12 |
13 | if ($request_method = 'OPTIONS') {
14 | return 204;
15 | }
16 |
17 | location / {
18 | proxy_pass http://localhost:8080;
19 | proxy_set_header Host $host;
20 | }
21 |
22 | location ~ /\.ht { deny all; }
23 | location ~ /\.hg { deny all; }
24 | location ~ /\.svn { deny all; }
25 | }
26 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 | tests/Unit
13 |
14 |
15 | tests/Integration
16 |
17 |
18 | tests/Api
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 |
5 | php:
6 | image: ${REGISTRY_URL}${REPOSITORY_NAME}php:${DOCKER_TAG}
7 | build:
8 | context: './../'
9 | dockerfile: 'docker/php/Dockerfile'
10 | args:
11 | COMPOSER_AUTH: '{"github-oauth": {"github.com": "${COMPOSER_GITHUB_TOKEN}"}}'
12 | environment:
13 | - SYMFONY_ENV
14 | - DB_HOST
15 | - DB_NAME
16 | - DB_USER
17 | - DB_PASS
18 | - APP_SECRET
19 | volumes:
20 | - "${JWT_PRIVATE_KEY_PATH}:/keys/jwt_private.pem:ro"
21 | - "${JWT_PUBLIC_KEY_PATH}:/keys/jwt_public.pem:ro"
22 |
23 | front:
24 | image: ${REGISTRY_URL}${REPOSITORY_NAME}front:${DOCKER_TAG}
25 | build: 'nginx'
26 | depends_on:
27 | - php
28 | volumes:
29 | - "${FRONTEND_HOME}:/srv:ro"
30 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
22 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
23 |
24 | if ($debug) {
25 | Debug::enable();
26 | }
27 |
28 | (new Dotenv())->load(__DIR__.'/../.env');
29 |
30 | $kernel = new AppKernel($env, $debug);
31 | $application = new Application($kernel);
32 | $application->run($input);
33 |
--------------------------------------------------------------------------------
/src/Common/Http/RequestObject.php:
--------------------------------------------------------------------------------
1 | 422,
18 | 'message' => 'Invalid data in request body',
19 | 'errors' => array_map(function (ConstraintViolation $violation) {
20 | return [
21 | 'path' => $violation->getPropertyPath(),
22 | 'message' => $violation->getMessage(),
23 | ];
24 | }, iterator_to_array($errors)),
25 | ],
26 | 422
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/config/config_dev.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
4 | framework:
5 | router:
6 | resource: "%kernel.root_dir%/config/routing_dev.yml"
7 | strict_requirements: true
8 | profiler: { only_exceptions: false }
9 |
10 | web_profiler:
11 | toolbar: true
12 | intercept_redirects: false
13 |
14 | monolog:
15 | handlers:
16 | main:
17 | type: stream
18 | path: "%kernel.logs_dir%/%kernel.environment%.log"
19 | level: debug
20 | console:
21 | type: console
22 | bubble: false
23 | verbosity_levels:
24 | VERBOSITY_VERBOSE: INFO
25 | VERBOSITY_VERY_VERBOSE: DEBUG
26 | channels: ["!doctrine"]
27 | console_very_verbose:
28 | type: console
29 | bubble: false
30 | verbosity_levels:
31 | VERBOSITY_VERBOSE: NOTICE
32 | VERBOSITY_VERY_VERBOSE: NOTICE
33 | VERBOSITY_DEBUG: DEBUG
34 | channels: ["doctrine"]
35 | # uncomment to get logging in your browser
36 | # you may have to allow bigger header sizes in your Web server configuration
37 | #firephp:
38 | # type: firephp
39 | # level: info
40 | #chromephp:
41 | # type: chromephp
42 | # level: info
43 |
44 | #swiftmailer:
45 | # delivery_address: me@example.com
46 |
--------------------------------------------------------------------------------
/docker/php/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:7.2-fpm
2 |
3 | RUN apt-get update \
4 | && apt-get install -y libpq-dev libgmp-dev git zip \
5 | && rm -rf /var/lib/apt/lists/*
6 |
7 | RUN docker-php-ext-install \
8 | gmp \
9 | mbstring \
10 | opcache \
11 | pdo pdo_pgsql
12 |
13 | RUN yes | pecl install apcu xdebug-beta \
14 | && echo "extension=apcu.so" > /usr/local/etc/php/conf.d/apcu.ini \
15 | && echo "apc.enable_cli=1" >> /usr/local/etc/php/conf.d/apcu.ini \
16 | && echo ";zend_extension=xdebug.so" > /usr/local/etc/php/conf.d/xdebug.ini \
17 | && echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
18 | && echo "xdebug.remote_autostart=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
19 | && echo "xdebug.remote_connect_back=on" >> /usr/local/etc/php/conf.d/xdebug.ini
20 |
21 | WORKDIR /app
22 |
23 | RUN curl --silent --show-error https://getcomposer.org/installer | \
24 | php -- --install-dir=/usr/bin/ --filename=composer && \
25 | composer global require hirak/prestissimo && \
26 | composer clear-cache
27 |
28 | COPY docker/php/config/www.conf /usr/local/etc/php-fpm.d/www.conf
29 | CMD ["php-fpm", "--allow-to-run-as-root"]
30 |
31 | ARG COMPOSER_AUTH
32 | ADD composer.json composer.lock ./
33 | RUN composer install --no-scripts --no-autoloader --no-suggest && \
34 | composer clear-cache
35 | COPY . /app/
36 | RUN composer dump --optimize
37 | RUN bin/console -e=prod cache:warmup
38 |
--------------------------------------------------------------------------------
/docker/shortcuts/run_tests:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | # Starts test suite
6 | #
7 | # Usage: test [] []
8 | #
9 | # Examples:
10 | # run_tests - starts all tests suites
11 | # run_tests unit - starts unit test suite
12 | # run_tests integration - starts integration test suite
13 | # run_tests integ - you may use part of string
14 | # run_tests u ./tests/User/ - you may run suite for part of tests
15 |
16 |
17 | suite=$(echo "$1" | awk '{print tolower($0)}')
18 | tests_path=$2
19 |
20 | run_unit_tests=false
21 | run_integration_tests=false
22 | # Normalize input
23 | if [[ "unit" == "$suite"* ]]; then
24 | run_unit_tests=true
25 | fi
26 | if [[ "integration" == "$suite"* ]]; then
27 | run_integration_tests=true
28 | fi
29 |
30 | if [[ true == "$run_unit_tests" ]]; then
31 | echo "Run Unit Test Suite"
32 |
33 | docker-compose run --no-deps --rm php bin/phpunit --testsuite unit "$tests_path"
34 | fi
35 |
36 | if [[ true == "$run_integration_tests" ]]; then
37 | echo "Run Integration Test Suite"
38 |
39 | [ -z "$COMPOSE_FILE" ] && COMPOSE_FILE=$(cat .env | grep COMPOSE_FILE | cut -d = -f 2)
40 | COMPOSE_FILE="$COMPOSE_FILE:workflow/docker/docker-compose.test.yml";
41 |
42 | export COMPOSE_FILE=$COMPOSE_FILE
43 |
44 | docker-compose up -d database_test
45 | cmd="bin/wait_for_db"
46 | cmd="$cmd && bin/console doctrine:schema:update --force"
47 | cmd="$cmd && bin/phpunit --testsuite integration $tests_path"
48 |
49 | passed=0;
50 | docker-compose run --rm php bash -c "$cmd" || passed=$?
51 |
52 | [ -z "$KEEP_TEST_DB" ] \
53 | && docker-compose kill database_test \
54 | && docker-compose rm -f database_test
55 |
56 | [ "0" = $passed ] || exit $passed
57 |
58 | fi
59 |
--------------------------------------------------------------------------------
/app/AppKernel.php:
--------------------------------------------------------------------------------
1 | getEnvironment(), ['dev', 'test'])) {
27 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
28 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
29 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
30 | }
31 |
32 | return $bundles;
33 | }
34 |
35 | public function getRootDir()
36 | {
37 | return __DIR__;
38 | }
39 |
40 | public function getCacheDir()
41 | {
42 | return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
43 | }
44 |
45 | public function getLogDir()
46 | {
47 | return dirname(__DIR__).'/var/logs';
48 | }
49 |
50 | public function registerContainerConfiguration(LoaderInterface $loader)
51 | {
52 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/Support/FixturesTrait.php:
--------------------------------------------------------------------------------
1 | normalizeFixtures($fixtures);
31 |
32 | $container = $this->getContainer();
33 | $loader = new ContainerAwareLoader($container);
34 | foreach ($fixtures as $fixture) {
35 | $loader->addFixture($fixture);
36 | }
37 |
38 | $em = $container->get('doctrine.orm.default_entity_manager');
39 | $purger = new ORMPurger($em);
40 | $purger->setPurgeMode(ORMPurger::PURGE_MODE_TRUNCATE);
41 | $executor = new ORMExecutor($em, $purger);
42 | $executor->execute($loader->getFixtures());
43 |
44 | self::$fixtureLoaded = true;
45 | self::$loadedFixtures = $fixtures;
46 |
47 | return self::$loadedFixtures;
48 | }
49 |
50 | /**
51 | * @param mixed $fixtures
52 | * @return AbstractFixture[]
53 | */
54 | private function normalizeFixtures($fixtures)
55 | {
56 | if (is_callable($fixtures)) {
57 | $fixtures = $this->addFixtureFromClosure($fixtures);
58 | }
59 | if (!is_array($fixtures)) {
60 | $fixtures = [$fixtures];
61 | }
62 |
63 | return array_map(function ($fixture) {
64 | if (is_string($fixture)) {
65 | return new $fixture();
66 | }
67 |
68 | return $fixture;
69 | }, $fixtures);
70 | }
71 |
72 | private function addFixtureFromClosure(callable $fixture)
73 | {
74 | return new AnonymousFixture($fixture);
75 | }
76 |
77 | abstract protected function getContainer(): ContainerInterface;
78 | }
79 |
--------------------------------------------------------------------------------
/app/config/config.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: parameters.yml }
3 | - { resource: security.yml }
4 | - { resource: services.yml }
5 |
6 | # Put parameters here that don't need to change on each machine where the app is deployed
7 | # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
8 | parameters:
9 | locale: en
10 |
11 | framework:
12 | #esi: ~
13 | #translator: { fallbacks: ["%locale%"] }
14 | secret: "%secret%"
15 | router:
16 | resource: "%kernel.root_dir%/config/routing.yml"
17 | strict_requirements: ~
18 | serializer:
19 | enabled: true
20 | form: ~
21 | csrf_protection: ~
22 | validation: { enable_annotations: true }
23 | templating:
24 | engines: ['twig']
25 | #assets_version: SomeVersionScheme
26 | default_locale: "%locale%"
27 | session:
28 | # handler_id set to null will use default session handler from php.ini
29 | handler_id: ~
30 | fragments: ~
31 | http_method_override: true
32 |
33 | # Twig Configuration
34 | twig:
35 | debug: "%kernel.debug%"
36 | strict_variables: "%kernel.debug%"
37 |
38 | # Doctrine Configuration
39 | doctrine:
40 | dbal:
41 | driver: pdo_pgsql
42 | host: "%env(DB_HOST)%"
43 | port: "5432"
44 | dbname: "%env(DB_NAME)%"
45 | user: "%env(DB_USER)%"
46 | password: "%env(DB_PASS)%"
47 | charset: UTF8
48 |
49 | orm:
50 | auto_generate_proxy_classes: "%kernel.debug%"
51 | auto_mapping: false
52 | mappings:
53 | AppBundle:
54 | type: annotation
55 | dir: '%kernel.root_dir%/../src/Model'
56 | prefix: 'App\Model'
57 |
58 | # Swiftmailer Configuration
59 | swiftmailer:
60 | transport: "%mailer_transport%"
61 | host: "%mailer_host%"
62 | username: "%mailer_user%"
63 | password: "%mailer_password%"
64 | spool: { type: memory }
65 |
66 | #fos_rest:
67 | # body_listener:
68 | # array_normalizer: fos_rest.normalizer.camel_keys
69 | #
70 | # exception:
71 | # codes: []
72 |
73 | lexik_jwt_authentication:
74 | private_key_path: '/keys/jwt_private.pem'
75 | public_key_path: '/keys/jwt_public.pem'
76 | pass_phrase: ~
77 | # We should use refresh tokens here!
78 | token_ttl: 3600
79 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fesor/projec-template",
3 | "license": "MIT",
4 | "type": "project",
5 | "description": "Basic API project template",
6 | "autoload": {
7 | "psr-4": { "App\\": "src/" },
8 | "classmap": [ "app/AppKernel.php", "app/AppCache.php" ]
9 | },
10 | "autoload-dev": {
11 | "psr-4": {"Tests\\": "tests"},
12 | "files": [ "vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php" ]
13 | },
14 | "require": {
15 | "php": ">=7.1.0",
16 | "doctrine/doctrine-bundle": "^1.6",
17 | "doctrine/orm": "^2.5",
18 | "sensio/distribution-bundle": "^5.0.19",
19 | "sensio/framework-extra-bundle": "^5.0.0",
20 | "symfony/monolog-bundle": "^3.1.0",
21 | "symfony/polyfill-apcu": "^1.0",
22 | "symfony/swiftmailer-bundle": "^2.6.4",
23 | "symfony/symfony": "3.4.*",
24 | "twig/twig": "^1.0||^2.0",
25 | "doctrine/doctrine-cache-bundle": "^1.3",
26 | "doctrine/doctrine-migrations-bundle": "~1.2.0",
27 | "fesor/request-objects": "^0.2.1",
28 | "friendsofsymfony/rest-bundle": "^2.1",
29 | "lexik/jwt-authentication-bundle": "^2.0",
30 | "symfony/dotenv": "^3.4"
31 | },
32 | "require-dev": {
33 | "friendsofphp/php-cs-fixer": "~2.0",
34 | "phpunit/phpunit": "^5.6",
35 | "symfony/phpunit-bridge": "^3.0",
36 | "doctrine/doctrine-fixtures-bundle": "^2.3",
37 | "fzaninotto/faker": "^1.7"
38 | },
39 | "scripts": {
40 | "start": [
41 | "composer install",
42 | "docker-compose up -d",
43 | "docker-compose run --rm php bin/wait_for_db",
44 | "docker/shortcuts/console doctr:migration:migrate -n --allow-no-migration",
45 | "docker/shortcuts/console doctrine:fixtures:load -n --fixtures tests/Fixtures/ORM"
46 | ],
47 | "prepare-project": [
48 | "ln -sf `pwd`/docker/scripts/hooks/pre-commit .git/hooks/pre-commit"
49 | ],
50 | "symfony-scripts": [
51 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
52 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
53 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget",
54 | "@prepare-project"
55 | ],
56 | "post-install-cmd": [
57 | "@symfony-scripts"
58 | ],
59 | "post-update-cmd": [
60 | "@symfony-scripts"
61 | ]
62 | },
63 | "config": {
64 | "bin-dir": "bin"
65 | },
66 | "extra": {
67 | "symfony-app-dir": "app",
68 | "symfony-bin-dir": "bin",
69 | "symfony-var-dir": "var",
70 | "branch-alias": {
71 | "dev-master": "1.x-dev"
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/tests/Support/ApiClientTrait.php:
--------------------------------------------------------------------------------
1 | 'application/json',
15 | 'Accept' => 'application/json',
16 | ];
17 | private $headers = [];
18 |
19 | abstract protected function getContainer(): ContainerInterface;
20 |
21 | abstract protected function getKernel(): KernelInterface;
22 |
23 | abstract protected function getFileFixturesPath(): string;
24 |
25 | protected function signedInAs(string $email)
26 | {
27 | $token = sha1($email); // fixme: just pseudo random string for example
28 | $this->headers['X-Authorization'] = "Bearer {$token}";
29 | }
30 |
31 | /**
32 | * @param string $method
33 | * @param string $uri
34 | * @param mixed|null $body
35 | *
36 | * @return Response
37 | */
38 | protected function request(string $method, string $uri, $body = null): Response
39 | {
40 | if (!in_array($method, ['GET', 'HEAD', 'OPTIONS'])) {
41 | $body = json_encode($body);
42 | } else {
43 | $body = null;
44 | }
45 |
46 | $request = Request::create($uri, $method, [], [], [], $this->headers(), $body);
47 |
48 | return $this->handleRequest($request);
49 | }
50 |
51 | protected function multipartRequest(string $uri, array $parameters = [], array $files = []): Response
52 | {
53 | $this->headers['Content-Type'] = null;
54 | $request = Request::create($uri, 'POST', $parameters, [], $this->processFiles($files), $this->headers());
55 |
56 | return $this->handleRequest($request);
57 | }
58 |
59 | private function headers()
60 | {
61 | $headers = array_filter(array_replace($this->defaultHeaders, $this->headers));
62 | $keys = array_map(function ($key) {
63 | if ($key === 'Content-Type') {
64 | return 'CONTENT_TYPE';
65 | }
66 |
67 | return 'HTTP_'.str_replace('-', '_', strtoupper($key));
68 | }, array_keys($headers));
69 |
70 | return array_combine($keys, array_values($headers));
71 | }
72 |
73 | private function processFiles(array $files = [])
74 | {
75 | return array_map(function (string $file) {
76 | $filePath = sprintf('%s/%s', $this->getFileFixturesPath(), $file);
77 | $temp = tmpfile();
78 | $tempFilePath = stream_get_meta_data($temp)['url'];
79 | stream_copy_to_stream(fopen($filePath, 'r'), $temp);
80 |
81 | return new UploadedFile(
82 | $tempFilePath,
83 | pathinfo($filePath, PATHINFO_BASENAME),
84 | $this->mimetypeByExt(pathinfo($filePath, PATHINFO_EXTENSION)),
85 | filesize($filePath),
86 | null,
87 | true
88 | );
89 | }, $files);
90 | }
91 |
92 | private function handleRequest(Request $request): Response
93 | {
94 | $kernel = $this->getKernel();
95 |
96 | return $kernel->handle($request);
97 | }
98 |
99 | private function mimetypeByExt($ext)
100 | {
101 | return [
102 | 'txt' => 'text/plain',
103 | 'html' => 'text/html',
104 | 'json' => 'application/json',
105 | 'jpg' => 'image/jpeg',
106 | 'jpeg' => 'image/jpeg',
107 | 'gif' => 'image/gif',
108 | 'png' => 'image/png',
109 | 'svg' => 'image/png',
110 | 'bmp' => 'image/bmp',
111 | 'mpeg' => 'video/mpeg',
112 | 'mp3' => 'audio/mpeg',
113 | 'wav' => 'audio/wav',
114 | 'zip' => 'application/zip',
115 | ][mb_strtolower($ext)] ?? 'application/octet-stream';
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/docker/php/config/www.conf:
--------------------------------------------------------------------------------
1 | ; Start a new pool named 'www'.
2 | ; the variable $pool can we used in any directive and will be replaced by the
3 | ; pool name ('www' here)
4 | [www]
5 |
6 | ; Per pool prefix
7 | ; It only applies on the following directives:
8 | ; - 'access.log'
9 | ; - 'slowlog'
10 | ; - 'listen' (unixsocket)
11 | ; - 'chroot'
12 | ; - 'chdir'
13 | ; - 'php_values'
14 | ; - 'php_admin_values'
15 | ; When not set, the global prefix (or NONE) applies instead.
16 | ; Note: This directive can also be relative to the global prefix.
17 | ; Default Value: none
18 | ;prefix = /path/to/pools/$pool
19 |
20 | ; Unix user/group of processes
21 | ; Note: The user is mandatory. If the group is not set, the default user's group
22 | ; will be used.
23 | user = root
24 | group = www-data
25 |
26 | ; The address on which to accept FastCGI requests.
27 | ; Valid syntaxes are:
28 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
29 | ; a specific port;
30 | ; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
31 | ; a specific port;
32 | ; 'port' - to listen on a TCP socket to all addresses
33 | ; (IPv6 and IPv4-mapped) on a specific port;
34 | ; '/path/to/unix/socket' - to listen on a unix socket.
35 | ; Note: This value is mandatory.
36 | listen = 127.0.0.1:9000
37 |
38 | ; Set listen(2) backlog.
39 | ; Default Value: 511 (-1 on FreeBSD and OpenBSD)
40 | ;listen.backlog = 511
41 |
42 | ; Set permissions for unix socket, if one is used. In Linux, read/write
43 | ; permissions must be set in order to allow connections from a web server. Many
44 | ; BSD-derived systems allow connections regardless of permissions.
45 | ; Default Values: user and group are set as the running user
46 | ; mode is set to 0660
47 | ;listen.owner = www-data
48 | ;listen.group = www-data
49 | ;listen.mode = 0660
50 | ; When POSIX Access Control Lists are supported you can set them using
51 | ; these options, value is a comma separated list of user/group names.
52 | ; When set, listen.owner and listen.group are ignored
53 | ;listen.acl_users =
54 | ;listen.acl_groups =
55 |
56 | ; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.
57 | ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
58 | ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
59 | ; must be separated by a comma. If this value is left blank, connections will be
60 | ; accepted from any ip address.
61 | ; Default Value: any
62 | ;listen.allowed_clients = 127.0.0.1
63 |
64 | ; Specify the nice(2) priority to apply to the pool processes (only if set)
65 | ; The value can vary from -19 (highest priority) to 20 (lower priority)
66 | ; Note: - It will only work if the FPM master process is launched as root
67 | ; - The pool processes will inherit the master process priority
68 | ; unless it specified otherwise
69 | ; Default Value: no set
70 | ; process.priority = -19
71 |
72 | ; Choose how the process manager will control the number of child processes.
73 | ; Possible Values:
74 | ; static - a fixed number (pm.max_children) of child processes;
75 | ; dynamic - the number of child processes are set dynamically based on the
76 | ; following directives. With this process management, there will be
77 | ; always at least 1 children.
78 | ; pm.max_children - the maximum number of children that can
79 | ; be alive at the same time.
80 | ; pm.start_servers - the number of children created on startup.
81 | ; pm.min_spare_servers - the minimum number of children in 'idle'
82 | ; state (waiting to process). If the number
83 | ; of 'idle' processes is less than this
84 | ; number then some children will be created.
85 | ; pm.max_spare_servers - the maximum number of children in 'idle'
86 | ; state (waiting to process). If the number
87 | ; of 'idle' processes is greater than this
88 | ; number then some children will be killed.
89 | ; ondemand - no children are created at startup. Children will be forked when
90 | ; new requests will connect. The following parameter are used:
91 | ; pm.max_children - the maximum number of children that
92 | ; can be alive at the same time.
93 | ; pm.process_idle_timeout - The number of seconds after which
94 | ; an idle process will be killed.
95 | ; Note: This value is mandatory.
96 | pm = dynamic
97 |
98 | ; The number of child processes to be created when pm is set to 'static' and the
99 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
100 | ; This value sets the limit on the number of simultaneous requests that will be
101 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
102 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
103 | ; CGI. The below defaults are based on a server without much resources. Don't
104 | ; forget to tweak pm.* to fit your needs.
105 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
106 | ; Note: This value is mandatory.
107 | pm.max_children = 5
108 |
109 | ; The number of child processes created on startup.
110 | ; Note: Used only when pm is set to 'dynamic'
111 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
112 | pm.start_servers = 2
113 |
114 | ; The desired minimum number of idle server processes.
115 | ; Note: Used only when pm is set to 'dynamic'
116 | ; Note: Mandatory when pm is set to 'dynamic'
117 | pm.min_spare_servers = 1
118 |
119 | ; The desired maximum number of idle server processes.
120 | ; Note: Used only when pm is set to 'dynamic'
121 | ; Note: Mandatory when pm is set to 'dynamic'
122 | pm.max_spare_servers = 3
123 |
124 | ; The number of seconds after which an idle process will be killed.
125 | ; Note: Used only when pm is set to 'ondemand'
126 | ; Default Value: 10s
127 | ;pm.process_idle_timeout = 10s;
128 |
129 | ; The number of requests each child process should execute before respawning.
130 | ; This can be useful to work around memory leaks in 3rd party libraries. For
131 | ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
132 | ; Default Value: 0
133 | ;pm.max_requests = 500
134 |
135 | ; The URI to view the FPM status page. If this value is not set, no URI will be
136 | ; recognized as a status page. It shows the following informations:
137 | ; pool - the name of the pool;
138 | ; process manager - static, dynamic or ondemand;
139 | ; start time - the date and time FPM has started;
140 | ; start since - number of seconds since FPM has started;
141 | ; accepted conn - the number of request accepted by the pool;
142 | ; listen queue - the number of request in the queue of pending
143 | ; connections (see backlog in listen(2));
144 | ; max listen queue - the maximum number of requests in the queue
145 | ; of pending connections since FPM has started;
146 | ; listen queue len - the size of the socket queue of pending connections;
147 | ; idle processes - the number of idle processes;
148 | ; active processes - the number of active processes;
149 | ; total processes - the number of idle + active processes;
150 | ; max active processes - the maximum number of active processes since FPM
151 | ; has started;
152 | ; max children reached - number of times, the process limit has been reached,
153 | ; when pm tries to start more children (works only for
154 | ; pm 'dynamic' and 'ondemand');
155 | ; Value are updated in real time.
156 | ; Example output:
157 | ; pool: www
158 | ; process manager: static
159 | ; start time: 01/Jul/2011:17:53:49 +0200
160 | ; start since: 62636
161 | ; accepted conn: 190460
162 | ; listen queue: 0
163 | ; max listen queue: 1
164 | ; listen queue len: 42
165 | ; idle processes: 4
166 | ; active processes: 11
167 | ; total processes: 15
168 | ; max active processes: 12
169 | ; max children reached: 0
170 | ;
171 | ; By default the status page output is formatted as text/plain. Passing either
172 | ; 'html', 'xml' or 'json' in the query string will return the corresponding
173 | ; output syntax. Example:
174 | ; http://www.foo.bar/status
175 | ; http://www.foo.bar/status?json
176 | ; http://www.foo.bar/status?html
177 | ; http://www.foo.bar/status?xml
178 | ;
179 | ; By default the status page only outputs short status. Passing 'full' in the
180 | ; query string will also return status for each pool process.
181 | ; Example:
182 | ; http://www.foo.bar/status?full
183 | ; http://www.foo.bar/status?json&full
184 | ; http://www.foo.bar/status?html&full
185 | ; http://www.foo.bar/status?xml&full
186 | ; The Full status returns for each process:
187 | ; pid - the PID of the process;
188 | ; state - the state of the process (Idle, Running, ...);
189 | ; start time - the date and time the process has started;
190 | ; start since - the number of seconds since the process has started;
191 | ; requests - the number of requests the process has served;
192 | ; request duration - the duration in µs of the requests;
193 | ; request method - the request method (GET, POST, ...);
194 | ; request URI - the request URI with the query string;
195 | ; content length - the content length of the request (only with POST);
196 | ; user - the user (PHP_AUTH_USER) (or '-' if not set);
197 | ; script - the main script called (or '-' if not set);
198 | ; last request cpu - the %cpu the last request consumed
199 | ; it's always 0 if the process is not in Idle state
200 | ; because CPU calculation is done when the request
201 | ; processing has terminated;
202 | ; last request memory - the max amount of memory the last request consumed
203 | ; it's always 0 if the process is not in Idle state
204 | ; because memory calculation is done when the request
205 | ; processing has terminated;
206 | ; If the process is in Idle state, then informations are related to the
207 | ; last request the process has served. Otherwise informations are related to
208 | ; the current request being served.
209 | ; Example output:
210 | ; ************************
211 | ; pid: 31330
212 | ; state: Running
213 | ; start time: 01/Jul/2011:17:53:49 +0200
214 | ; start since: 63087
215 | ; requests: 12808
216 | ; request duration: 1250261
217 | ; request method: GET
218 | ; request URI: /test_mem.php?N=10000
219 | ; content length: 0
220 | ; user: -
221 | ; script: /home/fat/web/docs/php/test_mem.php
222 | ; last request cpu: 0.00
223 | ; last request memory: 0
224 | ;
225 | ; Note: There is a real-time FPM status monitoring sample web page available
226 | ; It's available in: /usr/local/share/php/fpm/status.html
227 | ;
228 | ; Note: The value must start with a leading slash (/). The value can be
229 | ; anything, but it may not be a good idea to use the .php extension or it
230 | ; may conflict with a real PHP file.
231 | ; Default Value: not set
232 | ;pm.status_path = /status
233 |
234 | ; The ping URI to call the monitoring page of FPM. If this value is not set, no
235 | ; URI will be recognized as a ping page. This could be used to test from outside
236 | ; that FPM is alive and responding, or to
237 | ; - create a graph of FPM availability (rrd or such);
238 | ; - remove a server from a group if it is not responding (load balancing);
239 | ; - trigger alerts for the operating team (24/7).
240 | ; Note: The value must start with a leading slash (/). The value can be
241 | ; anything, but it may not be a good idea to use the .php extension or it
242 | ; may conflict with a real PHP file.
243 | ; Default Value: not set
244 | ;ping.path = /ping
245 |
246 | ; This directive may be used to customize the response of a ping request. The
247 | ; response is formatted as text/plain with a 200 response code.
248 | ; Default Value: pong
249 | ;ping.response = pong
250 |
251 | ; The access log file
252 | ; Default: not set
253 | ;access.log = log/$pool.access.log
254 |
255 | ; The access log format.
256 | ; The following syntax is allowed
257 | ; %%: the '%' character
258 | ; %C: %CPU used by the request
259 | ; it can accept the following format:
260 | ; - %{user}C for user CPU only
261 | ; - %{system}C for system CPU only
262 | ; - %{total}C for user + system CPU (default)
263 | ; %d: time taken to serve the request
264 | ; it can accept the following format:
265 | ; - %{seconds}d (default)
266 | ; - %{miliseconds}d
267 | ; - %{mili}d
268 | ; - %{microseconds}d
269 | ; - %{micro}d
270 | ; %e: an environment variable (same as $_ENV or $_SERVER)
271 | ; it must be associated with embraces to specify the name of the env
272 | ; variable. Some exemples:
273 | ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
274 | ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
275 | ; %f: script filename
276 | ; %l: content-length of the request (for POST request only)
277 | ; %m: request method
278 | ; %M: peak of memory allocated by PHP
279 | ; it can accept the following format:
280 | ; - %{bytes}M (default)
281 | ; - %{kilobytes}M
282 | ; - %{kilo}M
283 | ; - %{megabytes}M
284 | ; - %{mega}M
285 | ; %n: pool name
286 | ; %o: output header
287 | ; it must be associated with embraces to specify the name of the header:
288 | ; - %{Content-Type}o
289 | ; - %{X-Powered-By}o
290 | ; - %{Transfert-Encoding}o
291 | ; - ....
292 | ; %p: PID of the child that serviced the request
293 | ; %P: PID of the parent of the child that serviced the request
294 | ; %q: the query string
295 | ; %Q: the '?' character if query string exists
296 | ; %r: the request URI (without the query string, see %q and %Q)
297 | ; %R: remote IP address
298 | ; %s: status (response code)
299 | ; %t: server time the request was received
300 | ; it can accept a strftime(3) format:
301 | ; %d/%b/%Y:%H:%M:%S %z (default)
302 | ; The strftime(3) format must be encapsuled in a %{}t tag
303 | ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
304 | ; %T: time the log has been written (the request has finished)
305 | ; it can accept a strftime(3) format:
306 | ; %d/%b/%Y:%H:%M:%S %z (default)
307 | ; The strftime(3) format must be encapsuled in a %{}t tag
308 | ; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
309 | ; %u: remote user
310 | ;
311 | ; Default: "%R - %u %t \"%m %r\" %s"
312 | ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
313 |
314 | ; The log file for slow requests
315 | ; Default Value: not set
316 | ; Note: slowlog is mandatory if request_slowlog_timeout is set
317 | ;slowlog = log/$pool.log.slow
318 |
319 | ; The timeout for serving a single request after which a PHP backtrace will be
320 | ; dumped to the 'slowlog' file. A value of '0s' means 'off'.
321 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
322 | ; Default Value: 0
323 | ;request_slowlog_timeout = 0
324 |
325 | ; The timeout for serving a single request after which the worker process will
326 | ; be killed. This option should be used when the 'max_execution_time' ini option
327 | ; does not stop script execution for some reason. A value of '0' means 'off'.
328 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
329 | ; Default Value: 0
330 | ;request_terminate_timeout = 0
331 |
332 | ; Set open file descriptor rlimit.
333 | ; Default Value: system defined value
334 | ;rlimit_files = 1024
335 |
336 | ; Set max core size rlimit.
337 | ; Possible Values: 'unlimited' or an integer greater or equal to 0
338 | ; Default Value: system defined value
339 | ;rlimit_core = 0
340 |
341 | ; Chroot to this directory at the start. This value must be defined as an
342 | ; absolute path. When this value is not set, chroot is not used.
343 | ; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
344 | ; of its subdirectories. If the pool prefix is not set, the global prefix
345 | ; will be used instead.
346 | ; Note: chrooting is a great security feature and should be used whenever
347 | ; possible. However, all PHP paths will be relative to the chroot
348 | ; (error_log, sessions.save_path, ...).
349 | ; Default Value: not set
350 | ;chroot =
351 |
352 | ; Chdir to this directory at the start.
353 | ; Note: relative path can be used.
354 | ; Default Value: current directory or / when chroot
355 | ;chdir = /var/www
356 |
357 | ; Redirect worker stdout and stderr into main error log. If not set, stdout and
358 | ; stderr will be redirected to /dev/null according to FastCGI specs.
359 | ; Note: on highloaded environement, this can cause some delay in the page
360 | ; process time (several ms).
361 | ; Default Value: no
362 | ;catch_workers_output = yes
363 |
364 | ; Clear environment in FPM workers
365 | ; Prevents arbitrary environment variables from reaching FPM worker processes
366 | ; by clearing the environment in workers before env vars specified in this
367 | ; pool configuration are added.
368 | ; Setting to "no" will make all environment variables available to PHP code
369 | ; via getenv(), $_ENV and $_SERVER.
370 | ; Default Value: yes
371 | ;clear_env = no
372 |
373 | ; Limits the extensions of the main script FPM will allow to parse. This can
374 | ; prevent configuration mistakes on the web server side. You should only limit
375 | ; FPM to .php extensions to prevent malicious users to use other extensions to
376 | ; exectute php code.
377 | ; Note: set an empty value to allow all extensions.
378 | ; Default Value: .php
379 | ;security.limit_extensions = .php .php3 .php4 .php5 .php7
380 |
381 | ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
382 | ; the current environment.
383 | ; Default Value: clean env
384 | ;env[HOSTNAME] = $HOSTNAME
385 | ;env[PATH] = /usr/local/bin:/usr/bin:/bin
386 | ;env[TMP] = /tmp
387 | ;env[TMPDIR] = /tmp
388 | ;env[TEMP] = /tmp
389 |
390 | ; Additional php.ini defines, specific to this pool of workers. These settings
391 | ; overwrite the values previously defined in the php.ini. The directives are the
392 | ; same as the PHP SAPI:
393 | ; php_value/php_flag - you can set classic ini defines which can
394 | ; be overwritten from PHP call 'ini_set'.
395 | ; php_admin_value/php_admin_flag - these directives won't be overwritten by
396 | ; PHP call 'ini_set'
397 | ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
398 |
399 | ; Defining 'extension' will load the corresponding shared extension from
400 | ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
401 | ; overwrite previously defined php.ini values, but will append the new value
402 | ; instead.
403 |
404 | ; Note: path INI options can be relative and will be expanded with the prefix
405 | ; (pool, global or /usr/local)
406 |
407 | ; Default Value: nothing is defined by default except the values in php.ini and
408 | ; specified at startup with the -d argument
409 | ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
410 | ;php_flag[display_errors] = off
411 | ;php_admin_value[error_log] = /var/log/fpm-php.www.log
412 | ;php_admin_flag[log_errors] = on
413 | ;php_admin_value[memory_limit] = 32M
414 | php_admin_value[upload_max_filesize] = 20M
415 | php_admin_value[post_max_size] = 20M
416 |
417 |
--------------------------------------------------------------------------------