‪TYPO3CMS  9.5
AbstractCoreMatcher.php
Go to the documentation of this file.
1 <?php
2 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 
18 use PhpParser\Node;
19 use PhpParser\Node\Stmt\Class_;
20 use PhpParser\NodeVisitorAbstract;
23 
31 abstract class ‪AbstractCoreMatcher extends NodeVisitorAbstract implements ‪CodeScannerInterface
32 {
33  public const ‪NODE_RESOLVED_AS = 'nodeResolvedAs';
34 
40  protected ‪$matcherDefinitions = [];
41 
45  protected ‪$matches = [];
46 
53  protected ‪$flatMatcherDefinitions = [];
54 
58  protected ‪$currentCodeLine = 0;
59 
63  protected ‪$isCurrentLineIgnored = false;
64 
68  protected ‪$isFullFileIgnored = false;
69 
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 
168  protected function ‪isArgumentUnpackingUsed(array $arguments = []): bool
169  {
170  foreach ($arguments as $arg) {
171  if ($arg->unpack === true) {
172  return true;
173  }
174  }
175  return false;
176  }
177 
185  protected function ‪isLineIgnored(Node $node): bool
186  {
187  // Early return if this line is marked as ignored
188  $startLineOfNode = $node->getAttribute('startLine');
189  if ($startLineOfNode === $this->currentCodeLine) {
191  }
192 
193  $currentLineIsIgnored = false;
194  if ($startLineOfNode !== $this->currentCodeLine) {
195  $this->currentCodeLine = $startLineOfNode;
196  // First node of a new line may contain the annotation
197  $comments = $node->getAttribute('comments');
198  if (!empty($comments)) {
199  foreach ($comments as $comment) {
200  if (strstr($comment->getText(), '@extensionScannerIgnoreLine') !== false) {
201  $this->isCurrentLineIgnored = true;
202  $currentLineIsIgnored = true;
203  break;
204  }
205  }
206  }
207  }
208  return $currentLineIsIgnored;
209  }
210 
218  protected function ‪isFileIgnored(Node $node): bool
219  {
220  if ($this->isFullFileIgnored) {
221  return true;
222  }
223  $currentFileIsIgnored = false;
224  if ($node instanceof Class_) {
225  $comments = $node->getAttribute('comments');
226  if (!empty($comments)) {
227  foreach ($comments as $comment) {
228  if (strstr($comment->getText(), '@extensionScannerIgnoreFile') !== false) {
229  $this->isFullFileIgnored = true;
230  $currentFileIsIgnored = true;
231  break;
232  }
233  }
234  }
235  }
236  return $currentFileIsIgnored;
237  }
238 }
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\NODE_RESOLVED_AS
‪const NODE_RESOLVED_AS
Definition: AbstractCoreMatcher.php:33
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isArgumentUnpackingUsed
‪bool isArgumentUnpackingUsed(array $arguments=[])
Definition: AbstractCoreMatcher.php:162
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\validateMatcherDefinitionKeys
‪validateMatcherDefinitionKeys(string $key, array $matcherDefinition, array $requiredArrayKeys=[])
Definition: AbstractCoreMatcher.php:93
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher
Definition: AbstractCoreMatcher.php:3
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isLineIgnored
‪bool isLineIgnored(Node $node)
Definition: AbstractCoreMatcher.php:179
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher
Definition: AbstractCoreMatcher.php:32
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$currentCodeLine
‪int $currentCodeLine
Definition: AbstractCoreMatcher.php:54
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\getMatches
‪array getMatches()
Definition: AbstractCoreMatcher.php:69
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$isCurrentLineIgnored
‪bool $isCurrentLineIgnored
Definition: AbstractCoreMatcher.php:58
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$matches
‪array $matches
Definition: AbstractCoreMatcher.php:43
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\validateMatcherDefinitions
‪validateMatcherDefinitions(array $requiredArrayKeys=[])
Definition: AbstractCoreMatcher.php:86
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\isFileIgnored
‪bool isFileIgnored(Node $node)
Definition: AbstractCoreMatcher.php:212
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$matcherDefinitions
‪array $matcherDefinitions
Definition: AbstractCoreMatcher.php:39
‪TYPO3\CMS\Install\ExtensionScanner\CodeScannerInterface
Definition: CodeScannerInterface.php:22
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$isFullFileIgnored
‪bool $isFullFileIgnored
Definition: AbstractCoreMatcher.php:62
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\initializeFlatMatcherDefinitions
‪initializeFlatMatcherDefinitions()
Definition: AbstractCoreMatcher.php:132
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Install\ExtensionScanner\Php\Matcher\AbstractCoreMatcher\$flatMatcherDefinitions
‪array $flatMatcherDefinitions
Definition: AbstractCoreMatcher.php:50