├── src ├── Controller │ └── .gitignore ├── Repository │ └── .gitignore ├── Kernel.php └── Entity │ └── Example.php ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── FUNDING.yaml ├── release.yaml ├── workflows │ ├── release.yaml │ ├── triage.yaml │ ├── merge.yaml │ ├── renew.yaml │ └── integrate.yaml ├── SECURITY.md ├── dependabot.yaml ├── settings.yml ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md ├── composer-require-checker.json ├── psalm-baseline.xml ├── .env.test ├── .phive └── phars.xml ├── .gitignore ├── infection.json ├── .editorconfig ├── migrations ├── migration.tpl └── Version20200809104330.php ├── CHANGELOG.md ├── config ├── bootstrap.php ├── routes │ ├── dev │ │ └── framework.php │ └── attributes.php ├── bundles.php ├── packages │ ├── test │ │ ├── framework.php │ │ └── dama_doctrine_test_bundle.php │ ├── doctrine_migrations.php │ ├── framework.php │ ├── prod │ │ ├── framework.php │ │ └── doctrine.php │ └── doctrine.php └── services.php ├── public └── index.php ├── test ├── Functional │ ├── bootstrap.php │ ├── ExampleTest.php │ └── phpunit.xml ├── Integration │ ├── bootstrap.php │ ├── ExampleTest.php │ └── phpunit.xml ├── Util │ └── Helper.php └── Unit │ ├── Entity │ └── ExampleTest.php │ └── phpunit.xml ├── bin └── console ├── rector.php ├── LICENSE.md ├── psalm.xml ├── .php-cs-fixer.php ├── .yamllint.yaml ├── .env ├── README.md ├── Makefile ├── composer.json └── symfony.lock /src/Controller/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Repository/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | This pull request 2 | 3 | - [x] 4 | 5 | Follows #. 6 | Related to #. 7 | Fixes #. 8 | -------------------------------------------------------------------------------- /composer-require-checker.json: -------------------------------------------------------------------------------- 1 | { 2 | "scan-files": [ 3 | "bin/console" 4 | ], 5 | "symbol-whitelist": [] 6 | } 7 | -------------------------------------------------------------------------------- /psalm-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 2 | 3 | * @ergebnis-bot @localheinz 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Steps required to reproduce the problem 2 | 3 | 1. 4 | 2. 5 | 3. 6 | 7 | #### Expected Result 8 | 9 | - 10 | 11 | #### Actual Result 12 | 13 | - 14 | -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- 1 | # define your env variables for the test env here 2 | APP_SECRET='$ecretf0rt3st' 3 | DATABASE_URL=mysql://root:root@127.0.0.1:3306/database?charset=utf8mb4 4 | KERNEL_CLASS='App\Kernel' 5 | SYMFONY_DEPRECATIONS_HELPER=999999 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository 2 | 3 | github: 4 | - "ergebnis" 5 | - "localheinz" 6 | -------------------------------------------------------------------------------- /.phive/phars.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.github/release.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes 2 | 3 | changelog: 4 | exclude: 5 | authors: 6 | - "dependabot" 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.build/ 2 | /.note/ 3 | /.phive/ 4 | /vendor/ 5 | !/.phive/phars.xml 6 | 7 | ###> symfony/framework-bundle ### 8 | /.env.local 9 | /.env.local.php 10 | /.env.*.local 11 | /config/secrets/prod/prod.decrypt.private.php 12 | /public/bundles/ 13 | /var/ 14 | ###< symfony/framework-bundle ### 15 | -------------------------------------------------------------------------------- /infection.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignoreMsiWithNoMutations": true, 3 | "logs": { 4 | "text": ".build/infection/infection-log.txt" 5 | }, 6 | "minCoveredMsi": 100, 7 | "minMsi": 3, 8 | "phpUnit": { 9 | "configDir": "test\/Unit" 10 | }, 11 | "source": { 12 | "directories": [ 13 | "src" 14 | ] 15 | }, 16 | "timeout": 10 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.json] 12 | indent_size = 2 13 | 14 | [*.md] 15 | indent_size = 2 16 | 17 | [*.neon] 18 | indent_style = tab 19 | 20 | [*.{yaml,yml}] 21 | indent_size = 2 22 | 23 | [Makefile] 24 | indent_style = tab 25 | -------------------------------------------------------------------------------- /migrations/migration.tpl: -------------------------------------------------------------------------------- 1 | ; 6 | 7 | use Doctrine\DBAL; 8 | use Doctrine\Migrations; 9 | 10 | final class extends Migrations\AbstractMigration 11 | { 12 | public function up(DBAL\Schema\Schema $schema): void 13 | { 14 | 15 | } 16 | 17 | public function down(DBAL\Schema\Schema $schema): void 18 | { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Unreleased 8 | 9 | For a full diff see [`7fd0b8b...main`][7fd0b8b...main]. 10 | 11 | [7fd0b8b...main]: https://github.com/ergebnis/symfony-application-template/compare/7fd0b8b...main 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions 2 | 3 | name: "Release" 4 | 5 | on: # yamllint disable-line rule:truthy 6 | push: 7 | tags: 8 | - "**" 9 | 10 | jobs: 11 | release: 12 | name: "Release" 13 | 14 | runs-on: "ubuntu-latest" 15 | 16 | timeout-minutes: 5 17 | 18 | steps: 19 | - name: "Create release" 20 | uses: "ergebnis/.github/actions/github/release/create@1.9.2" 21 | with: 22 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 23 | -------------------------------------------------------------------------------- /config/bootstrap.php: -------------------------------------------------------------------------------- 1 | bootEnv(__DIR__ . '/../.env'); 21 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions of `ergebnis/symfony-application-template` have active support: 6 | 7 | - `x.y.z` 8 | 9 | ## Unsupported Versions 10 | 11 | The following versions of `ergebnis/symfony-application-template` have reached their end of life: 12 | 13 | - `x.y.z` 14 | 15 | ## Reporting a Vulnerability 16 | 17 | If you believe that you have found a security vulnerability, please send an email to `am@localheinz.com`. Ensure to include all details required to understand the severity of the issue. 18 | -------------------------------------------------------------------------------- /.github/workflows/triage.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions 2 | 3 | name: "Triage" 4 | 5 | on: # yamllint disable-line rule:truthy 6 | pull_request_target: 7 | types: 8 | - "opened" 9 | 10 | jobs: 11 | label: 12 | name: "Label" 13 | 14 | runs-on: "ubuntu-latest" 15 | 16 | timeout-minutes: 5 17 | 18 | steps: 19 | - name: "Add labels based on branch name" 20 | uses: "ergebnis/.github/actions/github/pull-request/add-label-based-on-branch-name@1.9.2" 21 | with: 22 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 23 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | import('@FrameworkBundle/Resources/config/routing/errors.xml')->prefix('/_error'); 18 | }; 19 | -------------------------------------------------------------------------------- /config/routes/attributes.php: -------------------------------------------------------------------------------- 1 | import('../../src/Controller/', 'attribute'); 18 | $routingConfigurator->import('../../src/Kernel.php', 'attribute'); 19 | }; 20 | -------------------------------------------------------------------------------- /src/Kernel.php: -------------------------------------------------------------------------------- 1 | bootEnv(\dirname(__DIR__, 2) . '/.env'); 22 | } 23 | -------------------------------------------------------------------------------- /test/Integration/bootstrap.php: -------------------------------------------------------------------------------- 1 | bootEnv(\dirname(__DIR__, 2) . '/.env'); 22 | } 23 | -------------------------------------------------------------------------------- /config/bundles.php: -------------------------------------------------------------------------------- 1 | ['test' => true], 16 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 17 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], 18 | Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], 19 | ]; 20 | -------------------------------------------------------------------------------- /test/Functional/ExampleTest.php: -------------------------------------------------------------------------------- 1 | extension('framework', [ 18 | 'session' => [ 19 | 'storage_factory_id' => 'session.storage.factory.mock_file', 20 | ], 21 | 'test' => true, 22 | ]); 23 | }; 24 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | extension('dama_doctrine_test', [ 18 | 'enable_static_connection' => true, 19 | 'enable_static_meta_data_cache' => true, 20 | 'enable_static_query_cache' => true, 21 | ]); 22 | }; 23 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | 5 | updates: 6 | - allow: 7 | - dependency-type: "all" 8 | commit-message: 9 | include: "scope" 10 | prefix: "composer" 11 | directory: "/" 12 | labels: 13 | - "dependency" 14 | open-pull-requests-limit: 10 15 | package-ecosystem: "composer" 16 | schedule: 17 | interval: "daily" 18 | versioning-strategy: "increase" 19 | 20 | - commit-message: 21 | include: "scope" 22 | prefix: "github-actions" 23 | directory: "/" 24 | labels: 25 | - "dependency" 26 | open-pull-requests-limit: 10 27 | package-ecosystem: "github-actions" 28 | schedule: 29 | interval: "daily" 30 | -------------------------------------------------------------------------------- /config/packages/doctrine_migrations.php: -------------------------------------------------------------------------------- 1 | extension('doctrine_migrations', [ 18 | 'custom_template' => '%kernel.project_dir%/migrations/migration.tpl', 19 | 'migrations_paths' => [ 20 | 'App\Migration' => '%kernel.project_dir%/migrations', 21 | ], 22 | ]); 23 | }; 24 | -------------------------------------------------------------------------------- /migrations/Version20200809104330.php: -------------------------------------------------------------------------------- 1 | addSql('CREATE TABLE example (id VARCHAR(36) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); 24 | } 25 | 26 | public function down(DBAL\Schema\Schema $schema): void 27 | { 28 | $this->addSql('CREATE SCHEMA public'); 29 | $this->addSql('DROP TABLE example'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | cacheDirectory(__DIR__ . '/.build/rector/'); 20 | 21 | $rectorConfig->import(__DIR__ . '/vendor/fakerphp/faker/rector-migrate.php'); 22 | 23 | $rectorConfig->paths([ 24 | __DIR__ . '/src/', 25 | __DIR__ . '/test/', 26 | ]); 27 | 28 | $rectorConfig->phpVersion(ValueObject\PhpVersion::PHP_83); 29 | 30 | $rectorConfig->sets([ 31 | PHPUnit\Set\PHPUnitSetList::PHPUNIT_100, 32 | ]); 33 | }; 34 | -------------------------------------------------------------------------------- /test/Util/Helper.php: -------------------------------------------------------------------------------- 1 | $fakers 25 | */ 26 | static $fakers = []; 27 | 28 | if (!\array_key_exists($locale, $fakers)) { 29 | $faker = Factory::create($locale); 30 | 31 | $faker->seed(9001); 32 | 33 | $fakers[$locale] = $faker; 34 | } 35 | 36 | return $fakers[$locale]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /config/packages/framework.php: -------------------------------------------------------------------------------- 1 | extension('framework', [ 18 | 'php_errors' => [ 19 | 'log' => true, 20 | ], 21 | 'router' => [ 22 | 'utf8' => true, 23 | ], 24 | 'secret' => '%env(APP_SECRET)%', 25 | 'session' => [ 26 | 'cookie_samesite' => 'lax', 27 | 'cookie_secure' => 'auto', 28 | 'handler_id' => null, 29 | ], 30 | ]); 31 | }; 32 | -------------------------------------------------------------------------------- /test/Unit/Entity/ExampleTest.php: -------------------------------------------------------------------------------- 1 | sentence(); 28 | 29 | $example = Entity\Example::fromName($name); 30 | 31 | self::assertSame($name, $example->name()); 32 | self::assertMatchesRegularExpression('/^[0-9a-fA-F]{8}(\-[0-9a-fA-F]{4}){3}\-[0-9a-fA-F]{12}$/', $example->id()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /config/packages/prod/framework.php: -------------------------------------------------------------------------------- 1 | extension('framework', [ 18 | 'cache' => [ 19 | 'pools' => [ 20 | 'doctrine.result_cache_pool' => [ 21 | 'adapter' => 'cache.app', 22 | ], 23 | 'doctrine.system_cache_pool' => [ 24 | 'adapter' => 'cache.system', 25 | ], 26 | ], 27 | ], 28 | 'router' => [ 29 | 'strict_requirements' => null, 30 | ], 31 | ]); 32 | }; 33 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | services(); 18 | 19 | $services->defaults() 20 | ->autoconfigure() 21 | ->autowire(); 22 | 23 | $services 24 | ->load( 25 | 'App\\', 26 | __DIR__ . '/../src/*', 27 | ) 28 | ->exclude([ 29 | __DIR__ . '/../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}', 30 | ]); 31 | 32 | $services 33 | ->load( 34 | 'App\\Controller\\', 35 | __DIR__ . '/../src/Controller', 36 | ) 37 | ->tag('controller.service_arguments'); 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2025 Andreas Möller 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the _Software_), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 11 | Software. 12 | 13 | THE SOFTWARE IS PROVIDED **AS IS**, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /config/packages/prod/doctrine.php: -------------------------------------------------------------------------------- 1 | extension('doctrine', [ 18 | 'orm' => [ 19 | 'auto_generate_proxy_classes' => false, 20 | 'metadata_cache_driver' => [ 21 | 'pool' => 'doctrine.system_cache_pool', 22 | 'type' => 'pool', 23 | ], 24 | 'query_cache_driver' => [ 25 | 'pool' => 'doctrine.system_cache_pool', 26 | 'type' => 'pool', 27 | ], 28 | 'result_cache_driver' => [ 29 | 'pool' => 'doctrine.result_cache_pool', 30 | 'type' => 'pool', 31 | ], 32 | ], 33 | ]); 34 | }; 35 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 | var/cache/test/App_KernelTestDebugContainer.xml 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Entity/Example.php: -------------------------------------------------------------------------------- 1 | id = Uuid\Uuid::uuid4()->toString(); 41 | $this->name = $name; 42 | } 43 | 44 | public static function fromName(string $name): self 45 | { 46 | return new self($name); 47 | } 48 | 49 | public function id(): string 50 | { 51 | return $this->id; 52 | } 53 | 54 | public function name(): string 55 | { 56 | return $this->name; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | save(); 28 | 29 | $ruleSet = PhpCsFixer\Config\RuleSet\Php83::create()->withHeader($license->header()); 30 | 31 | $config = PhpCsFixer\Config\Factory::fromRuleSet($ruleSet); 32 | 33 | $config->getFinder() 34 | ->exclude([ 35 | '.build/', 36 | '.github/', 37 | '.note/', 38 | 'var/', 39 | ]) 40 | ->ignoreDotFiles(false) 41 | ->in(__DIR__) 42 | ->name([ 43 | 'console', 44 | ]) 45 | ->notName([ 46 | '.env.local.php', 47 | ]); 48 | 49 | $config->setCacheFile(__DIR__ . '/.build/php-cs-fixer/.php-cs-fixer.cache'); 50 | 51 | return $config; 52 | -------------------------------------------------------------------------------- /.yamllint.yaml: -------------------------------------------------------------------------------- 1 | extends: "default" 2 | 3 | ignore: | 4 | .build/ 5 | .note/ 6 | var/ 7 | vendor/ 8 | 9 | rules: 10 | braces: 11 | max-spaces-inside-empty: 0 12 | max-spaces-inside: 1 13 | min-spaces-inside-empty: 0 14 | min-spaces-inside: 1 15 | brackets: 16 | max-spaces-inside-empty: 0 17 | max-spaces-inside: 0 18 | min-spaces-inside-empty: 0 19 | min-spaces-inside: 0 20 | colons: 21 | max-spaces-after: 1 22 | max-spaces-before: 0 23 | commas: 24 | max-spaces-after: 1 25 | max-spaces-before: 0 26 | min-spaces-after: 1 27 | comments: 28 | ignore-shebangs: true 29 | min-spaces-from-content: 1 30 | require-starting-space: true 31 | comments-indentation: "enable" 32 | document-end: 33 | present: false 34 | document-start: 35 | present: false 36 | indentation: 37 | check-multi-line-strings: false 38 | indent-sequences: true 39 | spaces: 2 40 | empty-lines: 41 | max-end: 0 42 | max-start: 0 43 | max: 1 44 | empty-values: 45 | forbid-in-block-mappings: true 46 | forbid-in-flow-mappings: true 47 | hyphens: 48 | max-spaces-after: 2 49 | key-duplicates: "enable" 50 | key-ordering: "disable" 51 | line-length: "disable" 52 | new-line-at-end-of-file: "enable" 53 | new-lines: 54 | type: "unix" 55 | octal-values: 56 | forbid-implicit-octal: true 57 | quoted-strings: 58 | quote-type: "double" 59 | trailing-spaces: "enable" 60 | truthy: 61 | allowed-values: 62 | - "false" 63 | - "true" 64 | 65 | yaml-files: 66 | - "*.yaml" 67 | - "*.yml" 68 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # In all environments, the following files are loaded if they exist, 2 | # the latter taking precedence over the former: 3 | # 4 | # * .env contains default values for the environment variables needed by the app 5 | # * .env.local uncommitted file with local overrides 6 | # * .env.$APP_ENV committed environment-specific defaults 7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides 8 | # 9 | # Real environment variables win over .env files. 10 | # 11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. 12 | # 13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). 14 | # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration 15 | 16 | ###> symfony/framework-bundle ### 17 | APP_ENV=dev 18 | APP_SECRET=94391022bc37474aea4e0752999d2abd 19 | #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 20 | #TRUSTED_HOSTS='^(localhost|example\.com)$' 21 | ###< symfony/framework-bundle ### 22 | 23 | ###> doctrine/doctrine-bundle ### 24 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 25 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 26 | # For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8" 27 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml 28 | DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7 29 | ###< doctrine/doctrine-bundle ### 30 | -------------------------------------------------------------------------------- /test/Functional/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | . 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/Integration/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | . 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/Unit/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ../../src/Kernel.php 36 | 37 | 38 | ../../src/ 39 | 40 | 41 | 42 | 43 | . 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /.github/workflows/merge.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions 2 | 3 | name: "Merge" 4 | 5 | on: # yamllint disable-line rule:truthy 6 | workflow_run: 7 | types: 8 | - "completed" 9 | workflows: 10 | - "Integrate" 11 | 12 | jobs: 13 | merge: 14 | name: "Merge" 15 | 16 | runs-on: "ubuntu-latest" 17 | 18 | timeout-minutes: 5 19 | 20 | if: > 21 | github.event.workflow_run.event == 'pull_request' && 22 | github.event.workflow_run.conclusion == 'success' && 23 | github.actor == 'dependabot[bot]' && ( 24 | startsWith(github.event.workflow_run.head_commit.message, 'composer(deps)') || 25 | startsWith(github.event.workflow_run.head_commit.message, 'composer(deps-dev)') || 26 | startsWith(github.event.workflow_run.head_commit.message, 'github-actions(deps)') 27 | ) 28 | 29 | steps: 30 | - name: "Request review from @ergebnis-bot" 31 | uses: "ergebnis/.github/actions/github/pull-request/request-review@1.9.2" 32 | with: 33 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 34 | reviewer: "ergebnis-bot" 35 | 36 | - name: "Assign @ergebnis-bot" 37 | uses: "ergebnis/.github/actions/github/pull-request/add-assignee@1.9.2" 38 | with: 39 | assignee: "ergebnis-bot" 40 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 41 | 42 | - name: "Approve pull request" 43 | uses: "ergebnis/.github/actions/github/pull-request/approve@1.9.2" 44 | with: 45 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 46 | 47 | - name: "Merge pull request" 48 | uses: "ergebnis/.github/actions/github/pull-request/merge@1.9.2" 49 | with: 50 | github-token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 51 | -------------------------------------------------------------------------------- /config/packages/doctrine.php: -------------------------------------------------------------------------------- 1 | extension('doctrine', [ 18 | 'dbal' => [ 19 | 'connections' => [ 20 | 'default' => [ 21 | 'charset' => 'utf8', 22 | 'default_table_options' => [ 23 | 'charset' => 'utf8mb4', 24 | 'collate' => 'utf8mb4_unicode_ci', 25 | ], 26 | 'driver' => 'pdo_pgsql', 27 | /** 28 | * @see https://github.com/doctrine/migrations/issues/1406#issuecomment-1988041445 29 | */ 30 | 'schema_filter' => '~^(?!doctrine_)~', 31 | 'server_version' => '12', 32 | 'url' => '%env(resolve:DATABASE_URL)%', 33 | 'use_savepoints' => true, 34 | ], 35 | ], 36 | 'default_connection' => 'default', 37 | ], 38 | 'orm' => [ 39 | 'auto_generate_proxy_classes' => true, 40 | 'default_entity_manager' => 'default', 41 | 'entity_managers' => [ 42 | 'default' => [ 43 | 'auto_mapping' => false, 44 | 'connection' => 'default', 45 | 'mappings' => [ 46 | 'app' => [ 47 | 'alias' => 'App', 48 | 'dir' => '%kernel.project_dir%/src/Entity', 49 | 'is_bundle' => false, 50 | 'prefix' => 'App\Entity', 51 | 'type' => 'attribute', 52 | ], 53 | ], 54 | 'naming_strategy' => 'doctrine.orm.naming_strategy.underscore_number_aware', 55 | ], 56 | ], 57 | ], 58 | ]); 59 | }; 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # symfony-application-template 2 | 3 | [![Integrate](https://github.com/ergebnis/symfony-application-template/workflows/Integrate/badge.svg)](https://github.com/ergebnis/symfony-application-template/actions) 4 | [![Merge](https://github.com/ergebnis/symfony-application-template/workflows/Merge/badge.svg)](https://github.com/ergebnis/symfony-application-template/actions) 5 | [![Release](https://github.com/ergebnis/symfony-application-template/workflows/Release/badge.svg)](https://github.com/ergebnis/symfony-application-template/actions) 6 | [![Renew](https://github.com/ergebnis/symfony-application-template/workflows/Renew/badge.svg)](https://github.com/ergebnis/symfony-application-template/actions) 7 | 8 | [![Code Coverage](https://codecov.io/gh/ergebnis/symfony-application-template/branch/main/graph/badge.svg)](https://codecov.io/gh/ergebnis/symfony-application-template) 9 | [![Type Coverage](https://shepherd.dev/github/ergebnis/symfony-application-template/coverage.svg)](https://shepherd.dev/github/ergebnis/symfony-application-template) 10 | 11 | This project provides a [GitHub template repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) for a [Symfony](https://symfony.com) application, using [GitHub Actions]https://docs.github.com/en/actions. 12 | 13 | ## Changelog 14 | 15 | The maintainers of this project record notable changes to this project in a [changelog](CHANGELOG.md). 16 | 17 | ## Contributing 18 | 19 | The maintainers of this project suggest following the [contribution guide](.github/CONTRIBUTING.md). 20 | 21 | ## Code of Conduct 22 | 23 | The maintainers of this project ask contributors to follow the [code of conduct](.github/CODE_OF_CONDUCT.md). 24 | 25 | ## General Support Policy 26 | 27 | The maintainers of this project provide limited support. 28 | 29 | You can support the maintenance of this project by [sponsoring @ergebnis](https://github.com/sponsors/ergebnis). 30 | 31 | ## PHP Version Support Policy 32 | 33 | This project supports the latest PHP version with [active support](https://www.php.net/supported-versions.php). 34 | 35 | The maintainers of this project add support for the latest PHP version following its initial release. 36 | 37 | ## Security Policy 38 | 39 | This project has a [security policy](.github/SECURITY.md). 40 | 41 | ## License 42 | 43 | This project uses the [MIT license](LICENSE.md). 44 | 45 | ## Social 46 | 47 | Follow [@localheinz](https://twitter.com/intent/follow?screen_name=localheinz) and [@ergebnis](https://twitter.com/intent/follow?screen_name=ergebnis) on Twitter. 48 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/repository-settings/app 2 | 3 | branches: 4 | - name: "main" 5 | 6 | # https://docs.github.com/en/rest/reference/repos#delete-branch-protection 7 | # https://docs.github.com/en/rest/reference/repos#update-branch-protection 8 | 9 | protection: 10 | enforce_admins: false 11 | required_pull_request_reviews: 12 | dismiss_stale_reviews: true 13 | require_code_owner_reviews: true 14 | required_approving_review_count: 1 15 | required_status_checks: 16 | checks: 17 | - context: "Code Coverage (8.3, locked)" 18 | - context: "Coding Standards (8.3, locked)" 19 | - context: "Dependency Analysis (8.3, locked)" 20 | - context: "Mutation Tests (8.3, locked)" 21 | - context: "Refactoring (8.3, locked)" 22 | - context: "Security Analysis (8.3, locked)" 23 | - context: "Static Code Analysis (8.3, locked)" 24 | - context: "Tests (8.3, locked)" 25 | strict: false 26 | restrictions: 27 | 28 | # https://docs.github.com/en/rest/reference/repos#list-branches--parameters 29 | 30 | # Note: User, app, and team restrictions are only available for organization-owned repositories. 31 | # Set to null to disable when using this configuration for a repository on a personal account. 32 | 33 | apps: [] 34 | teams: [] 35 | users: 36 | - "ergebnis-bot" 37 | 38 | # https://docs.github.com/en/rest/reference/issues#create-a-label 39 | # https://docs.github.com/en/rest/reference/issues#update-a-label 40 | 41 | labels: 42 | - name: "bug" 43 | color: "ee0701" 44 | description: "" 45 | 46 | - name: "dependency" 47 | color: "0366d6" 48 | description: "" 49 | 50 | - name: "enhancement" 51 | color: "0e8a16" 52 | description: "" 53 | 54 | - name: "question" 55 | color: "cc317c" 56 | description: "" 57 | 58 | - name: "security" 59 | color: "ee0701" 60 | description: "" 61 | 62 | # https://docs.github.com/en/rest/reference/repos#update-a-repository 63 | 64 | repository: 65 | allow_merge_commit: true 66 | allow_rebase_merge: false 67 | allow_squash_merge: false 68 | archived: false 69 | default_branch: "main" 70 | delete_branch_on_merge: true 71 | description: ":octocat: + :musical_score: Provides a GitHub template repository for a Symfony application, using GitHub Actions." 72 | enable_automated_security_fixes: true 73 | enable_vulnerability_alerts: true 74 | has_discussions: false 75 | has_downloads: true 76 | has_issues: true 77 | has_pages: false 78 | has_projects: false 79 | has_wiki: false 80 | is_template: true 81 | name: "symfony-application-template" 82 | private: false 83 | 84 | # https://docs.github.com/en/rest/reference/repos#replace-all-repository-topics 85 | 86 | topics: "symfony, application, template" 87 | -------------------------------------------------------------------------------- /.github/workflows/renew.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions 2 | 3 | name: "Renew" 4 | 5 | on: # yamllint disable-line rule:truthy 6 | schedule: 7 | - cron: "0 0 1 1 *" 8 | 9 | jobs: 10 | license: 11 | name: "License" 12 | 13 | runs-on: "ubuntu-latest" 14 | 15 | timeout-minutes: 5 16 | 17 | strategy: 18 | matrix: 19 | php-version: 20 | - "8.3" 21 | 22 | dependencies: 23 | - "locked" 24 | 25 | steps: 26 | - name: "Checkout" 27 | uses: "actions/checkout@v4.2.2" 28 | with: 29 | token: "${{ secrets.ERGEBNIS_BOT_TOKEN }}" 30 | 31 | - name: "Set up PHP" 32 | uses: "shivammathur/setup-php@2.31.1" 33 | with: 34 | coverage: "none" 35 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 36 | php-version: "${{ matrix.php-version }}" 37 | 38 | - name: "Set up problem matchers for PHP" 39 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 40 | 41 | - name: "Validate composer.json and composer.lock" 42 | run: "composer validate --ansi --strict" 43 | 44 | - name: "Determine composer cache directory" 45 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 46 | 47 | - name: "Cache dependencies installed with composer" 48 | uses: "actions/cache@v4.1.2" 49 | with: 50 | path: "${{ env.COMPOSER_CACHE_DIR }}" 51 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 52 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 53 | 54 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 55 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 56 | with: 57 | dependencies: "${{ matrix.dependencies }}" 58 | 59 | - name: "Cache cache directory for friendsofphp/php-cs-fixer" 60 | uses: "actions/cache@v4.1.2" 61 | with: 62 | path: ".build/php-cs-fixer" 63 | key: "php-${{ matrix.php-version }}-php-cs-fixer-${{ github.ref_name }}" 64 | restore-keys: | 65 | php-${{ matrix.php-version }}-php-cs-fixer-main 66 | php-${{ matrix.php-version }}-php-cs-fixer- 67 | 68 | - name: "Run friendsofphp/php-cs-fixer" 69 | run: "vendor/bin/php-cs-fixer fix --ansi --config=.php-cs-fixer.php --diff --show-progress=dots --verbose" 70 | 71 | - name: "Commit modified files" 72 | uses: "stefanzweifel/git-auto-commit-action@v5.0.1" 73 | with: 74 | commit_author: "ergebnis-bot " 75 | commit_message: "Enhancement: Update license year" 76 | commit_user_email: "bot@ergebn.is" 77 | commit_user_name: "ergebnis-bot" 78 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at am@localheinz.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We use [GitHub Actions](https://github.com/features/actions) as a continuous integration system. 4 | 5 | For details, take a look at the following workflow configuration files: 6 | 7 | - [`workflows/integrate.yaml`](workflows/integrate.yaml) 8 | - [`workflows/merge.yaml`](workflows/merge.yaml) 9 | - [`workflows/release.yaml`](workflows/release.yaml) 10 | - [`workflows/renew.yaml`](workflows/renew.yaml) 11 | - [`workflows/triage.yaml`](workflows/triage.yaml) 12 | 13 | ## Coding Standards 14 | 15 | We use [`ergebnis/composer-normalize`](https://github.com/ergebnis/composer-normalize) to normalize `composer.json`. 16 | 17 | We use [`yamllint`](https://github.com/adrienverge/yamllint) to enforce coding standards in YAML files. 18 | 19 | If you do not have `yamllint` installed yet, run 20 | 21 | ```sh 22 | brew install yamllint 23 | ``` 24 | 25 | to install `yamllint`. 26 | 27 | We use [`symplify/config-transformer`](https://github.com/symplify/config-transformer) to convert YAML configuration files to PHP. 28 | 29 | We use [`friendsofphp/php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to enforce coding standards in PHP files. 30 | 31 | Run 32 | 33 | ```sh 34 | make coding-standards 35 | ``` 36 | 37 | to automatically fix coding standard violations. 38 | 39 | ## Dependency Analysis 40 | 41 | We use [`maglnet/composer-require-checker`](https://github.com/maglnet/ComposerRequireChecker) to prevent the use of unknown symbols in production code. 42 | 43 | Run 44 | 45 | ```sh 46 | make dependency-analysis 47 | ``` 48 | 49 | to run a dependency analysis. 50 | 51 | ## Mutation Tests 52 | 53 | We use [`infection/infection`](https://github.com/infection/infection) to ensure a minimum quality of the tests. 54 | 55 | Enable `Xdebug` and run 56 | 57 | ```sh 58 | make mutation-tests 59 | ``` 60 | 61 | to run mutation tests. 62 | 63 | ## Refactoring 64 | 65 | We use [`rector/rector`](https://github.com/rectorphp/rector) to automatically refactor code. 66 | 67 | Run 68 | 69 | ```sh 70 | make refactoring 71 | ``` 72 | 73 | to automatically refactor code. 74 | 75 | ## Security Analysis 76 | 77 | We use [`composer`](https://github.com/composer/composer) to run a security analysis. 78 | 79 | Run 80 | 81 | ```sh 82 | make security-analysis 83 | ``` 84 | 85 | to run a security analysis. 86 | 87 | ## Static Code Analysis 88 | 89 | We use [`vimeo/psalm`](https://github.com/vimeo/psalm) to statically analyze the code. 90 | 91 | Run 92 | 93 | ```sh 94 | make static-code-analysis 95 | ``` 96 | 97 | to run a static code analysis. 98 | 99 | We also use the baseline feature of [`vimeo/psalm`](https://psalm.dev/docs/running_psalm/dealing_with_code_issues/#using-a-baseline-file). 100 | 101 | Run 102 | 103 | ```sh 104 | make static-code-analysis-baseline 105 | ``` 106 | 107 | to regenerate the baseline in [`../psalm-baseline.xml`](../psalm-baseline.xml). 108 | 109 | :exclamation: Ideally, the baseline should shrink over time. 110 | 111 | ## Symfony 112 | 113 | We use [`symfony/flex`](https://github.com/symfony/flex) to integrate packages into the application. 114 | 115 | Run 116 | 117 | ```sh 118 | make symfony 119 | ``` 120 | 121 | to synchronize recipes. 122 | 123 | ## Tests 124 | 125 | We use [`phpunit/phpunit`](https://github.com/sebastianbergmann/phpunit) to drive the development. 126 | 127 | Run 128 | 129 | ```sh 130 | make tests 131 | ``` 132 | 133 | to run all the tests. 134 | 135 | ## Extra lazy? 136 | 137 | Run 138 | 139 | ```sh 140 | make 141 | ``` 142 | 143 | to automatically refactor code, enforce coding standards, run a static code analysis, and run tests! 144 | 145 | ## Help 146 | 147 | :bulb: Run 148 | 149 | ```sh 150 | make help 151 | ``` 152 | 153 | to display a list of available targets with corresponding descriptions. 154 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APP_ENV:=test 2 | DATABASE_CONNECTION_NAME:=default 3 | ENTITY_MANAGER_NAME_DEFAULT:=default 4 | 5 | .PHONY: it 6 | it: refactoring coding-standards security-analysis static-code-analysis tests ## Runs the refactoring, coding-standards, security-analysis, static-code-analysis, and tests targets 7 | 8 | .PHONY: cache 9 | cache: vendor ## Warms up the cache 10 | composer dump-env ${APP_ENV} 11 | bin/console cache:warmup --env=${APP_ENV} 12 | 13 | .PHONY: code-coverage 14 | code-coverage: vendor ## Collects coverage from running unit tests with phpunit/phpunit 15 | vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-text 16 | 17 | .PHONY: coding-standards 18 | coding-standards: vendor ## Lints YAML files with yamllint, normalizes composer.json with ergebnis/composer-normalize, converts YAML configuration to PHP format, and fixes code style issues with friendsofphp/php-cs-fixer 19 | yamllint -c .yamllint.yaml --strict . 20 | composer normalize 21 | vendor/bin/config-transformer transform config/ 22 | vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --show-progress=dots --verbose 23 | 24 | .PHONY: dependency-analysis 25 | dependency-analysis: phive vendor ## Runs a dependency analysis with maglnet/composer-require-checker 26 | .phive/composer-require-checker check --config-file=$(shell pwd)/composer-require-checker.json --verbose 27 | 28 | .PHONY: doctrine 29 | doctrine: vendor environment ## Runs doctrine commands to set up a local test database 30 | bin/console doctrine:database:drop --connection=${DATABASE_CONNECTION_NAME} --env=${APP_ENV} --force --if-exists 31 | bin/console doctrine:database:create --connection=${DATABASE_CONNECTION_NAME} --env=${APP_ENV} 32 | bin/console doctrine:migrations:status --env=${APP_ENV} 33 | bin/console doctrine:migrations:migrate --env=${APP_ENV} --allow-no-migration --no-interaction 34 | bin/console doctrine:schema:validate --em=${ENTITY_MANAGER_NAME_DEFAULT} || (bin/console doctrine:migrations:diff --env=${APP_ENV} && false) 35 | 36 | .PHONY: environment 37 | environment: vendor ## Dumps environment variables 38 | composer dump-env ${APP_ENV} 39 | bin/console debug:dotenv 40 | 41 | .PHONY: help 42 | help: ## Displays this list of targets with descriptions 43 | @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' 44 | 45 | .PHONY: mutation-tests 46 | mutation-tests: vendor ## Runs mutation tests with infection/infection 47 | vendor/bin/infection --configuration=infection.json 48 | 49 | .PHONY: phive 50 | phive: .phive ## Installs dependencies with phive 51 | PHIVE_HOME=.build/phive phive install --trust-gpg-keys 0x033E5F8D801A2F8D 52 | 53 | .PHONY: refactoring 54 | refactoring: vendor ## Runs automated refactoring with rector/rector 55 | vendor/bin/rector process --config=rector.php 56 | 57 | .PHONY: security-analysis 58 | security-analysis: vendor ## Runs a security analysis with composer 59 | composer audit 60 | 61 | .PHONY: static-code-analysis 62 | static-code-analysis: vendor ## Runs a static code analysis with vimeo/psalm 63 | vendor/bin/psalm --config=psalm.xml --clear-cache 64 | vendor/bin/psalm --config=psalm.xml --show-info=false --stats --threads=4 65 | 66 | .PHONY: static-code-analysis-baseline 67 | static-code-analysis-baseline: vendor ## Generates a baseline for static code analysis vimeo/psalm 68 | vendor/bin/psalm --config=psalm.xml --clear-cache 69 | vendor/bin/psalm --config=psalm.xml --set-baseline=psalm-baseline.xml 70 | 71 | .PHONY: tests 72 | tests: vendor doctrine ## Runs unit, integration, and functional tests with phpunit/phpunit 73 | vendor/bin/phpunit --configuration=test/Unit/phpunit.xml 74 | vendor/bin/phpunit --configuration=test/Integration/phpunit.xml 75 | vendor/bin/phpunit --configuration=test/Functional/phpunit.xml 76 | 77 | .PHONY: symfony 78 | symfony: vendor ## Synchronizes symfony recipes 79 | composer symfony:sync-recipes 80 | 81 | vendor: composer.json composer.lock 82 | composer validate --strict 83 | composer install --no-interaction --no-progress 84 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ergebnis/symfony-application-template", 3 | "description": "Provides a GitHub repository template for a Symfony project, using GitHub Actions.", 4 | "license": "MIT", 5 | "type": "project", 6 | "authors": [ 7 | { 8 | "name": "Andreas Möller", 9 | "email": "am@localheinz.com", 10 | "homepage": "https://localheinz.com" 11 | } 12 | ], 13 | "homepage": "https://github.com/ergebnis/symfony-application-template", 14 | "support": { 15 | "issues": "https://github.com/ergebnis/symfony-application-template/issues", 16 | "source": "https://github.com/ergebnis/symfony-application-template", 17 | "security": "https://github.com/ergebnis/symfony-application-template/blob/main/.github/SECURITY.md" 18 | }, 19 | "require": { 20 | "php": "~8.3.0", 21 | "ext-ctype": "*", 22 | "ext-iconv": "*", 23 | "ext-mbstring": "*", 24 | "ext-pdo": "*", 25 | "ext-pdo_mysql": "*", 26 | "doctrine/collections": "^2.2.2", 27 | "doctrine/doctrine-bundle": "^2.13.0", 28 | "doctrine/doctrine-migrations-bundle": "^3.3.1", 29 | "doctrine/migrations": "^3.8.2", 30 | "doctrine/orm": "^3.3.0", 31 | "ramsey/uuid": "^4.7.6", 32 | "symfony/config": "^7.1.6", 33 | "symfony/console": "^7.1.6", 34 | "symfony/dependency-injection": "^7.1.6", 35 | "symfony/dotenv": "^7.1.6", 36 | "symfony/error-handler": "^7.1.2", 37 | "symfony/flex": "^2.4.7", 38 | "symfony/framework-bundle": "^7.1.6", 39 | "symfony/http-kernel": "^7.1.6", 40 | "symfony/routing": "^7.1.6", 41 | "symfony/runtime": "^7.1.6", 42 | "symfony/yaml": "^7.1.6" 43 | }, 44 | "require-dev": { 45 | "dama/doctrine-test-bundle": "^8.2.0", 46 | "ergebnis/composer-normalize": "^2.44.0", 47 | "ergebnis/factory-bot": "^1.8.0", 48 | "ergebnis/license": "^2.5.0", 49 | "ergebnis/php-cs-fixer-config": "^6.37.0", 50 | "ergebnis/phpunit-slow-test-detector": "^2.16.1", 51 | "fakerphp/faker": "^1.23.1", 52 | "infection/infection": "~0.27.11", 53 | "phpunit/phpunit": "^10.5.26", 54 | "psalm/plugin-phpunit": "~0.19.0", 55 | "psalm/plugin-symfony": "^5.2.5", 56 | "rector/rector": "^1.2.9", 57 | "symplify/config-transformer": "^12.3.4", 58 | "vimeo/psalm": "^5.26.1" 59 | }, 60 | "replace": { 61 | "paragonie/random_compat": "*", 62 | "symfony/polyfill-ctype": "*", 63 | "symfony/polyfill-iconv": "*", 64 | "symfony/polyfill-mbstring": "*", 65 | "symfony/polyfill-php56": "*", 66 | "symfony/polyfill-php70": "*", 67 | "symfony/polyfill-php71": "*", 68 | "symfony/polyfill-php72": "*", 69 | "symfony/polyfill-php73": "*", 70 | "symfony/polyfill-php74": "*", 71 | "symfony/polyfill-php80": "*", 72 | "symfony/polyfill-php81": "*", 73 | "symfony/polyfill-php82": "*", 74 | "symfony/polyfill-php83": "*" 75 | }, 76 | "conflict": { 77 | "symfony/symfony": "*" 78 | }, 79 | "autoload": { 80 | "psr-4": { 81 | "App\\": "src/" 82 | } 83 | }, 84 | "autoload-dev": { 85 | "psr-4": { 86 | "App\\Test\\": "test/" 87 | } 88 | }, 89 | "config": { 90 | "allow-plugins": { 91 | "composer/package-versions-deprecated": true, 92 | "ergebnis/composer-normalize": true, 93 | "infection/extension-installer": true, 94 | "symfony/flex": true, 95 | "symfony/runtime": true 96 | }, 97 | "audit": { 98 | "abandoned": "report" 99 | }, 100 | "platform": { 101 | "php": "8.3.0" 102 | }, 103 | "preferred-install": "dist", 104 | "sort-packages": true 105 | }, 106 | "extra": { 107 | "symfony": { 108 | "allow-contrib": false, 109 | "require": "^7.1.1" 110 | } 111 | }, 112 | "scripts": { 113 | "post-install-cmd": [ 114 | "@auto-scripts" 115 | ], 116 | "post-update-cmd": [ 117 | "@auto-scripts" 118 | ], 119 | "auto-scripts": { 120 | "cache:clear": "symfony-cmd", 121 | "assets:install %PUBLIC_DIR%": "symfony-cmd" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /symfony.lock: -------------------------------------------------------------------------------- 1 | { 2 | "amphp/amp": { 3 | "version": "v2.5.1" 4 | }, 5 | "amphp/byte-stream": { 6 | "version": "v1.8.0" 7 | }, 8 | "brick/math": { 9 | "version": "0.8.15" 10 | }, 11 | "composer/package-versions-deprecated": { 12 | "version": "1.11.99" 13 | }, 14 | "composer/pcre": { 15 | "version": "1.0.0" 16 | }, 17 | "composer/semver": { 18 | "version": "1.5.1" 19 | }, 20 | "composer/xdebug-handler": { 21 | "version": "1.4.0" 22 | }, 23 | "dama/doctrine-test-bundle": { 24 | "version": "4.0", 25 | "recipe": { 26 | "repo": "github.com/symfony/recipes-contrib", 27 | "branch": "master", 28 | "version": "4.0", 29 | "ref": "56eaa387b5e48ebcc7c95a893b47dfa1ad51449c" 30 | }, 31 | "files": [ 32 | "config/packages/test/dama_doctrine_test_bundle.yaml" 33 | ] 34 | }, 35 | "dnoegel/php-xdg-base-dir": { 36 | "version": "v0.1.1" 37 | }, 38 | "doctrine/cache": { 39 | "version": "1.10.2" 40 | }, 41 | "doctrine/collections": { 42 | "version": "1.6.7" 43 | }, 44 | "doctrine/common": { 45 | "version": "3.0.2" 46 | }, 47 | "doctrine/dbal": { 48 | "version": "2.10.2" 49 | }, 50 | "doctrine/deprecations": { 51 | "version": "v0.5.3" 52 | }, 53 | "doctrine/doctrine-bundle": { 54 | "version": "2.0", 55 | "recipe": { 56 | "repo": "github.com/symfony/recipes", 57 | "branch": "master", 58 | "version": "2.0", 59 | "ref": "a9f2463b9f73efe74482f831f03a204a41328555" 60 | }, 61 | "files": [ 62 | "config/packages/doctrine.yaml", 63 | "config/packages/prod/doctrine.yaml", 64 | "src/Entity/.gitignore", 65 | "src/Repository/.gitignore" 66 | ] 67 | }, 68 | "doctrine/doctrine-migrations-bundle": { 69 | "version": "2.2", 70 | "recipe": { 71 | "repo": "github.com/symfony/recipes", 72 | "branch": "master", 73 | "version": "2.2", 74 | "ref": "baaa439e3e3179e69e3da84b671f0a3e4a2f56ad" 75 | }, 76 | "files": [ 77 | "config/packages/doctrine_migrations.yaml", 78 | "migrations/.gitignore" 79 | ] 80 | }, 81 | "doctrine/event-manager": { 82 | "version": "1.1.1" 83 | }, 84 | "doctrine/inflector": { 85 | "version": "1.4.3" 86 | }, 87 | "doctrine/instantiator": { 88 | "version": "1.3.0" 89 | }, 90 | "doctrine/lexer": { 91 | "version": "1.2.0" 92 | }, 93 | "doctrine/migrations": { 94 | "version": "3.0.1" 95 | }, 96 | "doctrine/orm": { 97 | "version": "v2.7.3" 98 | }, 99 | "doctrine/persistence": { 100 | "version": "2.0.0" 101 | }, 102 | "doctrine/sql-formatter": { 103 | "version": "1.1.1" 104 | }, 105 | "ergebnis/classy": { 106 | "version": "0.5.2" 107 | }, 108 | "ergebnis/composer-normalize": { 109 | "version": "2.2.4" 110 | }, 111 | "ergebnis/factory-bot": { 112 | "version": "0.3.1" 113 | }, 114 | "ergebnis/json-normalizer": { 115 | "version": "0.11.0" 116 | }, 117 | "ergebnis/json-printer": { 118 | "version": "3.0.2" 119 | }, 120 | "ergebnis/json-schema-validator": { 121 | "version": "2.0.0" 122 | }, 123 | "ergebnis/license": { 124 | "version": "0.1.0" 125 | }, 126 | "fakerphp/faker": { 127 | "version": "v1.13.0" 128 | }, 129 | "felixfbecker/advanced-json-rpc": { 130 | "version": "v3.1.1" 131 | }, 132 | "felixfbecker/language-server-protocol": { 133 | "version": "v1.5.0" 134 | }, 135 | "friendsofphp/php-cs-fixer": { 136 | "version": "3.14", 137 | "recipe": { 138 | "repo": "github.com/symfony/recipes", 139 | "branch": "main", 140 | "version": "3.0", 141 | "ref": "be2103eb4a20942e28a6dd87736669b757132435" 142 | }, 143 | "files": [ 144 | ".php-cs-fixer.dist.php" 145 | ] 146 | }, 147 | "friendsofphp/proxy-manager-lts": { 148 | "version": "v1.0.1" 149 | }, 150 | "infection/abstract-testframework-adapter": { 151 | "version": "0.3.1" 152 | }, 153 | "infection/extension-installer": { 154 | "version": "0.1.1" 155 | }, 156 | "infection/include-interceptor": { 157 | "version": "0.2.4" 158 | }, 159 | "infection/infection": { 160 | "version": "0.20.2" 161 | }, 162 | "justinrainbow/json-schema": { 163 | "version": "5.2.9" 164 | }, 165 | "laminas/laminas-code": { 166 | "version": "3.4.1" 167 | }, 168 | "localheinz/diff": { 169 | "version": "1.0.1" 170 | }, 171 | "myclabs/deep-copy": { 172 | "version": "1.9.5" 173 | }, 174 | "netresearch/jsonmapper": { 175 | "version": "v2.1.0" 176 | }, 177 | "nikic/php-parser": { 178 | "version": "v4.3.0" 179 | }, 180 | "ondram/ci-detector": { 181 | "version": "3.5.1" 182 | }, 183 | "phar-io/manifest": { 184 | "version": "1.0.3" 185 | }, 186 | "phar-io/version": { 187 | "version": "2.0.1" 188 | }, 189 | "php-cs-fixer/diff": { 190 | "version": "v1.3.0" 191 | }, 192 | "phpdocumentor/reflection-common": { 193 | "version": "2.0.0" 194 | }, 195 | "phpdocumentor/reflection-docblock": { 196 | "version": "5.0.0" 197 | }, 198 | "phpdocumentor/type-resolver": { 199 | "version": "1.0.1" 200 | }, 201 | "phpspec/prophecy": { 202 | "version": "v1.10.2" 203 | }, 204 | "phpstan/phpstan": { 205 | "version": "1.10", 206 | "recipe": { 207 | "repo": "github.com/symfony/recipes-contrib", 208 | "branch": "main", 209 | "version": "1.0", 210 | "ref": "d74d4d719d5f53856c9c13544aa22d44144b1819" 211 | } 212 | }, 213 | "phpunit/php-code-coverage": { 214 | "version": "8.0.1" 215 | }, 216 | "phpunit/php-file-iterator": { 217 | "version": "3.0.0" 218 | }, 219 | "phpunit/php-invoker": { 220 | "version": "3.0.0" 221 | }, 222 | "phpunit/php-text-template": { 223 | "version": "2.0.0" 224 | }, 225 | "phpunit/php-timer": { 226 | "version": "3.0.0" 227 | }, 228 | "phpunit/phpunit": { 229 | "version": "4.7", 230 | "recipe": { 231 | "repo": "github.com/symfony/recipes", 232 | "branch": "master", 233 | "version": "4.7", 234 | "ref": "00fdb38c318774cd39f475a753028a5e8d25d47c" 235 | }, 236 | "files": [ 237 | ".env.test", 238 | "phpunit.xml.dist", 239 | "tests/bootstrap.php" 240 | ] 241 | }, 242 | "psalm/plugin-phpunit": { 243 | "version": "0.15.0" 244 | }, 245 | "psr/cache": { 246 | "version": "1.0.1" 247 | }, 248 | "psr/container": { 249 | "version": "1.0.0" 250 | }, 251 | "psr/event-dispatcher": { 252 | "version": "1.0.0" 253 | }, 254 | "psr/log": { 255 | "version": "1.1.2" 256 | }, 257 | "ramsey/collection": { 258 | "version": "1.0.1" 259 | }, 260 | "ramsey/uuid": { 261 | "version": "4.1.0" 262 | }, 263 | "sanmai/later": { 264 | "version": "0.1.2" 265 | }, 266 | "sanmai/pipeline": { 267 | "version": "v5.1.0" 268 | }, 269 | "sebastian/cli-parser": { 270 | "version": "1.0.1" 271 | }, 272 | "sebastian/code-unit": { 273 | "version": "1.0.0" 274 | }, 275 | "sebastian/code-unit-reverse-lookup": { 276 | "version": "2.0.0" 277 | }, 278 | "sebastian/comparator": { 279 | "version": "4.0.0" 280 | }, 281 | "sebastian/complexity": { 282 | "version": "2.0.2" 283 | }, 284 | "sebastian/diff": { 285 | "version": "4.0.0" 286 | }, 287 | "sebastian/environment": { 288 | "version": "5.0.1" 289 | }, 290 | "sebastian/exporter": { 291 | "version": "4.0.0" 292 | }, 293 | "sebastian/global-state": { 294 | "version": "4.0.0" 295 | }, 296 | "sebastian/lines-of-code": { 297 | "version": "1.0.3" 298 | }, 299 | "sebastian/object-enumerator": { 300 | "version": "4.0.0" 301 | }, 302 | "sebastian/object-reflector": { 303 | "version": "2.0.0" 304 | }, 305 | "sebastian/recursion-context": { 306 | "version": "4.0.0" 307 | }, 308 | "sebastian/resource-operations": { 309 | "version": "3.0.0" 310 | }, 311 | "sebastian/type": { 312 | "version": "2.0.0" 313 | }, 314 | "sebastian/version": { 315 | "version": "3.0.0" 316 | }, 317 | "seld/jsonlint": { 318 | "version": "1.8.3" 319 | }, 320 | "symfony/cache": { 321 | "version": "v5.0.4" 322 | }, 323 | "symfony/cache-contracts": { 324 | "version": "v2.0.1" 325 | }, 326 | "symfony/config": { 327 | "version": "v5.0.4" 328 | }, 329 | "symfony/console": { 330 | "version": "4.4", 331 | "recipe": { 332 | "repo": "github.com/symfony/recipes", 333 | "branch": "master", 334 | "version": "4.4", 335 | "ref": "ea8c0eda34fda57e7d5cd8cbd889e2a387e3472c" 336 | }, 337 | "files": [ 338 | "bin/console", 339 | "config/bootstrap.php" 340 | ] 341 | }, 342 | "symfony/dependency-injection": { 343 | "version": "v5.0.4" 344 | }, 345 | "symfony/deprecation-contracts": { 346 | "version": "v2.1.3" 347 | }, 348 | "symfony/doctrine-bridge": { 349 | "version": "v5.1.3" 350 | }, 351 | "symfony/dotenv": { 352 | "version": "v5.0.4" 353 | }, 354 | "symfony/error-handler": { 355 | "version": "v5.0.4" 356 | }, 357 | "symfony/event-dispatcher": { 358 | "version": "v5.0.4" 359 | }, 360 | "symfony/event-dispatcher-contracts": { 361 | "version": "v2.0.1" 362 | }, 363 | "symfony/filesystem": { 364 | "version": "v5.0.4" 365 | }, 366 | "symfony/finder": { 367 | "version": "v5.0.4" 368 | }, 369 | "symfony/flex": { 370 | "version": "1.0", 371 | "recipe": { 372 | "repo": "github.com/symfony/recipes", 373 | "branch": "master", 374 | "version": "1.0", 375 | "ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e" 376 | }, 377 | "files": [ 378 | ".env" 379 | ] 380 | }, 381 | "symfony/framework-bundle": { 382 | "version": "4.4", 383 | "recipe": { 384 | "repo": "github.com/symfony/recipes", 385 | "branch": "master", 386 | "version": "4.4", 387 | "ref": "23ecaccc551fe2f74baf613811ae529eb07762fa" 388 | }, 389 | "files": [ 390 | "config/bootstrap.php", 391 | "config/packages/cache.yaml", 392 | "config/packages/framework.yaml", 393 | "config/packages/test/framework.yaml", 394 | "config/routes/dev/framework.yaml", 395 | "config/services.yaml", 396 | "public/index.php", 397 | "src/Controller/.gitignore", 398 | "src/Kernel.php" 399 | ] 400 | }, 401 | "symfony/http-foundation": { 402 | "version": "v5.0.4" 403 | }, 404 | "symfony/http-kernel": { 405 | "version": "v5.0.4" 406 | }, 407 | "symfony/polyfill-intl-grapheme": { 408 | "version": "v1.17.0" 409 | }, 410 | "symfony/polyfill-intl-normalizer": { 411 | "version": "v1.17.0" 412 | }, 413 | "symfony/process": { 414 | "version": "v5.0.4" 415 | }, 416 | "symfony/routing": { 417 | "version": "4.2", 418 | "recipe": { 419 | "repo": "github.com/symfony/recipes", 420 | "branch": "master", 421 | "version": "4.2", 422 | "ref": "683dcb08707ba8d41b7e34adb0344bfd68d248a7" 423 | }, 424 | "files": [ 425 | "config/packages/prod/routing.yaml", 426 | "config/packages/routing.yaml", 427 | "config/routes.yaml" 428 | ] 429 | }, 430 | "symfony/runtime": { 431 | "version": "v6.0.7" 432 | }, 433 | "symfony/service-contracts": { 434 | "version": "v2.0.1" 435 | }, 436 | "symfony/stopwatch": { 437 | "version": "v5.0.4" 438 | }, 439 | "symfony/string": { 440 | "version": "v5.1.1" 441 | }, 442 | "symfony/var-dumper": { 443 | "version": "v5.0.4" 444 | }, 445 | "symfony/var-exporter": { 446 | "version": "v5.0.4" 447 | }, 448 | "symfony/yaml": { 449 | "version": "v5.0.4" 450 | }, 451 | "symplify/config-transformer": { 452 | "version": "9.0.23" 453 | }, 454 | "thecodingmachine/safe": { 455 | "version": "v1.3.3" 456 | }, 457 | "theseer/tokenizer": { 458 | "version": "1.1.3" 459 | }, 460 | "vimeo/psalm": { 461 | "version": "4.3.2" 462 | }, 463 | "webmozart/assert": { 464 | "version": "1.7.0" 465 | } 466 | } 467 | -------------------------------------------------------------------------------- /.github/workflows/integrate.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions 2 | 3 | name: "Integrate" 4 | 5 | on: # yamllint disable-line rule:truthy 6 | pull_request: null 7 | push: 8 | branches: 9 | - "main" 10 | 11 | jobs: 12 | code-coverage: 13 | name: "Code Coverage" 14 | 15 | runs-on: "ubuntu-latest" 16 | 17 | timeout-minutes: 5 18 | 19 | strategy: 20 | matrix: 21 | php-version: 22 | - "8.3" 23 | 24 | dependencies: 25 | - "locked" 26 | 27 | steps: 28 | - name: "Checkout" 29 | uses: "actions/checkout@v4.2.2" 30 | 31 | - name: "Set up PHP" 32 | uses: "shivammathur/setup-php@2.31.1" 33 | with: 34 | coverage: "xdebug" 35 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 36 | php-version: "${{ matrix.php-version }}" 37 | 38 | - name: "Set up problem matchers for PHP" 39 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 40 | 41 | - name: "Set up problem matchers for phpunit/phpunit" 42 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"" 43 | 44 | - name: "Validate composer.json and composer.lock" 45 | run: "composer validate --ansi --strict" 46 | 47 | - name: "Determine composer cache directory" 48 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 49 | 50 | - name: "Cache dependencies installed with composer" 51 | uses: "actions/cache@v4.1.2" 52 | with: 53 | path: "${{ env.COMPOSER_CACHE_DIR }}" 54 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 55 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 56 | 57 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 58 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 59 | with: 60 | dependencies: "${{ matrix.dependencies }}" 61 | 62 | - name: "Collect code coverage with Xdebug and phpunit/phpunit" 63 | env: 64 | XDEBUG_MODE: "coverage" 65 | run: "vendor/bin/phpunit --colors=always --configuration=test/Unit/phpunit.xml --coverage-clover=.build/phpunit/logs/clover.xml" 66 | 67 | - name: "Send code coverage report to codecov.io" 68 | uses: "codecov/codecov-action@v4.6.0" 69 | with: 70 | files: ".build/phpunit/logs/clover.xml" 71 | token: "${{ secrets.CODECOV_TOKEN }}" 72 | 73 | coding-standards: 74 | name: "Coding Standards" 75 | 76 | runs-on: "ubuntu-latest" 77 | 78 | timeout-minutes: 5 79 | 80 | strategy: 81 | matrix: 82 | php-version: 83 | - "8.3" 84 | 85 | dependencies: 86 | - "locked" 87 | 88 | steps: 89 | - name: "Checkout" 90 | uses: "actions/checkout@v4.2.2" 91 | 92 | - name: "Lint YAML files" 93 | uses: "ibiqlik/action-yamllint@v3.1.1" 94 | with: 95 | config_file: ".yamllint.yaml" 96 | file_or_dir: "." 97 | strict: true 98 | 99 | - name: "Set up PHP" 100 | uses: "shivammathur/setup-php@2.31.1" 101 | with: 102 | coverage: "none" 103 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 104 | php-version: "${{ matrix.php-version }}" 105 | 106 | - name: "Set up problem matchers for PHP" 107 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 108 | 109 | - name: "Validate composer.json and composer.lock" 110 | run: "composer validate --ansi --strict" 111 | 112 | - name: "Determine composer cache directory" 113 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 114 | 115 | - name: "Cache dependencies installed with composer" 116 | uses: "actions/cache@v4.1.2" 117 | with: 118 | path: "${{ env.COMPOSER_CACHE_DIR }}" 119 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 120 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 121 | 122 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 123 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 124 | with: 125 | dependencies: "${{ matrix.dependencies }}" 126 | 127 | - name: "Run ergebnis/composer-normalize" 128 | run: "composer normalize --ansi --dry-run" 129 | 130 | - name: "Run symplify/config-transformer" 131 | run: "vendor/bin/config-transformer transform --ansi --dry-run config/" 132 | 133 | - name: "Cache cache directory for friendsofphp/php-cs-fixer" 134 | uses: "actions/cache@v4.1.2" 135 | with: 136 | path: ".build/php-cs-fixer" 137 | key: "php-${{ matrix.php-version }}-php-cs-fixer-${{ github.ref_name }}" 138 | restore-keys: | 139 | php-${{ matrix.php-version }}-php-cs-fixer-main 140 | php-${{ matrix.php-version }}-php-cs-fixer- 141 | 142 | - name: "Run friendsofphp/php-cs-fixer" 143 | run: "vendor/bin/php-cs-fixer fix --ansi --config=.php-cs-fixer.php --diff --dry-run --show-progress=dots --verbose" 144 | 145 | dependency-analysis: 146 | name: "Dependency Analysis" 147 | 148 | runs-on: "ubuntu-latest" 149 | 150 | timeout-minutes: 5 151 | 152 | strategy: 153 | matrix: 154 | php-version: 155 | - "8.3" 156 | 157 | dependencies: 158 | - "locked" 159 | 160 | steps: 161 | - name: "Checkout" 162 | uses: "actions/checkout@v4.2.2" 163 | 164 | - name: "Set up PHP" 165 | uses: "shivammathur/setup-php@2.31.1" 166 | with: 167 | coverage: "none" 168 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 169 | php-version: "${{ matrix.php-version }}" 170 | tools: "phive" 171 | 172 | - name: "Set up problem matchers for PHP" 173 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 174 | 175 | - name: "Validate composer.json and composer.lock" 176 | run: "composer validate --ansi --strict" 177 | 178 | - name: "Determine composer cache directory" 179 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 180 | 181 | - name: "Cache dependencies installed with composer" 182 | uses: "actions/cache@v4.1.2" 183 | with: 184 | path: "${{ env.COMPOSER_CACHE_DIR }}" 185 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 186 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 187 | 188 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 189 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 190 | with: 191 | dependencies: "${{ matrix.dependencies }}" 192 | 193 | - name: "Install dependencies with phive" 194 | uses: "ergebnis/.github/actions/phive/install@1.9.2" 195 | with: 196 | trust-gpg-keys: "0x033E5F8D801A2F8D" 197 | 198 | - name: "Run maglnet/composer-require-checker" 199 | run: ".phive/composer-require-checker check --ansi --config-file=$(pwd)/composer-require-checker.json --verbose" 200 | 201 | mutation-tests: 202 | name: "Mutation Tests" 203 | 204 | runs-on: "ubuntu-latest" 205 | 206 | timeout-minutes: 5 207 | 208 | strategy: 209 | matrix: 210 | php-version: 211 | - "8.3" 212 | 213 | dependencies: 214 | - "locked" 215 | 216 | env: 217 | APP_ENV: "test" 218 | 219 | steps: 220 | - name: "Checkout" 221 | uses: "actions/checkout@v4.2.2" 222 | 223 | - name: "Set up PHP" 224 | uses: "shivammathur/setup-php@2.31.1" 225 | with: 226 | coverage: "xdebug" 227 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 228 | php-version: "${{ matrix.php-version }}" 229 | 230 | - name: "Set up problem matchers for PHP" 231 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 232 | 233 | - name: "Validate composer.json and composer.lock" 234 | run: "composer validate --ansi --strict" 235 | 236 | - name: "Determine composer cache directory" 237 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 238 | 239 | - name: "Cache dependencies installed with composer" 240 | uses: "actions/cache@v4.1.2" 241 | with: 242 | path: "${{ env.COMPOSER_CACHE_DIR }}" 243 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 244 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 245 | 246 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 247 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 248 | with: 249 | dependencies: "${{ matrix.dependencies }}" 250 | 251 | - name: "Dump environment variables" 252 | run: "composer dump-env ${{ env.APP_ENV }} --ansi" 253 | 254 | - name: "List environment variables" 255 | run: "bin/console debug:dotenv --ansi" 256 | 257 | - name: "Warm up cache" 258 | run: "bin/console cache:warmup --ansi" 259 | 260 | - name: "Run mutation tests with Xdebug and infection/infection" 261 | env: 262 | XDEBUG_MODE: "coverage" 263 | run: "vendor/bin/infection --ansi --configuration=infection.json --logger-github" 264 | 265 | refactoring: 266 | name: "Refactoring" 267 | 268 | runs-on: "ubuntu-latest" 269 | 270 | timeout-minutes: 5 271 | 272 | strategy: 273 | matrix: 274 | php-version: 275 | - "8.3" 276 | 277 | dependencies: 278 | - "locked" 279 | 280 | steps: 281 | - name: "Checkout" 282 | uses: "actions/checkout@v4.2.2" 283 | 284 | - name: "Set up PHP" 285 | uses: "shivammathur/setup-php@2.31.1" 286 | with: 287 | coverage: "none" 288 | extensions: "none, ctype, curl, dom, iconv, intl, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 289 | php-version: "${{ matrix.php-version }}" 290 | 291 | - name: "Set up problem matchers for PHP" 292 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 293 | 294 | - name: "Validate composer.json and composer.lock" 295 | run: "composer validate --ansi --strict" 296 | 297 | - name: "Determine composer cache directory" 298 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 299 | 300 | - name: "Cache dependencies installed with composer" 301 | uses: "actions/cache@v4.1.2" 302 | with: 303 | path: "${{ env.COMPOSER_CACHE_DIR }}" 304 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 305 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 306 | 307 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 308 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 309 | with: 310 | dependencies: "${{ matrix.dependencies }}" 311 | 312 | - name: "Cache cache directory for rector/rector" 313 | uses: "actions/cache@v4.1.2" 314 | with: 315 | path: ".build/rector" 316 | key: "php-${{ matrix.php-version }}-rector-${{ github.ref_name }}" 317 | restore-keys: | 318 | php-${{ matrix.php-version }}-rector-main 319 | php-${{ matrix.php-version }}-rector- 320 | 321 | - name: "Run automated refactoring with rector/rector" 322 | run: "vendor/bin/rector --ansi --config=rector.php --dry-run" 323 | 324 | security-analysis: 325 | name: "Security Analysis" 326 | 327 | runs-on: "ubuntu-latest" 328 | 329 | timeout-minutes: 5 330 | 331 | strategy: 332 | matrix: 333 | php-version: 334 | - "8.3" 335 | 336 | dependencies: 337 | - "locked" 338 | 339 | steps: 340 | - name: "Checkout" 341 | uses: "actions/checkout@v4.2.2" 342 | 343 | - name: "Set up PHP" 344 | uses: "shivammathur/setup-php@2.31.1" 345 | with: 346 | coverage: "none" 347 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 348 | php-version: "${{ matrix.php-version }}" 349 | 350 | - name: "Set up problem matchers for PHP" 351 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 352 | 353 | - name: "Validate composer.json and composer.lock" 354 | run: "composer validate --ansi --strict" 355 | 356 | - name: "Determine composer cache directory" 357 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 358 | 359 | - name: "Cache dependencies installed with composer" 360 | uses: "actions/cache@v4.1.2" 361 | with: 362 | path: "${{ env.COMPOSER_CACHE_DIR }}" 363 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 364 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 365 | 366 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 367 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 368 | with: 369 | dependencies: "${{ matrix.dependencies }}" 370 | 371 | - name: "Check installed packages for security vulnerability advisories" 372 | run: "composer audit --ansi" 373 | 374 | static-code-analysis: 375 | name: "Static Code Analysis" 376 | 377 | runs-on: "ubuntu-latest" 378 | 379 | timeout-minutes: 5 380 | 381 | strategy: 382 | matrix: 383 | php-version: 384 | - "8.3" 385 | 386 | dependencies: 387 | - "locked" 388 | 389 | env: 390 | APP_ENV: "test" 391 | 392 | steps: 393 | - name: "Checkout" 394 | uses: "actions/checkout@v4.2.2" 395 | 396 | - name: "Set up PHP" 397 | uses: "shivammathur/setup-php@2.31.1" 398 | with: 399 | coverage: "none" 400 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, opcache, pcntl, pdo, pdo_mysql, phar, posix, simplexml, tokenizer, xml, xmlwriter" 401 | php-version: "${{ matrix.php-version }}" 402 | 403 | - name: "Set up problem matchers for PHP" 404 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 405 | 406 | - name: "Validate composer.json and composer.lock" 407 | run: "composer validate --ansi --strict" 408 | 409 | - name: "Determine composer cache directory" 410 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 411 | 412 | - name: "Cache dependencies installed with composer" 413 | uses: "actions/cache@v4.1.2" 414 | with: 415 | path: "${{ env.COMPOSER_CACHE_DIR }}" 416 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 417 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 418 | 419 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 420 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 421 | with: 422 | dependencies: "${{ matrix.dependencies }}" 423 | 424 | - name: "Dump environment variables" 425 | run: "composer dump-env ${{ env.APP_ENV }} --ansi" 426 | 427 | - name: "List environment variables" 428 | run: "bin/console debug:dotenv --ansi" 429 | 430 | - name: "Warm up cache" 431 | run: "bin/console cache:warmup --ansi" 432 | 433 | - name: "Run vimeo/psalm" 434 | run: "vendor/bin/psalm --config=psalm.xml --output-format=github --shepherd --show-info=false --stats --threads=4" 435 | 436 | tests: 437 | name: "Tests" 438 | 439 | runs-on: "ubuntu-latest" 440 | 441 | timeout-minutes: 5 442 | 443 | strategy: 444 | matrix: 445 | php-version: 446 | - "8.3" 447 | 448 | dependencies: 449 | - "locked" 450 | 451 | services: 452 | database-default: 453 | env: 454 | MYSQL_DATABASE: "database" 455 | MYSQL_ROOT_PASSWORD: "root" 456 | image: "mariadb:10.6.11" 457 | ports: 458 | - "3306:3306" 459 | options: >- 460 | --health-cmd="mysqladmin ping" 461 | --health-interval=10s 462 | --health-timeout=5s 463 | --health-retries=3 464 | 465 | env: 466 | APP_ENV: "test" 467 | ENTITY_MANAGER_NAME_DEFAULT: "default" 468 | 469 | steps: 470 | - name: "Checkout" 471 | uses: "actions/checkout@v4.2.2" 472 | 473 | - name: "Set up PHP" 474 | uses: "shivammathur/setup-php@2.31.1" 475 | with: 476 | coverage: "none" 477 | extensions: "none, ctype, curl, dom, iconv, json, mbstring, pdo, pdo_mysql, phar, simplexml, tokenizer, xml, xmlwriter" 478 | php-version: "${{ matrix.php-version }}" 479 | 480 | - name: "Set up problem matchers for PHP" 481 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"" 482 | 483 | - name: "Set up problem matchers for phpunit/phpunit" 484 | run: "echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"" 485 | 486 | - name: "Validate composer.json and composer.lock" 487 | run: "composer validate --ansi --strict" 488 | 489 | - name: "Determine composer cache directory" 490 | uses: "ergebnis/.github/actions/composer/determine-cache-directory@1.9.2" 491 | 492 | - name: "Cache dependencies installed with composer" 493 | uses: "actions/cache@v4.1.2" 494 | with: 495 | path: "${{ env.COMPOSER_CACHE_DIR }}" 496 | key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" 497 | restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" 498 | 499 | - name: "Install ${{ matrix.dependencies }} dependencies with composer" 500 | uses: "ergebnis/.github/actions/composer/install@1.9.2" 501 | with: 502 | dependencies: "${{ matrix.dependencies }}" 503 | 504 | - name: "Dump environment variables" 505 | run: "composer dump-env ${{ env.APP_ENV }} --ansi" 506 | 507 | - name: "List environment variables" 508 | run: "bin/console debug:dotenv --ansi" 509 | 510 | - name: "Warm up cache" 511 | run: "bin/console cache:warmup --ansi" 512 | 513 | - name: "Show Doctrine migration status" 514 | run: "bin/console doctrine:migrations:status --ansi" 515 | 516 | - name: "Run Doctrine migrations" 517 | run: "bin/console doctrine:migrations:migrate --allow-no-migration --ansi --no-interaction" 518 | 519 | - name: "Validate Doctrine schema" 520 | run: "bin/console doctrine:schema:validate --ansi --em=${{ env.ENTITY_MANAGER_NAME_DEFAULT }}" 521 | 522 | - name: "Run unit tests with phpunit/phpunit" 523 | run: "vendor/bin/phpunit --colors=always --configuration=test/Unit/phpunit.xml" 524 | 525 | - name: "Run integration tests with phpunit/phpunit" 526 | run: "vendor/bin/phpunit --colors=always --configuration=test/Integration/phpunit.xml" 527 | 528 | - name: "Run functional tests with phpunit/phpunit" 529 | run: "vendor/bin/phpunit --colors=always --configuration=test/Functional/phpunit.xml" 530 | --------------------------------------------------------------------------------