├── tests ├── Unit │ └── .gitkeep └── Functional │ └── ApplicationAvailabilityFunctionalTest.php ├── docker-sync.yml ├── .gitignore ├── docker-compose-sync.yml ├── config ├── docker │ └── dev │ │ ├── docker-entrypoint.sh │ │ └── symfony.pool.conf └── packages │ └── doctrine.yaml ├── .php_cs.dist ├── .env.dist ├── dev.Dockerfile ├── docker-compose.yml ├── composer.json └── README.md /tests/Unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docker-sync.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | options: 4 | compose-dev-file-path: 'docker-compose-sync.yml' 5 | syncs: 6 | project_name-data-sync: # Replace project_name with the name of your project 7 | src: './' 8 | host_disk_mount_mode: 'cached' 9 | sync_excludes: 10 | - '.git' 11 | - '.idea' 12 | - 'var/cache/*' 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | # Make .env untracked and follow old rules of .env files: 4 | # - .env.dist file contains example values 5 | # - .env file is used for project and for docker-compose as well 6 | # The reason of it is docker look into .env file for variables used in config 7 | # and will not check .env.local, .env.${ENV} etc. 8 | # Also we cannot configure docker-compose to get variables from files different from .env 9 | .env 10 | -------------------------------------------------------------------------------- /docker-compose-sync.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | php: 5 | volumes: 6 | - ./composer.json:/var/www/html/composer.json 7 | - ./composer.lock:/var/www/html/composer.lock 8 | - project_name-data-sync:/var/www/html:nocopy # Replace project_name with the name of your project 9 | 10 | volumes: 11 | project_name-data-sync: # Replace project_name with the name of your project 12 | external: true 13 | -------------------------------------------------------------------------------- /config/docker/dev/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COMMAND="composer install --prefer-dist --no-progress --no-suggest --no-interaction" 4 | 5 | if [[ "prod" = "${APP_ENV}" ]]; then 6 | COMMAND="${COMMAND} --no-dev --optimize-autoloader --classmap-authoritative" 7 | fi 8 | 9 | if [[ ! -z "${WWW_DATA_UID}" ]]; then 10 | su \ 11 | -c "${COMMAND}" \ 12 | -s /bin/sh \ 13 | -m \ 14 | www-data 15 | else 16 | ${COMMAND} 17 | chown -R www-data var/ 18 | fi 19 | 20 | php-fpm 21 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | exclude(['Migrations']) 5 | ->in(__DIR__.'/src') 6 | ; 7 | 8 | return PhpCsFixer\Config::create() 9 | ->setRules([ 10 | '@Symfony' => true, 11 | '@PHP71Migration' => true, 12 | '@DoctrineAnnotation' => true, 13 | 'phpdoc_order' => true, 14 | 'array_syntax' => ['syntax' => 'short'], 15 | 'ordered_class_elements' => true, 16 | 'ordered_imports' => true, 17 | 'phpdoc_add_missing_param_annotation' => [ 18 | 'only_untyped' => false, 19 | ], 20 | ]) 21 | ->setFinder($finder) 22 | ; 23 | -------------------------------------------------------------------------------- /tests/Functional/ApplicationAvailabilityFunctionalTest.php: -------------------------------------------------------------------------------- 1 | request('GET', $url); 18 | 19 | $this->assertResponseIsSuccessful(); 20 | } 21 | 22 | public function urlProvider() 23 | { 24 | yield ['/']; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | # Docker configuration 2 | HOST_UID= 3 | EXTERNAL_HTTP_PORT=80 4 | EXTERNAL_DB_PORT=5432 5 | EXTERNAL_SMTP_PORT=1025 6 | EXTERNAL_SMTP_WEB_PORT=8025 7 | 8 | # PHP_IDE_CONFIG is necessary for xDebug 9 | # Create server mapping in PHPStorm with name Default 10 | # or change serverName value to appropriate one 11 | PHP_IDE_CONFIG=serverName=Default 12 | 13 | 14 | ###> doctrine/doctrine-bundle ### 15 | # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 16 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 17 | # Configure your db driver and server_version in config/packages/doctrine.yaml 18 | DB_HOST=db 19 | DB_PASSWORD=dev 20 | DB_USER=dev 21 | DB_NAME=dev 22 | ###< doctrine/doctrine-bundle ### 23 | 24 | ###> symfony/mailer ### 25 | MAILER_DSN=smtp://mailhog:1025 26 | ###< symfony/mailer ### 27 | 28 | SYMFONY_PHPUNIT_VERSION=9.1.1 29 | -------------------------------------------------------------------------------- /config/packages/doctrine.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Adds a fallback DATABASE_URL if the env var is not set. 3 | # This allows you to run cache:warmup even if your 4 | # environment variables are not available yet. 5 | # You should not need to change this value. 6 | env(DB_NAME): '' 7 | env(DB_USER): '' 8 | env(DB_PASSWORD): '' 9 | env(DB_HOST): '' 10 | 11 | doctrine: 12 | dbal: 13 | driver: 'pdo_pgsql' 14 | server_version: '12.2' 15 | 16 | dbname: '%env(DB_NAME)%' 17 | user: '%env(DB_USER)%' 18 | password: '%env(DB_PASSWORD)%' 19 | host: '%env(DB_HOST)%' 20 | orm: 21 | auto_generate_proxy_classes: '%kernel.debug%' 22 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware 23 | auto_mapping: true 24 | mappings: 25 | App: 26 | is_bundle: false 27 | type: annotation 28 | dir: '%kernel.project_dir%/src/Entity' 29 | prefix: 'App\Entity' 30 | alias: App 31 | -------------------------------------------------------------------------------- /dev.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-fpm-alpine 2 | 3 | RUN apk add --no-cache \ 4 | git \ 5 | icu-dev \ 6 | libzip-dev \ 7 | postgresql-dev \ 8 | zip 9 | 10 | RUN docker-php-ext-install \ 11 | intl \ 12 | opcache \ 13 | pdo \ 14 | pdo_pgsql \ 15 | zip 16 | 17 | ARG XDEBUG=yes 18 | RUN if [ "${XDEBUG}" = "yes" ]; then apk add --no-cache --virtual .xdebug-build-deps ${PHPIZE_DEPS} \ 19 | && pecl install xdebug \ 20 | && docker-php-ext-enable xdebug \ 21 | && apk del .xdebug-build-deps; fi; 22 | 23 | COPY --from=composer:2 /usr/bin/composer /usr/bin/composer 24 | 25 | ENV COMPOSER_ALLOW_SUPERUSER 1 26 | ENV COMPOSER_MEMORY_LIMIT -1 27 | 28 | ARG HOST_UID 29 | 30 | RUN if [ ! -z "${HOST_UID}" ]; then \ 31 | deluser www-data \ 32 | && addgroup www-data \ 33 | && adduser -u "${HOST_UID}" -G www-data -H -s /bin/sh -D www-data; \ 34 | fi 35 | 36 | ENV WWW_DATA_UID ${HOST_UID} 37 | 38 | RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" 39 | 40 | COPY ./config/docker/dev/symfony.pool.conf /usr/local/etc/php-fpm.d/ -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | php: 5 | build: 6 | context: ./ 7 | dockerfile: dev.Dockerfile 8 | args: 9 | - HOST_UID=${HOST_UID} 10 | depends_on: 11 | - db 12 | working_dir: /var/www/html 13 | volumes: 14 | - .:/var/www/html 15 | expose: 16 | - "9000" 17 | entrypoint: ./config/docker/dev/docker-entrypoint.sh 18 | environment: 19 | - COMPOSER_HOME=/var/www/html/var/composer 20 | - PHP_IDE_CONFIG 21 | - APP_ENV 22 | - SYMFONY_PHPUNIT_VERSION 23 | nginx: 24 | image: 4xxi/nginx:flex 25 | depends_on: 26 | - php 27 | ports: 28 | - "${EXTERNAL_HTTP_PORT-80}:80" 29 | volumes: 30 | - .:/var/www/html 31 | - ./var/log:/var/log/nginx 32 | db: 33 | image: postgres:12.2 34 | ports: 35 | - "${EXTERNAL_DB_PORT-5432}:5432" 36 | volumes: 37 | - db:/var/lib/postgresql/data 38 | environment: 39 | - POSTGRES_DB=${DB_NAME-dev} 40 | - POSTGRES_USER=${DB_USER-dev} 41 | - POSTGRES_PASSWORD=${DB_PASSWORD-dev} 42 | mailhog: 43 | image: mailhog/mailhog 44 | ports: 45 | - "${EXTERNAL_SMTP_PORT-8025}:1025" 46 | - "${EXTERNAL_SMTP_WEB_PORT-8025}:8025" 47 | 48 | volumes: 49 | db: 50 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4xxi/skeleton", 3 | "type": "project", 4 | "license": "MIT", 5 | "require": { 6 | "php": "^7.3", 7 | "ext-ctype": "*", 8 | "ext-iconv": "*", 9 | "symfony/flex": "^1.3.1" 10 | }, 11 | "flex-require": { 12 | "sensio/framework-extra-bundle": "^5.1", 13 | "symfony/console": "*", 14 | "symfony/dotenv": "*", 15 | "symfony/expression-language": "*", 16 | "symfony/form": "*", 17 | "symfony/framework-bundle": "*", 18 | "symfony/http-client": "*", 19 | "symfony/intl": "*", 20 | "symfony/mailer": "*", 21 | "symfony/monolog-bundle": "^3.1", 22 | "symfony/orm-pack": "*", 23 | "symfony/process": "*", 24 | "symfony/security-bundle": "*", 25 | "symfony/serializer-pack": "*", 26 | "symfony/translation": "*", 27 | "symfony/validator": "*", 28 | "symfony/yaml": "*" 29 | }, 30 | "require-dev": { 31 | "friendsofphp/php-cs-fixer": "^2.14", 32 | "vimeo/psalm": "^3.8", 33 | "weirdan/doctrine-psalm-plugin": "^0.8.0", 34 | "phpstan/phpstan": "^0.12" 35 | }, 36 | "flex-require-dev": { 37 | "symfony/debug-pack": "*", 38 | "symfony/maker-bundle": "^1.0", 39 | "symfony/profiler-pack": "*", 40 | "symfony/test-pack": "*", 41 | "doctrine/doctrine-fixtures-bundle": "*" 42 | }, 43 | "config": { 44 | "preferred-install": { 45 | "*": "dist" 46 | }, 47 | "sort-packages": true 48 | }, 49 | "autoload": { 50 | "psr-4": { 51 | "App\\": "src/" 52 | } 53 | }, 54 | "autoload-dev": { 55 | "psr-4": { 56 | "App\\Tests\\": "tests/" 57 | } 58 | }, 59 | "replace": { 60 | "paragonie/random_compat": "2.*", 61 | "symfony/polyfill-ctype": "*", 62 | "symfony/polyfill-iconv": "*" 63 | }, 64 | "scripts": { 65 | "auto-scripts": [ 66 | ], 67 | "post-install-cmd": [ 68 | "@auto-scripts" 69 | ], 70 | "post-update-cmd": [ 71 | "@auto-scripts" 72 | ] 73 | }, 74 | "conflict": { 75 | "symfony/symfony": "*" 76 | }, 77 | "extra": { 78 | "symfony": { 79 | "allow-contrib": false, 80 | "require": "4.4.*" 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /config/docker/dev/symfony.pool.conf: -------------------------------------------------------------------------------- 1 | ; Unix user/group of processes 2 | ; Note: The user is mandatory. If the group is not set, the default user's group 3 | ; will be used. 4 | user = www-data 5 | group = www-data 6 | 7 | ; The address on which to accept FastCGI requests. 8 | ; Valid syntaxes are: 9 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on 10 | ; a specific port; 11 | ; 'port' - to listen on a TCP socket to all addresses on a 12 | ; specific port; 13 | ; '/path/to/unix/socket' - to listen on a unix socket. 14 | ; Note: This value is mandatory. 15 | listen = 0.0.0.0:9000 16 | 17 | ; Choose how the process manager will control the number of child processes. 18 | ; Possible Values: 19 | ; static - a fixed number (pm.max_children) of child processes; 20 | ; dynamic - the number of child processes are set dynamically based on the 21 | ; following directives. With this process management, there will be 22 | ; always at least 1 children. 23 | ; pm.max_children - the maximum number of children that can 24 | ; be alive at the same time. 25 | ; pm.start_servers - the number of children created on startup. 26 | ; pm.min_spare_servers - the minimum number of children in 'idle' 27 | ; state (waiting to process). If the number 28 | ; of 'idle' processes is less than this 29 | ; number then some children will be created. 30 | ; pm.max_spare_servers - the maximum number of children in 'idle' 31 | ; state (waiting to process). If the number 32 | ; of 'idle' processes is greater than this 33 | ; number then some children will be killed. 34 | ; ondemand - no children are created at startup. Children will be forked when 35 | ; new requests will connect. The following parameter are used: 36 | ; pm.max_children - the maximum number of children that 37 | ; can be alive at the same time. 38 | ; pm.process_idle_timeout - The number of seconds after which 39 | ; an idle process will be killed. 40 | ; Note: This value is mandatory. 41 | pm = dynamic 42 | 43 | ; The number of child processes to be created when pm is set to 'static' and the 44 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. 45 | ; This value sets the limit on the number of simultaneous requests that will be 46 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. 47 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP 48 | ; CGI. The below defaults are based on a server without much resources. Don't 49 | ; forget to tweak pm.* to fit your needs. 50 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' 51 | ; Note: This value is mandatory. 52 | pm.max_children = 20 53 | 54 | ; The number of child processes created on startup. 55 | ; Note: Used only when pm is set to 'dynamic' 56 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 57 | pm.start_servers = 2 58 | 59 | ; The desired minimum number of idle server processes. 60 | ; Note: Used only when pm is set to 'dynamic' 61 | ; Note: Mandatory when pm is set to 'dynamic' 62 | pm.min_spare_servers = 1 63 | 64 | ; The desired maximum number of idle server processes. 65 | ; Note: Used only when pm is set to 'dynamic' 66 | ; Note: Mandatory when pm is set to 'dynamic' 67 | pm.max_spare_servers = 3 68 | 69 | catch_workers_output = yes 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 4xxi Symfony Skeleton 2 | ========== 3 | 4 | 4xxi Symfony Skeleton is an extension for the official [Symfony Skeleton](https://github.com/symfony/skeleton) 5 | (recommended way for starting new projects using [Symfony Flex](https://symfony.com/doc/current/setup/flex.html)). 6 | It's main idea is to keep simplicity of official Skeleton, while adding must-have dependencies and default configs used 7 | in 4xxi for developing majority of the projects. It contains bare Symfony Skeleton with the following additions: 8 | 9 | * A minimal set of must-have bundles for production environment 10 | * ORM Pack (Doctrine + Migrations) 11 | * FrameworkExtraBundle (Annotations) 12 | * MonologBundle 13 | * Sensiolabs SecurityChecker 14 | * A set of bundles and tools that are necessary for development 15 | * [PHP CS Fixer](https://cs.sensiolabs.org/) 16 | * [Psalm](https://psalm.dev/docs/) 17 | * [PhpStan](https://phpstan.org/user-guide/getting-started) 18 | * [PhpUnit](https://symfony.com/doc/current/testing.html) 19 | * Debug Pack (Debug + Profiler + Dumper) 20 | * Docker Compose and Docker Sync configs optimized for development under Linux and MacOS 21 | * Template for README.md with installation instructions 22 | 23 | Creating new project 24 | ========== 25 | 26 | Creating new project with 4xxi Symfony Skeleton is as easy as running 27 | ```bash 28 | composer create-project 4xxi/skeleton 29 | ``` 30 | where `` is the directory where you want to setup a new project. New project is ready for development 31 | immediately after this step. 32 | 33 | ## Additional configurations 34 | 35 | ### Docker 36 | 4xxi Symfony Skeleton comes with Docker configuration for local development (includes PHP 7.1, nginx and PostgreSQL) 37 | on Linux and MacOS. 38 | 39 | * Follow instructions in `docker-sync.yml` and `docker-compose-sync.yml` and update `project_name-data-sync` volume 40 | with the real name of your project. This is needed to keep a unique name for data volume used by Docker Sync for 41 | developers working simultaneously on several projects. 42 | * Optional: Add additional PHP extensions to PHP Docker container by following instructions in 43 | `config/docker/php/Dockerfile`. 44 | * Optional: Add additinal services (like Redis, RabbitMQ, Elasticsearch) in docker-compose.yml. 45 | 46 | ### Add Bundles and dependencies that are required by our project 47 | Projects created by Flex include only the mininum amount of dependencies by default. Most of additional components that 48 | were previously a part of Symfony Standard Edition are not installed, so it is up to you to install them if they are 49 | really needed. 50 | 51 | Most of components could be installed and auto-configured by Flex by running: 52 | ```bash 53 | composer req 54 | ``` 55 | The list of common Components that may be needed for the project: 56 | 57 | * api 58 | * asset 59 | * twig 60 | * workflow 61 | * web-link 62 | 63 | ### Update installation instructions 64 | 65 | When you are done with previous steps, update Installation Instructions and remove everything above them in this file. 66 | 67 | Installation Instructions 68 | ========== 69 | 70 | Everything below is a template for Installation Instructions. It should be updated with the full steps for setting up 71 | your project. 72 | 73 | ## Requirements 74 | 75 | * [Docker and Docker Compose](https://docs.docker.com/engine/installation) 76 | * [MacOS Only]: Docker Sync (run `gem install docker-sync` to install it) 77 | 78 | ## Configuration 79 | 80 | Application configuration is stored in `.env` file. 81 | 82 | Run `cp .env.dist .env` to apply the default configuration for local installations. 83 | 84 | ### HTTP port 85 | If you have nginx or apache installed and using 80 port on host system you can either stop them before proceeding or 86 | reconfigure Docker to use another port by changing value of `EXTERNAL_HTTP_PORT` in `.env` file. 87 | 88 | ### Application environment 89 | You can change application environment to `dev` of `prod` by changing `APP_ENV` variable in `.env` file. 90 | 91 | ### DB name and credentials 92 | DB name and credentials could by reconfigured by changing variables with `POSTGRES` prefix in `.env` file. It is 93 | recommended to restart containers after changing these values (new database will be automatically created on containers 94 | start). 95 | 96 | ## Installation 97 | 98 | ### 1. Start Containers and install dependencies 99 | On Linux: 100 | ```bash 101 | docker-compose up -d 102 | ``` 103 | On MacOS: 104 | ```bash 105 | docker-sync-stack start 106 | ``` 107 | ### 2. Run migrations, install fixtures 108 | ```bash 109 | docker-compose exec php bin/console doctrine:migrations:migrate 110 | ``` 111 | 112 | ### 3. Build frontend 113 | Place instructions to build frontend here. 114 | 115 | ### 4. Open project 116 | Just go to [http://localhost](http://localhost) 117 | 118 | 119 | Application commands 120 | ========== 121 | Add application-specific console commands and their description here. 122 | 123 | 124 | Useful commands and shortcuts 125 | ========== 126 | 127 | ## Shortcuts 128 | It is recommended to add short aliases for the following frequently used container commands: 129 | 130 | * `docker-compose exec php php` to run php in container 131 | * `docker-compose exec php composer` to run composer 132 | * `docker-compose exec php bin/console` to run Symfony CLI commands 133 | * `docker-compose exec db psql` to run PostgreSQL commands 134 | 135 | 136 | ## Checking code style and running tests 137 | Fix code style by running PHP CS Fixer: 138 | ```bash 139 | docker-compose exec php vendor/bin/php-cs-fixer fix 140 | ``` 141 | 142 | Run PHP Unit Tests: 143 | ```bash 144 | docker-compose exec php bin/phpunit 145 | ``` --------------------------------------------------------------------------------