|
<?php |
|
|
|
namespace Potherca\FileSplitter; |
|
|
|
use PhpParser\NodeTraverser; |
|
use PhpParser\NodeVisitor\NameResolver; |
|
|
|
set_error_handler(function ($severity, $message, $file, $line) { |
|
throw new \ErrorException($message, 0, $severity, $file, $line); |
|
}); |
|
|
|
$parameters = $argv; |
|
|
|
$command = basename(array_shift($parameters)); |
|
|
|
if (count($parameters) < 2 || in_array('--help', $parameters)) { |
|
echo <<<TXT |
|
Usage: |
|
|
|
{$command} [options] <subject-file> <target-directory> [path-code] |
|
|
|
With options: |
|
|
|
--help Display this help message |
|
--dry-run Show what would be written |
|
|
|
Where: |
|
|
|
- <subject-file> is the file that is to be split. |
|
- <target-directory> is the directory that split class files are to be written to. Must already exist. |
|
- path-code is the PHP code that is used to replace a found class with. Please be aware this MUST be valid PHP. |
|
In order to base the file-name on the name of each split of class, use '%class%'. |
|
|
|
Example: |
|
|
|
{$command} --dry-run 'path/to/multi.class.php' 'path/to/classes/' "__DIR__.'/%class%.php'" |
|
|
|
Please note that support for preserving code formatting depends on the parser used by this project. |
|
Support is still experimental so until it is stable, the split-out code might contain formatting changes. |
|
|
|
TXT; |
|
|
|
} else { |
|
require __DIR__.'/vendor/autoload.php'; |
|
|
|
/*/ Create variables from the command-line parameters /*/ |
|
|
|
$dryRun = false; |
|
|
|
$parameters = array_map(function ($parameter) use (&$dryRun) { |
|
$isNamedParam = strpos($parameter, '--') === 0; |
|
if ($isNamedParam && $parameter === '--dry-run') { |
|
$dryRun = true; |
|
} |
|
|
|
return $isNamedParam?null:$parameter; |
|
}, $parameters); |
|
|
|
$filePath = array_shift($parameters); |
|
$targetPath = rtrim(array_shift($parameters), '/'); |
|
$pathCode = array_shift($parameters); |
|
|
|
// @FIXME: Warn if {$pathCode} is not valid (i.e. can not be parsed). |
|
|
|
if (is_file($filePath) === false) { |
|
throw new \InvalidArgumentException("Could not find file at given path {$filePath}"); |
|
} elseif (is_dir($targetPath) === false) { |
|
throw new \InvalidArgumentException("Could not find directory at given path {$targetPath}"); |
|
} else { |
|
parseCode($filePath, $pathCode, $targetPath, $dryRun); |
|
} |
|
} |
|
|
|
/*EOF*/ |
|
|
|
/** |
|
* @param string $filePath |
|
* @param string $pathCode |
|
* @param string $targetPath |
|
* @param bool $dryRun |
|
*/ |
|
function parseCode($filePath, $pathCode, $targetPath, $dryRun) |
|
{ |
|
$code = file_get_contents($filePath); |
|
|
|
/*/ Set up Parser /*/ |
|
|
|
$lexer = new \PhpParser\Lexer\Emulative([ |
|
'usedAttributes' => [ |
|
'comments', |
|
'startLine', |
|
'endLine', |
|
'startTokenPos', |
|
'endTokenPos', |
|
], |
|
]); |
|
|
|
$parser = new \PhpParser\Parser\Php5($lexer); |
|
|
|
$traverser = new NodeTraverser(); |
|
$traverser->addVisitor(new \PhpParser\NodeVisitor\CloningVisitor()); |
|
|
|
$splitClassVisitor = new SplitClassVisitor($pathCode); |
|
|
|
$traverser->addVisitor($splitClassVisitor); |
|
|
|
$traverser->addVisitor(new NameResolver(null, [ |
|
'preserveOriginalNames' => false, |
|
'replaceNodes' => true, |
|
])); |
|
|
|
/*/ Parse the given file /*/ |
|
|
|
$originalStaments = $parser->parse($code); |
|
$originalTokens = $lexer->getTokens(); |
|
|
|
$statements = $traverser->traverse($originalStaments); |
|
|
|
if (is_array($statements)) { |
|
|
|
/*/ Convert AST to string /*/ |
|
$printer = new \PhpParser\PrettyPrinter\Standard(); |
|
|
|
$files = []; |
|
|
|
// Add the code of each class |
|
$classNodes = $splitClassVisitor->getClassNodes(); |
|
array_walk($classNodes, |
|
function ($node, $name) use (&$files, $printer, $targetPath, $originalStaments, $originalTokens) { |
|
$path = "{$targetPath}/{$name}.php"; |
|
|
|
//$code = $printer->prettyPrintFile([$node])."\n"; |
|
$code = $printer->printFormatPreserving([$node], $originalStaments, $originalTokens) . "\n"; |
|
|
|
$files[$path] = $code; |
|
}); |
|
|
|
// Add the original file |
|
//$files[$file] = $printer->prettyPrintFile($statements)."\n"; |
|
$files[$filePath] = $printer->printFormatPreserving($statements, $originalStaments, $originalTokens) . "\n"; |
|
|
|
/*/ Actually write the files /*/ |
|
|
|
array_walk($files, function ($content, $path) use ($dryRun) { |
|
|
|
if ($dryRun === true) { |
|
echo "\n# ================================================================================\nFILE: $path\nCONTENT: $content"; |
|
} else { |
|
echo "Writing content to {$path}\n"; |
|
file_put_contents($path, $content); |
|
} |
|
}); |
|
} |
|
} |