Skip to content

Commit 75ea311

Browse files
authored
Merge pull request #66 from smeghead/support-svg-link
add SVG link support. add `--svg-topurl` option. #65
2 parents 0832c92 + 8d40ff1 commit 75ea311

File tree

8 files changed

+207
-18
lines changed

8 files changed

+207
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
### Features
4+
5+
* add SVG link support. add `--svg-topurl` option. #65
6+
37
## v1.2.6 (2024-05-29)
48

59
### Features

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,25 @@ usage: php-class-diagram [OPTIONS] <target php source directory>
6161
A CLI tool that parses the PHP source directory and generates PlantUML class diagram scripts as output.
6262

6363
OPTIONS
64-
-h, --help show this help page.
65-
-v, --version show version.
66-
--class-diagram output class diagram script. (default)
67-
--package-diagram output package diagram script.
68-
--division-diagram output division diagram script.
69-
--jig-diagram output class diagram and package diagram script.
70-
--enable-class-properties describe properties in class diagram. (default)
71-
--disable-class-properties not describe properties in class diagram.
72-
--enable-class-methods describe methods in class diagram. (default)
73-
--disable-class-methods not describe methods in class diagram.
64+
-h, --help show this help page.
65+
-v, --version show version.
66+
--class-diagram output class diagram script. (default)
67+
--package-diagram output package diagram script.
68+
--division-diagram output division diagram script.
69+
--jig-diagram output class diagram and package diagram script.
70+
--enable-class-properties describe properties in class diagram. (default)
71+
--disable-class-properties not describe properties in class diagram.
72+
--enable-class-methods describe methods in class diagram. (default)
73+
--disable-class-methods not describe methods in class diagram.
7474
--enable-class-name-summary describe classname with Class summary of document comment. (default)
7575
--disable-class-name-summary describe classname without Class summary of document comment.
76-
--php5 parse php source file as php5.
77-
--php7 parse php source file as php7.
78-
--php8 parse php source file as php8. (not supported)
79-
--header='header string' additional header string. You can specify multiple header values.
80-
--include='wildcard' include target file pattern. (default: `*.php`) You can specify multiple include patterns.
81-
--exclude='wildcard' exclude target file pattern. You can specify multiple exclude patterns.
76+
--svg-topurl specifies the top URL when displaying the class as a link when outputting in SVG format.
77+
--php5 parse php source file as php5.
78+
--php7 parse php source file as php7.
79+
--php8 parse php source file as php8. (not supported)
80+
--header='header string' additional header string. You can specify multiple header values.
81+
--include='wildcard' include target file pattern. (default: `*.php`) You can specify multiple include patterns.
82+
--exclude='wildcard' exclude target file pattern. You can specify multiple exclude patterns.
8283
```
8384

8485
## How to execute

bin/php-class-diagram

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ $options = getopt('hv',[
2222
'disable-class-methods',
2323
'enable-class-name-summary',
2424
'disable-class-name-summary',
25+
'svg-topurl::',
2526
'php7',
2627
'php8',
2728
'header::',
@@ -48,6 +49,7 @@ OPTIONS
4849
--disable-class-methods not describe methods in class diagram.
4950
--enable-class-name-summary describe classname with Class summary of document comment. (default)
5051
--disable-class-name-summary describe classname without Class summary of document comment.
52+
--svg-topurl Specifies the top URL when displaying the class as a link when outputting in SVG format.
5153
--php5 parse php source file as php5.
5254
--php7 parse php source file as php7.
5355
--php8 parse php source file as php8. (not supported)

src/Config/Options.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,15 @@ public function excludes(): array
152152
}
153153
return $excludes;
154154
}
155+
156+
/**
157+
* @return string specified svgTopurl
158+
*/
159+
public function svgTopurl(): string
160+
{
161+
if ( ! isset($this->opt['svg-topurl'])) {
162+
return '';
163+
}
164+
return $this->opt['svg-topurl'];
165+
}
155166
}

src/DiagramElement/Entry.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ public function dump(int $level = 0): array
5353
? $this->class->getDescription()
5454
: '');
5555
$classIdentifier = sprintf(
56-
'%s "%s" as %s',
56+
'%s "%s" as %s%s',
5757
$meta,
5858
$this->class->getClassType()->getName() . (empty($classSummary) ? '' : sprintf("\\n<b>%s</b>", $classSummary)),
59-
$this->class->getClassNameAlias()
59+
$this->class->getClassNameAlias(),
60+
$this->getLinkExpression($meta)
6061
);
6162
if ($this->options->classProperties() || $this->options->classMethods()) {
6263
$lines[] = sprintf('%s%s {', $indent, $classIdentifier);
@@ -177,4 +178,17 @@ public function getUsingArrows(): array
177178
}
178179
return $arrows;
179180
}
181+
182+
private function getLinkExpression(string $meta): string
183+
{
184+
if (empty($this->options->svgTopurl())) {
185+
return '';
186+
}
187+
$path = sprintf('/%s/%s.php', $this->directory, $this->class->getClassType()->getName());
188+
return sprintf(
189+
' [[%s %s %s]]',
190+
$path,
191+
$this->class->getClassType()->getName(),
192+
ucfirst($meta));
193+
}
180194
}

src/DiagramElement/Relation.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public function getPackage(): Package
3434
public function dump(): array
3535
{
3636
$lines = ['@startuml class-diagram'];
37+
if ( ! empty($this->options->svgTopurl())) {
38+
$lines[] = ' skinparam svgLinkTarget _blank';
39+
$lines[] = sprintf(' skinparam topurl %s', $this->options->svgTopurl());
40+
}
3741
$lines = array_merge($lines, array_map(function ($x) {
3842
return ' ' . $x;
3943
}, $this->options->headers()));

test/OptionsTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,22 @@ public function testExcludeDefault(): void
286286

287287
$this->assertSame(0, count($options->excludes()), 'default exclude is empty.');
288288
}
289+
public function testSvgTopurlDefault(): void
290+
{
291+
$opt = [];
292+
293+
$options = new Options($opt);
294+
295+
$this->assertSame('*.php', $options->includes()[0], 'default include.');
296+
}
297+
public function testSvgTopurl(): void
298+
{
299+
$opt = [
300+
'svg-topurl' => 'https://github.com/smeghead/php-class-diagram',
301+
];
302+
303+
$options = new Options($opt);
304+
305+
$this->assertSame('https://github.com/smeghead/php-class-diagram', $options->svgTopurl(), 'specified svg-topurl.');
306+
}
289307
}

test/PackageSvgLinkTest.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
use Smeghead\PhpClassDiagram\Config\Options;
8+
use Smeghead\PhpClassDiagram\DiagramElement\{
9+
Relation,
10+
Entry,
11+
};
12+
use Smeghead\PhpClassDiagram\Php\PhpReader;
13+
14+
final class PackageSvgLink extends TestCase
15+
{
16+
private string $fixtureDir;
17+
18+
public function setUp(): void
19+
{
20+
$this->fixtureDir = sprintf('%s/fixtures', __DIR__);
21+
}
22+
23+
public function testDump_SvgLink_Classes(): void
24+
{
25+
$directory = sprintf('%s/namespace', $this->fixtureDir);
26+
$options = new Options([
27+
'disable-class-properties' => true,
28+
'disable-class-methods' => true,
29+
'svg-topurl' => 'https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/namespace',
30+
]);
31+
$files = [
32+
'product/Product.php',
33+
'product/Price.php',
34+
'product/Name.php',
35+
];
36+
$entries = [];
37+
foreach ($files as $f) {
38+
$filename = sprintf('%s/namespace/%s', $this->fixtureDir, $f);
39+
$classes = PhpReader::parseFile($directory, $filename, $options);
40+
foreach ($classes as $c) {
41+
$entries = array_merge($entries, [new Entry('product', $c->getInfo(), $options)]);
42+
}
43+
}
44+
$rel = new Relation($entries, $options);
45+
46+
$expected = <<<EOS
47+
@startuml class-diagram
48+
skinparam svgLinkTarget _blank
49+
skinparam topurl https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/namespace
50+
package product as product {
51+
class "Product" as product_Product [[/product/Product.php Product Class]]
52+
class "Price" as product_Price [[/product/Price.php Price Class]]
53+
class "Name" as product_Name [[/product/Name.php Name Class]]
54+
}
55+
product_Product ..> product_Name
56+
product_Product ..> product_Price
57+
product_Product ..> product_Product
58+
@enduml
59+
EOS;
60+
$this->assertSame($expected, implode(PHP_EOL, $rel->dump()), 'output PlantUML script.');
61+
}
62+
63+
public function testDump_SvgLink_Interfaces(): void
64+
{
65+
$directory = sprintf('%s/interface', $this->fixtureDir);
66+
$options = new Options([
67+
'disable-class-properties' => true,
68+
'enable-class-methods' => true,
69+
'svg-topurl' => 'https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/interface',
70+
]);
71+
$files = [
72+
'product/Interface_.php',
73+
];
74+
$entries = [];
75+
foreach ($files as $f) {
76+
$filename = sprintf('%s/%s', $directory, $f);
77+
$classes = PhpReader::parseFile($directory, $filename, $options);
78+
foreach ($classes as $c) {
79+
$entries = array_merge($entries, [new Entry(dirname($f), $c->getInfo(), $options)]);
80+
}
81+
}
82+
$rel = new Relation($entries, $options);
83+
$expected = <<<EOS
84+
@startuml class-diagram
85+
skinparam svgLinkTarget _blank
86+
skinparam topurl https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/interface
87+
package product as product {
88+
interface "Interface_" as product_Interface_ [[/product/Interface_.php Interface_ Interface]] {
89+
+method1(param1)
90+
}
91+
}
92+
@enduml
93+
EOS;
94+
$this->assertSame($expected, implode(PHP_EOL, $rel->dump()), 'output PlantUML script.');
95+
}
96+
public function testDump_SvgLink_ClassesWithoutNamespace(): void
97+
{
98+
$directory = sprintf('%s/no-namespace', $this->fixtureDir);
99+
$options = new Options([
100+
'disable-class-properties' => true,
101+
'disable-class-methods' => true,
102+
'svg-topurl' => 'https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/no-namespace',
103+
]);
104+
$files = [
105+
'product/Product.php',
106+
'product/Price.php',
107+
'product/Name.php',
108+
];
109+
$entries = [];
110+
foreach ($files as $f) {
111+
$filename = sprintf('%s/%s', $directory, $f);
112+
$classes = PhpReader::parseFile($directory, $filename, $options);
113+
foreach ($classes as $c) {
114+
$entries = array_merge($entries, [new Entry(dirname($f), $c->getInfo(), $options)]);
115+
}
116+
}
117+
$rel = new Relation($entries, $options);
118+
119+
$expected = <<<EOS
120+
@startuml class-diagram
121+
skinparam svgLinkTarget _blank
122+
skinparam topurl https://github.com/smeghead/php-class-diagram/tree/main/test/fixtures/no-namespace
123+
package product as product {
124+
class "Product" as product_Product [[/product/Product.php Product Class]]
125+
class "Price" as product_Price [[/product/Price.php Price Class]]
126+
class "Name" as product_Name [[/product/Name.php Name Class]]
127+
}
128+
product_Product ..> product_Name
129+
product_Product ..> product_Price
130+
product_Product ..> product_Product
131+
@enduml
132+
EOS;
133+
$this->assertSame($expected, implode(PHP_EOL, $rel->dump()), 'output PlantUML script.');
134+
}
135+
}

0 commit comments

Comments
 (0)