├── .gitignore ├── .php-cs-fixer.dist.php ├── README.md ├── .github ├── renovate.json └── workflows │ ├── code-style.yml │ └── upstream-check.yml ├── composer.json ├── LICENSE └── src ├── Fixer ├── StatementIndentationFixer.php └── NoSemicolonBeforeClosingTagFixer.php └── Config.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.php-cs-fixer.cache 3 | /composer.lock 4 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 10 | ->append([ 11 | __FILE__, 12 | ]) 13 | ; 14 | 15 | return (new Config()) 16 | ->setFinder($finder) 17 | ; 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [PHP-CS-Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) config for [REDAXO](https://github.com/redaxo/redaxo) 2 | 3 | ### Installation 4 | 5 | ``` 6 | composer require --dev redaxo/php-cs-fixer-config 7 | ``` 8 | 9 | Example `.php-cs-fixer.dist.php`: 10 | 11 | ```php 12 | in(__DIR__) 16 | ; 17 | 18 | return (Redaxo\PhpCsFixerConfig\Config::redaxo5()) // or `::redaxo6()` 19 | ->setFinder($finder) 20 | ; 21 | 22 | ``` 23 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:best-practices", 5 | ":timezone(Europe/Berlin)", 6 | ":disableDependencyDashboard", 7 | ":semanticCommitsDisabled" 8 | ], 9 | "packageRules": [ 10 | { 11 | "matchManagers": ["github-actions"], 12 | "groupName": "actions", 13 | "schedule": ["on the first day of the month"] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redaxo/php-cs-fixer-config", 3 | "description": "php-cs-fixer config for REDAXO", 4 | "type": "library", 5 | "keywords": [ 6 | "fixer", 7 | "standards", 8 | "static analysis", 9 | "static code analysis" 10 | ], 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "REDAXO Team", 15 | "email": "info@redaxo.org" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.1", 20 | "friendsofphp/php-cs-fixer": "3.90.0", 21 | "kubawerlos/php-cs-fixer-custom-fixers": "3.35.1" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Redaxo\\PhpCsFixerConfig\\": "src" 26 | } 27 | }, 28 | "config": { 29 | "preferred-install": { 30 | "*": "dist" 31 | }, 32 | "sort-packages": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/code-style.yml: -------------------------------------------------------------------------------- 1 | name: Code Style 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened, ready_for_review] 6 | 7 | jobs: 8 | php-cs-fixer: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 10 11 | if: github.event.pull_request.draft == false 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 16 | 17 | - name: Setup PHP 18 | uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # v2 19 | with: 20 | php-version: 8.1 21 | coverage: none # disable xdebug, pcov 22 | tools: cs2pr 23 | 24 | - name: Composer install 25 | uses: ramsey/composer-install@v3 26 | 27 | - name: Run php-cs-fixer 28 | run: vendor/bin/php-cs-fixer check --ansi --diff --format=checkstyle | cs2pr 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Yakamara Media GmbH & Co. KG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Fixer/StatementIndentationFixer.php: -------------------------------------------------------------------------------- 1 | isMonolithicPhp(); 42 | } 43 | 44 | protected function createProxyFixers(): array 45 | { 46 | return [new \PhpCsFixer\Fixer\Whitespace\StatementIndentationFixer()]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Fixer/NoSemicolonBeforeClosingTagFixer.php: -------------------------------------------------------------------------------- 1 | \n")], 30 | ); 31 | } 32 | 33 | public function isCandidate(Tokens $tokens): bool 34 | { 35 | return !$tokens->isMonolithicPhp(); 36 | } 37 | 38 | protected function applyFix(SplFileInfo $file, Tokens $tokens): void 39 | { 40 | for ($index = count($tokens) - 1; $index > 1; --$index) { 41 | if (!$tokens[$index]->isGivenKind(T_CLOSE_TAG)) { 42 | continue; 43 | } 44 | 45 | $prev = $index - 1; 46 | if ($tokens[$prev]->isWhitespace(' ')) { 47 | --$prev; 48 | } 49 | if (!$tokens[$prev]->equals(';')) { 50 | continue; 51 | } 52 | 53 | $tokens->clearAt($prev); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/upstream-check.yml: -------------------------------------------------------------------------------- 1 | name: Upstream 2 | 3 | on: 4 | pull_request: 5 | types: [ opened, synchronize, reopened, ready_for_review ] 6 | 7 | jobs: 8 | run: 9 | name: ${{ matrix.repo }}@${{ matrix.branch }} 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 10 12 | if: github.event.pull_request.draft == false 13 | 14 | concurrency: 15 | group: upstream-check-${{github.event_name}}-${{ matrix.repo }}-${{ matrix.branch }}-${{ github.head_ref || github.run_id }} 16 | cancel-in-progress: true 17 | 18 | env: 19 | PHP_CS_FIXER_IGNORE_ENV: 1 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | include: 25 | - repo: redaxo/redaxo 26 | branch: main 27 | php: '8.1' 28 | - repo: redaxo/redaxo 29 | branch: 6.x 30 | php: '8.4' 31 | - repo: yakamara/yform 32 | branch: master 33 | php: '8.1' 34 | 35 | steps: 36 | - name: Checkout ${{ matrix.repo }}@${{ matrix.branch }} 37 | uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 38 | with: 39 | repository: ${{ matrix.repo }} 40 | ref: ${{ matrix.branch }} 41 | 42 | - name: Setup PHP 43 | uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # v2 44 | with: 45 | php-version: ${{ matrix.php }} 46 | coverage: none 47 | 48 | - name: Set redaxo/php-cs-fixer-config to main branch 49 | run: composer require redaxo/php-cs-fixer-config:dev-main friendsofphp/php-cs-fixer:\* --dev --no-scripts --no-interaction --no-update --ansi 50 | 51 | - uses: ramsey/composer-install@v3 52 | with: 53 | dependency-versions: 'highest' # to trigger 'composer update' instead of 'composer install' 54 | composer-options: ${{ hashFiles('composer.lock') != '' && 'redaxo/php-cs-fixer-config' || '' }} --with-all-dependencies 55 | 56 | - name: Run php-cs-fixer with config from main branch 57 | run: vendor/bin/php-cs-fixer fix -v --ansi --diff || exit 0 58 | 59 | - name: Set redaxo/php-cs-fixer-config to current branch 60 | run: composer require redaxo/php-cs-fixer-config:dev-${{ github.head_ref }} --dev --with-all-dependencies --no-scripts --no-interaction --no-progress --ansi 61 | 62 | - name: Run php-cs-fixer 63 | run: vendor/bin/php-cs-fixer check -v --ansi --diff || echo "::warning file=src/Config.php::New changes in ${{ matrix.repo }}@${{ matrix.branch }}." 64 | -------------------------------------------------------------------------------- /src/Config.php: -------------------------------------------------------------------------------- 1 | > */ 17 | private array $defaultRules; 18 | 19 | /** 20 | * @deprecated use `Config::redaxo5()` or `Config::redaxo6()` instead 21 | */ 22 | public function __construct(string $name = 'REDAXO 5', string $phpMigration = '8x1', string $phpMigrationRisky = '8x0') 23 | { 24 | parent::__construct($name); 25 | 26 | $this->setUsingCache(true); 27 | $this->setParallelConfig(ParallelConfigFactory::detect()); 28 | $this->setRiskyAllowed(true); 29 | $this->registerCustomFixers(new Fixers()); 30 | $this->registerCustomFixers([ 31 | new NoSemicolonBeforeClosingTagFixer(), 32 | new StatementIndentationFixer(), 33 | ]); 34 | 35 | $this->defaultRules = [ 36 | '@PER-CS2x0' => true, 37 | '@PER-CS2x0:risky' => true, 38 | '@Symfony' => true, 39 | '@Symfony:risky' => true, 40 | '@PHP' . $phpMigration . 'Migration' => true, 41 | '@PHP' . $phpMigrationRisky . 'Migration:risky' => true, 42 | '@PHPUnit10x0Migration:risky' => true, 43 | 44 | 'array_indentation' => true, 45 | 'blank_line_before_statement' => false, 46 | 'comment_to_phpdoc' => true, 47 | 'concat_space' => ['spacing' => 'one'], 48 | 'declare_strict_types' => false, 49 | 'echo_tag_syntax' => ['format' => 'short'], 50 | 'fully_qualified_strict_types' => ['import_symbols' => true], 51 | 'global_namespace_import' => [ 52 | 'import_constants' => true, 53 | 'import_functions' => true, 54 | 'import_classes' => true, 55 | ], 56 | 'heredoc_to_nowdoc' => true, 57 | 'method_argument_space' => ['on_multiline' => 'ignore'], 58 | 'multiline_comment_opening_closing' => true, 59 | 'multiline_promoted_properties' => ['keep_blank_lines' => true], 60 | 'native_constant_invocation' => [ 61 | 'scope' => 'namespaced', 62 | 'strict' => false, 63 | ], 64 | 'no_alternative_syntax' => false, 65 | 'no_blank_lines_after_phpdoc' => false, 66 | 'no_superfluous_elseif' => true, 67 | 'no_superfluous_phpdoc_tags' => [ 68 | 'allow_mixed' => true, 69 | 'remove_inheritdoc' => true, 70 | ], 71 | 'no_unreachable_default_argument_value' => true, 72 | 'no_useless_else' => true, 73 | 'no_useless_return' => true, 74 | 'ordered_class_elements' => ['order' => [ 75 | 'use_trait', 76 | 'case', 77 | 'constant_public', 78 | 'constant_protected', 79 | 'constant_private', 80 | 'property', 81 | 'construct', 82 | 'phpunit', 83 | 'method', 84 | ]], 85 | 'php_unit_internal_class' => true, 86 | 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], 87 | 'phpdoc_align' => false, 88 | 'phpdoc_array_type' => true, 89 | 'phpdoc_no_package' => false, 90 | 'phpdoc_order' => true, 91 | 'phpdoc_separation' => false, 92 | 'phpdoc_to_comment' => false, 93 | 'phpdoc_var_annotation_correct_order' => true, 94 | 'psr_autoloading' => false, 95 | 'semicolon_after_instruction' => false, 96 | 'single_line_empty_body' => true, 97 | 'single_line_throw' => false, 98 | 'statement_indentation' => false, 99 | 'static_lambda' => true, 100 | 'string_implicit_backslashes' => ['single_quoted' => 'ignore'], 101 | 'trailing_comma_in_multiline' => [ 102 | 'after_heredoc' => true, 103 | 'elements' => ['arguments', 'arrays', 'match', 'parameters'], 104 | ], 105 | 'use_arrow_functions' => false, 106 | 'void_return' => false, 107 | 108 | PhpdocSingleLineVarFixer::name() => true, 109 | 110 | 'Redaxo/no_semicolon_before_closing_tag' => true, 111 | 'Redaxo/statement_indentation' => true, 112 | ]; 113 | 114 | $this->setRules([]); 115 | } 116 | 117 | public static function redaxo5(): self 118 | { 119 | return new self(); 120 | } 121 | 122 | public static function redaxo6(): self 123 | { 124 | $config = new self('REDAXO 6', '8x4', '8x2'); 125 | 126 | $config->defaultRules['general_phpdoc_annotation_remove'] = [ 127 | 'annotations' => ['author', 'package'], 128 | ]; 129 | 130 | $config->setRules([]); 131 | 132 | return $config; 133 | } 134 | 135 | public function setRules(array $rules): ConfigInterface 136 | { 137 | return parent::setRules(array_merge($this->defaultRules, $rules)); 138 | } 139 | } 140 | --------------------------------------------------------------------------------