├── .github
├── dependabot.yml
└── workflows
│ └── push.yml
├── .gitignore
├── .scrutinizer.yml
├── LICENSE
├── Makefile
├── README.md
├── composer.json
├── extension.neon
├── phpcs.xml.dist
├── phpmd.xml.dist
├── phpstan.neon
├── phpunit.xml.dist
├── psalm.xml
├── src
└── phpDocumentor
│ ├── GraphViz
│ ├── Attribute.php
│ ├── AttributeNotFound.php
│ ├── Attributes.php
│ ├── Edge.php
│ ├── Exception.php
│ ├── Graph.php
│ └── Node.php
│ └── PHPStan
│ ├── AttributeGetterMethodReflection.php
│ ├── AttributeSetterMethodReflection.php
│ ├── GraphNodeReflectionExtension.php
│ ├── MethodReflectionExtension.php
│ └── assets
│ └── attributes.xml
└── tests
└── phpDocumentor
├── GraphViz
└── Test
│ ├── AttributeTest.php
│ ├── EdgeTest.php
│ ├── GraphTest.php
│ └── NodeTest.php
└── PHPStan
└── MethodReflectionExtensionTest.php
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: composer
4 | directory: "/"
5 | schedule:
6 | interval: weekly
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/.github/workflows/push.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | pull_request:
6 | name: Qa workflow
7 | env:
8 | extensions: mbstring, intl, iconv, libxml, dom, json, simplexml, zlib, fileinfo
9 | key: cache-v1 # can be any string, change to clear the extension cache.
10 | defaultPHPVersion: '7.3'
11 | jobs:
12 | phpunit-with-coverage:
13 | runs-on: ubuntu-latest
14 | name: Unit tests
15 | steps:
16 | - uses: actions/checkout@v2
17 |
18 | - name: Install graphviz
19 | run: sudo apt-get update && sudo apt-get install -y graphviz
20 |
21 | - name: Setup PHP
22 | uses: shivammathur/setup-php@v2
23 | with:
24 | php-version: ${{ env.defaultPHPVersion }}
25 | ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
26 | tools: phive
27 |
28 | - name: Get composer cache directory
29 | id: composer-cache
30 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
31 |
32 | - name: Cache composer dependencies
33 | uses: actions/cache@v2
34 | with:
35 | path: ${{ steps.composer-cache.outputs.dir }}
36 | key: composer-${{ hashFiles('**/composer.lock') }}
37 | restore-keys: composer-
38 |
39 | - name: Install Composer dependencies
40 | run: |
41 | composer install --no-progress --prefer-dist --optimize-autoloader
42 |
43 | - name: Run PHPUnit
44 | run: php vendor/bin/phpunit
45 |
46 | phpunit:
47 | runs-on: ${{ matrix.operating-system }}
48 | strategy:
49 | matrix:
50 | operating-system:
51 | - ubuntu-latest
52 | php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1']
53 | name: Unit tests for PHP version ${{ matrix.php-versions }} on ${{ matrix.operating-system }}
54 | needs:
55 | - phpunit-with-coverage
56 | steps:
57 | - uses: actions/checkout@v2
58 |
59 | - name: Install graphviz
60 | run: sudo apt-get update && sudo apt-get install -y graphviz
61 |
62 | - name: Setup PHP
63 | uses: shivammathur/setup-php@v2
64 | with:
65 | php-version: ${{ matrix.php-versions }}
66 | extension-csv: mbstring, simplexml
67 | ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
68 |
69 | - name: Get composer cache directory
70 | id: composer-cache
71 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
72 |
73 | - name: Cache composer dependencies
74 | uses: actions/cache@v2
75 | with:
76 | path: ${{ steps.composer-cache.outputs.dir }}
77 | key: composer-${{ hashFiles('**/composer.lock') }}
78 | restore-keys: composer-
79 |
80 | - name: Install Composer dependencies
81 | run: |
82 | composer install --no-progress --prefer-dist --optimize-autoloader
83 |
84 | - name: Run PHPUnit
85 | run: php vendor/bin/phpunit
86 |
87 | codestyle:
88 | runs-on: ubuntu-latest
89 | steps:
90 | - uses: actions/checkout@v2
91 | - name: Restore/cache vendor folder
92 | uses: actions/cache@v1
93 | with:
94 | path: vendor
95 | key: all-build-${{ hashFiles('**/composer.lock') }}
96 | restore-keys: |
97 | all-build-${{ hashFiles('**/composer.lock') }}
98 | all-build-
99 | - name: Restore/cache tools folder
100 | uses: actions/cache@v1
101 | with:
102 | path: tools
103 | key: all-tools-${{ github.sha }}
104 | restore-keys: |
105 | all-tools-${{ github.sha }}-
106 | all-tools-
107 | - name: Code style check
108 | uses: docker://phpdoc/phpcs-ga:latest
109 | env:
110 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
111 | with:
112 | args: -d memory_limit=1024M
113 |
114 | phpstan:
115 | runs-on: ubuntu-latest
116 | steps:
117 | - uses: actions/checkout@v2
118 | - name: Setup PHP
119 | uses: shivammathur/setup-php@v2
120 | with:
121 | php-version: ${{ env.defaultPHPVersion }}
122 | ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
123 | tools: pecl
124 |
125 | - name: Get composer cache directory
126 | id: composer-cache
127 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
128 |
129 | - name: Cache composer dependencies
130 | uses: actions/cache@v2
131 | with:
132 | path: ${{ steps.composer-cache.outputs.dir }}
133 | key: composer-${{ hashFiles('**/composer.lock') }}
134 | restore-keys: composer-
135 |
136 | - name: Install Composer dependencies
137 | run: |
138 | composer install --no-progress --prefer-dist --optimize-autoloader
139 |
140 | - name: PHPStan
141 | uses: phpDocumentor/phpstan-ga@master
142 | env:
143 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
144 | with:
145 | args: analyse src tests --configuration phpstan.neon
146 |
147 | psalm:
148 | runs-on: ubuntu-latest
149 | steps:
150 | - uses: actions/checkout@v2
151 |
152 | - name: Setup PHP
153 | uses: shivammathur/setup-php@v2
154 | with:
155 | php-version: 7.3
156 | ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
157 | tools: pecl, psalm
158 |
159 | - name: Get composer cache directory
160 | id: composer-cache
161 | run: echo "::set-output name=dir::$(composer config cache-files-dir)"
162 |
163 | - name: Cache composer dependencies
164 | uses: actions/cache@v2
165 | with:
166 | path: ${{ steps.composer-cache.outputs.dir }}
167 | key: composer-${{ hashFiles('**/composer.lock') }}
168 | restore-keys: composer-
169 |
170 | - name: Install Composer dependencies
171 | run: |
172 | composer install --no-progress --prefer-dist --optimize-autoloader
173 |
174 | - name: Psalm
175 | run: vendor/bin/psalm.phar --output-format=github
176 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # IDE Shizzle; it is recommended to use a global .gitignore for this but since this is an OSS project we want to make
2 | # it easy to contribute
3 | .idea
4 | /nbproject/private/
5 | .buildpath
6 | .project
7 | .settings
8 |
9 | # Build folder and vendor folder are generated code; no need to version this
10 | build/
11 | vendor/
12 | temp/
13 | tools/
14 | *.phar
15 |
16 | # By default the phpunit.xml.dist is provided; you can override this using a local config file
17 | phpunit.xml
18 | composer.lock
19 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | before_commands:
2 | - "composer install --no-dev --prefer-source"
3 |
4 | checks:
5 | php:
6 | excluded_dependencies:
7 | - phpstan/phpstan
8 |
9 | tools:
10 | external_code_coverage:
11 | enabled: true
12 | timeout: 300
13 | filter:
14 | excluded_paths: ["tests", "vendor"]
15 | php_code_sniffer:
16 | enabled: true
17 | config:
18 | standard: PSR2
19 | filter:
20 | paths: ["src/*", "tests/*"]
21 | excluded_paths: []
22 | php_cpd:
23 | enabled: true
24 | excluded_dirs: ["tests", "vendor"]
25 | php_cs_fixer:
26 | enabled: true
27 | config:
28 | level: all
29 | filter:
30 | paths: ["src/*", "tests/*"]
31 | php_loc:
32 | enabled: true
33 | excluded_dirs: ["tests", "vendor"]
34 | php_mess_detector:
35 | enabled: true
36 | config:
37 | ruleset: phpmd.xml.dist
38 | design_rules: { eval_expression: false }
39 | filter:
40 | paths: ["src/*"]
41 | php_pdepend:
42 | enabled: true
43 | excluded_dirs: ["tests", "vendor"]
44 | php_analyzer:
45 | enabled: true
46 | filter:
47 | paths: ["src/*", "tests/*"]
48 | sensiolabs_security_checker: true
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Mike van Riel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is furnished
10 | to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: install-phive
2 | install-phive:
3 | mkdir tools; \
4 | wget -O tools/phive.phar https://phar.io/releases/phive.phar; \
5 | wget -O tools/phive.phar.asc https://phar.io/releases/phive.phar.asc; \
6 | gpg --keyserver pool.sks-keyservers.net --recv-keys 0x9D8A98B29B2D5D79; \
7 | gpg --verify tools/phive.phar.asc tools/phive.phar; \
8 | chmod +x tools/phive.phar
9 |
10 | .PHONY: setup
11 | setup: install-phive
12 | docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpdoc/phar-ga:latest php tools/phive.phar install --force-accept-unsigned
13 | .PHONY: phpcbf
14 | phpcbf:
15 | docker run -it --rm -v${CURDIR}:/opt/project -w /opt/project phpdoc/phpcs-ga:latest phpcbf ${ARGS}
16 |
17 | .PHONY: phpcs
18 | phpcs:
19 | docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpdoc/phpcs-ga:latest -d memory_limit=1024M -s
20 |
21 | .PHONY: phpstan
22 | phpstan:
23 | docker run -it --rm -v${CURDIR}:/opt/project -w /opt/project phpdoc/phpstan-ga:latest analyse src tests --configuration phpstan.neon ${ARGS}
24 |
25 | .PHONY: psalm
26 | psalm:
27 | docker run -it --rm -v${CURDIR}:/data -w /data php:7.3 vendor/bin/psalm.phar
28 |
29 | .PHONY: test
30 | test:
31 | docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:7.3 vendor/bin/phpunit
32 |
33 | .PHONY: pre-commit-test
34 | pre-commit-test: phpcs phpstan psalm test
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://opensource.org/licenses/MIT)
2 | [](https://travis-ci.org/phpDocumentor/GraphViz)
3 | [](https://ci.appveyor.com/project/phpDocumentor/GraphViz/branch/master)
4 | [](https://coveralls.io/github/phpDocumentor/GraphViz?branch=master)
5 | [](https://scrutinizer-ci.com/g/phpDocumentor/GraphViz/?branch=master)
6 | [](https://scrutinizer-ci.com/g/phpDocumentor/GraphViz/?branch=master)
7 | [](https://packagist.org/packages/phpDocumentor/GraphViz)
8 | [](https://packagist.org/packages/phpDocumentor/GraphViz)
9 |
10 |
11 | GraphViz
12 | ========
13 |
14 | GraphViz is a library meant for generating .dot files for GraphViz with a
15 | fluent interface.
16 |
17 |
18 | ### PHPStan extension
19 |
20 | This library contains a number of magic methods to set attributes on `Node`, `Graph` and `Edge`
21 | this will result in errors when using the library with checks by PHPStan. For your convenience this
22 | library provides an phpStan extension so your code can be checked correctly by phpstan.
23 |
24 | ```
25 | includes:
26 | - vendor/phpdocumentor/graphviz/extension.neon
27 | ```
28 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phpdocumentor/graphviz",
3 | "description": "Wrapper for Graphviz",
4 | "type": "library",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Mike van Riel",
9 | "email": "mike.vanriel@naenius.com"
10 | }
11 | ],
12 | "require": {
13 | "php": "^7.2 || ^8.0"
14 | },
15 | "autoload": {
16 | "psr-4": {
17 | "phpDocumentor\\GraphViz\\": "src/phpDocumentor/GraphViz",
18 | "phpDocumentor\\GraphViz\\PHPStan\\": "./src/phpDocumentor/PHPStan"
19 | }
20 | },
21 | "autoload-dev": {
22 | "psr-4": {
23 | "phpDocumentor\\GraphViz\\Test\\": "./tests/phpDocumentor/GraphViz/Test",
24 | "phpDocumentor\\GraphViz\\PHPStan\\": "./tests/phpDocumentor/PHPStan"
25 | }
26 | },
27 | "require-dev": {
28 | "phpunit/phpunit": "^8.2 || ^9.2",
29 | "mockery/mockery": "^1.2",
30 | "phpstan/phpstan": "^0.12",
31 | "ext-simplexml": "*",
32 | "psalm/phar": "^4.15 || ^5.0"
33 | },
34 | "extra": {
35 | "branch-alias": {
36 | "dev-master": "2.x-dev"
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/extension.neon:
--------------------------------------------------------------------------------
1 | services:
2 | -
3 | class: phpDocumentor\GraphViz\PHPStan\MethodReflectionExtension
4 | tags:
5 | - phpstan.broker.methodsClassReflectionExtension
6 | -
7 | class: phpDocumentor\GraphViz\PHPStan\GraphNodeReflectionExtension
8 | tags:
9 | - phpstan.broker.propertiesClassReflectionExtension
10 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 | The coding standard for phpDocumentor.
4 |
5 | src
6 | tests
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | tests/phpDocumentor/GraphViz/Test/GraphTest\.php
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/phpmd.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 40
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | includes:
2 | - /composer/vendor/phpstan/phpstan-mockery/extension.neon
3 | - ./extension.neon
4 |
5 | parameters:
6 | level: max
7 | ignoreErrors:
8 | #We have some runtime protection that needs to be tested. Ignore these errors
9 | - '#Call to an undefined method phpDocumentor\\GraphViz\\Edge::someNonExcistingMethod\(\)\.#'
10 | - '#Call to an undefined method phpDocumentor\\GraphViz\\Graph::MyMethod\(\)\.#'
11 | - '#Call to an undefined method phpDocumentor\\GraphViz\\Graph::getNotExisting\(\)\.#'
12 | - '#Call to an undefined method phpDocumentor\\GraphViz\\Node::someNonExistingMethod\(\)\.#'
13 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
17 | ./tests/phpDocumentor/GraphViz
18 |
19 |
20 | ./tests/phpDocumentor/PHPStan
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ./src/
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/phpDocumentor/GraphViz/Attribute.php:
--------------------------------------------------------------------------------
1 | key = $key;
42 | $this->value = $value;
43 | }
44 |
45 | /**
46 | * Sets the key for this attribute.
47 | *
48 | * @param string $key The new name of this attribute.
49 | */
50 | public function setKey(string $key): self
51 | {
52 | $this->key = $key;
53 |
54 | return $this;
55 | }
56 |
57 | /**
58 | * Returns the name for this attribute.
59 | */
60 | public function getKey(): string
61 | {
62 | return $this->key;
63 | }
64 |
65 | /**
66 | * Sets the value for this attribute.
67 | *
68 | * @param string $value The new value.
69 | */
70 | public function setValue(string $value): self
71 | {
72 | $this->value = $value;
73 |
74 | return $this;
75 | }
76 |
77 | /**
78 | * Returns the value for this attribute.
79 | */
80 | public function getValue(): string
81 | {
82 | return $this->value;
83 | }
84 |
85 | /**
86 | * Returns the attribute definition as is requested by GraphViz.
87 | */
88 | public function __toString(): string
89 | {
90 | $key = $this->getKey();
91 | if ($key === 'url') {
92 | $key = 'URL';
93 | }
94 |
95 | $value = $this->getValue();
96 | if ($this->isValueContainingSpecials()) {
97 | $value = '"' . $this->encodeSpecials() . '"';
98 | } elseif (!$this->isValueInHtml()) {
99 | $value = '"' . addslashes($value) . '"';
100 | }
101 |
102 | return $key . '=' . $value;
103 | }
104 |
105 | /**
106 | * Returns whether the value contains HTML.
107 | */
108 | public function isValueInHtml(): bool
109 | {
110 | $value = $this->getValue();
111 |
112 | return isset($value[0]) && ($value[0] === '<');
113 | }
114 |
115 | /**
116 | * Checks whether the value contains any any special characters needing escaping.
117 | */
118 | public function isValueContainingSpecials(): bool
119 | {
120 | return strstr($this->getValue(), '\\') !== false;
121 | }
122 |
123 | /**
124 | * Encode special characters so the escape sequences aren't removed
125 | *
126 | * @see http://www.graphviz.org/doc/info/attrs.html#k:escString
127 | */
128 | protected function encodeSpecials(): string
129 | {
130 | $value = $this->getValue();
131 | $regex = '(\'|"|\\x00|\\\\(?![\\\\NGETHLnlr]))';
132 |
133 | return (string) preg_replace($regex, '\\\\$0', $value);
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/phpDocumentor/GraphViz/AttributeNotFound.php:
--------------------------------------------------------------------------------
1 | attributes[$name] = new Attribute($name, $value);
26 |
27 | return $this;
28 | }
29 |
30 | /**
31 | * @throws AttributeNotFound
32 | */
33 | public function getAttribute(string $name): Attribute
34 | {
35 | if (!array_key_exists($name, $this->attributes)) {
36 | throw new AttributeNotFound($name);
37 | }
38 |
39 | return $this->attributes[$name];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/phpDocumentor/GraphViz/Edge.php:
--------------------------------------------------------------------------------
1 | from = $from;
46 | $this->to = $to;
47 | }
48 |
49 | /**
50 | * Factory method used to assist with fluent interface handling.
51 | *
52 | * See the examples for more details.
53 | *
54 | * @param Node $from Starting node to create an Edge from.
55 | * @param Node $to Destination node where to create and
56 | * edge to.
57 | */
58 | public static function create(Node $from, Node $to): self
59 | {
60 | return new self($from, $to);
61 | }
62 |
63 | /**
64 | * Returns the source Node for this Edge.
65 | */
66 | public function getFrom(): Node
67 | {
68 | return $this->from;
69 | }
70 |
71 | /**
72 | * Returns the destination Node for this Edge.
73 | */
74 | public function getTo(): Node
75 | {
76 | return $this->to;
77 | }
78 |
79 | /**
80 | * Magic method to provide a getter/setter to add attributes on the edge.
81 | *
82 | * Using this method we make sure that we support any attribute without too
83 | * much hassle. If the name for this method does not start with get or set
84 | * we return null.
85 | *
86 | * Set methods return this graph (fluent interface) whilst get methods
87 | * return the attribute value.
88 | *
89 | * @param string $name name of the invoked method, expect it to be
90 | * setX or getX.
91 | * @param mixed[] $arguments Arguments for the setter, only 1 is expected: value
92 | *
93 | * @return Attribute|Edge|null
94 | *
95 | * @throws AttributeNotFound
96 | */
97 | public function __call(string $name, array $arguments)
98 | {
99 | $key = strtolower(substr($name, 3));
100 | if (strtolower(substr($name, 0, 3)) === 'set') {
101 | return $this->setAttribute($key, (string) $arguments[0]);
102 | }
103 |
104 | if (strtolower(substr($name, 0, 3)) === 'get') {
105 | return $this->getAttribute($key);
106 | }
107 |
108 | return null;
109 | }
110 |
111 | /**
112 | * Returns the edge definition as is requested by GraphViz.
113 | */
114 | public function __toString(): string
115 | {
116 | $attributes = [];
117 | foreach ($this->attributes as $value) {
118 | $attributes[] = (string) $value;
119 | }
120 |
121 | $attributes = implode("\n", $attributes);
122 |
123 | $fromName = addslashes($this->getFrom()->getName());
124 | $toName = addslashes($this->getTo()->getName());
125 |
126 | return << "${toName}" [
128 | ${attributes}
129 | ]
130 | DOT;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/phpDocumentor/GraphViz/Exception.php:
--------------------------------------------------------------------------------
1 | setName($name)
88 | ->setType($directional ? 'digraph' : 'graph');
89 |
90 | return $graph;
91 | }
92 |
93 | /**
94 | * Sets the path for the execution. Only needed if it is not in the PATH env.
95 | *
96 | * @param string $path The path to execute dot from
97 | */
98 | public function setPath(string $path): self
99 | {
100 | $realpath = realpath($path);
101 | if ($path && $path === $realpath) {
102 | $this->path = $path . DIRECTORY_SEPARATOR;
103 | }
104 |
105 | return $this;
106 | }
107 |
108 | /**
109 | * Sets the name for this graph.
110 | *
111 | * If this is a subgraph you can prefix the name with _cluster_ to group all
112 | * contained nodes and add a border.
113 | *
114 | * @param string $name The new name for this graph.
115 | */
116 | public function setName(string $name): self
117 | {
118 | $this->name = $name;
119 |
120 | return $this;
121 | }
122 |
123 | /**
124 | * Returns the name for this Graph.
125 | */
126 | public function getName(): string
127 | {
128 | return $this->name;
129 | }
130 |
131 | /**
132 | * Sets the type for this graph.
133 | *
134 | * @param string $type Must be either "digraph", "graph" or "subgraph".
135 | *
136 | * @throws InvalidArgumentException If $type is not "digraph", "graph" or
137 | * "subgraph".
138 | */
139 | public function setType(string $type): self
140 | {
141 | if (!in_array($type, ['digraph', 'graph', 'subgraph'], true)) {
142 | throw new InvalidArgumentException(
143 | 'The type for a graph must be either "digraph", "graph" or '
144 | . '"subgraph"'
145 | );
146 | }
147 |
148 | $this->type = $type;
149 |
150 | return $this;
151 | }
152 |
153 | /**
154 | * Returns the type of this Graph.
155 | */
156 | public function getType(): string
157 | {
158 | return $this->type;
159 | }
160 |
161 | /**
162 | * Set if the Graph should be strict. If the graph is strict then
163 | * multiple edges are not allowed between the same pairs of nodes
164 | */
165 | public function setStrict(bool $isStrict): self
166 | {
167 | $this->strict = $isStrict;
168 |
169 | return $this;
170 | }
171 |
172 | public function isStrict(): bool
173 | {
174 | return $this->strict;
175 | }
176 |
177 | /**
178 | * Magic method to provide a getter/setter to add attributes on the Graph.
179 | *
180 | * Using this method we make sure that we support any attribute without
181 | * too much hassle. If the name for this method does not start with get
182 | * or set we return null.
183 | *
184 | * Set methods return this graph (fluent interface) whilst get methods
185 | * return the attribute value.
186 | *
187 | * @param string $name Name of the method including get/set
188 | * @param mixed[] $arguments The arguments, should be 1: the value
189 | *
190 | * @return Attribute|Graph|null
191 | *
192 | * @throws AttributeNotFound
193 | */
194 | public function __call(string $name, array $arguments)
195 | {
196 | $key = strtolower(substr($name, 3));
197 | if (strtolower(substr($name, 0, 3)) === 'set') {
198 | return $this->setAttribute($key, (string) $arguments[0]);
199 | }
200 |
201 | if (strtolower(substr($name, 0, 3)) === 'get') {
202 | return $this->getAttribute($key);
203 | }
204 |
205 | return null;
206 | }
207 |
208 | /**
209 | * Adds a subgraph to this graph; automatically changes the type to subgraph.
210 | *
211 | * Please note that an index is maintained using the name of the subgraph.
212 | * Thus if you have 2 subgraphs with the same name that the first will be
213 | * overwritten by the latter.
214 | *
215 | * @see Graph::create()
216 | *
217 | * @param Graph $graph The graph to add onto this graph as
218 | * subgraph.
219 | */
220 | public function addGraph(self $graph): self
221 | {
222 | $graph->setType('subgraph');
223 | $this->graphs[$graph->getName()] = $graph;
224 |
225 | return $this;
226 | }
227 |
228 | /**
229 | * Checks whether a graph with a certain name already exists.
230 | *
231 | * @param string $name Name of the graph to find.
232 | */
233 | public function hasGraph(string $name): bool
234 | {
235 | return isset($this->graphs[$name]);
236 | }
237 |
238 | /**
239 | * Returns the subgraph with a given name.
240 | *
241 | * @param string $name Name of the requested graph.
242 | */
243 | public function getGraph(string $name): self
244 | {
245 | return $this->graphs[$name];
246 | }
247 |
248 | /**
249 | * Sets a node in the $nodes array; uses the name of the node as index.
250 | *
251 | * Nodes can be retrieved by retrieving the property with the same name.
252 | * Thus 'node1' can be retrieved by invoking: $graph->node1
253 | *
254 | * @see Node::create()
255 | *
256 | * @param Node $node The node to set onto this Graph.
257 | */
258 | public function setNode(Node $node): self
259 | {
260 | $this->nodes[$node->getName()] = $node;
261 |
262 | return $this;
263 | }
264 |
265 | /**
266 | * Finds a node in this graph or any of its subgraphs.
267 | *
268 | * @param string $name Name of the node to find.
269 | */
270 | public function findNode(string $name): ?Node
271 | {
272 | if (isset($this->nodes[$name])) {
273 | return $this->nodes[$name];
274 | }
275 |
276 | foreach ($this->graphs as $graph) {
277 | $node = $graph->findNode($name);
278 | if ($node) {
279 | return $node;
280 | }
281 | }
282 |
283 | return null;
284 | }
285 |
286 | /**
287 | * Sets a node using a custom name.
288 | *
289 | * @see Graph::setNode()
290 | *
291 | * @param string $name Name of the node.
292 | * @param Node $value Node to set on the given name.
293 | */
294 | public function __set(string $name, Node $value): void
295 | {
296 | $this->nodes[$name] = $value;
297 | }
298 |
299 | /**
300 | * Returns the requested node by its name.
301 | *
302 | * @see Graph::setNode()
303 | *
304 | * @param string $name The name of the node to retrieve.
305 | */
306 | public function __get(string $name): ?Node
307 | {
308 | return $this->nodes[$name] ?? null;
309 | }
310 |
311 | /**
312 | * Links two nodes to eachother and registers the Edge onto this graph.
313 | *
314 | * @see Edge::create()
315 | *
316 | * @param Edge $edge The link between two classes.
317 | */
318 | public function link(Edge $edge): self
319 | {
320 | $this->edges[] = $edge;
321 |
322 | return $this;
323 | }
324 |
325 | /**
326 | * Exports this graph to a generated image.
327 | *
328 | * This is the only method that actually requires GraphViz.
329 | *
330 | * @link http://www.graphviz.org/content/output-formats
331 | * @uses GraphViz/dot
332 | *
333 | * @param string $type The type to export to; see the link above for a
334 | * list of supported types.
335 | * @param string $filename The path to write to.
336 | *
337 | * @throws Exception If an error occurred in GraphViz.
338 | */
339 | public function export(string $type, string $filename): self
340 | {
341 | $type = escapeshellarg($type);
342 | $filename = escapeshellarg($filename);
343 |
344 | // write the dot file to a temporary file
345 | $tmpfile = (string) tempnam(sys_get_temp_dir(), 'gvz');
346 | file_put_contents($tmpfile, (string) $this);
347 |
348 | // escape the temp file for use as argument
349 | $tmpfileArg = escapeshellarg($tmpfile);
350 |
351 | // create the dot output
352 | $output = [];
353 | $code = 0;
354 | exec($this->path . "dot -T${type} -o${filename} < ${tmpfileArg} 2>&1", $output, $code);
355 | unlink($tmpfile);
356 |
357 | if ($code !== 0) {
358 | throw new Exception(
359 | 'An error occurred while creating the graph; GraphViz returned: '
360 | . implode(PHP_EOL, $output)
361 | );
362 | }
363 |
364 | return $this;
365 | }
366 |
367 | /**
368 | * Generates a DOT file for use with GraphViz.
369 | *
370 | * GraphViz is not used in this method; it is safe to call it even without
371 | * GraphViz installed.
372 | */
373 | public function __toString(): string
374 | {
375 | $elements = array_merge(
376 | $this->graphs,
377 | $this->attributes,
378 | $this->edges,
379 | $this->nodes
380 | );
381 |
382 | $attributes = [];
383 | foreach ($elements as $value) {
384 | $attributes[] = (string) $value;
385 | }
386 |
387 | $attributes = implode(PHP_EOL, $attributes);
388 |
389 | $strict = ($this->isStrict() ? 'strict ' : '');
390 |
391 | return <<getType()} "{$this->getName()}" {
393 | ${attributes}
394 | }
395 | DOT;
396 | }
397 | }
398 |
--------------------------------------------------------------------------------
/src/phpDocumentor/GraphViz/Node.php:
--------------------------------------------------------------------------------
1 | setName($name);
44 | if ($label === null) {
45 | return;
46 | }
47 |
48 | $this->setLabel($label);
49 | }
50 |
51 | /**
52 | * Factory method used to assist with fluent interface handling.
53 | *
54 | * See the examples for more details.
55 | *
56 | * @param string $name Name of the new node.
57 | * @param string|null $label Optional label text.
58 | */
59 | public static function create(string $name, ?string $label = null): self
60 | {
61 | return new self($name, $label);
62 | }
63 |
64 | /**
65 | * Sets the name for this node.
66 | *
67 | * Not to confuse with the label.
68 | *
69 | * @param string $name Name for this node.
70 | */
71 | public function setName(string $name): self
72 | {
73 | $this->name = $name;
74 |
75 | return $this;
76 | }
77 |
78 | /**
79 | * Returns the name for this node.
80 | */
81 | public function getName(): string
82 | {
83 | return $this->name;
84 | }
85 |
86 | /**
87 | * Magic method to provide a getter/setter to add attributes on the Node.
88 | *
89 | * Using this method we make sure that we support any attribute without
90 | * too much hassle. If the name for this method does not start with get or
91 | * set we return null.
92 | *
93 | * Set methods return this graph (fluent interface) whilst get methods
94 | * return the attribute value.
95 | *
96 | * @param string $name Method name; either getX or setX is expected.
97 | * @param mixed[] $arguments List of arguments; only 1 is expected for setX.
98 | *
99 | * @return Attribute|Node|null
100 | *
101 | * @throws AttributeNotFound
102 | */
103 | public function __call(string $name, array $arguments)
104 | {
105 | $key = strtolower(substr($name, 3));
106 | if (strtolower(substr($name, 0, 3)) === 'set') {
107 | return $this->setAttribute($key, (string) $arguments[0]);
108 | }
109 |
110 | if (strtolower(substr($name, 0, 3)) === 'get') {
111 | return $this->getAttribute($key);
112 | }
113 |
114 | return null;
115 | }
116 |
117 | /**
118 | * Returns the node definition as is requested by GraphViz.
119 | */
120 | public function __toString(): string
121 | {
122 | $attributes = [];
123 | foreach ($this->attributes as $value) {
124 | $attributes[] = (string) $value;
125 | }
126 |
127 | $attributes = implode("\n", $attributes);
128 |
129 | $name = addslashes($this->getName());
130 |
131 | return <<classReflection = $classReflection;
39 | $this->name = $name;
40 | }
41 |
42 | public function getDeclaringClass(): ClassReflection
43 | {
44 | return $this->classReflection;
45 | }
46 |
47 | public function isStatic(): bool
48 | {
49 | return false;
50 | }
51 |
52 | public function isPrivate(): bool
53 | {
54 | return false;
55 | }
56 |
57 | public function isPublic(): bool
58 | {
59 | return true;
60 | }
61 |
62 | public function getName(): string
63 | {
64 | return $this->name;
65 | }
66 |
67 | public function getPrototype(): ClassMemberReflection
68 | {
69 | return $this;
70 | }
71 |
72 | /**
73 | * @return ParametersAcceptor[]
74 | */
75 | public function getVariants(): array
76 | {
77 | return [
78 | new FunctionVariant(
79 | TemplateTypeMap::createEmpty(),
80 | null,
81 | [],
82 | false,
83 | new ObjectType(Attribute::class)
84 | ),
85 | ];
86 | }
87 |
88 | public function getDocComment(): ?string
89 | {
90 | return null;
91 | }
92 |
93 | public function isDeprecated(): TrinaryLogic
94 | {
95 | return TrinaryLogic::createNo();
96 | }
97 |
98 | public function getDeprecatedDescription(): ?string
99 | {
100 | return null;
101 | }
102 |
103 | public function isFinal(): TrinaryLogic
104 | {
105 | return TrinaryLogic::createNo();
106 | }
107 |
108 | public function isInternal(): TrinaryLogic
109 | {
110 | return TrinaryLogic::createNo();
111 | }
112 |
113 | public function getThrowType(): ?Type
114 | {
115 | return new ObjectType(AttributeNotFound::class);
116 | }
117 |
118 | public function hasSideEffects(): TrinaryLogic
119 | {
120 | return TrinaryLogic::createMaybe();
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/phpDocumentor/PHPStan/AttributeSetterMethodReflection.php:
--------------------------------------------------------------------------------
1 | classReflection = $classReflection;
41 | $this->name = $name;
42 | $this->attributeType = $attributeType;
43 | }
44 |
45 | public function getDeclaringClass(): ClassReflection
46 | {
47 | return $this->classReflection;
48 | }
49 |
50 | public function isStatic(): bool
51 | {
52 | return false;
53 | }
54 |
55 | public function isPrivate(): bool
56 | {
57 | return false;
58 | }
59 |
60 | public function isPublic(): bool
61 | {
62 | return true;
63 | }
64 |
65 | public function getName(): string
66 | {
67 | return $this->name;
68 | }
69 |
70 | public function getPrototype(): ClassMemberReflection
71 | {
72 | return $this;
73 | }
74 |
75 | /**
76 | * @return ParametersAcceptor[]
77 | */
78 | public function getVariants(): array
79 | {
80 | return [
81 | new FunctionVariant(
82 | TemplateTypeMap::createEmpty(),
83 | TemplateTypeMap::createEmpty(),
84 | [
85 | new DummyParameter('value', $this->attributeType, false, null, false, null),
86 | ],
87 | false,
88 | new ObjectType($this->classReflection->getName())
89 | ),
90 | ];
91 | }
92 |
93 | public function getDocComment(): ?string
94 | {
95 | return null;
96 | }
97 |
98 | public function isDeprecated(): TrinaryLogic
99 | {
100 | return TrinaryLogic::createNo();
101 | }
102 |
103 | public function getDeprecatedDescription(): ?string
104 | {
105 | return null;
106 | }
107 |
108 | public function isFinal(): TrinaryLogic
109 | {
110 | return TrinaryLogic::createNo();
111 | }
112 |
113 | public function isInternal(): TrinaryLogic
114 | {
115 | return TrinaryLogic::createNo();
116 | }
117 |
118 | public function getThrowType(): ?Type
119 | {
120 | return new ObjectType(AttributeNotFound::class);
121 | }
122 |
123 | public function hasSideEffects(): TrinaryLogic
124 | {
125 | return TrinaryLogic::createYes();
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/phpDocumentor/PHPStan/GraphNodeReflectionExtension.php:
--------------------------------------------------------------------------------
1 | getName() === Graph::class;
29 | }
30 |
31 | public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
32 | {
33 | return new AnnotationPropertyReflection(
34 | $classReflection,
35 | new ObjectType(Node::class),
36 | true,
37 | true
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/phpDocumentor/PHPStan/MethodReflectionExtension.php:
--------------------------------------------------------------------------------
1 | 'node',
45 | Graph::class => 'graph',
46 | Edge::class => 'edge',
47 | ];
48 |
49 | public function hasMethod(ClassReflection $classReflection, string $methodName): bool
50 | {
51 | if (!array_key_exists($classReflection->getName(), self::SUPPORTED_CLASSES)) {
52 | return false;
53 | }
54 |
55 | $methods = $this->getMethodsFromSpec(self::SUPPORTED_CLASSES[$classReflection->getName()]);
56 | $expectedAttribute = $this->getAttributeFromMethodName($methodName);
57 |
58 | return in_array($expectedAttribute, $methods, true);
59 | }
60 |
61 | public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
62 | {
63 | if (stripos($methodName, 'get') === 0) {
64 | return new AttributeGetterMethodReflection($classReflection, $methodName);
65 | }
66 |
67 | $attributeName = $this->getAttributeFromMethodName($methodName);
68 |
69 | return new AttributeSetterMethodReflection(
70 | $classReflection,
71 | $methodName,
72 | $this->getAttributeInputType($attributeName)
73 | );
74 | }
75 |
76 | /**
77 | * @return string[]
78 | */
79 | private function getMethodsFromSpec(string $className): array
80 | {
81 | $simpleXml = $this->getAttributesXmlDoc();
82 |
83 | $elements = $simpleXml->xpath(sprintf("xsd:complexType[@name='%s']/xsd:attribute", $className));
84 |
85 | if ($elements === false) {
86 | throw new InvalidArgumentException(
87 | sprintf('Class "%s" does not exist in Graphviz spec', $className)
88 | );
89 | }
90 |
91 | return array_map(
92 | static function (SimpleXMLElement $attribute): string {
93 | return strtolower((string) $attribute['ref']);
94 | },
95 | $elements
96 | );
97 | }
98 |
99 | private function getAttributeInputType(string $ref): Type
100 | {
101 | $simpleXml = $this->getAttributesXmlDoc();
102 | $attributes = $simpleXml->xpath(sprintf("xsd:attribute[@name='%s']", $ref));
103 |
104 | if (empty($attributes)) {
105 | return new StringType();
106 | }
107 |
108 | $type = $attributes[0]['type'];
109 | $type = str_replace('xsd:', '', (string) $type);
110 | switch ($type) {
111 | case 'boolean':
112 | return new BooleanType();
113 |
114 | case 'decimal':
115 | return new FloatType();
116 |
117 | case 'string':
118 | default:
119 | return new StringType();
120 | }
121 | }
122 |
123 | private function getAttributesXmlDoc(): SimpleXMLElement
124 | {
125 | $fileContent = file_get_contents(__DIR__ . '/assets/attributes.xml');
126 |
127 | if ($fileContent === false) {
128 | throw new RuntimeException('Cannot read attributes spec');
129 | }
130 |
131 | $xml = simplexml_load_string($fileContent);
132 | if ($xml === false) {
133 | throw new RuntimeException('Cannot read attributes spec');
134 | }
135 |
136 | return $xml;
137 | }
138 |
139 | private function getAttributeFromMethodName(string $methodName): string
140 | {
141 | return strtolower(substr($methodName, 3));
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/phpDocumentor/PHPStan/assets/attributes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
20 |
21 |
22 |
23 |
24 |
25 | All Graphviz attributes are specified by name-value pairs. Thus, to
26 | set the fillcolor of a node abc, one would use
27 |
28 |
29 | abc [fillcolor = red]
30 |
31 |
32 | Similarly, to set the arrowhead style of an edge abc -> def,
33 | one would use
34 |
35 |
36 | abc -> def [arrowhead = diamond]
37 |
38 |
39 | Further details concerning the setting of attributes can be found
40 | in the description of the
41 | DOT language.
42 |
43 |
44 |
45 |
46 |
47 |
48 | At present, most device-independent units are either inches or
49 | points,
50 | which we take as 72 points per inch.
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Some attributes, such as
60 | dir or arrowtail, are
61 | ambiguous when used in
62 | DOT
63 | with an undirected graph since the head and tail of an edge are meaningless.
64 | As a convention, the first time an undirected edge appears, the
65 | DOT
66 | parser will assign the left node as the tail node and the right node as
67 | the head. For example, the edge A -- B will have tail A
68 | and head B. It is the user's responsibility to handle such
69 | edges consistently. If the edge appears later, in the format
70 |
71 |
72 | B -- A [taillabel = "tail"]
73 |
74 |
75 | the drawing will attach the tail label to node A.
76 | To avoid possible confusion when such attributes are required, the user
77 | is encouraged to use a directed graph.
78 | If it is important to make the graph appear undirected, this can be
79 | done using the dir, arrowtail
80 | or arrowhead attributes.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | For undirected edges T -- H;, one of the nodes, usually
114 | the righthand one, is treated as the head for the purpose of
115 | interpreting forward and back.
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | String allowing escape sequences which are replaced according
133 | to the context.
134 | For node attributes, the substring \N is replaced by the name of the node,
135 | and the substring \G by the name of the graph.
136 | For graph or cluster attributes, the substring \G is replaced by the
137 | name of the graph or cluster.
138 | For edge attributes, the substring \E is replaced by the name of the edge,
139 | the substring \G is replaced by the name of the graph or cluster,
140 | and the substrings \T and \H by the names of
141 | the tail and head nodes, respectively.
142 | The name of an edge is the string formed from the name of the
143 | tail node, the appropriate edge operator (-- or ->) and the name of the
144 | head node.
145 |
146 |
147 | In addition, if the associated attribute is
148 | label,
149 | headlabel or taillabel,
150 | the escape sequences \n, \l and \r
151 | divide the label into lines, centered, left-justified, and right-justified,
152 | respectively.
153 |
154 |
155 |
156 |
157 |
158 |
163 |
164 |
165 |
166 |
167 |
168 | These specify the order in which nodes and edges are drawn in concrete
169 | output. The default breadthfirst is the simplest, but when the graph
170 | layout does not avoid edge-node overlap, this mode will sometimes have
171 | edges drawn over nodes and sometimes on top of nodes. If the mode
172 | nodesfirst is chosen, all nodes are drawn first, followed by the
173 | edges. This guarantees an edge-node overlap will not be mistaken for
174 | an edge ending at a node. On the other hand, usually for aesthetic
175 | reasons, it may be desirable that all edges appear beneath nodes, even
176 | if the resulting drawing is ambiguous. This can be achieved by choosing
177 | edgesfirst.
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | These specify the granularity of packing connected components when
193 | the pack attribute is true. A value of node causes
194 | packing at the node and edge label, with no overlapping of these objects.
195 | This produces a layout with the least area, but it also allows interleaving,
196 | where a node of one component may lie between two nodes in another
197 | component. A value of graph does a packing using the bounding box of the
198 | component. Thus, there will be a rectangular region around a component
199 | free of elements of any other component.
200 | A value of clust guarantees that top-level clusters are kept intact.
201 | What effect a value has also depends on the layout algorithm. For
202 | example, neato does not support clusters, so a value of clust will
203 | have the same effect as the default node value.
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 | These specify the 8 row or column major orders for traversing a
219 | rectangular array, the first character corresponding to the major
220 | order and the second to the minor order. Thus, for "BL", the
221 | major order is from bottom to top, and the minor order is from left
222 | to right. This means the bottom row is traversed first, from left
223 | to right, then the next row up, from left to right, and so on,
224 | until the topmost row is traversed.
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
244 |
245 |
246 |
247 |
248 |
249 | List of pointf, separated by spaces.
250 |
251 |
252 |
253 |
254 |
255 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 | Corresponding to directed graphs drawn
274 | from top to bottom, from left to right, from bottom to top, and from
275 | right to left, respectively.
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 | Specifies the path to images referenced within the graph.
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 | Factor damping force motions. On each iteration, a nodes movement
352 | is limited to this factor of its potential motion. By being less than
353 | 1.0, the system tends to "cool", thereby preventing cycling.
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 | Spring constant used in virtual physical model. It roughly corresponds
364 | to an ideal edge length (in inches), in that increasing K tends to
365 | increase the distance between nodes.
366 | Note that the edge attribute len can be used to
367 | override this value for adjacent nodes.
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 | Hyperlinks incorporated into device-dependent output.
378 | At present, used in ps2, cmap, i*map and svg formats.
379 | For all these formats, URLs can be attached to nodes, edges and
380 | clusters. URL attributes can also be attached to the root graph in ps2,
381 | cmap and i*map formats. This serves as the base URL for relative URLs in the
382 | former, and as the default image map file in the latter.
383 |
384 |
385 | For svg, cmapx and imap output, the active area for a node is its
386 | visible image.
387 | For example, an unfilled node with no drawn boundary will only be active on its label.
388 | For other output, the active area is its bounding box.
389 | The active area for a cluster is its bounding box.
390 | For edges, the active areas are small circles where the edge contacts its head
391 | and tail nodes. In addition, for svg, cmapx and imap, the active area
392 | includes a thin polygon approximating the edge. The circles may
393 | overlap the related node, and the edge URL dominates.
394 | If the edge has a label, this will also be active.
395 | Finally, if the edge has a head or tail label, this will also be active.
396 |
397 |
398 | Note that, for edges, the attributes headURL,
399 | tailURL, labelURL and
400 | edgeURL allow control of various parts of an
401 | edge. Also note that, if active areas of two edges overlap, it is unspecified
402 | which area dominates.
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 | Style of arrowhead on the head node of an edge.
413 | See also the dir attribute,
414 | and the undirected note.
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 | Multiplicative scale factor for arrowheads.
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 | Style of arrowhead on the tail node of an edge.
435 | See also the dir attribute,
436 | and the undirected note.
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 | Bounding box of drawing in integer points.
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 | When attached to the root graph, this color is used as the background for
457 | entire canvas. When a cluster attribute, it is used as the initial
458 | background for the cluster. If a cluster has a filled
459 | style, the
460 | cluster's fillcolor will overlay the
461 | background color.
462 |
463 |
464 | If no background color is specified for the root graph, no graphics
465 | operation are performed on the background. This works fine for
466 | PostScript but for bitmap output, all bits are initialized to something.
467 | This means that when the bitmap output is included in some other
468 | document, all of the bits within the bitmap's bounding box will be
469 | set, overwriting whatever color or graphics where already on the page.
470 | If this effect is not desired, and you only want to set bits explicitly
471 | assigned in drawing the graph, set bgcolor="transparent".
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 | If true, the drawing is centered in the output canvas.
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 | Specifies the character encoding used when interpreting string input
492 | as a text label. The default value is UTF-8.
493 | The other legal value is iso-8859-1 or,
494 | equivalently,
495 | Latin1. The charset attribute is case-insensitive.
496 | Note that if the character encoding used in the input does not
497 | match the charset value, the resulting output may be very strange.
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 | Mode used for handling clusters. If clusterrank is local, a
508 | subgraph whose name begins with "cluster" is given special treatment.
509 | The subgraph is laid out separately, and then integrated as a unit into
510 | its parent graph, with a bounding rectangle drawn about it.
511 | If the cluster has a label parameter, this label
512 | is displayed within the rectangle.
513 | Note also that there can be clusters within clusters.
514 | At present, the modes global and none
515 | appear to be identical, both turning off the special cluster processing.
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 | Basic drawing color for graphics, not text. For the latter, use the
526 | fontcolor attribute.
527 |
528 |
529 | For edges, the value
530 | can either be a single color or a colorList.
531 | In the latter case, the edge is drawn using parallel splines or lines,
532 | one for each color in the list, in the order given.
533 | The head arrow, if any, is drawn using the first color in the list,
534 | and the tail arrow, if any, the second color. This supports the common
535 | case of drawing opposing edges, but using parallel splines instead of
536 | separately routed multiedges.
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 | This attribute specifies a color scheme namespace. If defined, it specifies
547 | the context for interpreting color names. In particular, if a
548 | color value has form xxx or //xxx,
549 | then the color xxx will be evaluated according to the current color scheme.
550 | If no color scheme is set, the standard X11 naming is used.
551 | For example, if colorscheme=bugn9, then color=7
552 | is interpreted as /bugn9/7.
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 | Comments are inserted into output. Device-dependent.
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 | If true, allow edges between clusters. (See lhead and ltail below.)
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 | If true, use edge concentrators.
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 | If false, the edge is not used in ranking the nodes.
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 | If true, attach edge label to edge by a 2-segment
603 | polyline, underlining the label, then going to the closest point of spline.
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 | This specifies the distance between nodes in separate connected
614 | components. If set too small, connected components may overlap.
615 | Only applicable if pack=false.
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 | Set the number of dimensions used for the layout. The maximum value
626 | allowed is 10.
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 | Set edge type for drawing arrowheads. This indicates which ends of the
637 | edge should be decorated with an arrowhead. The actual style of the
638 | arrowhead can be specified using the arrowhead
639 | and arrowtail attributes.
640 | See undirected.
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 | Only valid when mode="ipsep".
651 | If true, constraints are generated for each edge in the largest (heuristic)
652 | directed acyclic subgraph such that the edge must point downwards.
653 | If hier, generates level constraints similar to those used with
654 | mode="hier". The main difference is that, in the latter
655 | case, only these constraints are involved, so a faster solver can be used.
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 | Distortion factor for shape=polygon.
666 | Positive values cause top part to
667 | be larger than bottom; negative values do the opposite.
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 | This specifies the expected number of pixels per inch on a display device.
678 | For bitmap output, this guarantees that text rendering will be
679 | done more accurately, both in size and in placement. For SVG output,
680 | it is used to guarantee that the dimensions in the output correspond to
681 | the correct number of points or inches.
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 | If edgeURL is defined, this is the link used for the non-label
692 | parts of an edge. This value overrides any URL
693 | defined for the edge.
694 | Also, this value is used near the head or tail node unless overridden
695 | by a headURL or tailURL value,
696 | respectively.
697 | See undirected.
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 | Synonym for edgeURL.
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 | If the edge has a URL or edgeURL
718 | attribute, this attribute determines which window of the
719 | browser is used
720 | for the URL attached to the non-label part of the edge.
721 | Setting it to "_graphviz" will open a new window if it
722 | doesn't already exist, or reuse it if it does.
723 | If undefined, the value of the target is used.
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 | Tooltip annotation attached to the non-label part of an edge.
734 | This is used only if the edge has a URL
735 | or edgeURL attribute.
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 | Terminating condition. If the length squared of all energy gradients are
746 | < epsilon, the algorithm stops.
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 | Fraction to increase polygons (multiply
757 | coordinates by 1 + esep) for purposes of spline edge routing.
758 | This should normally be strictly less than
759 | sep.
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 | Color used to fill the background of a node or cluster
770 | assuming style=filled.
771 | If fillcolor is not defined, color is
772 | used. (For clusters, if color is not defined,
773 | bgcolor is used.) If this is not defined,
774 | the default is used, except for
775 | shape=point or when the output
776 | format is MIF,
777 | which use black by default.
778 |
779 |
780 | Note that a cluster inherits the root graph's attributes if defined.
781 | Thus, if the root graph has defined a fillcolor, this will override a
782 | color or bgcolor attribute set for the cluster.
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 | If true, the node size is specified by the values of the
793 | width
794 | and height attributes only
795 | and is not expanded to contain the text label.
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 | Color used for text.
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 | Font used for text. This very much depends on the output format and, for
816 | non-bitmap output such as PostScript or SVG, the availability of the font
817 | when the graph is displayed or printed. As such, it is best to rely on
818 | font faces that are generally available, such as Times-Roman, Helvetica or
819 | Courier.
820 |
821 |
822 | If Graphviz was built using the
823 | fontconfig library, the latter library
824 | will be used to search for the font. However, if the fontname string
825 | contains a slash character "/", it is treated as a pathname for the font
826 | file, though font lookup will append the usual font suffixes.
827 |
828 |
829 | If Graphviz does not use fontconfig, fontname will be
830 | considered the name of a Type 1 or True Type font file.
831 | If you specify fontname=schlbk, the tool will look for a
832 | file named schlbk.ttf or schlbk.pfa or schlbk.pfb
833 | in one of the directories specified by
834 | the fontpath attribute.
835 | The lookup does support various aliases for the common fonts.
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 | Allows user control of how basic fontnames are represented in SVG output.
846 | If fontnames is undefined or svg,
847 | the output will try to use known SVG fontnames. For example, the
848 | default font Times-Roman will be mapped to the
849 | basic SVG font serif. This can be overridden by setting
850 | fontnames to ps or gd.
851 | In the former case, known PostScript font names such as
852 | Times-Roman will be used in the output.
853 | In the latter case, the fontconfig font conventions
854 | are used. Thus, Times-Roman would be treated as
855 | Nimbus Roman No9 L. These last two options are useful
856 | with SVG viewers that support these richer fontname spaces.
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 | Directory list used by libgd to search for bitmap fonts if Graphviz
867 | was not built with the fontconfig library.
868 | If fontpath is not set, the environment
869 | variable DOTFONTPATH is checked.
870 | If that is not set, GDFONTPATH is checked.
871 | If not set, libgd uses its compiled-in font path.
872 | Note that fontpath is an attribute of the root graph.
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 | Font size, in points, used for text.
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 | If the end points of an edge belong to the same group, i.e., have the
893 | same group attribute, parameters are set to avoid crossings and keep
894 | the edges straight.
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 | If headURL is defined, it is
905 | output as part of the head label of the edge.
906 | Also, this value is used near the head node, overriding any
907 | URL value.
908 | See undirected.
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 | If true, the head of an edge is clipped to the boundary of the head node;
919 | otherwise, the end of the edge goes to the center of the node, or the
920 | center of a port, if applicable.
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 | Synonym for headURL.
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 | Text label to be placed near head of edge.
941 | See undirected.
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 | Indicates where on the head node to attach the head of the edge.
952 | In the default case, the edge is aimed towards the center of the node,
953 | and then clipped at the node boundary.
954 | See undirected.
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 | If the edge has a headURL,
965 | this attribute determines which window of the
966 | browser is used
967 | for the URL. Setting it to "_graphviz" will open a new window if it
968 | doesn't already exist, or reuse it if it does.
969 | If undefined, the value of the target is used.
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 | Tooltip annotation attached to the head of an edge. This is used only
980 | if the edge has a headURL attribute.
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 | Height of node, in inches. This is taken as the initial, minimum height
991 | of the node. If fixedsize is true, this
992 | will be the final height of the node. Otherwise, if the node label
993 | requires more height to fit, the node's height will be increased to
994 | contain the label. Note also that, if the output format is dot, the
995 | value given to height will be the final value.
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 | Synonym for URL.
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 | Gives the name of a file containing an image to be displayed inside
1016 | a node. The image file must be in one of the recognized formats,
1017 | typically JPEG, PNG, GIF or Postscript, and be able to be converted
1018 | into the desired output format.
1019 |
1020 |
1021 | Unlike with the shapefile attribute,
1022 | the image is treated as node
1023 | content rather than the entire node. In particular, an image can
1024 | be contained in a node of any shape, not just a rectangle.
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
1033 |
1034 | Attribute controlling how an image fills its
1035 | containing node. In general, the image is given its natural size,
1036 | (cf. dpi),
1037 | and the node size is made large enough to contain its image, its
1038 | label, its margin, and its peripheries.
1039 | Its width and height will also be at least as large as its
1040 | minimum width and height.
1041 | If, however, fixedsize=true,
1042 | the width and height attributes specify the exact size of the node.
1043 |
1044 |
1045 | During rendering, in the default case (imagescale=false),
1046 | the image retains its natural size.
1047 | If true,
1048 | the image is uniformly scaled (i.e., its aspect ratio is
1049 | preserved) to fit inside the node.
1050 | At least one dimension of the image will be as large as possible
1051 | given the size of the node.
1052 | When width,
1053 | the width of the image is scaled to fill the node width.
1054 | The corresponding property holds when imagescale=height.
1055 | When both,
1056 | both the height and the width are scaled separately to fill the node.
1057 |
1058 |
1059 | In all cases, if a dimension of the image is larger than the
1060 | corresponding dimension of the node, that dimension of the
1061 | image is scaled down to fit the node. As with the case of
1062 | expansion, if imagescale=true, width and height are
1063 | scaled uniformly.
1064 |
1065 |
1066 |
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 | Text label attached to objects.
1074 | If a node's shape is record, then the label can
1075 | have a special format
1076 | which describes the record layout.
1077 |
1078 |
1079 |
1080 |
1081 |
1082 |
1083 |
1084 |
1085 |
1086 | If labelURL is defined, this is the link used for the label
1087 | of an edge. This value overrides any URL
1088 | defined for the edge.
1089 |
1090 |
1091 |
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
1098 | This, along with labeldistance, determine
1099 | where the
1100 | headlabel (taillabel) are placed with respect to the head (tail)
1101 | in polar coordinates. The origin in the coordinate system is
1102 | the point where the edge touches the node. The ray of 0 degrees
1103 | goes from the origin back along the edge, parallel to the edge
1104 | at the origin.
1105 |
1106 |
1107 | The angle, in degrees, specifies the rotation from the 0 degree ray,
1108 | with positive angles moving counterclockwise and negative angles
1109 | moving clockwise.
1110 |
1111 |
1112 |
1113 |
1114 |
1115 |
1116 |
1117 |
1118 |
1119 | Multiplicative scaling factor adjusting the distance that
1120 | the headlabel (taillabel) is from the head (tail) node.
1121 | The default distance is 10 points. See labelangle
1122 | for more details.
1123 |
1124 |
1125 |
1126 |
1127 |
1128 |
1129 |
1130 |
1131 |
1132 | If true, allows edge labels to be less constrained in position.
1133 | In particular, it may appear on top of other edges.
1134 |
1135 |
1136 |
1137 |
1138 |
1139 |
1140 |
1141 |
1142 |
1143 | Color used for headlabel and taillabel.
1144 | If not set, defaults to edge's fontcolor.
1145 |
1146 |
1147 |
1148 |
1149 |
1150 |
1151 |
1152 |
1153 |
1154 | Font used for headlabel and taillabel.
1155 | If not set, defaults to edge's fontname.
1156 |
1157 |
1158 |
1159 |
1160 |
1161 |
1162 |
1163 |
1164 |
1165 | Font size, in points, used for headlabel and taillabel.
1166 | If not set, defaults to edge's fontsize.
1167 |
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 |
1176 | Synonym for labelURL.
1177 |
1178 |
1179 |
1180 |
1181 |
1182 |
1183 |
1184 |
1185 |
1186 | Justification for cluster labels. If r, the label
1187 | is right-justified within bounding rectangle; if l, left-justified;
1188 | else the label is centered.
1189 | Note that a subgraph inherits attributes from its parent. Thus, if
1190 | the root graph sets labeljust to l, the subgraph inherits
1191 | this value.
1192 |
1193 |
1194 |
1195 |
1196 |
1197 |
1198 |
1199 |
1200 |
1201 | Top/bottom placement of graph and cluster labels.
1202 | If the attribute is t, place label at the top;
1203 | if the attribute is b, place label at the bottom.
1204 | By default, root
1205 | graph labels go on the bottom and cluster labels go on the top.
1206 | Note that a subgraph inherits attributes from its parent. Thus, if
1207 | the root graph sets labelloc to b, the subgraph inherits
1208 | this value.
1209 |
1210 |
1211 |
1212 |
1213 |
1214 |
1215 |
1216 |
1217 |
1218 | If the edge has a URL or labelURL
1219 | attribute, this attribute determines which window of the
1220 | browser is used
1221 | for the URL attached to the label.
1222 | Setting it to "_graphviz" will open a new window if it
1223 | doesn't already exist, or reuse it if it does.
1224 | If undefined, the value of the target is used.
1225 |
1226 |
1227 |
1228 |
1229 |
1230 |
1231 |
1232 |
1233 |
1234 | Tooltip annotation attached to label of an edge.
1235 | This is used only if the edge has a URL
1236 | or labelURL attribute.
1237 |
1238 |
1239 |
1240 |
1241 |
1242 |
1243 |
1244 |
1245 |
1246 | If true, the graph is rendered in landscape mode. Synonymous with
1247 | rotate=90 or
1248 | orientation=landscape.
1249 |
1250 |
1251 |
1252 |
1253 |
1254 |
1255 |
1256 |
1257 |
1258 | Specifies layers in which the node or edge is present.
1259 |
1260 |
1261 |
1262 |
1263 |
1264 |
1265 |
1266 |
1267 |
1268 | Specifies a linearly ordered list of layer names attached to the graph
1269 | The graph is then output in separate layers. Only those components
1270 | belonging to the current output layer appear. For more information,
1271 | see the page How to use drawing layers (overlays).
1272 |
1273 |
1274 |
1275 |
1276 |
1277 |
1278 |
1279 |
1280 |
1281 | Specifies the separator characters used to split the
1282 | layers attribute into a list of layer names.
1283 |
1284 |
1285 |
1286 |
1287 |
1288 |
1289 |
1290 |
1291 |
1292 | Specifies the name of the layout algorithm to use, such as dot
1293 | or neato. Normally, graphs should be kept independent of a type of
1294 | layout. In some cases, however, it can be convenient to embed the type
1295 | of layout desired within the graph. For example, a graph containing
1296 | position information from a layout might want to record what the
1297 | associated layout algorithm was.
1298 |
1299 |
1300 | This attribute takes precedence over
1301 | the -K flag
1302 | or the actual command name used.
1303 |
1304 |
1305 |
1306 |
1307 |
1308 |
1309 |
1310 |
1311 |
1312 | Preferred edge length, in inches.
1313 |
1314 |
1315 |
1316 |
1317 |
1318 |
1319 |
1320 |
1321 |
1322 | Specifies strictness of level constraints in neato
1323 | when mode="ipsep" or "hier".
1324 | Larger positive values mean stricter constraints, which demand more
1325 | separation between levels. On the other hand, negative values will relax
1326 | the constraints by allowing some overlap between the levels.
1327 |
1328 |
1329 |
1330 |
1331 |
1332 |
1333 |
1334 |
1335 |
1336 | Logical head of an edge. When compound is true,
1337 | if lhead is defined and is the name of a cluster containing
1338 | the real head,
1339 | the edge is clipped to the boundary of the cluster.
1340 | See undirected.
1341 |
1342 |
1343 |
1344 |
1345 |
1346 |
1347 |
1348 |
1349 |
1350 | Label position, in points.
1351 | The position indicates the center of the label.
1352 |
1353 |
1354 |
1355 |
1356 |
1357 |
1358 |
1359 |
1360 |
1361 | Logical tail of an edge. When compound is true,
1362 | if ltail is defined and is the name of a cluster
1363 | containing the real tail,
1364 | the edge is clipped to the boundary of the cluster.
1365 | See undirected.
1366 |
1367 |
1368 |
1369 |
1370 |
1371 |
1372 |
1373 |
1374 |
1375 | For graphs, this sets x and y margins of canvas, in inches. If the margin
1376 | is a single double, both margins are set equal to the given value.
1377 |
1378 |
1379 | Note that the margin is not part of the drawing but just empty space
1380 | left around the drawing. It basically corresponds to a translation of
1381 | drawing, as would be necessary to center a drawing on a page. Nothing
1382 | is actually drawn in the margin. To actually extend the background of
1383 | a drawing, see the pad attribute.
1384 |
1385 |
1386 | For nodes, this attribute specifies space left around the node's label.
1387 | By default, the value is 0.11,0.055.
1388 |
1389 |
1390 |
1391 |
1392 |
1393 |
1394 |
1395 |
1396 |
1397 | Sets the number of iterations used.
1398 |
1399 |
1400 |
1401 |
1402 |
1403 |
1404 |
1405 |
1406 |
1407 | Multiplicative scale factor used to alter the MinQuit (default = 8)
1408 | and MaxIter (default = 24) parameters used during crossing
1409 | minimization. These correspond to the
1410 | number of tries without improvement before quitting and the
1411 | maximum number of iterations in each pass.
1412 |
1413 |
1414 |
1415 |
1416 |
1417 |
1418 |
1419 |
1420 |
1421 | Specifies the minimum separation between all nodes.
1422 |
1423 |
1424 |
1425 |
1426 |
1427 |
1428 |
1429 |
1430 |
1431 | Minimum edge length (rank difference between head and tail).
1432 |
1433 |
1434 |
1435 |
1436 |
1437 |
1438 |
1439 |
1440 |
1441 | Technique for optimizing the layout. If mode is major,
1442 | neato uses stress majorization. If mode is KK,
1443 | neato uses a version of the gradient descent method. The only advantage
1444 | to the latter technique is that it is sometimes appreciably faster for
1445 | small (number of nodes < 100) graphs. A significant disadvantage is that
1446 | it may cycle.
1447 |
1448 |
1449 | There are two new, experimental modes in neato, hier, which adds a top-down
1450 | directionality similar to the layout used in dot, and ipsep, which
1451 | allows the graph to specify minimum vertical and horizontal distances
1452 | between nodes. (See the sep attribute.)
1453 |
1454 |
1455 |
1456 |
1457 |
1458 |
1459 |
1460 |
1461 |
1462 | This value specifies how the distance matrix is computed for the input
1463 | graph. The distance matrix specifies the ideal distance between every
1464 | pair of nodes. neato attemps to find a layout which best achieves
1465 | these distances. By default, it uses the length of the shortest path,
1466 | where the length of each edge is given by its len
1467 | attribute. If model is circuit, neato uses the
1468 | circuit resistance
1469 | model to compute the distances. This tends to emphasize clusters. If
1470 | model is subset, neato uses the subset model. This sets the
1471 | edge length to be the number of nodes that are neighbors of exactly one
1472 | of the end points, and then calculates the shortest paths. This helps
1473 | to separate nodes with high degree.
1474 |
1475 |
1476 |
1477 |
1478 |
1479 |
1480 |
1481 |
1482 |
1483 | If Graphviz is built with MOSEK defined, mode=ipsep and mosek=true,
1484 | the Mosek software (www.mosek.com) is use to solve the ipsep constraints.
1485 |
1486 |
1487 |
1488 |
1489 |
1490 |
1491 |
1492 |
1493 |
1494 | Minimum space between two adjacent nodes in the same rank, in inches.
1495 |
1496 |
1497 |
1498 |
1499 |
1500 |
1501 |
1502 |
1503 |
1504 | By default, the justification of multi-line labels is done within the
1505 | largest context that makes sense. Thus, in the label of a polygonal
1506 | node, a left-justified line will align with the left side of the node
1507 | (shifted by the prescribed margin).
1508 | In record nodes, left-justified
1509 | line will line up with the left side of the enclosing column of fields.
1510 | If nojustify is true, multi-line labels will be justified
1511 | in the context of itself. For example, if the attribute is set,
1512 | the first label line is long, and the second is shorter and left-justified,
1513 | the second will align with the left-most character in the first line,
1514 | regardless of how large the node might be.
1515 |
1516 |
1517 |
1518 |
1519 |
1520 |
1521 |
1522 |
1523 |
1524 | If set, normalize coordinates of final
1525 | layout so that the first point is at the origin, and then rotate the
1526 | layout so that the first edge is horizontal.
1527 |
1528 |
1529 |
1530 |
1531 |
1532 |
1533 |
1534 |
1535 |
1536 | Used to set number of iterations in
1537 | network simplex applications, used in
1538 | computing node x coordinates.
1539 | If defined, # iterations = nslimit * # nodes;
1540 | otherwise, # iterations = MAXINT.
1541 |
1542 |
1543 |
1544 |
1545 |
1546 |
1547 |
1548 |
1549 |
1550 | Used to set number of iterations in
1551 | network simplex applications, used for ranking nodes.
1552 | If defined, # iterations = nslimit1 * # nodes;
1553 | otherwise, # iterations = MAXINT.
1554 |
1555 |
1556 |
1557 |
1558 |
1559 |
1560 |
1561 |
1562 |
1563 | If "out" for a graph G, and n is a node in G, then edges n->* appear
1564 | left-to-right in the same order in which they are defined.
1565 | If "in", the edges *->n appear
1566 | left-to-right in the same order in which they are defined for all
1567 | nodes n.
1568 |
1569 |
1570 |
1571 |
1572 |
1573 |
1591 |
1592 |
1593 |
1594 |
1595 |
1596 | Specify order in which nodes and edges are drawn.
1597 |
1598 |
1599 |
1600 |
1601 |
1602 |
1603 |
1604 |
1605 |
1606 | Determines if and how node overlaps should be removed. Nodes are first
1607 | enlarged using the sep attribute.
1608 | If true, overlaps are retained.
1609 | If the value is scale, overlaps are removed by uniformly scaling in x and y.
1610 | If the value converts to false, node overlaps are removed by a
1611 | Voronoi-based technique.
1612 | If the value is scalexy, x and y are separately
1613 | scaled to remove overlaps.
1614 | If the value is orthoxy or orthoyx, overlaps
1615 | are moved by optimizing two constraint problems, one for the x axis and
1616 | one for the y. The suffix indicates which axis is processed first.
1617 | If the value is ortho, the technique is similar to orthoxy except a
1618 | heuristic is used to reduce the bias between the two passes.
1619 | If the value is ortho_yx, the technique is the same as ortho, except
1620 | the roles of x and y are reversed.
1621 | The values portho, porthoxy, porthoxy, and portho_yx are similar
1622 | to the previous four, except only pseudo-orthogonal ordering is
1623 | enforced.
1624 |
1625 |
1626 | If the value is compress, the layout will be scaled down as much as
1627 | possible without introducing any overlaps, obviously assuming there are
1628 | none to begin with.
1629 |
1630 |
1631 | If the value is ipsep, and the layout is done by neato with
1632 | mode="ipsep", the overlap removal constraints are
1633 | incorporated into the layout algorithm itself.
1634 | N.B. At present, this only supports one level of clustering.
1635 |
1636 |
1637 | If the value is vpsc, overlap removal is similarly to ortho, except
1638 | quadratic optimization is used to minimize node displacement.
1639 | N.B. At present, this mode only works when mode="ipsep".
1640 |
1641 |
1642 | Except for fdp, the layouts assume overlap="true" as the default.
1643 | Fdp first uses a number of passes using built-in, force-directed technique
1644 | to remove overlaps. Thus, fdp accepts overlap with an integer
1645 | prefix followed by a colon, specifying the number of tries. If there is
1646 | no prefix, no initial tries will be performed. If there is nothing following
1647 | a colon, none of the above methods will be attempted. By default, fdp
1648 | uses overlap="9:portho". Note that overlap="true",
1649 | overlap="0:true" and overlap="0:" all turn off all overlap
1650 | removal.
1651 |
1652 |
1653 | Except for the Voronoi method, all of these transforms preserve the
1654 | orthogonal ordering of the original layout. That is, if the x coordinates
1655 | of two nodes are originally the same, they will remain the same, and if
1656 | the x coordinate of one node is originally less than the x coordinate of
1657 | another, this relation will still hold in the transformed layout. The
1658 | similar properties hold for the y coordinates.
1659 | This is not quite true for the "porth*" cases. For these, orthogonal
1660 | ordering is only preserved among nodes related by an edge.
1661 |
1662 |
1663 | NOTEThe methods orthoxy and orthoyx are still evolving. The semantics of these may change, or these methods may disappear altogether.
1664 |
1665 |
1666 |
1667 |
1668 |
1669 |
1670 |
1671 |
1672 |
1673 | This is true if the value of pack is true (case-insensitive) or a
1674 | non-negative integer. If true, each connected component of the graph is
1675 | laid out separately, and then the graphs are packed tightly.
1676 | If pack has an integral value, this is used as the size,
1677 | in points, of
1678 | a margin around each part; otherwise, a default margin of 8 is used.
1679 | If pack is interpreted as false, the entire graph is laid out together.
1680 | The granularity and method of packing is influenced by the
1681 | packmode attribute.
1682 |
1683 |
1684 | For layouts which always do packing, such a twopi, the pack
1685 | attribute is just used to set the margin.
1686 |
1687 |
1688 |
1689 |
1690 |
1691 |
1692 |
1693 |
1694 |
1695 | This indicates the granularity and method used for packing
1696 | (cf. packMode). Note that defining
1697 | packmode will automatically turn on packing as though one had
1698 | set pack=true.
1699 |
1700 |
1701 |
1702 |
1703 |
1704 |
1705 |
1706 |
1707 |
1708 | The pad attribute specifies how much, in inches, to extend the
1709 | drawing area around the minimal area needed to draw the graph.
1710 | If the pad is a single double, both the x and y pad values are set
1711 | equal to the given value. This area is part of the
1712 | drawing and will be filled with the background color, if appropriate.
1713 |
1714 |
1715 | Normally, a small pad is used for aesthetic reasons, especially when
1716 | a background color is used, to avoid having nodes and edges abutting
1717 | the boundary of the drawn region.
1718 |
1719 |
1720 |
1721 |
1722 |
1723 |
1724 |
1725 |
1726 |
1727 | Width and height of output pages, in inches. If this is set and is
1728 | smaller than the size of the layout, a rectangular array of pages of
1729 | the specified page size is overlaid on the layout, with origins
1730 | aligned in the lower-left corner, thereby partitioning the layout
1731 | into pages. The pages are then produced one at a time, in
1732 | pagedir order.
1733 |
1734 |
1735 | At present, this only works for PostScript output. For other types of
1736 | output, one should use another tool to split the output into multiple
1737 | output files. Or use the viewport to generate
1738 | multiple files.
1739 |
1740 |
1741 |
1742 |
1743 |
1744 |
1745 |
1746 |
1747 |
1748 | If the page attribute is set and applicable,
1749 | this attribute specifies the order in which the pages are emitted.
1750 | This is limited to one of the 8 row or column major orders.
1751 |
1752 |
1753 |
1754 |
1755 |
1756 |
1757 |
1758 |
1759 |
1760 | Color used to draw the bounding box around a cluster.
1761 | If pencolor is not defined, color is
1762 | used. If this is not defined, bgcolor is used.
1763 | If this is not defined, the default is used.
1764 |
1765 |
1766 | Note that a cluster inherits the root graph's attributes if defined.
1767 | Thus, if the root graph has defined a pencolor, this will override a
1768 | color or bgcolor attribute set for the cluster.
1769 |
1770 |
1771 |
1772 |
1773 |
1774 |
1775 |
1776 |
1777 |
1778 | Set number of peripheries used in polygonal shapes and cluster
1779 | boundaries. Note that
1780 | user-defined shapes are treated as a
1781 | form of box shape, so the default
1782 | peripheries value is 1 and the user-defined shape will be drawn in
1783 | a bounding rectangle. Setting peripheries=0 will turn this off.
1784 | Also, 1 is the maximum peripheries value for clusters.
1785 |
1786 |
1787 |
1788 |
1789 |
1790 |
1791 |
1792 |
1793 |
1794 | If true and the node has a pos attribute on input, neato prevents the
1795 | node from moving from the input position. This property can also be specified
1796 | in the pos attribute itself (cf. the point type).
1797 |
1798 |
1799 |
1800 |
1801 |
1802 |
1803 |
1804 |
1805 |
1806 | Position of node, or spline control points.
1807 | For nodes, the position indicates the center of the node.
1808 | On output, the coordinates are in points.
1809 |
1810 |
1811 | In neato and fdp, pos can be used to set the initial position of a node.
1812 | By default, the coordinates are assumed to be in inches. However, the
1813 | -s command line flag can be used to specify
1814 | different units.
1815 |
1816 |
1817 | When the -n command line flag is used with
1818 | neato, it is assumed the positions have been set by one of the layout
1819 | programs, and are therefore in points. Thus, neato -n can accept
1820 | input correctly without requiring a -s flag and, in fact,
1821 | ignores any such flag.
1822 |
1823 |
1824 |
1825 |
1826 |
1827 |
1828 |
1829 |
1830 |
1831 | If quantum > 0.0, node label dimensions
1832 | will be rounded to integral multiples of the quantum.
1833 |
1834 |
1835 |
1836 |
1837 |
1838 |
1839 |
1840 |
1841 |
1842 | Rank constraints on the nodes in a subgraph.
1843 | If same, all nodes are placed on the same rank.
1844 | If min, all nodes are placed on the minimum rank.
1845 | If source, all nodes are placed on the minimum rank, and
1846 | the only nodes on the minimum rank belong to some subgraph whose
1847 | rank attribute is "source" or "min".
1848 | Analogous criteria hold for rank=max and rank=sink.
1849 | (Note: the
1850 | minimum rank is topmost or leftmost, and the maximum rank is bottommost
1851 | or rightmost.)
1852 |
1853 |
1854 |
1855 |
1856 |
1857 |
1858 |
1859 |
1860 |
1861 | Sets direction of graph layout. For example, if rankdir="LR",
1862 | and barring cycles, an edge T -> H; will go
1863 | from left to right. By default, graphs are laid out from top to bottom.
1864 |
1865 |
1866 |
1867 |
1868 |
1869 |
1870 |
1871 |
1872 |
1873 | In dot, this gives the desired rank separation, in inches. This is
1874 | the minimum vertical distance between the bottom of the nodes in one
1875 | rank and the tops of nodes in the next. If the value
1876 | contains "equally", the centers of all ranks are spaced equally apart.
1877 | Note that both
1878 | settings are possible, e.g., ranksep = "1.2 equally".
1879 | In twopi, specifies radial separation of concentric circles.
1880 |
1881 |
1882 |
1883 |
1884 |
1885 |
1886 |
1887 |
1888 |
1889 | Sets the aspect ratio (drawing height/drawing width) for the drawing.
1890 | Note that this is adjusted before
1891 | the size attribute constraints are enforced.
1892 |
1893 |
1894 | If ratio is numeric, it is taken as the desired aspect ratio.
1895 | Then, if the actual aspect ratio is less than the desired ratio,
1896 | the drawing height is scaled up to achieve the
1897 | desired ratio; if the actual ratio is greater than that desired ratio,
1898 | the drawing width is scaled up.
1899 |
1900 |
1901 | If ratio = fill and the size
1902 | attribute is set, node positions are scaled, separately in both x
1903 | and y, so that the final drawing exactly fills the specified size.
1904 |
1905 |
1906 | If ratio = compress and the size
1907 | attribute is set, dot attempts to compress the initial layout to fit
1908 | in the given size. This achieves a tighter packing of nodes but
1909 | reduces the balance and symmetry. This feature only works in dot.
1910 |
1911 |
1912 | If ratio = expand, the size
1913 | attribute is set, and both the width and the height of the graph are
1914 | less than the value in size, node positions are scaled
1915 | uniformly until at least
1916 | one dimension fits size exactly.
1917 | Note that this is distinct from using size as the
1918 | desired size, as here the drawing is expanded before edges are generated and
1919 | all node and text sizes remain unchanged.
1920 |
1921 |
1922 | If ratio = auto, the page
1923 | attribute is set and the graph cannot be drawn on a single page,
1924 | then size is set to an ``ideal'' value.
1925 | In particular, the size in a given dimension will be the smallest integral
1926 | multiple of the page size in that dimension which is at least half the
1927 | current size. The two dimensions are then scaled independently to the
1928 | new size. This feature only works in dot.
1929 |
1930 |
1931 |
1932 |
1933 |
1934 |
1935 |
1936 |
1937 |
1938 | Rectangles for fields of records, in points.
1939 |
1940 |
1941 |
1942 |
1943 |
1944 |
1945 |
1946 |
1947 |
1948 | If true, force polygon to be regular.
1949 |
1950 |
1951 |
1952 |
1953 |
1954 |
1955 |
1956 |
1957 |
1958 | If true and there are multiple clusters, run cross
1959 | minimization a second time.
1960 |
1961 |
1962 |
1963 |
1964 |
1965 |
1966 |
1967 |
1968 |
1969 | This is a synonym for the dpi attribute.
1970 |
1971 |
1972 |
1973 |
1974 |
1975 |
1976 |
1977 |
1978 |
1979 | This specifies nodes to be used as the center of the
1980 | layout and the root of the generated spanning tree. As a graph attribute,
1981 | this gives the name of the node. As a node attribute (circo only), it
1982 | specifies that the node should be used as a central node. In twopi,
1983 | this will actually be the central node. In circo, the block containing
1984 | the node will be central in the drawing of its connected component.
1985 | If not defined,
1986 | twopi will pick a most central node, and circo will pick a random node.
1987 |
1988 |
1989 |
1990 |
1991 |
1992 |
1993 |
1994 |
1995 |
1996 | If 90, set drawing orientation to landscape.
1997 |
1998 |
1999 |
2000 |
2001 |
2002 |
2003 |
2004 |
2005 |
2006 | Edges with the same head and the same samehead value are aimed
2007 | at the same point on the head.
2008 | See undirected.
2009 |
2010 |
2011 |
2012 |
2013 |
2014 |
2015 |
2016 |
2017 |
2018 | Edges with the same tail and the same sametail value are aimed
2019 | at the same point on the tail.
2020 | See undirected.
2021 |
2022 |
2023 |
2024 |
2025 |
2026 |
2027 |
2028 |
2029 |
2030 | If the input graph defines the vertices
2031 | attribute, and output is dot or xdot, this gives
2032 | the number of points used for a node whose shape is a circle or ellipse.
2033 | It plays the same role in neato, when adjusting the layout to avoid
2034 | overlapping nodes, and in image maps.
2035 |
2036 |
2037 |
2038 |
2039 |
2040 |
2041 |
2042 |
2043 |
2044 | During network simplex, maximum number of edges with negative cut values
2045 | to search when looking for one with minimum cut value.
2046 |
2047 |
2048 |
2049 |
2050 |
2051 |
2052 |
2053 |
2054 |
2055 | Fraction to increase polygons (multiply
2056 | coordinates by 1 + sep) for purposes of determining overlap. Guarantees
2057 | a minimal non-zero distance between nodes.
2058 | If unset but esep is defined, sep will be
2059 | set to esep/0.8. If esep is unset, the default value
2060 | is used.
2061 |
2062 |
2063 | When overlap="ipsep" or "vpsc",
2064 | sep gives a minimum distance, in inches, to be left between nodes.
2065 | In this case, if sep is a pointf, the x and y separations can be
2066 | specified separately.
2067 |
2068 |
2069 |
2070 |
2071 |
2072 |
2073 |
2074 |
2075 |
2076 | Set the shape of a node.
2077 |
2078 |
2079 |
2080 |
2081 |
2082 |
2083 |
2084 |
2085 |
2086 | (Deprecated) If defined, shapefile specifies a file containing user-supplied node content.
2087 | The shape of the node is set to box.
2088 | The image in the shapefile must be
2089 | rectangular. The image formats supported as well as the precise semantics of
2090 | how the file is used depends on the
2091 | output format. For further details, see
2092 | External PostScript files.
2093 |
2094 |
2095 | There is one exception to this usage.
2096 | If shape is set to "epsf", shapefile gives
2097 | a filename containing a definition of the node in PostScript.
2098 | The graphics defined must be contain all of the
2099 | node content, including any desired boundaries.
2100 | For further details, see
2101 |
2102 | External PostScript files.
2103 |
2104 |
2105 |
2106 |
2107 |
2108 |
2109 |
2110 |
2111 |
2112 | Print guide boxes in PostScript at the beginning of
2113 | routesplines if 1, or at the end if 2. (Debugging)
2114 |
2115 |
2116 |
2117 |
2118 |
2119 |
2120 |
2121 |
2122 |
2123 | Number of sides if shape=polygon.
2124 |
2125 |
2126 |
2127 |
2128 |
2129 |
2130 |
2131 |
2132 |
2133 | Maximum width and height of drawing, in inches.
2134 | If defined and the drawing is too large, the drawing is uniformly
2135 | scaled down so that it fits within the given size.
2136 |
2137 |
2138 | If size ends in an exclamation point (!),
2139 | then it is taken to be
2140 | the desired size. In this case, if both dimensions of the drawing are
2141 | less than size, the drawing is scaled up uniformly until at
2142 | least one dimension equals its dimension in size.
2143 |
2144 |
2145 | Note that there is some interaction between the size and
2146 | ratio attributes.
2147 |
2148 |
2149 |
2150 |
2151 |
2152 |
2153 |
2154 |
2155 |
2156 | Skew factor for shape=polygon. Positive values
2157 | skew top of polygon to right; negative to left.
2158 |
2159 |
2160 |
2161 |
2162 |
2163 |
2164 |
2165 |
2166 |
2167 | Controls how, and if, edges are represented. If true, edges are drawn as
2168 | splines routed around nodes; if false, edges are drawn as line segments.
2169 | If set to "", no edges are drawn at all.
2170 |
2171 |
2172 | (1 March 2007) The values line and spline can be
2173 | used as synonyms for false and true, respectively.
2174 | In addition, the value polyline specifies that edges should be
2175 | drawn as polylines.
2176 |
2177 |
2178 | By default, the attribute is unset. How this is interpreted depends on
2179 | the layout. For dot, the default is to draw edges as splines. For all
2180 | other layouts, the default is to draw edges as line segments. Note that
2181 | for these latter layouts, if splines="true", this
2182 | requires non-overlapping nodes (cf. overlap).
2183 | If fdp is used for layout and splines="compound", then the edges are
2184 | drawn to avoid clusters as well as nodes.
2185 |
2186 |
2187 |
2188 |
2189 |
2190 |
2191 |
2192 |
2193 |
2194 | Parameter used to determine the initial layout of nodes. If unset, the
2195 | nodes are randomly placed in a unit square with
2196 | the same seed is always used for the random number generator, so the
2197 | initial placement is repeatable.
2198 |
2199 |
2200 |
2201 |
2202 |
2203 |
2204 |
2205 |
2206 |
2207 | Set style for node or edge. For cluster subgraph, if "filled", the
2208 | cluster box's background is filled.
2209 |
2210 |
2211 |
2212 |
2213 |
2214 |
2215 |
2216 |
2217 |
2218 | A URL or pathname specifying an XML style sheet, used in SVG output.
2219 |
2220 |
2221 |
2222 |
2223 |
2224 |
2225 |
2226 |
2227 |
2228 | If tailURL is defined, it is
2229 | output as part of the tail label of the edge.
2230 | Also, this value is used near the tail node, overriding any
2231 | URL value.
2232 | See undirected.
2233 |
2234 |
2235 |
2236 |
2237 |
2238 |
2239 |
2240 |
2241 |
2242 | If true, the tail of an edge is clipped to the boundary of the tail node;
2243 | otherwise, the end of the edge goes to the center of the node, or the
2244 | center of a port, if applicable.
2245 |
2246 |
2247 |
2248 |
2249 |
2250 |
2251 |
2252 |
2253 |
2254 | Synonym for tailURL.
2255 |
2256 |
2257 |
2258 |
2259 |
2260 |
2261 |
2262 |
2263 |
2264 | Text label to be placed near tail of edge.
2265 | See undirected.
2266 |
2267 |
2268 |
2269 |
2270 |
2271 |
2272 |
2273 |
2274 |
2275 | Indicates where on the tail node to attach the tail of the edge.
2276 | See undirected.
2277 |
2278 |
2279 |
2280 |
2281 |
2282 |
2283 |
2284 |
2285 |
2286 | If the edge has a tailURL,
2287 | this attribute determines which window of the
2288 | browser is used
2289 | for the URL. Setting it to "_graphviz" will open a new window if it
2290 | doesn't already exist, or reuse it if it does.
2291 | If undefined, the value of the target is used.
2292 |
2293 |
2294 |
2295 |
2296 |
2297 |
2298 |
2299 |
2300 |
2301 | Tooltip annotation attached to the tail of an edge. This is used only
2302 | if the edge has a tailURL attribute.
2303 |
2304 |
2305 |
2306 |
2307 |
2308 |
2309 |
2310 |
2311 |
2312 | If the object has a URL, this attribute determines which window
2313 | of the browser is used for the URL.
2314 | See W3C documentation.
2315 |
2316 |
2317 |
2318 |
2319 |
2320 |
2321 |
2322 |
2323 |
2324 | Tooltip annotation attached to the node or edge. If unset, Graphviz
2325 | will use the object's label if defined.
2326 | Note that if the label is a record specification or an HTML-like
2327 | label, the resulting tooltip may be unhelpful. In this case, if
2328 | tooltips will be generated, the user should set a tooltip
2329 | attribute explicitly.
2330 |
2331 |
2332 |
2333 |
2334 |
2335 |
2336 |
2337 |
2338 |
2339 | If set explicitly to true or false, the value determines whether or not
2340 | internal bitmap rendering relies on a truecolor color model or uses
2341 | a color palette.
2342 | If the attribute is unset, truecolor is not used
2343 | unless there is a shapefile property
2344 | for some node in the graph.
2345 | The output model will use the input model when possible.
2346 |
2347 |
2348 | Use of color palettes results in less memory usage during creation of the
2349 | bitmaps and smaller output files.
2350 |
2351 |
2352 | Usually, the only time it is necessary to specify the truetype model
2353 | is if the graph uses more than 256 colors.
2354 | However, if one uses bgcolor=transparent with
2355 | a color palette, font
2356 | antialiasing can show up as a fuzzy white area around characters.
2357 | Using truecolor=true avoids this problem.
2358 |
2359 |
2360 |
2361 |
2362 |
2363 |
2364 |
2365 |
2366 |
2367 | If the input graph defines this attribute, the node is polygonal,
2368 | and output is dot or xdot, this attribute provides the
2369 | coordinates of the vertices of the node's polygon, in inches.
2370 | If the node is an ellipse or circle, the
2371 | samplepoints attribute affects
2372 | the output.
2373 |
2374 |
2375 |
2376 |
2377 |
2378 |
2379 |
2380 |
2381 |
2382 | Clipping window on final drawing.
2383 |
2384 |
2385 |
2386 |
2387 |
2388 |
2389 |
2390 |
2391 |
2392 | Factor to scale up drawing to allow margin for expansion in
2393 | Voronoi technique. dim' = (1+2*margin)*dim.
2394 |
2395 |
2396 |
2397 |
2398 |
2399 |
2400 |
2401 |
2402 |
2403 | Weight of edge. In dot, the heavier the weight, the shorter,
2404 | straighter and more vertical the edge is. In neato, the heavier the
2405 | weight, the more neato will try to place the end points so that the
2406 | length of the edge is len.
2407 |
2408 |
2409 |
2410 |
2411 |
2412 |
2413 |
2414 |
2415 |
2416 | Width of node, in inches. This is taken as the initial, minimum width
2417 | of the node. If fixedsize is true, this
2418 | will be the final width of the node. Otherwise, if the node label
2419 | requires more width to fit, the node's width will be increased to
2420 | contain the label. Note also that, if the output format is dot, the
2421 | value given to width will be the final value.
2422 |
2423 |
2424 |
2425 |
2426 |
2427 |
2428 |
2429 |
2430 |
2431 | Provides z coordinate value for 3D layouts and displays. If the
2432 | graph has dim set to 3 (or more),
2433 | neato will use a node's z value
2434 | for the z coordinate of its initial position if
2435 | its pos attribute is also defined.
2436 |
2437 |
2438 | Even if no z values are specified in the input, it is necessary to
2439 | declare a z attribute for nodes, e.g, using node[z=""]
2440 | in order to get z values on output.
2441 | Thus, setting dim=3 but not declaring z will
2442 | cause neato -Tvrml to
2443 | layout the graph in 3D but project the layout onto the xy-plane
2444 | for the rendering. If the z attribute is declared, the final rendering
2445 | will be in 3D.
2446 |
2447 |
2448 |
2449 |
2450 |
2451 |
2452 |
2453 |
2454 |
2455 |
2456 |
2457 |
2458 |
2459 |
2460 |
2461 |
2462 |
2463 |
2464 |
2465 |
2466 |
2467 |
2468 |
2469 |
2470 |
2471 |
2472 |
2473 |
2474 |
2475 |
2476 |
2477 |
2478 |
2479 |
2480 |
2481 |
2482 |
2483 |
2484 |
2485 |
2486 |
2487 |
2488 |
2489 |
2490 |
2491 |
2492 |
2493 |
2494 |
2495 |
2496 |
2497 |
2498 |
2499 |
2500 |
2501 |
2502 |
2503 |
2504 |
2505 |
2506 |
2507 |
2508 |
2509 |
2510 |
2511 |
2512 |
2513 |
2514 |
2515 |
2516 |
2517 |
2518 |
2519 |
2520 |
2521 |
2522 |
2523 |
2524 |
2525 |
2526 |
2527 |
2528 |
2529 |
2530 |
2531 |
2532 |
2533 |
2534 |
2535 |
2536 |
2537 |
2538 |
2539 |
2540 |
2541 |
2542 |
2543 |
2544 |
2545 |
2546 |
2547 |
2548 |
2549 |
2550 |
2551 |
2552 |
2553 |
2554 |
2555 |
2556 |
2557 |
2558 |
2559 |
2560 |
2561 |
2562 |
2563 |
2564 |
2565 |
2566 |
2567 |
2568 |
2569 |
2570 |
2571 |
2572 |
2573 |
2574 |
2575 |
2576 |
2577 |
2578 |
2579 |
2580 |
2581 |
2582 |
2583 |
2584 |
2585 |
2586 |
2587 |
2588 |
2589 |
2590 |
2591 |
2592 |
2593 |
2594 |
2595 |
2596 |
2597 |
2598 |
2599 |
2600 |
2601 |
2602 |
2603 |
2604 |
2605 |
2606 |
2607 |
2608 |
2609 |
2610 |
2611 |
2612 |
2613 |
2614 |
2615 |
2616 |
2617 |
2618 |
2619 |
2620 |
2621 |
2622 |
2623 |
2624 |
2625 |
2626 |
2627 |
2628 |
2629 |
2630 |
2631 |
2632 |
2633 |
2634 |
2635 |
2636 |
2637 |
2638 |
2639 |
2640 |
2641 |
2642 |
2643 |
2644 |
2645 |
2646 |
2647 |
2648 |
2649 |
2650 |
2651 |
2652 |
2653 |
2654 |
2655 |
2656 |
2657 |
--------------------------------------------------------------------------------
/tests/phpDocumentor/GraphViz/Test/AttributeTest.php:
--------------------------------------------------------------------------------
1 | fixture = new Attribute('a', '1');
33 | }
34 |
35 | /**
36 | * Tests the construct method
37 | *
38 | * @covers \phpDocumentor\GraphViz\Attribute::__construct
39 | * @returnn void
40 | */
41 | public function testConstruct(): void
42 | {
43 | $fixture = new Attribute('MyKey', 'MyValue');
44 | $this->assertInstanceOf(
45 | Attribute::class,
46 | $fixture
47 | );
48 | $this->assertSame('MyKey', $fixture->getKey());
49 | $this->assertSame('MyValue', $fixture->getValue());
50 | }
51 |
52 | /**
53 | * Tests the getting and setting of the key.
54 | *
55 | * @covers \phpDocumentor\GraphViz\Attribute::getKey
56 | * @covers \phpDocumentor\GraphViz\Attribute::setKey
57 | */
58 | public function testKey(): void
59 | {
60 | $this->assertSame(
61 | $this->fixture->getKey(),
62 | 'a',
63 | 'Expecting the key to match the initial state'
64 | );
65 | $this->assertSame(
66 | $this->fixture,
67 | $this->fixture->setKey('b'),
68 | 'Expecting a fluent interface'
69 | );
70 | $this->assertSame(
71 | $this->fixture->getKey(),
72 | 'b',
73 | 'Expecting the key to contain the new value'
74 | );
75 | }
76 |
77 | /**
78 | * Tests the getting and setting of the value.
79 | *
80 | * @covers \phpDocumentor\GraphViz\Attribute::getValue
81 | * @covers \phpDocumentor\GraphViz\Attribute::setValue
82 | */
83 | public function testValue(): void
84 | {
85 | $this->assertSame(
86 | $this->fixture->getValue(),
87 | '1',
88 | 'Expecting the value to match the initial state'
89 | );
90 | $this->assertSame(
91 | $this->fixture,
92 | $this->fixture->setValue('2'),
93 | 'Expecting a fluent interface'
94 | );
95 | $this->assertSame(
96 | $this->fixture->getValue(),
97 | '2',
98 | 'Expecting the value to contain the new value'
99 | );
100 | }
101 |
102 | /**
103 | * Tests whether a string starting with a < is recognized as HTML.
104 | *
105 | * @covers \phpDocumentor\GraphViz\Attribute::isValueInHtml
106 | */
107 | public function testIsValueInHtml(): void
108 | {
109 | $this->fixture->setValue('a');
110 | $this->assertFalse(
111 | $this->fixture->isValueInHtml(),
112 | 'Expected value to not be a HTML code'
113 | );
114 |
115 | $this->fixture->setValue('test');
116 | $this->assertTrue(
117 | $this->fixture->isValueInHtml(),
118 | 'Expected value to be recognized as a HTML code'
119 | );
120 | }
121 |
122 | /**
123 | * Tests whether the toString provides a valid GraphViz attribute string.
124 | *
125 | * @covers \phpDocumentor\GraphViz\Attribute::__toString
126 | */
127 | public function testToString(): void
128 | {
129 | $this->fixture = new Attribute('a', 'b');
130 | $this->assertSame(
131 | 'a="b"',
132 | (string) $this->fixture,
133 | 'Strings should be surrounded with quotes'
134 | );
135 |
136 | $this->fixture->setValue('a"a');
137 | $this->assertSame(
138 | 'a="a\"a"',
139 | (string) $this->fixture,
140 | 'Strings should be surrounded with quotes'
141 | );
142 |
143 | $this->fixture->setKey('url');
144 | $this->assertSame(
145 | 'URL="a\"a"',
146 | (string) $this->fixture,
147 | 'The key named URL must be uppercased'
148 | );
149 |
150 | $this->fixture->setValue('test');
151 | $this->assertSame(
152 | 'URL=test',
153 | (string) $this->fixture,
154 | 'HTML strings should not be surrounded with quotes'
155 | );
156 | }
157 |
158 | /**
159 | * Tests whether the toString provides a valid GraphViz attribute string.
160 | *
161 | * @covers \phpDocumentor\GraphViz\Attribute::__toString
162 | * @covers \phpDocumentor\GraphViz\Attribute::encodeSpecials
163 | */
164 | public function testToStringWithSpecials(): void
165 | {
166 | $this->fixture = new Attribute('a', 'b');
167 |
168 | $this->fixture->setValue('a\la');
169 | $this->assertSame(
170 | 'a="a\la"',
171 | (string) $this->fixture,
172 | 'Specials should not be escaped'
173 | );
174 | $this->fixture->setValue('a\l"a');
175 | $this->assertSame(
176 | 'a="a\l\"a"',
177 | (string) $this->fixture,
178 | 'Specials should not be escaped, but quotes should'
179 | );
180 | $this->fixture->setValue('a\\\\l"a');
181 | $this->assertSame(
182 | 'a="a\\\\l\"a"',
183 | (string) $this->fixture,
184 | 'Double backslashes should stay the same'
185 | );
186 | }
187 |
188 | /**
189 | * Tests whether the isValueContainingSpecials function
190 | *
191 | * @covers \phpDocumentor\GraphViz\Attribute::isValueContainingSpecials
192 | */
193 | public function testIsValueContainingSpecials(): void
194 | {
195 | $this->fixture->setValue('+ name : string\l+ home_country : string\l');
196 | $this->assertTrue($this->fixture->isValueContainingSpecials());
197 |
198 | $this->fixture->setValue('+ ship(): boolean');
199 | $this->assertFalse($this->fixture->isValueContainingSpecials());
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/tests/phpDocumentor/GraphViz/Test/EdgeTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(
48 | Edge::class,
49 | $fixture
50 | );
51 | $this->assertSame(
52 | $fromNode,
53 | $fixture->getFrom()
54 | );
55 | $this->assertSame(
56 | $toNode,
57 | $fixture->getTo()
58 | );
59 | }
60 |
61 | /**
62 | * Tests the create method
63 | *
64 | * @covers \phpDocumentor\GraphViz\Edge::create
65 | */
66 | public function testCreate(): void
67 | {
68 | $this->assertInstanceOf(
69 | Edge::class,
70 | Edge::create(new Node('from'), new Node('to'))
71 | );
72 | }
73 |
74 | /**
75 | * Tests whether the getFrom method returns the same node as passed
76 | * in the create method
77 | *
78 | * @covers \phpDocumentor\GraphViz\Edge::getFrom
79 | */
80 | public function testGetFrom(): void
81 | {
82 | $from = new Node('from');
83 | $edge = Edge::create($from, new Node('to'));
84 | $this->assertSame($from, $edge->getFrom());
85 | }
86 |
87 | /**
88 | * Tests the getTo method returns the same node as passed
89 | * in the create method
90 | *
91 | * @covers \phpDocumentor\GraphViz\Edge::getTo
92 | */
93 | public function testGetTo(): void
94 | {
95 | $to = new Node('to');
96 | $edge = Edge::create(new Node('from'), $to);
97 | $this->assertSame($to, $edge->getTo());
98 | }
99 |
100 | /**
101 | * Tests the magic __call method, to work as described, return the object
102 | * instance for a setX method, return the value for an getX method, and null
103 | * for the remaining method calls
104 | *
105 | * @covers \phpDocumentor\GraphViz\Edge::__call
106 | * @covers \phpDocumentor\GraphViz\Edge::setAttribute
107 | * @covers \phpDocumentor\GraphViz\Edge::getAttribute
108 | */
109 | public function testCall(): void
110 | {
111 | $label = 'my label';
112 | $fixture = new Edge(new Node('from'), new Node('to'));
113 | $this->assertInstanceOf(Edge::class, $fixture->setLabel($label));
114 | $this->assertSame($label, $fixture->getLabel()->getValue());
115 | $this->assertNull($fixture->someNonExcistingMethod());
116 | }
117 |
118 | /**
119 | * @covers \phpDocumentor\GraphViz\Edge::getAttribute
120 | * @covers \phpDocumentor\GraphViz\AttributeNotFound::__construct
121 | */
122 | public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
123 | {
124 | $fixture = new Edge(new Node('from'), new Node('to'));
125 |
126 | $this->expectException(AttributeNotFound::class);
127 | $this->expectExceptionMessage('Attribute with name "label" was not found');
128 |
129 | $fixture->getLabel();
130 | }
131 |
132 | /**
133 | * Tests whether the magic __toString method returns a well formatted string
134 | * as specified in the DOT standard
135 | *
136 | * @covers \phpDocumentor\GraphViz\Edge::__toString
137 | */
138 | public function testToString(): void
139 | {
140 | $fixture = new Edge(new Node('from'), new Node('to'));
141 | $fixture->setLabel('MyLabel');
142 | $fixture->setWeight(45);
143 |
144 | $dot = << "to" [
146 | label="MyLabel"
147 | weight="45"
148 | ]
149 | DOT;
150 |
151 | $this->assertSame($dot, (string) $fixture);
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/tests/phpDocumentor/GraphViz/Test/GraphTest.php:
--------------------------------------------------------------------------------
1 | fixture = new Graph();
48 | }
49 |
50 | /**
51 | * Tears down the fixture, for example, closes a network connection.
52 | * This method is called after a test is executed.
53 | */
54 | protected function tearDown(): void
55 | {
56 | m::close();
57 | }
58 |
59 | /**
60 | * @covers \phpDocumentor\GraphViz\Graph::create
61 | */
62 | public function testCreate(): void
63 | {
64 | $fixture = Graph::create();
65 | $this->assertInstanceOf(
66 | Graph::class,
67 | $fixture
68 | );
69 | $this->assertSame(
70 | 'G',
71 | $fixture->getName()
72 | );
73 | $this->assertSame(
74 | 'digraph',
75 | $fixture->getType()
76 | );
77 |
78 | $fixture = Graph::create('MyName', false);
79 | $this->assertSame(
80 | 'MyName',
81 | $fixture->getName()
82 | );
83 | $this->assertSame(
84 | 'graph',
85 | $fixture->getType()
86 | );
87 | }
88 |
89 | /**
90 | * @covers \phpDocumentor\GraphViz\Graph::setName
91 | */
92 | public function testSetName(): void
93 | {
94 | $this->assertSame(
95 | $this->fixture,
96 | $this->fixture->setName('otherName'),
97 | 'Expecting a fluent interface'
98 | );
99 | }
100 |
101 | /**
102 | * @covers \phpDocumentor\GraphViz\Graph::getName
103 | */
104 | public function testGetName(): void
105 | {
106 | $this->assertSame(
107 | $this->fixture->getName(),
108 | 'G',
109 | 'Expecting the name to match the initial state'
110 | );
111 | $this->fixture->setName('otherName');
112 | $this->assertSame(
113 | $this->fixture->getName(),
114 | 'otherName',
115 | 'Expecting the name to contain the new value'
116 | );
117 | }
118 |
119 | /**
120 | * @covers \phpDocumentor\GraphViz\Graph::setType
121 | */
122 | public function testSetType(): void
123 | {
124 | $this->assertSame(
125 | $this->fixture,
126 | $this->fixture->setType('digraph'),
127 | 'Expecting a fluent interface'
128 | );
129 | $this->assertSame(
130 | $this->fixture,
131 | $this->fixture->setType('graph'),
132 | 'Expecting a fluent interface'
133 | );
134 | $this->assertSame(
135 | $this->fixture,
136 | $this->fixture->setType('subgraph'),
137 | 'Expecting a fluent interface'
138 | );
139 | }
140 |
141 | /**
142 | * @covers \phpDocumentor\GraphViz\Graph::setType
143 | */
144 | public function testSetTypeException(): void
145 | {
146 | $this->expectException(InvalidArgumentException::class);
147 | $this->fixture->setType('fakegraphg');
148 | }
149 |
150 | /**
151 | * @covers \phpDocumentor\GraphViz\Graph::getType
152 | */
153 | public function testGetType(): void
154 | {
155 | $this->assertSame(
156 | $this->fixture->getType(),
157 | 'digraph'
158 | );
159 | $this->fixture->setType('graph');
160 | $this->assertSame(
161 | $this->fixture->getType(),
162 | 'graph'
163 | );
164 | }
165 |
166 | public function testSetStrict(): void
167 | {
168 | $this->assertSame(
169 | $this->fixture,
170 | $this->fixture->setStrict(true),
171 | 'Expecting a fluent interface'
172 | );
173 | $this->assertSame(
174 | $this->fixture,
175 | $this->fixture->setStrict(false),
176 | 'Expecting a fluent interface'
177 | );
178 | }
179 |
180 | public function testIsStrict(): void
181 | {
182 | $this->assertSame(
183 | $this->fixture->isStrict(),
184 | false
185 | );
186 | $this->fixture->setStrict(true);
187 | $this->assertSame(
188 | $this->fixture->isStrict(),
189 | true
190 | );
191 | }
192 |
193 | public function testSetPath(): void
194 | {
195 | $this->assertSame(
196 | $this->fixture,
197 | $this->fixture->setPath(__DIR__),
198 | 'Expecting a fluent interface'
199 | );
200 | }
201 |
202 | /**
203 | * @covers \phpDocumentor\GraphViz\Graph::__call
204 | * @covers \phpDocumentor\GraphViz\Graph::getAttribute
205 | * @covers \phpDocumentor\GraphViz\Graph::setAttribute
206 | */
207 | public function test__call(): void
208 | {
209 | $this->assertNull($this->fixture->MyMethod());
210 | $this->assertSame($this->fixture, $this->fixture->setBgColor('black'));
211 | $this->assertSame('black', $this->fixture->getBgColor()->getValue());
212 | }
213 |
214 | /**
215 | * @covers \phpDocumentor\GraphViz\Graph::getAttribute
216 | * @covers \phpDocumentor\GraphViz\AttributeNotFound::__construct
217 | */
218 | public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
219 | {
220 | $this->expectException(AttributeNotFound::class);
221 | $this->expectExceptionMessage('Attribute with name "notexisting" was not found');
222 |
223 | $this->fixture->getNotExisting();
224 | }
225 |
226 | /**
227 | * @covers \phpDocumentor\GraphViz\Graph::addGraph
228 | */
229 | public function testAddGraph(): void
230 | {
231 | $mock = m::mock(Graph::class);
232 | $mock->expects('setType');
233 | $mock->expects('getName');
234 |
235 | $this->assertSame(
236 | $this->fixture,
237 | $this->fixture->addGraph($mock)
238 | );
239 | }
240 |
241 | /**
242 | * @covers \phpDocumentor\GraphViz\Graph::hasGraph
243 | */
244 | public function testHasGraph(): void
245 | {
246 | $mock = m::mock(Graph::class);
247 | $mock->expects('getName')->andReturn('MyName');
248 | $mock->expects('setType');
249 |
250 | $this->assertFalse($this->fixture->hasGraph('MyName'));
251 | $this->fixture->addGraph($mock);
252 | $this->assertTrue($this->fixture->hasGraph('MyName'));
253 | }
254 |
255 | /**
256 | * @covers \phpDocumentor\GraphViz\Graph::getGraph
257 | */
258 | public function testGetGraph(): void
259 | {
260 | $mock = m::mock(Graph::class);
261 | $mock->expects('setType');
262 | $mock->expects('getName')->andReturn('MyName');
263 |
264 | $this->fixture->addGraph($mock);
265 | $this->assertSame(
266 | $mock,
267 | $this->fixture->getGraph('MyName')
268 | );
269 | }
270 |
271 | /**
272 | * @covers \phpDocumentor\GraphViz\Graph::setNode
273 | */
274 | public function testSetNode(): void
275 | {
276 | $mock = m::mock(Node::class);
277 | $mock->expects('getName')->andReturn('MyName');
278 |
279 | $this->assertSame(
280 | $this->fixture,
281 | $this->fixture->setNode($mock)
282 | );
283 | }
284 |
285 | /**
286 | * @covers \phpDocumentor\GraphViz\Graph::findNode
287 | */
288 | public function testFindNode(): void
289 | {
290 | $this->assertNull($this->fixture->findNode('MyNode'));
291 |
292 | $mock = m::mock(Node::class);
293 | $mock->expects('getName')->andReturn('MyName');
294 |
295 | $this->fixture->setNode($mock);
296 | $this->assertSame(
297 | $mock,
298 | $this->fixture->findNode('MyName')
299 | );
300 |
301 | $subGraph = Graph::create();
302 | $mock2 = m::mock(Node::class);
303 | $mock2->expects('getName')->andReturn('MyName2');
304 |
305 | $subGraph->setNode($mock2);
306 |
307 | $this->fixture->addGraph($subGraph);
308 | $this->assertSame(
309 | $mock2,
310 | $this->fixture->findNode('MyName2')
311 | );
312 | }
313 |
314 | /**
315 | * @covers \phpDocumentor\GraphViz\Graph::__set
316 | */
317 | public function test__set(): void
318 | {
319 | $mock = m::mock(Node::class);
320 |
321 | $this->fixture->__set('myNode', $mock);
322 |
323 | self::assertSame($mock, $this->fixture->myNode);
324 | }
325 |
326 | /**
327 | * @covers \phpDocumentor\GraphViz\Graph::__get
328 | */
329 | public function test__get(): void
330 | {
331 | $mock = m::mock(Node::class);
332 |
333 | $this->fixture->myNode = $mock;
334 | $this->assertSame(
335 | $mock,
336 | $this->fixture->myNode
337 | );
338 | }
339 |
340 | /**
341 | * @covers \phpDocumentor\GraphViz\Graph::link
342 | */
343 | public function testLink(): void
344 | {
345 | $mock = m::mock(Edge::class);
346 |
347 | $this->assertSame(
348 | $this->fixture,
349 | $this->fixture->link($mock)
350 | );
351 | }
352 |
353 | /**
354 | * @covers \phpDocumentor\GraphViz\Graph::export
355 | */
356 | public function testExportException(): void
357 | {
358 | $graph = Graph::create('My First Graph');
359 | $filename = tempnam(sys_get_temp_dir(), 'tst');
360 |
361 | if ($filename === false) {
362 | $this->assertFalse('Failed to create destination file');
363 |
364 | return;
365 | }
366 |
367 | $this->expectException(Exception::class);
368 | $graph->export('fpd', $filename);
369 | }
370 |
371 | /**
372 | * @covers \phpDocumentor\GraphViz\Graph::export
373 | */
374 | public function testExport(): void
375 | {
376 | $graph = Graph::create('My First Graph');
377 | $filename = tempnam(sys_get_temp_dir(), 'tst');
378 |
379 | if ($filename === false) {
380 | $this->assertFalse('Failed to create destination file');
381 |
382 | return;
383 | }
384 |
385 | $this->assertSame(
386 | $graph,
387 | $graph->export('pdf', $filename)
388 | );
389 | $this->assertTrue(is_readable($filename));
390 | }
391 |
392 | /**
393 | * @covers \phpDocumentor\GraphViz\Graph::__toString
394 | */
395 | public function test__toString(): void
396 | {
397 | $graph = Graph::create('My First Graph');
398 | $this->assertSame(
399 | $this->normalizeLineEndings((string) $graph),
400 | $this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . PHP_EOL . '}'))
401 | );
402 |
403 | $graph->setLabel('PigeonPost');
404 | $this->assertSame(
405 | $this->normalizeLineEndings((string) $graph),
406 | $this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . 'label="PigeonPost"' . PHP_EOL . '}'))
407 | );
408 |
409 | $graph->setStrict(true);
410 | $this->assertSame(
411 | $this->normalizeLineEndings((string) $graph),
412 | $this->normalizeLineEndings(
413 | ('strict digraph "My First Graph" {' . PHP_EOL . 'label="PigeonPost"' . PHP_EOL . '}')
414 | )
415 | );
416 | }
417 |
418 | /**
419 | * Help avoid issue of "#Warning: Strings contain different line endings!" on Windows.
420 | */
421 | private function normalizeLineEndings(string $string): string
422 | {
423 | $result = preg_replace('~\R~u', "\r\n", $string);
424 | if ($result === null) {
425 | throw new RuntimeException('Normalize line endings failed');
426 | }
427 |
428 | return $result;
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/tests/phpDocumentor/GraphViz/Test/NodeTest.php:
--------------------------------------------------------------------------------
1 | fixture = new Node('name', 'label');
34 | }
35 |
36 | /**
37 | * Tests the construct method
38 | *
39 | * @covers \phpDocumentor\GraphViz\Node::__construct
40 | * @returnn void
41 | */
42 | public function testConstruct(): void
43 | {
44 | $fixture = new Node('MyName', 'MyLabel');
45 | $this->assertInstanceOf(
46 | Node::class,
47 | $fixture
48 | );
49 | $this->assertSame('MyName', $fixture->getName());
50 | $this->assertSame('MyLabel', $fixture->getLabel()->getValue());
51 | }
52 |
53 | /**
54 | * Tests the create method
55 | *
56 | * @covers \phpDocumentor\GraphViz\Node::create
57 | * @returnn void
58 | */
59 | public function testCreate(): void
60 | {
61 | $this->assertInstanceOf(
62 | Node::class,
63 | Node::create('name', 'label')
64 | );
65 | }
66 |
67 | /**
68 | * Tests the getting and setting of the name.
69 | *
70 | * @covers \phpDocumentor\GraphViz\Node::getName
71 | * @covers \phpDocumentor\GraphViz\Node::setName
72 | */
73 | public function testName(): void
74 | {
75 | $this->assertSame(
76 | $this->fixture->getName(),
77 | 'name',
78 | 'Expecting the name to match the initial state'
79 | );
80 | $this->assertSame(
81 | $this->fixture,
82 | $this->fixture->setName('otherName'),
83 | 'Expecting a fluent interface'
84 | );
85 | $this->assertSame(
86 | $this->fixture->getName(),
87 | 'otherName',
88 | 'Expecting the name to contain the new value'
89 | );
90 | }
91 |
92 | /**
93 | * Tests the magic __call method, to work as described, return the object
94 | * instance for a setX method, return the value for an getX method, and null
95 | * for the remaining method calls
96 | *
97 | * @covers \phpDocumentor\GraphViz\Node::__call
98 | * @covers \phpDocumentor\GraphViz\Node::getAttribute
99 | * @covers \phpDocumentor\GraphViz\Node::setAttribute
100 | */
101 | public function testCall(): void
102 | {
103 | $fontname = 'Bitstream Vera Sans';
104 | $this->assertInstanceOf(Node::class, $this->fixture->setfontname($fontname));
105 | $this->assertSame($fontname, $this->fixture->getfontname()->getValue());
106 | $this->assertNull($this->fixture->someNonExistingMethod());
107 | }
108 |
109 | /**
110 | * @covers \phpDocumentor\GraphViz\Node::getAttribute
111 | * @covers \phpDocumentor\GraphViz\AttributeNotFound::__construct
112 | */
113 | public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
114 | {
115 | $this->expectException(AttributeNotFound::class);
116 | $this->expectExceptionMessage('Attribute with name "fontname" was not found');
117 |
118 | $this->fixture->getFontname();
119 | }
120 |
121 | /**
122 | * Tests whether the magic __toString method returns a well formatted string
123 | * as specified in the DOT standard
124 | *
125 | * @covers \phpDocumentor\GraphViz\Node::__toString
126 | */
127 | public function testToString(): void
128 | {
129 | $this->fixture->setfontsize(12);
130 | $this->fixture->setfontname('Bitstream Vera Sans');
131 |
132 | $dot = <<assertSame($dot, (string) $this->fixture);
141 | }
142 |
143 | /**
144 | * Tests whether the magic __toString method returns a well formatted string
145 | * as specified in the DOT standard when the label contains slashes.
146 | *
147 | * @covers \phpDocumentor\GraphViz\Node::__toString
148 | */
149 | public function testToStringWithLabelContainingSlashes(): void
150 | {
151 | $this->fixture->setfontsize(12);
152 | $this->fixture->setfontname('Bitstream Vera Sans');
153 | $this->fixture->setLabel('\phpDocumentor\Descriptor\ProjectDescriptor');
154 |
155 | $dot = <<assertSame($dot, (string) $this->fixture);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/tests/phpDocumentor/PHPStan/MethodReflectionExtensionTest.php:
--------------------------------------------------------------------------------
1 | fixture = new MethodReflectionExtension();
32 | }
33 |
34 | /**
35 | * @dataProvider existingMethodProvider
36 | */
37 | public function testNodeHasMethodReturnsTrue(string $className, string $methodName): void
38 | {
39 | $classReflection = m::mock(ClassReflection::class);
40 | $classReflection->shouldReceive('getName')->andReturn($className);
41 |
42 | $this->assertTrue($this->fixture->hasMethod($classReflection, $methodName));
43 | }
44 |
45 | /**
46 | * @return array>
47 | */
48 | public function existingMethodProvider(): array
49 | {
50 | return [
51 | 'node::getLabel' => [
52 | 'className' => Node::class,
53 | 'methodName' => 'getLabel',
54 | ],
55 | 'node::setLabel' => [
56 | 'className' => Node::class,
57 | 'methodName' => 'setLabel',
58 | ],
59 | 'graph::setFontSize' => [
60 | 'className' => Graph::class,
61 | 'methodName' => 'setFontSize',
62 | ],
63 | 'graph::getFontSize' => [
64 | 'className' => Graph::class,
65 | 'methodName' => 'getFontSize',
66 | ],
67 | ];
68 | }
69 |
70 | public function testAttributeType(): void
71 | {
72 | $classReflection = m::mock(ClassReflection::class);
73 | $classReflection->shouldReceive('getName')->andReturn(Node::class);
74 |
75 | $method = $this->fixture->getMethod($classReflection, 'setFontSize');
76 |
77 | $this->assertInstanceOf(FloatType::class, $method->getVariants()[0]->getParameters()[0]->getType());
78 | }
79 |
80 | public function testAttributeTypeOfNoneExisting(): void
81 | {
82 | $classReflection = m::mock(ClassReflection::class);
83 | $classReflection->shouldReceive('getName')->andReturn(Node::class);
84 |
85 | $method = $this->fixture->getMethod($classReflection, 'setColor');
86 |
87 | $this->assertInstanceOf(StringType::class, $method->getVariants()[0]->getParameters()[0]->getType());
88 | }
89 | }
90 |
--------------------------------------------------------------------------------