I want to make sure all classes in some dir (src/Controller/CP
) extend some other class AbstractCPController
.
So that
class SupportTicketTagController extends AbstractController
would show PHPCS error, and
class SupportTicketTagController extends AbstractCPController
would be fine.
Is that possible with PHPCS?
Advertisement
Answer
I ended up creating my own Sniff. Its far from perfect but may serve as a base for somebody in the future:
<?php declare(strict_types=1); namespace MyCodingStandardSniffsClasses; use PHP_CodeSnifferFixer; use PHP_CodeSnifferSniffsSniff; use PHP_CodeSnifferFilesFile; /** * Sniff for catching classes not marked as abstract or final */ final class ClassInheritanceSniff implements Sniff { private ?Fixer $fixer; private $position; public function register(): array { return [T_CLASS]; } public function process(File $file, $position): void { $this->fixer = $file->fixer; $this->position = $position; $tokens = $file->getTokens(); $className = $tokens[$file->findNext(T_STRING, $position + 1)]['content']; if ($className === 'AbstractCPController') { return; } $curlyOpenLine = $file->findNext(T_OPEN_CURLY_BRACKET, $position + 1); $extendsLine = $file->findNext(T_EXTENDS, $position + 1, $curlyOpenLine - 1); $implementsLine = $file->findNext(T_IMPLEMENTS, $position + 1, $curlyOpenLine - 1); $extendedClasses = []; $implementedInterfaces = []; if ($extendsLine) { $extendsLineMax = $curlyOpenLine - 1; if ($implementsLine > $extendsLine) { $extendsLineMax = $implementsLine - 1; } $lastClassName = ''; for ($i = $extendsLine + 1; $i < $extendsLineMax; $i++) { if ($tokens[$i]['code'] == T_STRING || $tokens[$i]['code'] == T_NS_SEPARATOR) { $lastClassName .= $tokens[$i]['content']; } else { if ($lastClassName) { $extendedClasses[] = $lastClassName; $lastClassName = ''; } } } if ($lastClassName) { $extendedClasses[] = $lastClassName; } } if ($implementsLine) { $implementsLineMax = $curlyOpenLine - 1; if ($extendsLine > $implementsLine) { $implementsLineMax = $extendsLine - 1; } $lastClassName = ''; for ($i = $implementsLine + 1; $i < $implementsLineMax; $i++) { if ($tokens[$i]['code'] == T_STRING || $tokens[$i]['code'] == T_NS_SEPARATOR) { $lastClassName .= $tokens[$i]['content']; } else { if ($lastClassName) { $implementedInterfaces[] = $lastClassName; $lastClassName = ''; } } } if ($lastClassName) { $implementedInterfaces[] = $lastClassName; } } foreach ($extendedClasses as $class) { if (str_ends_with($class, 'AbstractCPController')) { return; } } $file->addError( 'All CP Controller classes should extend from AbstractCPController', $position - 1, self::class ); } }