Skip to content

SlevomatCodingStandard.Classes.ClassStructure: group based on method name prefix #1749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use SlevomatCodingStandard\Helpers\NamespaceHelper;
use SlevomatCodingStandard\Helpers\PropertyHelper;
use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
use SlevomatCodingStandard\Helpers\StringHelper;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function array_diff;
use function array_filter;
Expand Down Expand Up @@ -415,8 +416,18 @@ private function resolveMethodGroup(File $phpcsFile, int $pointer, string $metho
{
foreach ($this->getNormalizedMethodGroups() as $group => $methodRequirements) {
foreach ($methodRequirements as $methodRequirement) {
if ($methodRequirement['name'] !== null && $method !== strtolower($methodRequirement['name'])) {
continue;
if ($methodRequirement['name'] !== null) {
$requiredName = strtolower($methodRequirement['name']);

if (StringHelper::endsWith($requiredName, '*')) {
$methodNamePrefix = substr($requiredName, 0, -1);

if ($method === $methodNamePrefix || !StringHelper::startsWith($method, $methodNamePrefix)) {
continue;
}
} elseif ($method !== $requiredName) {
continue;
}
}

if (
Expand Down
14 changes: 12 additions & 2 deletions doc/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ constants, properties, static properties, methods, all public methods, all prote
<rule ref="SlevomatCodingStandard.Classes.ClassStructure">
<properties>
<property name="methodGroups" type="array">
<element key="inject method" value="inject"/>
<element key="inject methods" value="inject*"/>
<element key="phpunit before" value="setUp, @before, #PHPUnit\Framework\Attributes\Before"/>
</property>

Expand All @@ -80,13 +82,21 @@ constants, properties, static properties, methods, all public methods, all prote
<!-- You don't care about the order among the properties. The same can be done with "properties" shortcut -->
<element value="public properties, protected properties, private properties"/>

<!-- Constructor is first, then all public methods, then protected/private methods and magic methods are last -->
<!-- Constructor is first -->
<element value="constructor"/>

<!-- PHPUnit's before hooks are placed before all other public methods using a custom method group regardless their visibility -->
<!-- Then inject method followed by all other inject methods based on their prefix using a custom method group regardless their visibility -->
<element value="inject method"/>
<element value="inject methods"/>

<!-- PHPUnit's before hooks are placed before all other public methods using a custom method group -->
<element value="phpunit before"/>

<!-- Then all public methods, followed by protected/private methods -->
<element value="all public methods"/>
<element value="methods"/>

<!-- Magic methods are last -->
<element value="magic methods"/>
</property>
</properties>
Expand Down
8 changes: 7 additions & 1 deletion tests/Sniffs/Classes/ClassStructureSniffTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ClassStructureSniffTest extends TestCase
];

private const METHOD_GROUPS = [
'inject method' => 'inject',
'inject methods' => 'inject*',
'phpunit before class' => 'setUpBeforeClass, @beforeClass, #PHPUnit\Framework\Attributes\BeforeClass',
'phpunit after class' => 'tearDownAfterClass, @afterClass, #PHPUnit\Framework\Attributes\AfterClass',
'phpunit before' => 'setUp, @before, #PHPUnit\Framework\Attributes\Before',
Expand All @@ -48,6 +50,8 @@ class ClassStructureSniffTest extends TestCase
'constructor',
'static constructors',
'destructor',
'inject method',
'inject methods',
'phpunit before class',
'phpunit after class',
'phpunit before',
Expand Down Expand Up @@ -209,12 +213,14 @@ public function testErrorsWithMethodGroupRules(): void
],
);

self::assertSame(5, $report->getErrorCount());
self::assertSame(7, $report->getErrorCount());
self::assertSniffError($report, 22, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 33, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 44, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 48, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 67, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 71, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertSniffError($report, 75, ClassStructureSniff::CODE_INCORRECT_GROUP_ORDER);
self::assertAllFixedInFile($report);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ public function __destruct()
{
}

public function inject($foo)
{
}

public function injectFoo($foo)
{
}

public static function setUpBeforeClass()
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ private function dolor()
protected function afterUsingAnnotation()
{
}

public function injectFoo($foo)
{
}

public function inject($foo)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ public function __destruct()
{
}

public function inject($foo)
{
}

public function injectFoo($foo)
{
}

public static function setUpBeforeClass()
{
}
Expand Down