Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. AttributesOrderSniff.php

class AttributesOrderSniff

Hierarchy

  • class \SlevomatCodingStandard\Sniffs\Attributes\AttributesOrderSniff implements \PHP_CodeSniffer\Sniffs\Sniff

Expanded class hierarchy of AttributesOrderSniff

File

vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.php, line 24

Namespace

SlevomatCodingStandard\Sniffs\Attributes
View source
class AttributesOrderSniff implements Sniff {
    public const CODE_INCORRECT_ORDER = 'IncorrectOrder';
    
    /** @var list<string> */
    public $order = [];
    
    /** @var bool */
    public $orderAlphabetically = false;
    
    /**
     * @return array<int, (int|string)>
     */
    public function register() : array {
        return [
            T_ATTRIBUTE,
        ];
    }
    
    /**
     * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
     * @param int $attributeOpenerPointer
     */
    public function process(File $phpcsFile, $attributeOpenerPointer) : void {
        if (!AttributeHelper::isValidAttribute($phpcsFile, $attributeOpenerPointer)) {
            return;
        }
        if ($this->order === [] && !$this->orderAlphabetically) {
            throw new UnexpectedValueException('Neither manual or alphabetical order is set.');
        }
        if ($this->order !== [] && $this->orderAlphabetically) {
            throw new UnexpectedValueException('Only one order can be set.');
        }
        $this->order = $this->normalizeOrder($this->order);
        $tokens = $phpcsFile->getTokens();
        $pointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $attributeOpenerPointer - 1);
        if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
            return;
        }
        $attributesGroups = [
            AttributeHelper::getAttributes($phpcsFile, $attributeOpenerPointer),
        ];
        $lastAttributeCloserPointer = $tokens[$attributeOpenerPointer]['attribute_closer'];
        do {
            $nextPointer = TokenHelper::findNextNonWhitespace($phpcsFile, $lastAttributeCloserPointer + 1);
            if ($tokens[$nextPointer]['code'] !== T_ATTRIBUTE) {
                break;
            }
            $attributesGroups[] = AttributeHelper::getAttributes($phpcsFile, $nextPointer);
            $lastAttributeCloserPointer = $tokens[$nextPointer]['attribute_closer'];
        } while (true);
        if ($this->orderAlphabetically) {
            $actualOrder = $attributesGroups;
            $expectedOrder = $actualOrder;
            uasort($expectedOrder, static function (array $attributesGroup1, array $attributesGroup2) : int {
                return strnatcmp($attributesGroup1[0]->getName(), $attributesGroup2[0]->getName());
            });
        }
        else {
            $actualOrder = [];
            foreach ($attributesGroups as $attributesGroupNo => $attributesGroup) {
                $attributeName = $this->normalizeAttributeName($attributesGroup[0]->getName());
                foreach ($this->order as $orderPosition => $attributeNameOnPosition) {
                    if ($attributeName === $attributeNameOnPosition || substr($attributeNameOnPosition, -1) === '\\' && strpos($attributeName, $attributeNameOnPosition) === 0 || substr($attributeNameOnPosition, -1) === '*' && strpos($attributeName, substr($attributeNameOnPosition, 0, -1)) === 0) {
                        $actualOrder[$attributesGroupNo] = $orderPosition;
                        continue 2;
                    }
                }
                // Unknown order - add to the end
                $actualOrder[$attributesGroupNo] = 999;
            }
            $expectedOrder = $actualOrder;
            asort($expectedOrder);
        }
        if ($expectedOrder === $actualOrder) {
            return;
        }
        $fix = $phpcsFile->addFixableError('Incorrect order of attributes.', $attributeOpenerPointer, self::CODE_INCORRECT_ORDER);
        if (!$fix) {
            return;
        }
        $attributesGroupsContent = [];
        foreach ($attributesGroups as $attributesGroupNo => $attributesGroup) {
            $attributesGroupsContent[$attributesGroupNo] = TokenHelper::getContent($phpcsFile, $attributesGroup[0]->getAttributePointer(), $tokens[$attributesGroup[0]->getAttributePointer()]['attribute_closer']);
        }
        $areOnSameLine = $tokens[$attributeOpenerPointer]['line'] === $tokens[$lastAttributeCloserPointer]['line'];
        $attributesStartPointer = $attributeOpenerPointer;
        $attributesEndPointer = $lastAttributeCloserPointer;
        $indentation = IndentationHelper::getIndentation($phpcsFile, $attributeOpenerPointer);
        $phpcsFile->fixer
            ->beginChangeset();
        FixerHelper::removeBetweenIncluding($phpcsFile, $attributesStartPointer, $attributesEndPointer);
        foreach (array_keys($expectedOrder) as $position => $attributesGroupNo) {
            if ($areOnSameLine) {
                if ($position !== 0) {
                    $phpcsFile->fixer
                        ->addContent($attributesStartPointer, ' ');
                }
                $phpcsFile->fixer
                    ->addContent($attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
            }
            else {
                if ($position !== 0) {
                    $phpcsFile->fixer
                        ->addContent($attributesStartPointer, $indentation);
                }
                $phpcsFile->fixer
                    ->addContent($attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
                if ($position !== count($attributesGroups) - 1) {
                    $phpcsFile->fixer
                        ->addNewline($attributesStartPointer);
                }
            }
        }
        $phpcsFile->fixer
            ->endChangeset();
    }
    
    /**
     * @param list<string> $order
     * @return list<string>
     */
    private function normalizeOrder(array $order) : array {
        foreach ($order as $itemNo => $item) {
            $order[$itemNo] = $this->normalizeAttributeName(trim($item));
        }
        return $order;
    }
    private function normalizeAttributeName(string $name) : string {
        return ltrim($name, '\\');
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
AttributesOrderSniff::$order public property @var list&lt;string&gt;
AttributesOrderSniff::$orderAlphabetically public property @var bool
AttributesOrderSniff::CODE_INCORRECT_ORDER public constant
AttributesOrderSniff::normalizeAttributeName private function
AttributesOrderSniff::normalizeOrder private function *
AttributesOrderSniff::process public function * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*
Overrides Sniff::process
AttributesOrderSniff::register public function * Overrides Sniff::register

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal