Skip to content

Instantly share code, notes, and snippets.

@jeffery
Created September 11, 2011 13:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffery/1209578 to your computer and use it in GitHub Desktop.
Save jeffery/1209578 to your computer and use it in GitHub Desktop.
Script to visualize dependencies in a PHP project using PHP_Depend results
#!/usr/bin/env php
<?php
/**
* Usage:
* pdepend --jdepend-xml=/tmp/jdepend.xml /path/to/source
*
* ./dependencies.php /tmp/jdepend.xml -o /tmp/jdepend.svg
*/
class Dependencies
{
/**
* @var DOMDocument
*/
protected $logFile = null;
/**
* @var string
*/
protected $output = null;
protected $colors = array(
'#aaaaaa',
'#aaabbb',
'#bbbbbb',
'#bbbccc',
'#cccccc',
'#cccddd',
'#dddddd',
'#dddeee',
'#eeeeee',
'#eeefff',
'#ffffff'
);
public function __construct(array $options)
{
if ($this->parseOptions($options)) {
$this->evaluate();
}
}
protected function evaluate()
{
$output = "digraph {\n" .
" rankdir = LR\n";
$xpath = new DOMXPath($this->logFile);
$nodes = $xpath->query("//Packages/Package");
$names = array();
foreach ($nodes as $i => $node) {
$name = "p{$i}";
$label = $node->getAttribute('name');
$d = (int) 10 * round($node->getElementsByTagName("D")->item(0)->nodeValue, 1);
$options = sprintf(
'style=filled, fillcolor="%s", label="%s"',
$this->colors[$d],
str_replace('\\', '::', $label)
);
$output .= " {$name} [{$options}];\n";
$names[$name] = $label;
}
foreach ($names as $name => $label) {
$nodes = $xpath->query("//Packages/Package[@name = '{$label}']/DependsUpon/Package");
foreach ($nodes as $node) {
if (false === ($idx = array_search($node->nodeValue, $names))) {
continue;
}
if ($this->isCycle($label, $node->nodeValue)) {
$output .= " {$name} -> {$idx} [color=\"red\"];\n";
} else {
$output .= " {$name} -> {$idx};\n";
}
}
}
$output .= "}\n";
$this->dumpOutput($output);
}
protected function isCycle($name0, $name1)
{
$xpath = new DOMXPath($this->logFile);
return $xpath->query("//Packages/Package[
@name = '{$name0}'
]/UsedBy/Package[
text() = '{$name1}'
]")->length > 0;
}
protected function dumpOutput($output)
{
if ($this->output) {
$this->dumpOutputToFile($output);
} else {
$this->dumpOutputToStdout($output);
}
}
protected function dumpOutputToFile($output)
{
$file = $this->output;
$ext = pathinfo($file, PATHINFO_EXTENSION);
if ($ext === '') {
$ext = 'svg';
$file .= '.svg';
}
$dir = pathinfo($file, PATHINFO_DIRNAME);
if (false === file_exists($dir)) {
mkdir($dir, 0775, true);
}
$input = tempnam(sys_get_temp_dir(), 'dot_');
file_put_contents($input, $output);
shell_exec(
sprintf(
'dot -T%s -o%s %s',
escapeshellarg($ext),
escapeshellarg($file),
escapeshellarg($input)
)
);
unlink($input);
}
protected function dumpOutputToStdout($output)
{
echo $output;
}
protected function parseOptions(array $options)
{
if (in_array('-h', $options) || in_array('--help', $options)) {
return $this->printHelp();
}
$logFile = array_shift($options);
if (false === file_exists($logFile)) {
fwrite(STDERR, 'The specified log file "' . $logFile . '" not exists.' . PHP_EOL);
return $this->printHelp();
}
$this->logFile = new DOMDocument();
$this->logFile->load($logFile);
if (count($options) % 2 == 1) {
return $this->printHelp();
}
for ($i = 0; $i < count($options); $i+=2) {
switch ($options[$i]) {
case '-o':
case '--output':
$this->output = $options[$i+1];
break;
default:
fwrite(STDERR, 'Unknown option <' . $options[$i] . '>' . PHP_EOL);
return $this->printHelp();
}
}
return true;
}
protected function printHelp()
{
echo 'Usage: ', basename(__FILE__), ' <logfile>',
PHP_EOL, PHP_EOL,
' -o --output $O Write the generated image into this file. Otherwise ', PHP_EOL,
' output generated dot file on STDOUT.',
PHP_EOL, PHP_EOL,
' -h --help Displays this help text.', PHP_EOL;
return false;
}
public static function main(array $argv)
{
$options = $argv;
array_shift($options);
new Dependencies($options);
}
}
Dependencies::main($argv);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment