Skip to content

Commit 7d36ce9

Browse files
committed
Fixes #13. Implemented Ely\multiline_if_statement_braces fixer
1 parent e9ad4a9 commit 7d36ce9

File tree

7 files changed

+195
-9
lines changed

7 files changed

+195
-9
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
## [Unreleased]
88
### Added
99
- Enh #12: Implemented `Ely\align_multiline_parameters` fixer.
10+
- Enh #13: Implemented `Ely\multiline_if_statement_braces` fixer.
1011
- Enabled `Ely\align_multiline_parameters` for Ely.by codestyle in `['types' => false, 'defaults' => false]` mode.
12+
- Enabled `Ely\multiline_if_statement_braces` for Ely.by codestyle in `['keep_on_own_line' => true]` mode.
1113
- Enabled
1214
[`PhpCsFixerCustomFixers/multiline_promoted_properties`](https://github.com/kubawerlos/php-cs-fixer-custom-fixers#multilinepromotedpropertiesfixer)
1315
fixer for Ely.by codestyle in 2+ parameters mode.

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,28 @@ and `do-while`.
286286
$c = 'next statement';
287287
```
288288

289+
### `Ely/multiline_if_statement_braces`
290+
291+
Ensures that multiline if statement body curly brace placed on the right line.
292+
293+
```diff
294+
--- Original
295+
+++ New
296+
@@ @@
297+
<?php
298+
if ($condition1 === 123
299+
- && $condition2 = 321) {
300+
+ && $condition2 = 321
301+
+) {
302+
// Do something here
303+
}
304+
```
305+
306+
**Configuration:**
307+
308+
* `keep_on_own_line` - should this place closing bracket on its own line? If it's set to `false`, than
309+
curly bracket will be placed right after the last condition statement. **Default**: `true`.
310+
289311
### `Ely/remove_class_name_method_usages` (Yii2)
290312

291313
Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84)

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"require": {
2222
"php": "^7.4 || ^8.0",
2323
"friendsofphp/php-cs-fixer": "^3.13",
24-
"kubawerlos/php-cs-fixer-custom-fixers": "^3.13"
24+
"kubawerlos/php-cs-fixer-custom-fixers": "^3.13",
25+
"symfony/polyfill-php80": "^1.15"
2526
},
2627
"require-dev": {
2728
"ergebnis/composer-normalize": "^2.28",

composer.lock

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Ely\CS\Fixer\Whitespace;
5+
6+
use Ely\CS\Fixer\AbstractFixer;
7+
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
8+
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
9+
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
10+
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
11+
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
12+
use PhpCsFixer\FixerDefinition\CodeSample;
13+
use PhpCsFixer\FixerDefinition\FixerDefinition;
14+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
15+
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
16+
use PhpCsFixer\Tokenizer\Tokens;
17+
use PhpCsFixer\Tokenizer\TokensAnalyzer;
18+
use SplFileInfo;
19+
20+
final class MultilineIfStatementBracesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface {
21+
22+
/**
23+
* @internal
24+
*/
25+
public const C_KEEP_ON_OWN_LINE = 'keep_on_own_line';
26+
27+
public function getDefinition(): FixerDefinitionInterface {
28+
return new FixerDefinition(
29+
'Ensures that multiline if statement body curly brace placed on the right line.',
30+
[
31+
new CodeSample(
32+
'<?php
33+
if ($condition1 == true
34+
&& $condition2 === false) {}
35+
',
36+
),
37+
new CodeSample(
38+
'<?php
39+
if ($condition1 == true
40+
&& $condition2 === false
41+
) {}
42+
',
43+
[self::C_KEEP_ON_OWN_LINE => false],
44+
),
45+
],
46+
);
47+
}
48+
49+
public function isCandidate(Tokens $tokens): bool {
50+
return $tokens->isTokenKindFound(T_IF);
51+
}
52+
53+
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface {
54+
return new FixerConfigurationResolver([
55+
(new FixerOptionBuilder(self::C_KEEP_ON_OWN_LINE, 'adjusts the position of condition closing brace.'))
56+
->setAllowedTypes(['bool'])
57+
->setDefault(true)
58+
->getOption(),
59+
]);
60+
}
61+
62+
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
63+
$keepOnOwnLine = $this->configuration[self::C_KEEP_ON_OWN_LINE];
64+
$tokensAnalyzer = new TokensAnalyzer($tokens);
65+
$eol = $this->whitespacesConfig->getLineEnding();
66+
foreach ($tokens as $i => $token) {
67+
if (!$token->isGivenKind(T_IF)) {
68+
continue;
69+
}
70+
71+
$openBraceIndex = $tokens->getNextTokenOfKind($i, ['(']);
72+
if (!$tokensAnalyzer->isBlockMultiline($tokens, $openBraceIndex)) {
73+
continue;
74+
}
75+
76+
$closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBraceIndex);
77+
/** @var \PhpCsFixer\Tokenizer\Token $statementBeforeClosingBrace */
78+
$statementBeforeClosingBrace = $tokens[$closingBraceIndex - 1];
79+
if ($keepOnOwnLine) {
80+
if (!$statementBeforeClosingBrace->isWhitespace()
81+
|| !str_contains($statementBeforeClosingBrace->getContent(), $eol)
82+
) {
83+
$indent = WhitespacesAnalyzer::detectIndent($tokens, $i);
84+
$tokens->ensureWhitespaceAtIndex($closingBraceIndex, 0, $eol . $indent);
85+
}
86+
} else {
87+
$tokens->removeLeadingWhitespace($closingBraceIndex);
88+
}
89+
}
90+
}
91+
92+
}

src/Rules.php

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ public static function create(array $overwrittenRules = []): array {
228228
],
229229
'Ely/blank_line_before_return' => true,
230230
'Ely/line_break_after_statements' => true,
231+
'Ely/multiline_if_statement_braces' => true,
231232
'Ely/remove_class_name_method_usages' => true,
232233
], $overwrittenRules);
233234
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Ely\CS\Test\Fixer\Whitespace;
5+
6+
use Ely\CS\Fixer\Whitespace\MultilineIfStatementBracesFixer;
7+
use PhpCsFixer\AbstractFixer;
8+
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
9+
10+
/**
11+
* @covers \Ely\CS\Fixer\Whitespace\MultilineIfStatementBracesFixer
12+
*/
13+
class MultilineIfStatementBracesFixerTest extends AbstractFixerTestCase {
14+
15+
/**
16+
* @dataProvider provideFixCases
17+
*/
18+
public function testFixOnNewLine(string $expected, ?string $input = null): void {
19+
$this->doTest($expected, $input);
20+
}
21+
22+
public function provideFixCases(): iterable {
23+
yield 'simple' => [
24+
'<?php
25+
if ($condition1
26+
&& $condition2
27+
) {}',
28+
'<?php
29+
if ($condition1
30+
&& $condition2) {}',
31+
];
32+
33+
yield 'nested' => [
34+
'<?php
35+
function foo() {
36+
if ($condition1
37+
&& $condition2
38+
) {}
39+
}',
40+
'<?php
41+
function foo() {
42+
if ($condition1
43+
&& $condition2) {}
44+
}',
45+
];
46+
}
47+
48+
/**
49+
* @dataProvider provideInvertedFixCases
50+
*/
51+
public function testFixOnSameLine(string $expected, ?string $input = null): void {
52+
$this->fixer->configure([
53+
MultilineIfStatementBracesFixer::C_KEEP_ON_OWN_LINE => false,
54+
]);
55+
$this->doTest($expected, $input);
56+
}
57+
58+
public function provideInvertedFixCases(): iterable {
59+
foreach ($this->provideFixCases() as $name => $case) {
60+
yield $name => [$case[1], $case[0]];
61+
}
62+
}
63+
64+
protected function createFixer(): AbstractFixer {
65+
return new MultilineIfStatementBracesFixer();
66+
}
67+
68+
}

0 commit comments

Comments
 (0)