‪TYPO3CMS  ‪main
AbstractCoreMatcher.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PhpParser\Node;
21 use PhpParser\Node\Stmt\Class_;
22 use PhpParser\NodeVisitorAbstract;
25 
33 abstract class ‪AbstractCoreMatcher extends NodeVisitorAbstract implements ‪CodeScannerInterface
34 {
35  public const ‪NODE_RESOLVED_AS = 'nodeResolvedAs';
36 
42  protected ‪$matcherDefinitions = [];
43 
47  protected ‪$matches = [];
48 
55  protected ‪$flatMatcherDefinitions = [];
56 
60  protected ‪$currentCodeLine = 0;
61 
65  protected ‪$isCurrentLineIgnored = false;
66 
70  protected ‪$isFullFileIgnored = false;
71 
75  public function ‪getMatches(): array
76  {
77  return ‪$this->matches;
78  }
79 
92  protected function ‪validateMatcherDefinitions(array $requiredArrayKeys = [])
93  {
94  foreach ($this->matcherDefinitions as $key => $matcherDefinition) {
95  $this->‪validateMatcherDefinitionKeys($key, $matcherDefinition, $requiredArrayKeys);
96  }
97  }
98 
99  protected function ‪validateMatcherDefinitionKeys(string $key, array $matcherDefinition, array $requiredArrayKeys = []): void
100  {
101  // Each config must point to at least one .rst file
102  if (empty($matcherDefinition['restFiles'])) {
103  throw new \InvalidArgumentException(
104  'Each configuration must have at least one referenced "restFiles" entry. Offending key: ' . $key,
105  1500496068
106  );
107  }
108  foreach ($matcherDefinition['restFiles'] as $file) {
109  if (empty($file)) {
110  throw new \InvalidArgumentException(
111  'Empty restFiles definition',
112  1500735983
113  );
114  }
115  }
116  // Config broken if not all required array keys are specified in config
117  $sharedArrays = array_intersect(array_keys($matcherDefinition), $requiredArrayKeys);
118  if (count($sharedArrays) !== count($requiredArrayKeys)) {
119  $missingKeys = array_diff($requiredArrayKeys, array_keys($matcherDefinition));
120  throw new \InvalidArgumentException(
121  'Required matcher definitions missing: ' . implode(', ', $missingKeys) . ' offending key: ' . $key,
122  1500492001
123  );
124  }
125  }
126 
138  protected function ‪initializeFlatMatcherDefinitions()
139  {
140  $methodNameArray = [];
141  foreach ($this->matcherDefinitions as $classAndMethod => ‪$details) {
142  $method = ‪GeneralUtility::trimExplode('::', $classAndMethod);
143  if (count($method) !== 2) {
144  $method = ‪GeneralUtility::trimExplode('->', $classAndMethod);
145  }
146  if (count($method) !== 2) {
147  throw new \RuntimeException(
148  'Keys in $this->matcherDefinitions must have a Class\Name->method or Class\Name::method structure',
149  1500557309
150  );
151  }
152  $method = $method[1];
153  if (!array_key_exists($method, $methodNameArray)) {
154  $methodNameArray[$method]['candidates'] = [];
155  }
156  $methodNameArray[$method]['candidates'][] = ‪$details;
157  }
158  $this->flatMatcherDefinitions = $methodNameArray;
159  }
160 
167  protected function ‪isArgumentUnpackingUsed(array $arguments = []): bool
168  {
169  foreach ($arguments as $arg) {
170  if ($arg->unpack === true) {
171  return true;
172  }
173  }
174  return false;
175  }
176 
181  protected function ‪isLineIgnored(Node $node): bool
182  {
183  // Early return if this line is marked as ignored
184  $startLineOfNode = $node->getAttribute('startLine');
185  if ($startLineOfNode === $this->currentCodeLine) {
187  }
188 
189  $currentLineIsIgnored = false;
190  if ($startLineOfNode !== $this->currentCodeLine) {
191  $this->currentCodeLine = $startLineOfNode;
192  // First node of a new line may contain the annotation
193  $comments = $node->getAttribute('comments');
194  if (!empty($comments)) {
195  foreach ($comments as $comment) {
196  if (str_contains($comment->getText(), '@extensionScannerIgnoreLine')) {
197  $this->isCurrentLineIgnored = true;
198  $currentLineIsIgnored = true;
199  break;
200  }
201  }
202  }
203  }
204  return $currentLineIsIgnored;
205  }
206 
211  protected function ‪isFileIgnored(Node $node): bool
212  {
213  if ($this->isFullFileIgnored) {
214  return true;
215  }
216  $currentFileIsIgnored = false;
217  if ($node instanceof Class_) {
218  $comments = $node->getAttribute('comments');
219  if (!empty($comments)) {
220  foreach ($comments as $comment) {
221  if (str_contains($comment->getText(), '@extensionScannerIgnoreFile')) {
222  $this->isFullFileIgnored = true;
223  $currentFileIsIgnored = true;
224  break;
225  }
226  }
227  }
228  }
229  return $currentFileIsIgnored;
230  }
231 }
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isArgumentUnpackingUsed
‪isArgumentUnpackingUsed(array $arguments=[])
Definition: AbstractCoreMatcher.php:161
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isLineIgnored
‪isLineIgnored(Node $node)
Definition: AbstractCoreMatcher.php:175
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\NODE_RESOLVED_AS
‪const NODE_RESOLVED_AS
Definition: AbstractCoreMatcher.php:35
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\validateMatcherDefinitionKeys
‪validateMatcherDefinitionKeys(string $key, array $matcherDefinition, array $requiredArrayKeys=[])
Definition: AbstractCoreMatcher.php:93
‪TYPO3\CMS\Webhooks\Message\$details
‪identifier readonly UriInterface readonly array $details
Definition: MfaVerificationErrorOccurredMessage.php:37
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher
Definition: AbstractCoreMatcher.php:18
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher
Definition: AbstractCoreMatcher.php:34
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$currentCodeLine
‪int $currentCodeLine
Definition: AbstractCoreMatcher.php:56
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$isCurrentLineIgnored
‪bool $isCurrentLineIgnored
Definition: AbstractCoreMatcher.php:60
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isFileIgnored
‪isFileIgnored(Node $node)
Definition: AbstractCoreMatcher.php:205
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$matches
‪array $matches
Definition: AbstractCoreMatcher.php:45
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\validateMatcherDefinitions
‪validateMatcherDefinitions(array $requiredArrayKeys=[])
Definition: AbstractCoreMatcher.php:86
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$matcherDefinitions
‪array $matcherDefinitions
Definition: AbstractCoreMatcher.php:41
‪TYPO3\CMS\Install\ExtensionScanner\CodeScannerInterface
Definition: CodeScannerInterface.php:24
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\getMatches
‪getMatches()
Definition: AbstractCoreMatcher.php:69
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$isFullFileIgnored
‪bool $isFullFileIgnored
Definition: AbstractCoreMatcher.php:64
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\initializeFlatMatcherDefinitions
‪initializeFlatMatcherDefinitions()
Definition: AbstractCoreMatcher.php:132
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$flatMatcherDefinitions
‪array $flatMatcherDefinitions
Definition: AbstractCoreMatcher.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:817