private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult)
{
$name = $this->getFileRelativePathname($file);
try {
$lintingResult->check();
} catch (LintingException $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_INVALID));
$this->errorsManager->report(new Error(Error::TYPE_INVALID, $name));
return;
}
$old = file_get_contents($file->getRealPath());
$tokens = Tokens::fromCode($old);
$oldHash = $tokens->getCodeHash();
$newHash = $oldHash;
$new = $old;
$appliedFixers = array();
try {
foreach ($this->fixers as $fixer) {
if (!$fixer->supports($file) || !$fixer->isCandidate($tokens)) {
continue;
}
$fixer->fix($file, $tokens);
if ($tokens->isChanged()) {
$tokens->clearEmptyTokens();
$tokens->clearChanged();
$appliedFixers[] = $fixer->getName();
}
}
} catch (\Exception $e) {
$this->processException($name);
return;
} catch (\ParseError $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT));
$this->errorsManager->report(new Error(Error::TYPE_LINT, $name));
return;
} catch (\Throwable $e) {
$this->processException($name);
return;
}
$fixInfo = null;
if (!empty($appliedFixers)) {
$new = $tokens->generateCode();
$newHash = $tokens->getCodeHash();
}
// We need to check if content was changed and then applied changes.
// But we can't simple check $appliedFixers, because one fixer may revert
// work of other and both of them will mark collection as changed.
// Therefore we need to check if code hashes changed.
if ($oldHash !== $newHash) {
try {
$this->linter->lintSource($new)->check();
} catch (LintingException $e) {
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent(FixerFileProcessedEvent::STATUS_LINT));
$this->errorsManager->report(new Error(Error::TYPE_LINT, $name));
return;
}
if (!$this->isDryRun) {
if (false === @file_put_contents($file->getRealPath(), $new)) {
$error = error_get_last();
throw new IOException(sprintf('Failed to write file "%s", "%s".', $file->getPathname(), $error ? $error['message'] : 'no reason available'), 0, null, $file->getRealPath());
}
}
$fixInfo = array('appliedFixers' => $appliedFixers, 'diff' => $this->differ->diff($old, $new));
}
$this->cacheManager->setFile($name, $new);
$this->dispatchEvent(FixerFileProcessedEvent::NAME, new FixerFileProcessedEvent($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES));
return $fixInfo;
}