AbstractFixer.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\ConfigurationException\InvalidForEnvFixerConfigurationException;
  15. use PhpCsFixer\ConfigurationException\RequiredFixerConfigurationException;
  16. use PhpCsFixer\Console\Application;
  17. use PhpCsFixer\Fixer\ConfigurableFixerInterface;
  18. use PhpCsFixer\Fixer\FixerInterface;
  19. use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
  20. use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
  21. use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
  22. use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
  23. use PhpCsFixer\Tokenizer\Tokens;
  24. use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
  25. use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
  26. /**
  27. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  28. *
  29. * @internal
  30. */
  31. abstract class AbstractFixer implements FixerInterface
  32. {
  33. /**
  34. * @var null|array<string, mixed>
  35. */
  36. protected $configuration;
  37. /**
  38. * @var WhitespacesFixerConfig
  39. */
  40. protected $whitespacesConfig;
  41. /**
  42. * @var null|FixerConfigurationResolverInterface
  43. */
  44. private $configurationDefinition;
  45. public function __construct()
  46. {
  47. if ($this instanceof ConfigurableFixerInterface) {
  48. try {
  49. $this->configure([]);
  50. } catch (RequiredFixerConfigurationException $e) {
  51. // ignore
  52. }
  53. }
  54. if ($this instanceof WhitespacesAwareFixerInterface) {
  55. $this->whitespacesConfig = $this->getDefaultWhitespacesFixerConfig();
  56. }
  57. }
  58. final public function fix(\SplFileInfo $file, Tokens $tokens): void
  59. {
  60. if ($this instanceof ConfigurableFixerInterface && null === $this->configuration) {
  61. throw new RequiredFixerConfigurationException($this->getName(), 'Configuration is required.');
  62. }
  63. if (0 < $tokens->count() && $this->isCandidate($tokens) && $this->supports($file)) {
  64. $this->applyFix($file, $tokens);
  65. }
  66. }
  67. public function isRisky(): bool
  68. {
  69. return false;
  70. }
  71. public function getName(): string
  72. {
  73. $nameParts = explode('\\', static::class);
  74. $name = substr(end($nameParts), 0, -\strlen('Fixer'));
  75. return Utils::camelCaseToUnderscore($name);
  76. }
  77. public function getPriority(): int
  78. {
  79. return 0;
  80. }
  81. public function supports(\SplFileInfo $file): bool
  82. {
  83. return true;
  84. }
  85. /**
  86. * @param array<string, mixed> $configuration
  87. */
  88. public function configure(array $configuration): void
  89. {
  90. if (!$this instanceof ConfigurableFixerInterface) {
  91. throw new \LogicException('Cannot configure using Abstract parent, child not implementing "PhpCsFixer\Fixer\ConfigurableFixerInterface".');
  92. }
  93. foreach ($this->getConfigurationDefinition()->getOptions() as $option) {
  94. if (!$option instanceof DeprecatedFixerOption) {
  95. continue;
  96. }
  97. $name = $option->getName();
  98. if (\array_key_exists($name, $configuration)) {
  99. Utils::triggerDeprecation(new \InvalidArgumentException(sprintf(
  100. 'Option "%s" for rule "%s" is deprecated and will be removed in version %d.0. %s',
  101. $name,
  102. $this->getName(),
  103. Application::getMajorVersion() + 1,
  104. str_replace('`', '"', $option->getDeprecationMessage())
  105. )));
  106. }
  107. }
  108. try {
  109. $this->configuration = $this->getConfigurationDefinition()->resolve($configuration);
  110. } catch (MissingOptionsException $exception) {
  111. throw new RequiredFixerConfigurationException(
  112. $this->getName(),
  113. sprintf('Missing required configuration: %s', $exception->getMessage()),
  114. $exception
  115. );
  116. } catch (InvalidOptionsForEnvException $exception) {
  117. throw new InvalidForEnvFixerConfigurationException(
  118. $this->getName(),
  119. sprintf('Invalid configuration for env: %s', $exception->getMessage()),
  120. $exception
  121. );
  122. } catch (ExceptionInterface $exception) {
  123. throw new InvalidFixerConfigurationException(
  124. $this->getName(),
  125. sprintf('Invalid configuration: %s', $exception->getMessage()),
  126. $exception
  127. );
  128. }
  129. }
  130. public function getConfigurationDefinition(): FixerConfigurationResolverInterface
  131. {
  132. if (!$this instanceof ConfigurableFixerInterface) {
  133. throw new \LogicException(sprintf('Cannot get configuration definition using Abstract parent, child "%s" not implementing "PhpCsFixer\Fixer\ConfigurableFixerInterface".', static::class));
  134. }
  135. if (null === $this->configurationDefinition) {
  136. $this->configurationDefinition = $this->createConfigurationDefinition();
  137. }
  138. return $this->configurationDefinition;
  139. }
  140. public function setWhitespacesConfig(WhitespacesFixerConfig $config): void
  141. {
  142. if (!$this instanceof WhitespacesAwareFixerInterface) {
  143. throw new \LogicException('Cannot run method for class not implementing "PhpCsFixer\Fixer\WhitespacesAwareFixerInterface".');
  144. }
  145. $this->whitespacesConfig = $config;
  146. }
  147. abstract protected function applyFix(\SplFileInfo $file, Tokens $tokens): void;
  148. protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
  149. {
  150. if (!$this instanceof ConfigurableFixerInterface) {
  151. throw new \LogicException('Cannot create configuration definition using Abstract parent, child not implementing "PhpCsFixer\Fixer\ConfigurableFixerInterface".');
  152. }
  153. throw new \LogicException('Not implemented.');
  154. }
  155. private function getDefaultWhitespacesFixerConfig(): WhitespacesFixerConfig
  156. {
  157. static $defaultWhitespacesFixerConfig = null;
  158. if (null === $defaultWhitespacesFixerConfig) {
  159. $defaultWhitespacesFixerConfig = new WhitespacesFixerConfig(' ', "\n");
  160. }
  161. return $defaultWhitespacesFixerConfig;
  162. }
  163. }