├── .changes ├── 3.0.0.md ├── 3.1.0.md ├── 3.1.1.md ├── 3.2.0.md ├── 3.2.1.md ├── 3.3.0.md ├── 3.4.0.md ├── 4.0.0.md ├── 4.0.1.md ├── 4.1.0.md ├── 4.2.0.md ├── 4.2.1.md ├── 4.2.2.md ├── header.tpl.md └── unreleased │ └── .gitkeep ├── .changie.yaml ├── .editorconfig ├── .github ├── linters │ ├── .ecrc │ ├── .phpcs.xml.dist │ ├── .phplint.yml │ └── phpstan.neon.dist └── workflows │ ├── docker.yml │ ├── gh-pages.yml │ ├── release.yml │ └── unit-tests.yaml ├── .gitignore ├── .mega-linter.yml ├── CHANGELOG-1.x.md ├── CHANGELOG-2.x.md ├── CHANGELOG-3.x.md ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── autoload.php ├── bin ├── umlwriter └── umlwriter.1 ├── box.json ├── box.json.dist ├── composer.json ├── docs ├── 01_Features │ ├── Configuration.md │ └── Services.md ├── 02_Console_Commands │ └── diagram_class.md ├── 03_Cookbook │ ├── 01_UmlWriter_public_architecture.md │ ├── 02_UmlWriter_public_methods_only.md │ └── 03_Custom_autoloader.md ├── 90_For_Developers │ ├── 1_Generators.md │ └── 2_Creating_a_Generator.md ├── README.md ├── architecture │ └── README.md ├── assets │ └── images │ │ ├── .gitkeep │ │ ├── archi-config.graphviz.svg │ │ ├── archi-console.graphviz.svg │ │ ├── archi-generator.graphviz.svg │ │ ├── archi-service.graphviz.svg │ │ └── mygenerator-results.png ├── images │ ├── graphviz_logo.png │ └── plantuml_logo.png ├── installation.md └── usage │ ├── README.md │ ├── console.md │ ├── docker.md │ └── programmatically.md ├── entrypoint.sh ├── examples ├── application │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── configuration │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── console-commands │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── custom-autoloader │ ├── bootstrap.php │ ├── datasource.php │ ├── options.php │ └── reflection-properties.php ├── custom-generator │ ├── app.php │ ├── batch.php │ ├── bootstrap.php │ ├── datasource.php │ ├── my-generator-factory.php │ ├── my-generator.php │ └── options.php ├── formatter │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── from-yaml │ ├── .umlwriter.yaml │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── generator │ ├── bootstrap.php │ ├── datasource.php │ ├── my-generator-factory.php │ ├── my-generator.php │ └── options.php ├── graphviz.php ├── plantuml.php ├── public-architecture │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── public-methods-only │ ├── bootstrap.php │ ├── datasource.php │ └── options.php └── services │ ├── bootstrap.php │ ├── datasource.php │ └── options.php ├── mkdocs.yml ├── patches └── graph-graphviz_add_subgraph_cluster-42.patch ├── phpunit.xml.dist ├── resources ├── build.php └── gh-pages-hook.sh ├── src ├── Config │ └── Loader │ │ └── YamlFileLoader.php ├── Console │ ├── Application.php │ └── Command │ │ └── ClassDiagramCommand.php ├── Generator │ ├── GeneratorFactory.php │ └── GeneratorFactoryInterface.php └── Service │ ├── ClassDiagramRenderer.php │ ├── ConfigurationHandler.php │ └── ContainerService.php ├── tests ├── FeatureTest.php ├── PlantUMLIssueTest.php ├── TestCase.php ├── bootstrap.php ├── fixtures │ ├── 001_simpleClass.gv │ ├── 001_simpleClass.php │ ├── 001_simpleClass.puml │ ├── 002_simpleClassExtends.gv │ ├── 002_simpleClassExtends.php │ ├── 002_simpleClassExtends.puml │ ├── 003_simpleClassImplements.gv │ ├── 003_simpleClassImplements.php │ ├── 003_simpleClassImplements.puml │ ├── 004_Method.gv │ ├── 004_Method.php │ ├── 004_Method.puml │ ├── 005_InheritMethod.gv │ ├── 005_InheritMethod.php │ ├── 005_InheritMethod.puml │ ├── 006_Constant.gv │ ├── 006_Constant.php │ ├── 006_Constant.puml │ ├── 007_InheritConstant.gv │ ├── 007_InheritConstant.php │ ├── 007_InheritConstant.puml │ ├── 008_Property.gv │ ├── 008_Property.php │ └── 008_Property.puml └── issues │ ├── gh-7.php │ └── gh-7.puml └── vendor-bin ├── graph-composer └── composer.json ├── php-cs └── composer.json ├── phplint └── composer.json ├── phpstan └── composer.json └── phpunit └── composer.json /.changes/3.0.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.0.0 - 2021-12-26 3 | 4 | This major version is only PHP 8 compatible. 5 | 6 | ### Changed 7 | 8 | - Support **Typed properties** features, now minimum PHP requirement is 8.0 9 | 10 | Read more about this feature at : 11 | 12 | - 13 | - 14 | 15 | **Full Changelog**: [2.1.1...3.0.0](https://github.com/llaville/umlwriter/compare/2.1.1...3.0.0) 16 | -------------------------------------------------------------------------------- /.changes/3.1.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.1.0 - 2022-01-03 3 | 4 | ### Added 5 | 6 | - `manifest` option to show PHAR metadata contents (dependencies embedded) 7 | 8 | ### Changed 9 | 10 | - `.github/workflows/gh-pages.yml` workflow to generate dynamically UML graphs 11 | - simplify examples now `resources/graph-uml/build.php` script exists 12 | 13 | ### Fixed 14 | 15 | - Composer 2.2 plugins compatibility 16 | 17 | **Full Changelog**: [3.0.0...3.1.0](https://github.com/llaville/umlwriter/compare/3.0.0...3.1.0) 18 | -------------------------------------------------------------------------------- /.changes/3.1.1.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.1.1 - 2022-01-04 3 | 4 | ### Changed 5 | 6 | - raise `bartlett/graph-uml` constraint to be compatible with `graphp/*` packages and patch provided 7 | 8 | ### Fixed 9 | 10 | - `graphp/graph` constraint to specific commit compatible with patch provided (see `patches` directory) 11 | - `graphp/graphviz` constraint to specific commit compatible with patch provided (see `patches` directory) 12 | 13 | **Full Changelog**: [3.1.0...3.1.1](https://github.com/llaville/umlwriter/compare/3.1.0...3.1.1) 14 | -------------------------------------------------------------------------------- /.changes/3.2.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.2.0 - 2022-02-26 3 | 4 | ### Added 5 | 6 | - support for Symfony 6.x components 7 | - `release` workflow to automate creating a new GitHub release with PHAR artifact (that contains a manifest) 8 | 9 | ### Changed 10 | 11 | - PHAR manifest (simple text format) is built with `bartlett/box-manifest` package 12 | - Application version used now the [Composer runtime API 2.0](https://getcomposer.org/doc/07-runtime.md) to get packages installed 13 | 14 | ### Removed 15 | 16 | - `Bartlett\UmlWriter\Console\Application::VERSION` constant. 17 | 18 | **Full Changelog**: [3.1.1...3.2.0](https://github.com/llaville/umlwriter/compare/3.1.1...3.2.0) 19 | -------------------------------------------------------------------------------- /.changes/3.2.1.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.2.1 - 2022-09-12 3 | 4 | ### Changed 5 | 6 | - synchronize with latest commit of `graphp/graphviz` project 7 | - use `bartlett/graph-uml` recent version 1.3.0 8 | 9 | **Full Changelog**: [3.2.0...3.2.1](https://github.com/llaville/umlwriter/compare/3.2.0...3.2.1) 10 | -------------------------------------------------------------------------------- /.changes/3.3.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.3.0 - 2022-12-17 3 | 4 | ### Changed 5 | 6 | - add support to `roave/better-reflection` v6 7 | - Upgrade `psr/container` dependency by adding support to v2 8 | 9 | ### Removed 10 | 11 | - Drop support for Symfony 4 and allow Symfony 6 support 12 | 13 | **Full Changelog**: [3.2.1...3.3.0](https://github.com/llaville/umlwriter/compare/3.2.1...3.3.0) 14 | -------------------------------------------------------------------------------- /.changes/3.4.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 3.4.0 - 2023-04-11 3 | 4 | ### Added 5 | 6 | - support to PHPUnit 10 7 | - Provides docker image that only support Graphviz generator (no PlantUML yet supported) 8 | 9 | ### Changed 10 | 11 | - migrate configuration for PHPUnit 10 12 | 13 | ### Fixed 14 | 15 | - as per [Lock down include wrappers to avoid abuse from third parties](https://github.com/composer/composer/pull/11015), we replaced `Composer\Autoload\includeFile` 16 | 17 | **Full Changelog**: [3.3.0...3.4.0](https://github.com/llaville/umlwriter/compare/3.3.0...3.4.0) 18 | -------------------------------------------------------------------------------- /.changes/4.0.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.0.0 - 2023-12-27 3 | 4 | ### Added 5 | 6 | - Allows Symfony 7 7 | 8 | ### Changed 9 | 10 | - replaces support from old Symfony LTS version (5.4) to new one (6.4) 11 | - `ClassDiagramRenderer::__invoke` method accept now either a Symfony `Finder` instance or a PHP `Generator` as first argument to identify the datasource, and return a Graph object instead of the statement results 12 | 13 | ### Removed 14 | 15 | - drop support to PHP 8.0 16 | - drop support to PHPUnit 9 17 | 18 | **Full Changelog**: [3.4.0...4.0.0](https://github.com/llaville/umlwriter/compare/3.4.0...4.0.0) 19 | -------------------------------------------------------------------------------- /.changes/4.0.1.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.0.1 - 2023-12-27 3 | 4 | No code changed since 4.0.0 5 | 6 | ### Fixed 7 | 8 | - BOX config file `box.json.dist` syntax error 9 | 10 | **Full Changelog**: [4.0.0...4.0.1](https://github.com/llaville/umlwriter/compare/4.0.0...4.0.1) 11 | -------------------------------------------------------------------------------- /.changes/4.1.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.1.0 - 2024-05-22 3 | 4 | > [!IMPORTANT] This version is the last to support PHP 8.1 5 | 6 | ### Added 7 | 8 | - New autoloader (`autoload.php`) that is able to respect custom `vendor-dir` configuration 9 | 10 | ### Removed 11 | 12 | - Bootstrap file (`bootstrap.php`) that is replaced by new autoloader (`autoload.php`) 13 | 14 | **Full Changelog**: [4.0.1...4.1.0](https://github.com/llaville/umlwriter/compare/4.0.1...4.1.0) 15 | -------------------------------------------------------------------------------- /.changes/4.2.0.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.2.0 - 2024-05-23 3 | 4 | ### Removed 5 | 6 | - support to PHP 8.1 7 | 8 | **Full Changelog**: [4.1.0...4.2.0](https://github.com/llaville/umlwriter/compare/4.1.0...4.2.0) 9 | -------------------------------------------------------------------------------- /.changes/4.2.1.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.2.1 - 2024-11-18 3 | 4 | This release should be considered as a maintenance version that is compatible with PHP 8.4 5 | 6 | ### Added 7 | 8 | - support to PHP 8.4 9 | 10 | **Full Changelog**: [4.2.0...4.2.1](https://github.com/llaville/umlwriter/compare/4.2.0...4.2.1) 11 | -------------------------------------------------------------------------------- /.changes/4.2.2.md: -------------------------------------------------------------------------------- 1 | 2 | ## 4.2.2 - 2024-12-03 3 | 4 | This release should be considered as a maintenance version that is fully compatible with PHP 8.4 5 | 6 | Especially due to publication of `roave/better-reflection` [6.44.0](https://github.com/Roave/BetterReflection/releases/tag/6.44.0) 7 | 8 | **Full Changelog**: [4.2.1...4.2.2](https://github.com/llaville/umlwriter/compare/4.2.0...4.2.1) 9 | -------------------------------------------------------------------------------- /.changes/header.tpl.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes in 4.x 3 | 4 | All notable changes of the UmlWriter 3 release series will be documented in this file. 5 | 6 | This project adheres to [Semantic Versioning](http://semver.org/), 7 | using the [Keep a CHANGELOG](http://keepachangelog.com) principles. 8 | and is generated by [Changie](https://github.com/miniscruff/changie). 9 | -------------------------------------------------------------------------------- /.changes/unreleased/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llaville/umlwriter/009f931493d6f70a22b92e04e064ff5491a693f6/.changes/unreleased/.gitkeep -------------------------------------------------------------------------------- /.changie.yaml: -------------------------------------------------------------------------------- 1 | changesDir: .changes 2 | unreleasedDir: unreleased 3 | headerPath: header.tpl.md 4 | changelogPath: CHANGELOG.md 5 | versionExt: md 6 | versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}' 7 | kindFormat: '### {{.Kind}}' 8 | changeFormat: '- {{.Body}}' 9 | kinds: 10 | - label: Added 11 | auto: minor 12 | - label: Changed 13 | auto: minor 14 | - label: Deprecated 15 | auto: patch 16 | - label: Removed 17 | auto: minor 18 | - label: Fixed 19 | auto: patch 20 | - label: Security 21 | auto: patch 22 | newlines: 23 | afterHeaderTemplate: 0 24 | beforeKind: 1 25 | afterKind: 1 26 | beforeVersion: 1 27 | endOfVersion: 1 28 | envPrefix: CHANGIE_ 29 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://editorconfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.bat] 15 | end_of_line = crlf 16 | 17 | # PHP should follow the PSR-2 standard 18 | [*.php] 19 | indent_size = 4 20 | 21 | [*.gv] 22 | trim_trailing_whitespace = false 23 | 24 | [*.puml] 25 | trim_trailing_whitespace = false 26 | 27 | [*.md] 28 | indent_size = unset 29 | -------------------------------------------------------------------------------- /.github/linters/.ecrc: -------------------------------------------------------------------------------- 1 | { 2 | "Verbose": false, 3 | "Debug": false, 4 | "IgnoreDefaults": false, 5 | "SpacesAftertabs": false, 6 | "NoColor": false, 7 | "Exclude": ["\\.idea", "\\.editorconfig", "\\.github", "vendor", "LICENSE", "mkdocs\\.yml", "**/*\\.gv", "**/*\\.puml", "\\.changes"], 8 | "AllowedContentTypes": [], 9 | "PassedFiles": [], 10 | "Disable": { 11 | "EndOfLine": false, 12 | "Indentation": false, 13 | "InsertFinalNewline": false, 14 | "TrimTrailingWhitespace": false, 15 | "IndentSize": false, 16 | "MaxLineLength": false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/linters/.phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 6 | My custom coding standard. 7 | 8 | ../../src 9 | ../../examples 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/linters/.phplint.yml: -------------------------------------------------------------------------------- 1 | path: . 2 | jobs: 5 3 | extensions: 4 | - php 5 | exclude: 6 | - tests/fixtures 7 | - vendor 8 | warning: false 9 | -------------------------------------------------------------------------------- /.github/linters/phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | paths: 4 | - ../../src/ 5 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Docker 3 | 4 | on: 5 | workflow_dispatch: 6 | # https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/ 7 | inputs: 8 | tag: 9 | description: "The Docker Image Tag" 10 | required: false 11 | default: "latest" 12 | type: string 13 | #push: 14 | # branches: 15 | # - 'master' 16 | 17 | jobs: 18 | build: 19 | env: 20 | DOCKER_BUILD_TAG: llaville/umlwriter:${{ github.event.inputs.tag || 'latest' }} 21 | 22 | runs-on: ubuntu-22.04 23 | 24 | steps: 25 | - # https://github.com/actions/checkout 26 | name: Checkout code 27 | uses: actions/checkout@v4 28 | 29 | - # https://github.com/docker/setup-qemu-action 30 | name: Set up QEMU 31 | uses: docker/setup-qemu-action@v3 32 | 33 | - # https://github.com/docker/setup-buildx-action 34 | name: Set up Docker Buildx 35 | uses: docker/setup-buildx-action@v3 36 | 37 | - # https://github.com/docker/login-action 38 | name: Login to DockerHub 39 | uses: docker/login-action@v3 40 | with: 41 | registry: ghcr.io 42 | username: ${{ secrets.DOCKER_USERNAME }} 43 | password: ${{ secrets.DOCKER_PASSWORD }} 44 | 45 | - # https://github.com/docker/build-push-action 46 | name: Build and push Docker images 47 | uses: docker/build-push-action@v5 48 | with: 49 | push: true 50 | tags: ${{ env.DOCKER_BUILD_TAG }} 51 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: GitHub-Pages 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | - "4.2" 9 | paths: 10 | - docs/** 11 | pull_request: 12 | workflow_dispatch: 13 | 14 | jobs: 15 | deploy: 16 | uses: llaville/.github/.github/workflows/gh-pages.yml@master 17 | with: 18 | destination-dir: "4.2" 19 | hook-script: "resources/gh-pages-hook.sh" 20 | force-orphan: false 21 | graph-uml: false 22 | php-version: "8.2" 23 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release 3 | 4 | on: 5 | push: 6 | tags: 7 | - "[0-9]+.[0-9]+.[0-9]+" 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: write 12 | 13 | jobs: 14 | tests: 15 | uses: ./.github/workflows/unit-tests.yaml 16 | 17 | build: 18 | needs: tests 19 | 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: 26 | - ubuntu-22.04 27 | php: 28 | - 8.2 29 | tools: 30 | - box:4.6 # available since https://github.com/shivammathur/setup-php/releases/tag/2.27.0 31 | 32 | steps: 33 | - # https://github.com/actions/checkout 34 | name: Checkout 35 | uses: actions/checkout@v4 36 | 37 | - # https://github.com/shivammathur/setup-php 38 | name: Setup PHP runtime 39 | uses: shivammathur/setup-php@v2 40 | with: 41 | php-version: ${{ matrix.php }} 42 | coverage: "none" 43 | tools: ${{ matrix.tools }} 44 | 45 | - # https://getcomposer.org/doc/06-config.md#platform 46 | name: Setup Composer Platform 47 | run: | 48 | composer config platform.php 8.2 49 | 50 | - # https://github.com/ramsey/composer-install 51 | name: Install Composer dependencies 52 | uses: ramsey/composer-install@v3 53 | with: 54 | composer-options: "--prefer-dist" 55 | env: # https://github.com/ramsey/composer-install?tab=readme-ov-file#fork-and-private-repositories 56 | COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_AUTH }}"}}' 57 | 58 | - # https://github.com/llaville/box-manifest 59 | name: Download BOX Manifest Artifact 60 | env: 61 | BOX_MANIFEST_VERSION: ${{ vars.BOX_MANIFEST_VERSION || '4.1.1' }} 62 | run: | 63 | curl -Ls "https://github.com/llaville/box-manifest/releases/download/$BOX_MANIFEST_VERSION/box-manifest.phar" -o /usr/local/bin/box-manifest 64 | chmod +x /usr/local/bin/box-manifest 65 | 66 | - # https://github.com/llaville/box-manifest 67 | name: Build Release Artifact 68 | run: | 69 | box-manifest make build stub configure -r console-table.txt -r plain.txt -r sbom.json --output-stub stub.php --output-conf box.json.dist -vvv --ansi 70 | box compile -c box.json.dist -vvv --ansi 71 | 72 | - # https://github.com/softprops/action-gh-release 73 | name: Create Release from current tag 74 | if: github.ref_type == 'tag' 75 | uses: softprops/action-gh-release@v2 76 | with: # https://github.com/softprops/action-gh-release#-customizing 77 | prerelease: false 78 | draft: false 79 | body_path: ${{ github.workspace }}/.changes/${{ github.ref_name }}.md 80 | # https://github.com/softprops/action-gh-release#%EF%B8%8F-uploading-release-assets 81 | files: 82 | ${{ github.workspace }}/bin/umlwriter.phar 83 | fail_on_unmatched_files: true 84 | tag_name: ${{ github.ref_name }} 85 | -------------------------------------------------------------------------------- /.github/workflows/unit-tests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Unit Tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - master 8 | - "4.2" 9 | paths-ignore: 10 | - 'docs/**' 11 | workflow_call: 12 | 13 | jobs: 14 | lint_files: 15 | uses: llaville/.github/.github/workflows/mega-linter.yml@master 16 | with: 17 | repository: ${{ github.repository }} 18 | php-version: "8.2" 19 | 20 | unit_tests: 21 | needs: lint_files 22 | 23 | runs-on: ${{ matrix.os }} 24 | 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | os: 29 | - ubuntu-22.04 30 | php: 31 | - 8.2 32 | - 8.3 33 | - 8.4 34 | 35 | name: UML Class Writer 36 | 37 | steps: 38 | - # https://github.com/actions/checkout 39 | name: Checkout 40 | uses: actions/checkout@v4 41 | 42 | - # https://github.com/shivammathur/setup-php 43 | name: Setup PHP runtime 44 | uses: shivammathur/setup-php@v2 45 | with: 46 | php-version: ${{ matrix.php }} 47 | coverage: "none" 48 | 49 | - # https://github.com/ramsey/composer-install 50 | name: Install Composer dependencies 51 | uses: ramsey/composer-install@v3 52 | with: 53 | composer-options: "--prefer-dist" 54 | 55 | - # https://github.com/sebastianbergmann/phpunit/tree/10.5 56 | name: Unit tests with PHPUnit 10 57 | run: vendor/bin/phpunit --testdox --do-not-cache-result --no-progress 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # CUSTOM 3 | ###################################### 4 | 5 | site/ 6 | docs/assets/images/ 7 | 8 | ###### Composer dependencies ###### 9 | vendor/ 10 | 11 | ###### PHPLint ###### 12 | .phplint.cache/ 13 | 14 | ###### PHPUnit ###### 15 | .phpunit.cache/ 16 | 17 | ###### Mega-Linter ###### 18 | megalinter-reports/ 19 | 20 | ###################################### 21 | # GENERIC 22 | ###################################### 23 | 24 | ###### std ###### 25 | *.lock 26 | *.log 27 | 28 | ###### patches/diffs ###### 29 | *.patch 30 | *.diff 31 | *.orig 32 | *.rej 33 | 34 | ###### archives ###### 35 | *.tgz 36 | *.zip 37 | *.phar 38 | 39 | ###### git ###### 40 | .gitignore 41 | # cannot ignore .github folder because Mega-Linter ACTION_ACTIONLINT be check 42 | .git 43 | 44 | ###################################### 45 | # Operating Systems 46 | ###################################### 47 | 48 | ###### OSX ###### 49 | ._* 50 | .DS* 51 | .Spotlight-V100 52 | .Trashes 53 | 54 | ###### Windows ###### 55 | Thumbs.db 56 | ehthumbs.db 57 | Desktop.ini 58 | $RECYCLE.BIN/ 59 | *.lnk 60 | 61 | 62 | ###################################### 63 | # Editors 64 | ###################################### 65 | 66 | ###### Sublime ###### 67 | *.sublime-workspace 68 | *.sublime-project 69 | 70 | ###### Eclipse ###### 71 | .classpath 72 | .buildpath 73 | .project 74 | .settings/ 75 | 76 | ###### Netbeans ###### 77 | nbproject/private/ 78 | 79 | ###### Intellij IDE ###### 80 | .idea/ 81 | .idea_modules/ 82 | 83 | ###### vim ###### 84 | *.swp 85 | *.swo 86 | *~ 87 | 88 | ###### TextMate ###### 89 | .tm_properties 90 | *.tmproj 91 | 92 | ###### BBEdit ###### 93 | *.bbprojectd 94 | *.bbproject 95 | -------------------------------------------------------------------------------- /.mega-linter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | PRINT_ALPACA: false 3 | SHOW_ELAPSED_TIME: true 4 | EXCLUDED_DIRECTORIES: [".git", ".changes"] 5 | IGNORE_GITIGNORED_FILES: true 6 | ENABLE: 7 | - ACTION 8 | - DOCKERFILE 9 | - EDITORCONFIG 10 | - JSON 11 | - MARKDOWN 12 | - PHP 13 | - YAML 14 | DISABLE_LINTERS: 15 | - JSON_PRETTIER 16 | - JSON_V8R 17 | - MARKDOWN_MARKDOWN_TABLE_FORMATTER 18 | - MARKDOWN_MARKDOWN_LINK_CHECK 19 | - PHP_BUILTIN 20 | - PHP_PHPCSFIXER 21 | - PHP_PSALM 22 | - YAML_V8R 23 | DOCKERFILE_HADOLINT_ARGUMENTS: "-t error" 24 | EDITORCONFIG_EDITORCONFIG_CHECKER_CLI_LINT_MODE: project 25 | MARKDOWN_MARKDOWNLINT_CONFIG_FILE: ".markdown-lint.json" 26 | MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: "(\\.github)" 27 | PHP_PHPSTAN_CLI_LINT_MODE: project # to avoid https://github.com/nvuillam/mega-linter/issues/725 28 | PHP_PHPSTAN_DISABLE_ERRORS: true # because this project is not yet compatible with PHPStan 2.0 embedded with MegaLinter 8.2.0 or greater 29 | PHP_PHPCS_CLI_LINT_MODE: project 30 | PHP_PHPCS_CONFIG_FILE: ".phpcs.xml.dist" 31 | PHP_PHPCS_ARGUMENTS: "-n" 32 | PHP_PHPLINT_CLI_LINT_MODE: project 33 | PHP_PHPLINT_ARGUMENTS: "--no-cache" 34 | YAML_PRETTIER_FILTER_REGEX_EXCLUDE: "(\\.github|mkdocs\\.yml|\\.mega-linter\\.yml|\\.changie\\.yaml)" # As it cannot be added in .gitignore for ML actionlint linter 35 | YAML_YAMLLINT_FILTER_REGEX_EXCLUDE: "(\\.github|mkdocs\\.yml)" # As it cannot be added in .gitignore for ML actionlint linter 36 | CONFIG_REPORTER: false 37 | UPDATED_SOURCES_REPORTER: false 38 | CONSOLE_REPORTER: true 39 | LOG_LEVEL: INFO 40 | PRINT_ALL_FILES: false 41 | -------------------------------------------------------------------------------- /CHANGELOG-1.x.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes in 1.x 3 | 4 | All notable changes of the UmlWriter 1 release series will be documented in this file. 5 | 6 | This project adheres to [Semantic Versioning](http://semver.org/), 7 | using the [Keep a CHANGELOG](http://keepachangelog.com) principles. 8 | 9 | ## 1.3.1 - 2019-11-24 10 | 11 | ### Added 12 | 13 | introduced this CHANGELOG file. See request [#10](https://github.com/llaville/umlwriter/issues/10) by Remi Collet 14 | 15 | ### Security 16 | 17 | security alert [CVE-2019-10910](https://github.com/advisories/GHSA-pgwj-prpq-jpc2) fixed 18 | 19 | ## 1.3.0 - 2018-11-26 20 | 21 | ### Added 22 | 23 | add support to PHP-Parser 3.1 for running on PHP >= 5.5 and for parsing PHP 5.2 to PHP 7.2 24 | 25 | ## 1.2.0 - 2017-02-28 26 | 27 | ### Changed 28 | 29 | allow symfony components v3 30 | 31 | ## 1.1.0 - 2015-12-09 32 | 33 | ### Removed 34 | 35 | drop support to PHP 5.3 36 | 37 | ## 1.0.0 - 2015-04-02 38 | 39 | first stable release 40 | -------------------------------------------------------------------------------- /CHANGELOG-2.x.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes in 2.x 3 | 4 | All notable changes of the UmlWriter 2 release series will be documented in this file. 5 | 6 | This project adheres to [Semantic Versioning](http://semver.org/), 7 | using the [Keep a CHANGELOG](http://keepachangelog.com) principles. 8 | 9 | ## 2.1.1 - 2022-01-04 10 | 11 | ### Changed 12 | 13 | - raise `bartlett/graph-uml` constraint to be compatible with `graphp/*` packages and patch provided 14 | 15 | ### Fixed 16 | 17 | - `graphp/graph` constraint to specific commit compatible with patch provided (see `patches` directory) 18 | - `graphp/graphviz` constraint to specific commit compatible with patch provided (see `patches` directory) 19 | 20 | ## 2.1.0 - 2021-12-25 21 | 22 | ### Added 23 | 24 | - `no-statement` option to `diagram:class` command to hide diagram statements (displayed by default) 25 | - more examples, used to generate dynamically diagrams for documentation 26 | 27 | ### Changed 28 | 29 | - update all examples to generate image in target folder, if provided as first argument 30 | - CI generated svg images dynamically to be sure to have the latest version 31 | - raise `bartlett/graph-uml` and `bartlett/graph-plantuml-generator` minimum version 32 | 33 | ## 2.0.0 - 2021-12-02 34 | 35 | ### Changed 36 | 37 | - switch LICENSE from BSD 3-Clause "New" or "Revised" License to MIT 38 | - migrate from `goaop/parser-reflection` v2 to `roave/better-reflection` v4 (PHP 8 not yet compatible) 39 | - only PHP 7 compatible 40 | 41 | ## 2.0.0-rc.3 - 2021-11-20 42 | 43 | ### Changed 44 | 45 | - Allow installation with PHP 8 46 | - Remove `graphp/graphviz` fork usage since `bartlett/graph-uml` 1.0.0-rc.3 47 | - Patch `graphp/graphviz` package with rather than using forks with branches 48 | 49 | If you need a good introduction about vendor patches, 50 | read this excellent article 51 | 52 | ## 2.0.0-rc.2 - 2019-09-10 53 | 54 | ### Changed 55 | 56 | - raise `bartlett/graph-uml` and `bartlett/graph-plantuml-generator` dependencies to version `1.0.0-rc.2` 57 | 58 | ## 2.0.0-rc.1 - 2019-05-31 59 | 60 | ### Added 61 | 62 | - add `--output` option to save image in a file. 63 | - add `--format` option to specify what is the format of image to build. 64 | 65 | ### Changed 66 | 67 | - change case of options names 68 | from [Kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles) to [Snake case](https://en.wikipedia.org/wiki/Snake_case) 69 | 70 | ### Fixed 71 | 72 | - usage of Symfony OptionsResolver Component in **ConfigurationHandler** 73 | - usage of Symfony Finder allows now to parse a combination of folder and file at same times. 74 | See `docs/01_Features/umlwriter_config.svg` for example. 75 | 76 | ## 2.0.0-beta.3 - 2019-05-14 77 | 78 | ### Added 79 | 80 | - introduces `ContainerService` class implement `psr/container` to handle all internal and runtime services. 81 | - support of EditorConfig () 82 | - be able to personalize graph render (at least colors and orientation) 83 | - add some new options to `diagram:class` command: 84 | - `--without-constants` to hide all class constants 85 | - `--without-properties` to hide all class properties 86 | - `--without-methods` to hide all class methods 87 | - `--hide-private` to hide private methods/properties 88 | - `--hide-protected` to hide protected methods/properties 89 | - introduces support of external YAML config file that is loaded by `--configuration` option 90 | 91 | ### Changed 92 | 93 | - `diagram:class` command accept multiple data sources (file or directory) at same time. 94 | - console commands used now lazy loading (see ) 95 | 96 | ## 2.0.0-beta.2 - 2019-05-03 97 | 98 | ### Added 99 | 100 | - UmlWriter 2.0 is now able to build UML Class diagrams in PlantUML format. 101 | - provides `plantuml.jar` to draw images locally (with help of project) 102 | 103 | ## 2.0.0-beta.1 - 2019-04-24 104 | 105 | Two years after [GH-8](https://github.com/llaville/umlwriter/issues/8) report was written, 106 | PHP 7 compatibility is now up and ready with this first new major pre-release version. 107 | 108 | UmlWriter 2.0 become a simple facade to [graph-uml](https://github.com/llaville/graph-uml) project 109 | that is able to produce UML diagrams with GraphViz backend. More backends will come later ! 110 | 111 | Unit tests and documentation should be re-write, and will be available in next pre-release (2.0.0-beta.2) 112 | -------------------------------------------------------------------------------- /CHANGELOG-3.x.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes in 3.x 3 | 4 | All notable changes of the UmlWriter 3 release series will be documented in this file. 5 | 6 | This project adheres to [Semantic Versioning](http://semver.org/), 7 | using the [Keep a CHANGELOG](http://keepachangelog.com) principles. 8 | and is generated by [Changie](https://github.com/miniscruff/changie). 9 | 10 | ## 3.4.0 - 2023-04-11 11 | 12 | ### Added 13 | 14 | - support to PHPUnit 10 15 | - Provides docker image that only support Graphviz generator (no PlantUML yet supported) 16 | 17 | ### Changed 18 | 19 | - migrate configuration for PHPUnit 10 20 | 21 | ### Fixed 22 | 23 | - as per [Lock down include wrappers to avoid abuse from third parties](https://github.com/composer/composer/pull/11015), we replaced `Composer\Autoload\includeFile` 24 | 25 | **Full Changelog**: [3.3.0...3.4.0](https://github.com/llaville/umlwriter/compare/3.3.0...3.4.0) 26 | 27 | ## 3.3.0 - 2022-12-17 28 | 29 | ### Changed 30 | 31 | - add support to `roave/better-reflection` v6 32 | - Upgrade `psr/container` dependency by adding support to v2 33 | 34 | ### Removed 35 | 36 | - Drop support for Symfony 4 and allow Symfony 6 support 37 | 38 | **Full Changelog**: [3.2.1...3.3.0](https://github.com/llaville/umlwriter/compare/3.2.1...3.3.0) 39 | 40 | ## 3.2.1 - 2022-09-12 41 | 42 | ### Changed 43 | 44 | - synchronize with latest commit of `graphp/graphviz` project 45 | - use `bartlett/graph-uml` recent version 1.3.0 46 | 47 | **Full Changelog**: [3.2.0...3.2.1](https://github.com/llaville/umlwriter/compare/3.2.0...3.2.1) 48 | 49 | ## 3.2.0 - 2022-02-26 50 | 51 | ### Added 52 | 53 | - support for Symfony 6.x components 54 | - `release` workflow to automate creating a new GitHub release with PHAR artifact (that contains a manifest) 55 | 56 | ### Changed 57 | 58 | - PHAR manifest (simple text format) is built with `bartlett/box-manifest` package 59 | - Application version used now the [Composer runtime API 2.0](https://getcomposer.org/doc/07-runtime.md) to get packages installed 60 | 61 | ### Removed 62 | 63 | - `Bartlett\UmlWriter\Console\Application::VERSION` constant. 64 | 65 | **Full Changelog**: [3.1.1...3.2.0](https://github.com/llaville/umlwriter/compare/3.1.1...3.2.0) 66 | 67 | ## 3.1.1 - 2022-01-04 68 | 69 | ### Changed 70 | 71 | - raise `bartlett/graph-uml` constraint to be compatible with `graphp/*` packages and patch provided 72 | 73 | ### Fixed 74 | 75 | - `graphp/graph` constraint to specific commit compatible with patch provided (see `patches` directory) 76 | - `graphp/graphviz` constraint to specific commit compatible with patch provided (see `patches` directory) 77 | 78 | **Full Changelog**: [3.1.0...3.1.1](https://github.com/llaville/umlwriter/compare/3.1.0...3.1.1) 79 | 80 | ## 3.1.0 - 2022-01-03 81 | 82 | ### Added 83 | 84 | - `manifest` option to show PHAR metadata contents (dependencies embedded) 85 | 86 | ### Changed 87 | 88 | - `.github/workflows/gh-pages.yml` workflow to generate dynamically UML graphs 89 | - simplify examples now `resources/graph-uml/build.php` script exists 90 | 91 | ### Fixed 92 | 93 | - Composer 2.2 plugins compatibility 94 | 95 | **Full Changelog**: [3.0.0...3.1.0](https://github.com/llaville/umlwriter/compare/3.0.0...3.1.0) 96 | 97 | ## 3.0.0 - 2021-12-26 98 | 99 | This major version is only PHP 8 compatible. 100 | 101 | ### Changed 102 | 103 | - Support **Typed properties** features, now minimum PHP requirement is 8.0 104 | 105 | Read more about this feature at : 106 | 107 | - 108 | - 109 | 110 | **Full Changelog**: [2.1.1...3.0.0](https://github.com/llaville/umlwriter/compare/2.1.1...3.0.0) 111 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes in 4.x 3 | 4 | All notable changes of the UmlWriter 3 release series will be documented in this file. 5 | 6 | This project adheres to [Semantic Versioning](http://semver.org/), 7 | using the [Keep a CHANGELOG](http://keepachangelog.com) principles. 8 | and is generated by [Changie](https://github.com/miniscruff/changie). 9 | 10 | ## 4.2.2 - 2024-12-03 11 | 12 | This release should be considered as a maintenance version that is fully compatible with PHP 8.4 13 | 14 | Especially due to publication of `roave/better-reflection` [6.44.0](https://github.com/Roave/BetterReflection/releases/tag/6.44.0) 15 | 16 | **Full Changelog**: [4.2.1...4.2.2](https://github.com/llaville/umlwriter/compare/4.2.0...4.2.1) 17 | 18 | ## 4.2.1 - 2024-11-18 19 | 20 | This release should be considered as a maintenance version that is compatible with PHP 8.4 21 | 22 | ### Added 23 | 24 | - support to PHP 8.4 25 | 26 | **Full Changelog**: [4.2.0...4.2.1](https://github.com/llaville/umlwriter/compare/4.2.0...4.2.1) 27 | 28 | ## 4.2.0 - 2024-05-23 29 | 30 | ### Removed 31 | 32 | - support to PHP 8.1 33 | 34 | **Full Changelog**: [4.1.0...4.2.0](https://github.com/llaville/umlwriter/compare/4.1.0...4.2.0) 35 | 36 | ## 4.1.0 - 2024-05-22 37 | 38 | > [!IMPORTANT] This version is the last to support PHP 8.1 39 | 40 | ### Added 41 | 42 | - New autoloader (`autoload.php`) that is able to respect custom `vendor-dir` configuration 43 | 44 | ### Removed 45 | 46 | - Bootstrap file (`bootstrap.php`) that is replaced by new autoloader (`autoload.php`) 47 | 48 | **Full Changelog**: [4.0.1...4.1.0](https://github.com/llaville/umlwriter/compare/4.0.1...4.1.0) 49 | 50 | ## 4.0.1 - 2023-12-27 51 | 52 | No code changed since 4.0.0 53 | 54 | ### Fixed 55 | 56 | - BOX config file `box.json.dist` syntax error 57 | 58 | **Full Changelog**: [4.0.0...4.0.1](https://github.com/llaville/umlwriter/compare/4.0.0...4.0.1) 59 | 60 | ## 4.0.0 - 2023-12-27 61 | 62 | ### Added 63 | 64 | - Allows Symfony 7 65 | 66 | ### Changed 67 | 68 | - replaces support from old Symfony LTS version (5.4) to new one (6.4) 69 | - `ClassDiagramRenderer::__invoke` method accept now either a Symfony `Finder` instance or a PHP `Generator` as first argument to identify the datasource, and return a Graph object instead of the statement results 70 | 71 | ### Removed 72 | 73 | - drop support to PHP 8.0 74 | - drop support to PHPUnit 9 75 | 76 | **Full Changelog**: [3.4.0...4.0.0](https://github.com/llaville/umlwriter/compare/3.4.0...4.0.0) 77 | 78 | ## 3.4.0 - 2023-04-11 79 | 80 | ### Added 81 | 82 | - support to PHPUnit 10 83 | - Provides docker image that only support Graphviz generator (no PlantUML yet supported) 84 | 85 | ### Changed 86 | 87 | - migrate configuration for PHPUnit 10 88 | 89 | ### Fixed 90 | 91 | - as per [Lock down include wrappers to avoid abuse from third parties](https://github.com/composer/composer/pull/11015), we replaced `Composer\Autoload\includeFile` 92 | 93 | **Full Changelog**: [3.3.0...3.4.0](https://github.com/llaville/umlwriter/compare/3.3.0...3.4.0) 94 | 95 | ## 3.3.0 - 2022-12-17 96 | 97 | ### Changed 98 | 99 | - add support to `roave/better-reflection` v6 100 | - Upgrade `psr/container` dependency by adding support to v2 101 | 102 | ### Removed 103 | 104 | - Drop support for Symfony 4 and allow Symfony 6 support 105 | 106 | **Full Changelog**: [3.2.1...3.3.0](https://github.com/llaville/umlwriter/compare/3.2.1...3.3.0) 107 | 108 | ## 3.2.1 - 2022-09-12 109 | 110 | ### Changed 111 | 112 | - synchronize with latest commit of `graphp/graphviz` project 113 | - use `bartlett/graph-uml` recent version 1.3.0 114 | 115 | **Full Changelog**: [3.2.0...3.2.1](https://github.com/llaville/umlwriter/compare/3.2.0...3.2.1) 116 | 117 | ## 3.2.0 - 2022-02-26 118 | 119 | ### Added 120 | 121 | - support for Symfony 6.x components 122 | - `release` workflow to automate creating a new GitHub release with PHAR artifact (that contains a manifest) 123 | 124 | ### Changed 125 | 126 | - PHAR manifest (simple text format) is built with `bartlett/box-manifest` package 127 | - Application version used now the [Composer runtime API 2.0](https://getcomposer.org/doc/07-runtime.md) to get packages installed 128 | 129 | ### Removed 130 | 131 | - `Bartlett\UmlWriter\Console\Application::VERSION` constant. 132 | 133 | **Full Changelog**: [3.1.1...3.2.0](https://github.com/llaville/umlwriter/compare/3.1.1...3.2.0) 134 | 135 | ## 3.1.1 - 2022-01-04 136 | 137 | ### Changed 138 | 139 | - raise `bartlett/graph-uml` constraint to be compatible with `graphp/*` packages and patch provided 140 | 141 | ### Fixed 142 | 143 | - `graphp/graph` constraint to specific commit compatible with patch provided (see `patches` directory) 144 | - `graphp/graphviz` constraint to specific commit compatible with patch provided (see `patches` directory) 145 | 146 | **Full Changelog**: [3.1.0...3.1.1](https://github.com/llaville/umlwriter/compare/3.1.0...3.1.1) 147 | 148 | ## 3.1.0 - 2022-01-03 149 | 150 | ### Added 151 | 152 | - `manifest` option to show PHAR metadata contents (dependencies embedded) 153 | 154 | ### Changed 155 | 156 | - `.github/workflows/gh-pages.yml` workflow to generate dynamically UML graphs 157 | - simplify examples now `resources/graph-uml/build.php` script exists 158 | 159 | ### Fixed 160 | 161 | - Composer 2.2 plugins compatibility 162 | 163 | **Full Changelog**: [3.0.0...3.1.0](https://github.com/llaville/umlwriter/compare/3.0.0...3.1.0) 164 | 165 | ## 3.0.0 - 2021-12-26 166 | 167 | This major version is only PHP 8 compatible. 168 | 169 | ### Changed 170 | 171 | - Support **Typed properties** features, now minimum PHP requirement is 8.0 172 | 173 | Read more about this feature at : 174 | 175 | - 176 | - 177 | 178 | **Full Changelog**: [2.1.1...3.0.0](https://github.com/llaville/umlwriter/compare/2.1.1...3.0.0) 179 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.4 2 | ARG PHP_VERSION=8.2 3 | 4 | FROM php:${PHP_VERSION}-cli-alpine 5 | 6 | # https://github.com/opencontainers/image-spec/blob/main/annotations.md 7 | 8 | LABEL org.opencontainers.image.title="llaville/umlwriter" 9 | LABEL org.opencontainers.image.description="Docker image of bartlett/umlwriter Composer package" 10 | LABEL org.opencontainers.image.source="https://github.com/llaville/umlwriter" 11 | LABEL org.opencontainers.image.licenses="MIT" 12 | LABEL org.opencontainers.image.authors="llaville" 13 | 14 | COPY entrypoint.sh /entrypoint.sh 15 | RUN chmod +x /entrypoint.sh \ 16 | && cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini 17 | 18 | # Install dependencies 19 | RUN apk add --no-cache --update git bash graphviz ttf-dejavu 20 | 21 | # Create a group and user 22 | RUN addgroup appgroup && adduser appuser -D -G appgroup 23 | 24 | # Tell docker that all future commands should run as the appuser user 25 | USER appuser 26 | 27 | # Install Composer v2 binary version 28 | COPY --from=composer/composer:2-bin /composer /usr/bin/composer 29 | ENV COMPOSER_ALLOW_SUPERUSER 1 30 | ENV COMPOSER_PREFER_STABLE 1 31 | RUN composer global config allow-plugins.cweagans/composer-patches true && \ 32 | composer global config minimum-stability dev && \ 33 | composer global require --no-progress bartlett/umlwriter ^4 34 | 35 | # Following recommendation at https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#workdir 36 | 37 | ENTRYPOINT ["/entrypoint.sh"] 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2024 Laurent Laville 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 10 | furnished 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # UmlWriter 3 | 4 | [![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) 5 | [![GitHub Discussions](https://img.shields.io/github/discussions/llaville/umlwriter)](https://github.com/llaville/umlwriter/discussions) 6 | 7 | | Releases | Branch | PHP | Packagist | License | Documentation | 8 | |:--------------|:-------------------------------------------:|:-------------------------------------------------------------:|:---------------------------------------------------------:|:----------------------------------------------:|:----------------------------------------------------------------:| 9 | | Stable v4.1.x | [![Branch 4.1][Branch_41x-img]][Branch_41x] | [![Minimum PHP Version)][PHPVersion_41x-img]][PHPVersion_41x] | [![Stable Version 4.1][Packagist_41x-img]][Packagist_41x] | [![License 4.1][License_41x-img]][License_41x] | [![Documentation 4.1][Documentation_41x-img]][Documentation_41x] | 10 | | Stable v4.2.x | [![Branch 4.2][Branch_42x-img]][Branch_42x] | [![Minimum PHP Version)][PHPVersion_42x-img]][PHPVersion_42x] | [![Stable Version 4.2][Packagist_42x-img]][Packagist_42x] | [![License 4.2][License_42x-img]][License_42x] | [![Documentation 4.2][Documentation_42x-img]][Documentation_42x] | 11 | 12 | [Branch_41x-img]: https://img.shields.io/badge/branch-4.1-orange 13 | [Branch_41x]: https://github.com/llaville/umlwriter/tree/4.1 14 | [PHPVersion_41x-img]: https://img.shields.io/packagist/php-v/bartlett/umlwriter/4.1.0 15 | [PHPVersion_41x]: https://www.php.net/supported-versions.php 16 | [Packagist_41x-img]: https://img.shields.io/badge/packagist-v4.1.0-blue 17 | [Packagist_41x]: https://packagist.org/packages/bartlett/umlwriter 18 | [License_41x-img]: https://img.shields.io/packagist/l/bartlett/umlwriter 19 | [License_41x]: https://github.com/llaville/umlwriter/blob/4.1/LICENSE 20 | [Documentation_41x-img]: https://img.shields.io/badge/documentation-v4.1-green 21 | [Documentation_41x]: https://github.com/llaville/umlwriter/tree/4.1/docs 22 | 23 | [Branch_42x-img]: https://img.shields.io/badge/branch-4.2-orange 24 | [Branch_42x]: https://github.com/llaville/umlwriter/tree/4.2 25 | [PHPVersion_42x-img]: https://img.shields.io/packagist/php-v/bartlett/umlwriter/4.2.2 26 | [PHPVersion_42x]: https://www.php.net/supported-versions.php 27 | [Packagist_42x-img]: https://img.shields.io/badge/packagist-v4.2.2-blue 28 | [Packagist_42x]: https://packagist.org/packages/bartlett/umlwriter 29 | [License_42x-img]: https://img.shields.io/packagist/l/bartlett/umlwriter 30 | [License_42x]: https://github.com/llaville/umlwriter/blob/4.2/LICENSE 31 | [Documentation_42x-img]: https://img.shields.io/badge/documentation-v4.2-green 32 | [Documentation_42x]: https://github.com/llaville/umlwriter/tree/4.2/docs 33 | 34 | **UmlWriter** is a library that adds the ability to generate UML class diagrams. 35 | 36 | ## Documentation 37 | 38 | All the documentation is available on [website](https://llaville.github.io/umlwriter/4.2), 39 | generated from the [docs](https://github.com/llaville/umlwriter/tree/4.2/docs) folder. 40 | 41 | ## Usage 42 | 43 | This library includes a console CLI version with only one command: `diagram:class` 44 | 45 | ```bash 46 | bin/umlwriter diagram:class src/ 47 | ``` 48 | 49 | **NOTE** use verbose level 1 or 2 for more details. 50 | 51 | ## Contributors 52 | 53 | - Laurent Laville (Lead Developer) 54 | 55 | ## Credits 56 | 57 | [bartlett/graph-uml](https://github.com/llaville/graph-uml) is a refactored version (with more features) of [clue/graph-uml](https://github.com/clue/graph-uml) project, licensed under MIT. 58 | -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | loadClass($class); 31 | } 32 | 33 | private static function getAutoloadFile(): string 34 | { 35 | if (isset($GLOBALS['_composer_autoload_path'])) { 36 | $possibleAutoloadPaths = [ 37 | dirname($GLOBALS['_composer_autoload_path']) 38 | ]; 39 | $autoloader = basename($GLOBALS['_composer_autoload_path']); 40 | } else { 41 | $possibleAutoloadPaths = [ 42 | // local dev repository 43 | __DIR__, 44 | // dependency 45 | dirname(__DIR__, 3), 46 | ]; 47 | $autoloader = 'vendor/autoload.php'; 48 | } 49 | 50 | foreach ($possibleAutoloadPaths as $possibleAutoloadPath) { 51 | if (file_exists($possibleAutoloadPath . DIRECTORY_SEPARATOR . $autoloader)) { 52 | return $possibleAutoloadPath . DIRECTORY_SEPARATOR . $autoloader; 53 | } 54 | } 55 | 56 | throw new \RuntimeException( 57 | sprintf( 58 | 'Unable to find "%s" in "%s" paths.', 59 | $autoloader, 60 | implode('", "', $possibleAutoloadPaths) 61 | ) 62 | ); 63 | } 64 | } 65 | 66 | spl_autoload_register(__NAMESPACE__ . '\Autoload::load', true, true); 67 | } 68 | -------------------------------------------------------------------------------- /bin/umlwriter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 21 | -------------------------------------------------------------------------------- /bin/umlwriter.1: -------------------------------------------------------------------------------- 1 | '\" t 2 | .\" Title: umlwriter 3 | .\" Author: [see the "AUTHORS" section] 4 | .\" Generator: DocBook XSL Stylesheets v1.78.1 5 | .\" Date: 2015-04-02 6 | .\" Manual: \ \& 7 | .\" Source: \ \& 1.0.0 8 | .\" Language: English 9 | .\" 10 | .TH "UMLWRITER" "1" "2015\-04\-02" "\ \& 1\&.0\&.0" "\ \&" 11 | .\" ----------------------------------------------------------------- 12 | .\" * Define some portability stuff 13 | .\" ----------------------------------------------------------------- 14 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | .\" http://bugs.debian.org/507673 16 | .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html 17 | .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | .ie \n(.g .ds Aq \(aq 19 | .el .ds Aq ' 20 | .\" ----------------------------------------------------------------- 21 | .\" * set default formatting 22 | .\" ----------------------------------------------------------------- 23 | .\" disable hyphenation 24 | .nh 25 | .\" disable justification (adjust text to left margin only) 26 | .ad l 27 | .\" ----------------------------------------------------------------- 28 | .\" * MAIN CONTENT STARTS HERE * 29 | .\" ----------------------------------------------------------------- 30 | .SH "NAME" 31 | umlwriter \- Create UML class diagrams from your PHP source 32 | .SH "SYNOPSIS" 33 | .sp 34 | \fBumlwriter\fR [\fIoptions\fR] \fIcommand\fR [\fIarguments\fR] 35 | .SH "DESCRIPTION" 36 | .sp 37 | The umlwriter(1) command parse any data source, and return UML diagram statements in processor format\&. 38 | .SH "OPTIONS" 39 | .PP 40 | \fB\-h, \-\-help\fR 41 | .RS 4 42 | Display this help message\&. 43 | .RE 44 | .PP 45 | \fB\-q, \-\-quiet\fR 46 | .RS 4 47 | Do not output any message\&. 48 | .RE 49 | .PP 50 | \fB\-v|vv|v, \-\-verbose\fR 51 | .RS 4 52 | Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\&. 53 | .RE 54 | .PP 55 | \fB\-V, \-\-version\fR 56 | .RS 4 57 | Display this application version\&. 58 | .RE 59 | .PP 60 | \fB\-\-ansi\fR 61 | .RS 4 62 | Force ANSI output\&. 63 | .RE 64 | .PP 65 | \fB\-\-no\-ansi\fR 66 | .RS 4 67 | Disable ANSI output\&. 68 | .RE 69 | .PP 70 | \fB\-\-manifest\fR 71 | .RS 4 72 | Show which versions of dependencies are bundled (PHAR version only)\&. 73 | .RE 74 | .SH "DIAGRAM:RENDER COMMAND" 75 | .sp 76 | The umlwriter(1) \fIdiagram:render\fR command is used to generate diagram about all objects, present in a data source 77 | .sp 78 | Usage: 79 | .sp 80 | .if n \{\ 81 | .RS 4 82 | .\} 83 | .nf 84 | umlwriter diagram:render [\-\-reflector[="\&.\&.\&."]] [\-\-processor[="\&.\&.\&."]] source 85 | .fi 86 | .if n \{\ 87 | .RE 88 | .\} 89 | .sp 90 | Where: 91 | .sp 92 | \fBsource\fR Identify a data source\&. File or directory 93 | .sp 94 | \fB\-\-reflector\fR Reverse\-engine compatible (case insensitive) (default: "reflect") 95 | .sp 96 | \fB\-\-processor\fR Diagram processor (case insensitive) 97 | .SH "DIAGRAM:RENDER:CLASS COMMAND" 98 | .sp 99 | The umlwriter(1) \fIdiagram:render:class\fR command is used to generate diagram about a single class, and its direct dependencies, present in a data source 100 | .sp 101 | Usage: 102 | .sp 103 | .if n \{\ 104 | .RS 4 105 | .\} 106 | .nf 107 | umlwriter diagram:render:class [\-\-reflector[="\&.\&.\&."]] [\-\-processor[="\&.\&.\&."]] source object 108 | .fi 109 | .if n \{\ 110 | .RE 111 | .\} 112 | .sp 113 | Where: 114 | .sp 115 | \fBsource\fR Identify a data source\&. File or directory 116 | .sp 117 | \fBobject\fR Identify the class (fully qualified name) 118 | .sp 119 | \fB\-\-reflector\fR Reverse\-engine compatible (case insensitive) (default: "reflect") 120 | .sp 121 | \fB\-\-processor\fR Diagram processor (case insensitive) 122 | .SH "DIAGRAM:RENDER:NAMESPACE COMMAND" 123 | .sp 124 | The umlwriter(1) \fIdiagram:render:namespace\fR command is used to generate diagram about a single namespace, with all its objects, present in a data source 125 | .sp 126 | Usage: 127 | .sp 128 | .if n \{\ 129 | .RS 4 130 | .\} 131 | .nf 132 | umlwriter diagram:render:namespace [\-\-reflector[="\&.\&.\&."]] [\-\-processor[="\&.\&.\&."]] source object 133 | .fi 134 | .if n \{\ 135 | .RE 136 | .\} 137 | .sp 138 | Where: 139 | .sp 140 | \fBsource\fR Identify a data source\&. File or directory 141 | .sp 142 | \fBobject\fR Identify the namespace 143 | .sp 144 | \fB\-\-reflector\fR Reverse\-engine compatible (case insensitive) (default: "reflect") 145 | .sp 146 | \fB\-\-processor\fR Diagram processor (case insensitive) 147 | .SH "EXIT STATUS" 148 | .PP 149 | \fB0\fR 150 | .RS 4 151 | Success 152 | .RE 153 | .PP 154 | \fB1\fR 155 | .RS 4 156 | Failure (syntax or usage error; configuration error; unexpected error)\&. 157 | .RE 158 | .SH "BUGS" 159 | .sp 160 | Report any issue at https://github\&.com/llaville/umlwriter/issues 161 | .SH "AUTHORS" 162 | .sp 163 | The Command\-Line Interface (CLI) version was introduced in version 1\&.0 and is written by Laurent Laville\&. 164 | .SH "SEE ALSO" 165 | .sp 166 | Main web site: http://php5\&.laurent\-laville\&.org/umlwriter/ 167 | .SH "COPYRIGHT" 168 | .sp 169 | Copyright (C) 2015 Laurent Laville\&. 170 | .SH "LICENSE" 171 | .sp 172 | Free use of this software is granted under the terms of the BSD 3\-clause license\&. 173 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "alias": "umlwriter.phar", 3 | "directories": [ 4 | "bin", 5 | "src", 6 | "vendor" 7 | ], 8 | "compression": "GZ", 9 | "files": [ 10 | "autoload.php" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /box.json.dist: -------------------------------------------------------------------------------- 1 | { 2 | "alias": "umlwriter.phar", 3 | "directories": [ 4 | "bin", 5 | "src", 6 | "vendor" 7 | ], 8 | "compression": "GZ", 9 | "files": [ 10 | "autoload.php" 11 | ], 12 | "dump-autoload": false, 13 | "files-bin": [ 14 | "console-table.txt", 15 | "plain.txt", 16 | "sbom.json", 17 | ".box.manifests.bin" 18 | ], 19 | "map": [ 20 | { 21 | "console-table.txt": ".box.manifests/console-table.txt" 22 | }, 23 | { 24 | "plain.txt": ".box.manifests/plain.txt" 25 | }, 26 | { 27 | "sbom.json": ".box.manifests/sbom.json" 28 | } 29 | ], 30 | "stub": "stub.php" 31 | } 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bartlett/umlwriter", 3 | "description": "Create UML class diagrams from your PHP source.", 4 | "keywords": ["UML", "Graphviz", "PlantUML"], 5 | "type": "library", 6 | "license": "MIT", 7 | "homepage": "https://github.com/llaville/umlwriter", 8 | "support": { 9 | "source": "https://github.com/llaville/umlwriter", 10 | "issues": "https://github.com/llaville/umlwriter/issues" 11 | }, 12 | "require": { 13 | "php": "^8.2", 14 | "bartlett/graph-plantuml-generator": "^1.6", 15 | "bartlett/graph-uml": "^1.6", 16 | "composer-runtime-api": "^2.0", 17 | "cweagans/composer-patches": "^1.7", 18 | "graphp/graph": "1.x-dev#0adb04d as 1.0.0", 19 | "graphp/graphviz": "1.x-dev#686f747 as 1.0.0", 20 | "psr/container": "^2.0", 21 | "roave/better-reflection": "^6.0", 22 | "symfony/config": "^7.0", 23 | "symfony/console": "^7.0", 24 | "symfony/finder": "^7.0", 25 | "symfony/options-resolver": "^7.0", 26 | "symfony/yaml": "^7.0" 27 | }, 28 | "require-dev": { 29 | "jawira/plantuml": "^1.2024", 30 | "bamarni/composer-bin-plugin": "^1.8" 31 | }, 32 | "authors": [ 33 | { 34 | "name": "Laurent Laville", 35 | "homepage": "https://github.com/llaville", 36 | "role": "Lead" 37 | } 38 | ], 39 | "bin": [ 40 | "bin/umlwriter" 41 | ], 42 | "config": { 43 | "sort-packages": true, 44 | "allow-plugins": { 45 | "bamarni/composer-bin-plugin": true, 46 | "cweagans/composer-patches": true 47 | }, 48 | "preferred-install": { 49 | "graphp/graphviz": "source", 50 | "*": "dist" 51 | } 52 | }, 53 | "autoload": { 54 | "psr-4": { 55 | "Bartlett\\UmlWriter\\": "src/" 56 | } 57 | }, 58 | "autoload-dev": { 59 | "psr-4": { 60 | "Bartlett\\UmlWriter\\Tests\\": "tests/" 61 | } 62 | }, 63 | "extra": { 64 | "enable-patching": true, 65 | "bamarni-bin": { 66 | "bin-links": true, 67 | "target-directory": "vendor-bin", 68 | "forward-command": true 69 | } 70 | }, 71 | "scripts": { 72 | "bin": "echo 'bin not installed'", 73 | "code:check": "vendor/bin/phpstan analyse --configuration .github/linters/phpstan.neon.dist --ansi --verbose", 74 | "code:lint": "vendor/bin/phplint --configuration .github/linters/.phplint.yml --verbose --progress=indicator --ansi", 75 | "style:check": "vendor/bin/phpcs --standard=.github/linters/.phpcs.xml.dist --warning-severity=0 --colors", 76 | "tests:unit": "vendor/bin/phpunit --configuration phpunit.xml.dist" 77 | }, 78 | "scripts-descriptions" : { 79 | "code:check": "Run PHPStan code analysis on project source code", 80 | "code:lint": "Run PHPLint on project source code", 81 | "style:check": "Run PHP CodeSniffer on project source code", 82 | "tests:unit": "Run unit tests on project source code" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /docs/01_Features/Configuration.md: -------------------------------------------------------------------------------- 1 | 2 | # Configuration 3 | 4 | UmlWriter v3 can be configured in two ways (YAML file or console command arguments). 5 | Without changes, following defaults will be applied. 6 | 7 | ## Defaults 8 | 9 | | Option | Value | Default | Description | 10 | |-----------------|----------|----------|----------------------------------------------------------------------------------------------------------------------------------| 11 | | show_constants | boolean | true | whether to show class constants as readonly static variables (or just omit them completely) | 12 | | show_properties | boolean | true | whether to show class properties | 13 | | show_methods | boolean | true | whether to show class or interface methods | 14 | | show_private | boolean | true | whether to also show private methods/properties | 15 | | show_protected | boolean | true | whether to also show protected methods/properties | 16 | | add_parents | boolean | true | whether to show add parent classes or interfaces | 17 | | only_self | boolean | true | whether to only show methods/properties that are actually defined in this class
(and not those merely inherited from base) | 18 | | label_format | string | record | whether to use html or record formatted labels (graphviz specific feature).
Others generator may have different values | 19 | | indent_string | string | ' ' | string to indent graph statement parts (two blanks) | 20 | | paths | array | ['src'] | data source (file or directory) to parse | 21 | | generator | string | graphviz | identification returned by `getName()` method
of a class implementing `Bartlett\GraphUml\Generator\GeneratorInterface` | 22 | | graph.name | string | G | name of the graph | 23 | | graph.overlap | boolean | false | determines if and how node overlaps should be removed.
More details at | 24 | | graph.rankdir | string | TB | sets direction of graph layout (Top to Bottom).
See | 25 | | node.fontname | string | Verdana | font name to use to draw node of the graph | 26 | | node.fontsize | integer | 8 | font size to draw node of the graph | 27 | | node.shape | string | none | set the shape of nodes | 28 | | node.margin | integer | 0 | see for details | 29 | | node.fillcolor | string | #FEFECE | color used to fill background color of nodes.
See | 30 | | node.style | string | filled | see | 31 | | edge.fontname | string | Verdana | font name to use to draw edge of the graph | 32 | | edge.fontsize | integer | 8 | font size to draw edge of the graph | 33 | 34 | ## Console command 35 | 36 | See all arguments and options details in [Console Commands](../02_Console_Commands/diagram_class.md) section. 37 | 38 | ## YAML file (example) 39 | 40 | Attributes to configure graph (node, edge, cluster) may be found at: 41 | 42 | - 43 | 44 | And to configure colors for graphviz and plantuml generators: 45 | 46 | - 47 | - 48 | 49 | ```yaml 50 | parameters: 51 | generator: graphviz 52 | 53 | graph: 54 | name: G 55 | overlap: 'false' 56 | rankdir: LR 57 | bgcolor: transparent 58 | 59 | node: 60 | fillcolor: '#FEFECE' 61 | style: filled 62 | 63 | edge: ~ 64 | 65 | cluster: 66 | Bartlett\UmlWriter\Console: 67 | graph: 68 | bgcolor: BurlyWood 69 | Symfony\Component\Console: 70 | graph: 71 | bgcolor: LightSteelBlue 72 | Symfony\Contracts\Service: 73 | graph: 74 | bgcolor: LightSteelBlue 75 | 76 | paths: 77 | - src/ 78 | 79 | show_constants: true 80 | show_properties: true 81 | show_methods: true 82 | show_private: false 83 | show_protected: false 84 | 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/01_Features/Services.md: -------------------------------------------------------------------------------- 1 | 2 | # Services 3 | 4 | UmlWriter v3 contains two different services. 5 | 6 | * **ContainerService** implements a [PSR-11](https://www.php-fig.org/psr/psr-11/) compatible service container 7 | that allows you to standardize and centralize the way objects are constructed. 8 | 9 | * **ClassDiagramRenderer** that is in charge to add vertices and edges in the graph 10 | corresponding to data source(s) parsed. 11 | 12 | ## Service Container 13 | 14 | We distinguish two kind of services: 15 | 16 | * **internal** like `ClassDiagramRenderer` and `ClassDiagramCommand` that cannot be changed at runtime. 17 | * **runtime** like `InputInterface`, `OutputInterface` and `GeneratorFactoryInterface` (the others) that could be changed. 18 | 19 | ## Class Diagram Renderer 20 | 21 | * Is in charge to add vertices and edge with the `__invoke()` method. 22 | 23 | * `getGraph()` method allows retrieving current graph to let you ability to personalize render by setting graph, node or edge attributes. 24 | 25 | * Is able to retrieve all namespaces, classes, interfaces found during parse data source with `getMetadata()` method. 26 | 27 | ```php 28 | in($dataSource)->name('*.php'); 40 | 41 | $generatorFactory = new GeneratorFactory(); 42 | // creates instance of Bartlett\GraphUml\Generator\GraphVizGenerator 43 | $generator = $generatorFactory->createInstance('graphviz'); 44 | 45 | $renderer = new ClassDiagramRenderer(); 46 | // generates UML class diagram of all objects found in dataSource (in graphviz format) 47 | $graph = $renderer($finder, $generator); 48 | // show all metadata 49 | var_dump($renderer->getMetadata()); 50 | ``` 51 | 52 | That could produce such results (with UmlWriter src directory) 53 | 54 | ```text 55 | array(3) { 56 | ["classes"]=> 57 | array(8) { 58 | [0]=> 59 | string(53) "Bartlett\UmlWriter\Generator\AbstractGeneratorFactory" 60 | [1]=> 61 | string(45) "Bartlett\UmlWriter\Generator\GeneratorFactory" 62 | [2]=> 63 | string(47) "Bartlett\UmlWriter\Service\ConfigurationHandler" 64 | [3]=> 65 | string(47) "Bartlett\UmlWriter\Service\ClassDiagramRenderer" 66 | [4]=> 67 | string(43) "Bartlett\UmlWriter\Service\ContainerService" 68 | [5]=> 69 | string(38) "Bartlett\UmlWriter\Console\Application" 70 | [6]=> 71 | string(54) "Bartlett\UmlWriter\Console\Command\ClassDiagramCommand" 72 | [7]=> 73 | string(47) "Bartlett\UmlWriter\Config\Loader\YamlFileLoader" 74 | } 75 | ["interfaces"]=> 76 | array(1) { 77 | [0]=> 78 | string(54) "Bartlett\UmlWriter\Generator\GeneratorFactoryInterface" 79 | } 80 | ["namespaces"]=> 81 | array(5) { 82 | [0]=> 83 | string(28) "Bartlett\UmlWriter\Generator" 84 | [3]=> 85 | string(26) "Bartlett\UmlWriter\Service" 86 | [6]=> 87 | string(26) "Bartlett\UmlWriter\Console" 88 | [7]=> 89 | string(34) "Bartlett\UmlWriter\Console\Command" 90 | [8]=> 91 | string(32) "Bartlett\UmlWriter\Config\Loader" 92 | } 93 | } 94 | ``` 95 | -------------------------------------------------------------------------------- /docs/02_Console_Commands/diagram_class.md: -------------------------------------------------------------------------------- 1 | 2 | # Class Diagrams 3 | 4 | UmlWriter includes only one command `diagram:class` to print UML class diagram statements. 5 | 6 | ## Features 7 | 8 | * Parse one to many data source (file or directory) at same times with `paths` argument. 9 | * Show (default) or hide all class constants by `--without-constants` option. 10 | * Show (default) or hide all class properties by `--without-properties` option. 11 | * Show (default) or hide all class methods by `--without-methods` option. 12 | * Show (default) or hide private methods and private properties by `--hide-private` options. 13 | * Show (default) or hide protected methods and protected properties by `--hide-protected` options. 14 | * Can be use your own autoloader and initialize what ever you want by `--bootstrap` option. 15 | * Use either `GraphViz`, `PlantUml` or your own generator by `--generator` option. 16 | * Can be able to configure all graph render options and more by `--configuration` option. 17 | 18 | ## Synoptic 19 | 20 | ```text 21 | Description: 22 | Generate class diagram statements of a given data source 23 | 24 | Usage: 25 | diagram:class [options] [--] [...] 26 | 27 | Arguments: 28 | paths Data source (file or directory) 29 | 30 | Options: 31 | -o, --output=OUTPUT Path to output image file 32 | --format=FORMAT Set output format (depending of each generator) 33 | --generator=GENERATOR Graph generator 34 | --executable=EXECUTABLE Generator external binary resource 35 | --bootstrap=BOOTSTRAP A PHP script that is included before graph run 36 | -c, --configuration=CONFIGURATION Read configuration from YAML file 37 | --without-constants Hide all class constants 38 | --without-properties Hide all class properties 39 | --without-methods Hide all class methods 40 | --hide-private Hide private methods/properties 41 | --hide-protected Hide protected methods/properties 42 | --no-statement Do not show diagram statements 43 | -h, --help Display help for the given command. When no command is given display help for the list command 44 | -q, --quiet Do not output any message 45 | -V, --version Display this application version 46 | --ansi|--no-ansi Force (or disable --no-ansi) ANSI output 47 | -n, --no-interaction Do not ask any interactive question 48 | -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug 49 | ``` 50 | 51 | ## Examples 52 | 53 | Here are a list of concrete examples you can find in **Cookbook** 54 | 55 | * Show only public elements in [UmlWriter architecture](../03_Cookbook/01_UmlWriter_public_architecture.md) 56 | * Show only public methods in [UmlWriter architecture](../03_Cookbook/02_UmlWriter_public_methods_only.md) 57 | * Use a [custom autoloader](../03_Cookbook/03_Custom_autoloader.md) 58 | -------------------------------------------------------------------------------- /docs/03_Cookbook/01_UmlWriter_public_architecture.md: -------------------------------------------------------------------------------- 1 | 2 | # Architecture Diagram 3 | 4 | Generate UmlWriter graph architecture with only public elements and default render options. 5 | 6 | ## Console Command 7 | 8 | When you're in project folder, invoke `diagram:class` command with following arguments: 9 | 10 | ```bash 11 | bin/umlwriter diagram:class src/ --hide-private --hide-protected --format=svg 12 | ``` 13 | 14 | Will output this [graph statements](../assets/images/public-architecture.html.gv) and image look like 15 | 16 | ![Graph UML Example](../assets/images/public-architecture.graphviz.svg) 17 | 18 | ## Batch PHP 19 | 20 | Produces same results as previous console command. 21 | 22 | ```php 23 | in($dataSource)->name('*.php'); 33 | 34 | $generatorFactory = new GeneratorFactory(); 35 | // creates instance of Bartlett\GraphUml\Generator\GraphVizGenerator 36 | $generator = $generatorFactory->createInstance('graphviz'); 37 | 38 | $renderer = new ClassDiagramRenderer(); 39 | $options = [ 40 | 'show_private' => false, 41 | 'show_protected' => false, 42 | 'node.fillcolor' => '#FEFECE', 43 | 'node.style' => 'filled', 44 | ]; 45 | // generates UML class diagram of all objects found in dataSource (in graphviz format) 46 | $graph = $renderer($finder, $generator, $options); 47 | 48 | $target = $generator->createImageFile($graph); 49 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/03_Cookbook/02_UmlWriter_public_methods_only.md: -------------------------------------------------------------------------------- 1 | 2 | # Architecture Diagram (public visibility) 3 | 4 | Generate UmlWriter graph architecture with only public methods and default render options. 5 | 6 | ## Console Command 7 | 8 | When you're in project folder, invoke `diagram:class` command with following arguments: 9 | 10 | ```bash 11 | bin/umlwriter diagram:class src/ --hide-private --hide-protected --without-constants --without-properties --format=svg 12 | ``` 13 | 14 | Will output this [graph statements](../assets/images/public-methods-only.html.gv) and image look like 15 | 16 | ![Graph UML Example](../assets/images/public-methods-only.graphviz.svg) 17 | 18 | ## Batch PHP 19 | 20 | Produces same results as previous console command. 21 | 22 | ```php 23 | in($dataSource)->name('*.php'); 34 | 35 | $generatorFactory = new GeneratorFactory(); 36 | // creates instance of Bartlett\GraphUml\Generator\GraphVizGenerator 37 | $generator = $generatorFactory->createInstance('graphviz'); 38 | 39 | $renderer = new ClassDiagramRenderer(); 40 | $options = [ 41 | 'show_private' => false, 42 | 'show_protected' => false, 43 | 'show_constants' => false, 44 | 'show_properties' => false, 45 | 'node.fillcolor' => '#FEFECE', 46 | 'node.style' => 'filled', 47 | ]; 48 | // generates UML class diagram of all objects found in dataSource (in graphviz format) 49 | $graph = $renderer($finder, $generator, $options); 50 | 51 | $target = $generator->createImageFile($graph); 52 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/03_Cookbook/03_Custom_autoloader.md: -------------------------------------------------------------------------------- 1 | 2 | # Custom Class Autoloader 3 | 4 | In this example we need a custom autoloader to load non-standard classes. 5 | 6 | ```php 7 | addClassMap( 13 | [ 14 | 'Name\\Space\\Foo' => __DIR__ . '/reflection-properties.php', 15 | 'Name\\Space\\Bar' => __DIR__ . '/reflection-properties.php', 16 | ] 17 | ); 18 | ``` 19 | 20 | Our data source is only one file: `reflection-properties.php` with such contents 21 | 22 | ```php 23 | in($dataSource)->name('*.php'); 70 | 71 | $generatorFactory = new GeneratorFactory(); 72 | // creates instance of Bartlett\GraphUml\Generator\GraphVizGenerator 73 | $generator = $generatorFactory->createInstance('graphviz'); 74 | 75 | $renderer = new ClassDiagramRenderer(); 76 | // generates UML class diagram of all objects found in dataSource 77 | $graph = $renderer($finder, $generator); 78 | 79 | $target = $generator->createImageFile($graph); 80 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/90_For_Developers/1_Generators.md: -------------------------------------------------------------------------------- 1 | 2 | # Generators 3 | 4 | GraPHP UML used at least two components : 5 | 6 | - the mathematical graph/network [GraPHP](https://github.com/graphp/graph) library to draw UML diagrams. 7 | - any generator that implement the following contract. 8 | GraPHP UML uses [GraphVizGenerator](https://github.com/llaville/graph-uml/blob/master/src/Generator/GraphVizGenerator.php) 9 | as default, but allow others that may be registered later at runtime. 10 | UmlWrite includes as alternative the [GraPHP PlantUML Generator](https://github.com/llaville/graph-plantuml-generator) 11 | 12 | ## Contract 13 | 14 | Each generator used to build graph statements should implement following interface. 15 | 16 | ```php 17 | 2 | # Creating a new Generator 3 | 4 | You must follow these steps: 5 | 6 | ## **1.** creates your generator class 7 | 8 | This class must follow the `GeneratorInterface` contract. 9 | 10 | ```php 11 | options); 26 | } 27 | 28 | public function getName(): string 29 | { 30 | return 'mygenerator'; 31 | } 32 | 33 | public function createScript(Graph $graph): string 34 | { 35 | return 'TODO: Implement createScript() method.'; 36 | } 37 | 38 | public function createImageFile(Graph $graph, string $cmdFormat): string 39 | { 40 | return '/image_generation_not_implemented'; 41 | } 42 | } 43 | ``` 44 | 45 | ## **2.** creates your generator factory class 46 | 47 | This factory should be able to load your new generator class. 48 | 49 | ```php 50 | addClassMap( 84 | [ 85 | 'Name\\Space\\MyGenerator' => __DIR__ . '/resources.php', 86 | 'Name\\Space\\MyGeneratorFactory' => __DIR__ . '/resources.php', 87 | ] 88 | ); 89 | }; 90 | ``` 91 | 92 | ## **4.** on console command 93 | 94 | Now if you want to use the `diagram:class` command, you'll need to modify the application launcher `bin/launcher` 95 | to inject the new generator factory in service container. 96 | 97 | ```php 98 | set(GeneratorFactoryInterface::class, fn() => new MyGeneratorFactory()); 111 | 112 | $application = new Application($container); 113 | $application->run(); 114 | ``` 115 | 116 | You have then to invoke `bin/umlwriter diagram:class --generator=mygenerator` command to get results. 117 | 118 | ![MyGenerator Results](../assets/images/mygenerator-results.png) 119 | 120 | ## **5.** on batch mode 121 | 122 | Alternative way is to use the batch PHP mode. 123 | 124 | ```php 125 | in($dataSource)->name('*.php'); 139 | 140 | $generatorFactory = new MyGeneratorFactory(); 141 | // creates instance of Name\Space\MyGenerator 142 | $generator = $generatorFactory->createInstance('mygenerator'); 143 | 144 | $renderer = new ClassDiagramRenderer(); 145 | // generates UML class diagram of all objects found in dataSource 146 | $graph = $renderer($finder, $generator); 147 | 148 | $script = $generator->createScript($graph); 149 | 150 | echo $script, PHP_EOL; 151 | ``` 152 | 153 | That will only display 154 | 155 | ```text 156 | TODO: Implement createScript() method. 157 | ``` 158 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 | # About 3 | 4 | ![Graph Composer](./assets/images/graph-composer.svg) 5 | 6 | ## Features 7 | 8 | The main features provided by this library are: 9 | 10 | * Parse one to many PHP file 11 | * Parse one to many directory 12 | * Configuration is handled by a YAML file or console command arguments 13 | * build UML statements of a class diagram 14 | * draw png/svg image formats if backends installed (graphviz, plantuml server) 15 | * two generators provided by default: 16 | 17 | | GraphViz | PlantUML | 18 | |---------------------------------------------:|---------------------------------------------:| 19 | | ![GraphViz logo](./images/graphviz_logo.png) | ![PlantUML logo](./images/plantuml_logo.png) | 20 | 21 | Currently, the following language features are supported: 22 | 23 | * Property and method visibility 24 | * Static properties and methods 25 | * Method return types natively and from doc comment 26 | * Parameter types from type hinting and doc comment 27 | * Parameter default values 28 | * Class constants with value 29 | * Property types from doc comment 30 | * Property default values 31 | * Implemented interfaces and parent classes 32 | * Abstract classes 33 | 34 | ## Usage 35 | 36 | > Learn more about different usages with console, Docker and programmatically. 37 | 38 | See [Getting-Started's Guide](usage/README.md) to know how to use it. 39 | 40 | ## Installation 41 | 42 | > Learn how to install `umlwriter` application in different way. 43 | 44 | See [Installation Guide](installation.md) 45 | 46 | ## Architecture 47 | 48 | > As a developer you want to learn more about UMLWriter architecture. 49 | 50 | See [Architecture's Guide](architecture/README.md) 51 | -------------------------------------------------------------------------------- /docs/architecture/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Architecture 3 | 4 | This guide is dedicated to all PHP developers that want to learn more about each UMLWriter components. 5 | 6 | ## Command Line Runner 7 | 8 | `UmlWriter` is a basic Symfony Console Application. 9 | 10 | ![Command Line Runner UML](../assets/images/archi-console.graphviz.svg) 11 | 12 | ## Configuration 13 | 14 | `UmlWriter` assume a zero configuration by default, that you can change to whatever you want. 15 | 16 | ![Configuration UML](../assets/images/archi-config.graphviz.svg) 17 | 18 | ## Generator 19 | 20 | `UmlWriter` provides a factory that is able to build `graphviz` and `plantuml` graph format. 21 | 22 | ![Generator UML](../assets/images/archi-generator.graphviz.svg) 23 | 24 | ## Service 25 | 26 | `UmlWriter` provides a basic and light container service for dependency injection. 27 | 28 | ![Service UML](../assets/images/archi-service.graphviz.svg) 29 | -------------------------------------------------------------------------------- /docs/assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llaville/umlwriter/009f931493d6f70a22b92e04e064ff5491a693f6/docs/assets/images/.gitkeep -------------------------------------------------------------------------------- /docs/assets/images/archi-config.graphviz.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | cluster_0 13 | 14 | Bartlett\UmlWriter\Config\Loader 15 | 16 | 17 | cluster_1 18 | 19 | Symfony\Component\Config\Loader 20 | 21 | 22 | 23 | Bartlett\\UmlWriter\\Config\\Loader\\YamlFileLoader 24 | 25 | 26 | 27 | YamlFileLoader 28 | 29 | 30 | + load(resource : mixed, type : string = «unknown») : array 31 | + supports(resource, type : string = «unknown») : bool 32 | 33 | 34 | 35 | Symfony\\Component\\Config\\Loader\\FileLoader 36 | 37 | 38 | 39 | «abstract» 40 | FileLoader 41 | 42 | 43 | + __construct(locator : Symfony\Component\Config\FileLocatorInterface, env : string = «unknown») 44 | + setCurrentDir(dir : string) 45 | + getLocator() : Symfony\Component\Config\FileLocatorInterface 46 | + import(resource : mixed, type : string = «unknown», ignoreErrors : bool = false, sourceResource : string = «unknown», exclude : mixed = «unknown») 47 | 48 | 49 | 50 | Bartlett\\UmlWriter\\Config\\Loader\\YamlFileLoader->Symfony\\Component\\Config\\Loader\\FileLoader 51 | 52 | 53 | 54 | 55 | 56 | Symfony\\Component\\Config\\Loader\\Loader 57 | 58 | 59 | 60 | «abstract» 61 | Loader 62 | 63 | 64 | + __construct(env : string = «unknown») 65 | + getResolver() : Symfony\Component\Config\Loader\LoaderResolverInterface 66 | + setResolver(resolver : Symfony\Component\Config\Loader\LoaderResolverInterface) 67 | + import(resource : mixed, type : string = «unknown») 68 | + resolve(resource : mixed, type : string = «unknown») : Symfony\Component\Config\Loader\LoaderInterface 69 | 70 | 71 | 72 | Symfony\\Component\\Config\\Loader\\FileLoader->Symfony\\Component\\Config\\Loader\\Loader 73 | 74 | 75 | 76 | 77 | 78 | Symfony\\Component\\Config\\Loader\\LoaderInterface 79 | 80 | 81 | 82 | «interface» 83 | LoaderInterface 84 | 85 | 86 | + «abstract» load(resource : mixed, type : string = «unknown») 87 | + «abstract» supports(resource : mixed, type : string = «unknown») 88 | + «abstract» getResolver() 89 | + «abstract» setResolver(resolver : Symfony\Component\Config\Loader\LoaderResolverInterface) 90 | 91 | 92 | 93 | Symfony\\Component\\Config\\Loader\\Loader->Symfony\\Component\\Config\\Loader\\LoaderInterface 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/assets/images/archi-generator.graphviz.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | cluster_0 13 | 14 | Bartlett\UmlWriter\Generator 15 | 16 | 17 | 18 | Bartlett\\UmlWriter\\Generator\\GeneratorFactoryInterface 19 | 20 | 21 | 22 | «interface» 23 | GeneratorFactoryInterface 24 | 25 | 26 | + «abstract» createInstance(provider : string, format : string, executable : string) : Bartlett\GraphUml\Generator\GeneratorInterface 27 | 28 | 29 | 30 | Bartlett\\UmlWriter\\Generator\\GeneratorFactory 31 | 32 | 33 | 34 | GeneratorFactory 35 | 36 | 37 | + createInstance(provider : string, format : string = 'svg', executable : string = '') : Bartlett\GraphUml\Generator\GeneratorInterface 38 | 39 | 40 | 41 | Bartlett\\UmlWriter\\Generator\\GeneratorFactory->Bartlett\\UmlWriter\\Generator\\GeneratorFactoryInterface 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/assets/images/archi-service.graphviz.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | cluster_0 13 | 14 | Bartlett\UmlWriter\Service 15 | 16 | 17 | cluster_1 18 | 19 | Psr\Container 20 | 21 | 22 | 23 | Bartlett\\UmlWriter\\Service\\ContainerService 24 | 25 | 26 | 27 | ContainerService 28 | 29 | 30 | + __construct() 31 | + set(id : string, service : mixed) : void 32 | + get(id : string) : ?mixed 33 | + has(id : string) : bool 34 | 35 | 36 | 37 | Psr\\Container\\ContainerInterface 38 | 39 | 40 | 41 | «interface» 42 | ContainerInterface 43 | 44 | 45 | + «abstract» get(id : string) 46 | + «abstract» has(id : string) : bool 47 | 48 | 49 | 50 | Bartlett\\UmlWriter\\Service\\ContainerService->Psr\\Container\\ContainerInterface 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/assets/images/mygenerator-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llaville/umlwriter/009f931493d6f70a22b92e04e064ff5491a693f6/docs/assets/images/mygenerator-results.png -------------------------------------------------------------------------------- /docs/images/graphviz_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llaville/umlwriter/009f931493d6f70a22b92e04e064ff5491a693f6/docs/images/graphviz_logo.png -------------------------------------------------------------------------------- /docs/images/plantuml_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llaville/umlwriter/009f931493d6f70a22b92e04e064ff5491a693f6/docs/images/plantuml_logo.png -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | 2 | # Installation 3 | 4 | 1. [Requirements](#requirements) 5 | 1. [PHAR](#phar) 6 | 1. [Docker](#docker) 7 | 1. [Phive](#phive) 8 | 1. [Composer](#composer) 9 | 1. [Git](#git) 10 | 11 | ## Requirements 12 | 13 | * PHP 8.2 or greater 14 | * [graphp/graph](https://github.com/graphp/graph) package from master branch (considered as future stable v1.0.0) 15 | * [graphp/graphviz](https://github.com/graphp/graphviz) package from master branch (considered as future stable v1.0.0) 16 | * [bartlett/graph-uml](https://github.com/llaville/graph-uml) Core engine to build UML diagrams in PHP 17 | * [bartlett/graph-plantuml-generator](https://github.com/llaville/graph-plantuml-generator) A PlantUML generator for graph-uml. 18 | * [roave/better-reflection](https://github.com/Roave/BetterReflection) the Reflection API 19 | 20 | ## PHAR 21 | 22 | The preferred method of installation is to use the umlWriter PHAR version which can be downloaded from the most recent 23 | [Github Release][releases]. This method ensures you will not have any dependency conflict issue. 24 | 25 | ## Docker 26 | 27 | Retrieve official image with [Docker][docker] 28 | 29 | ```shell 30 | docker pull ghcr.io/llaville/umlwriter:v4.2 31 | or 32 | docker pull ghcr.io/llaville/umlwriter:latest 33 | ``` 34 | 35 | ## Phive 36 | 37 | You can install application globally with [Phive][phive] 38 | 39 | ```shell 40 | phive install llaville/umlwriter --force-accept-unsigned 41 | ``` 42 | 43 | To upgrade global installation of the application use the following command: 44 | 45 | ```shell 46 | phive update llaville/umlwriter --force-accept-unsigned 47 | ``` 48 | 49 | You can also install application locally to your project with [Phive][phive] and configuration file `.phive/phars.xml` 50 | 51 | ```xml 52 | 53 | 54 | 55 | 56 | ``` 57 | 58 | ```shell 59 | phive install --force-accept-unsigned 60 | ``` 61 | 62 | ## Composer 63 | 64 | The recommended way to install this library is [through composer][composer]. 65 | If you don't know yet what is composer, have a look [on introduction][composer-intro]. 66 | 67 | ```shell 68 | composer require bartlett/umlwriter ^4.2 69 | ``` 70 | 71 | If you cannot install it because of a dependency conflict, or you prefer to install it for your project, we recommend 72 | you to take a look at [bamarni/composer-bin-plugin][bamarni/composer-bin-plugin]. Example: 73 | 74 | ```shell 75 | composer require --dev bamarni/composer-bin-plugin 76 | composer bin umlwriter require --dev bartlett/umlwriter 77 | 78 | vendor/bin/umlwriter 79 | ``` 80 | 81 | ## Git 82 | 83 | The UmlWriter can be directly used from [GitHub][github-repo] by cloning the repository into a directory of your choice. 84 | 85 | ```shell 86 | git clone -b 4.2 https://github.com/llaville/umlwriter.git 87 | ``` 88 | 89 | ## Extra resources 90 | 91 | Additionally, you'll have to install GraphViz (`dot` executable) and/or PlantUML jar with Java Runtime (java executable). 92 | Users of Debian/Ubuntu-based distributions may simply invoke: 93 | 94 | ```shell 95 | sudo apt update 96 | sudo apt-get install graphviz 97 | sudo apt-get install openjdk-17-jre-headless 98 | ``` 99 | 100 | while remaining users should install from [GraphViz Download][graphviz-resources] page 101 | and from [PlantUML Download][plantuml-resources] page. 102 | 103 | [releases]: https://github.com/llaville/umlwriter/releases 104 | [composer]: https://getcomposer.org 105 | [composer-intro]: http://getcomposer.org/doc/00-intro.md 106 | [bamarni/composer-bin-plugin]: https://github.com/bamarni/composer-bin-plugin 107 | [github-repo]: https://github.com/llaville/umlwriter.git 108 | [graphviz-resources]: http://www.graphviz.org/download/ 109 | [plantuml-resources]: https://plantuml.com/en/download 110 | [phive]: https://github.com/phar-io/phive 111 | [docker]: https://docs.docker.com/get-docker/ 112 | -------------------------------------------------------------------------------- /docs/usage/README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | 1. [Console CLI](console.md) 4 | 2. [Docker CLI](docker.md) 5 | 3. [Programmatically](programmatically.md) 6 | -------------------------------------------------------------------------------- /docs/usage/console.md: -------------------------------------------------------------------------------- 1 | 2 | # Console CLI 3 | 4 | Generate UML class diagram from PHP source files should be as simple as running `umlwriter diagram:class` 5 | with one or more source paths (zero configuration by default). 6 | 7 | It will however assume some defaults that you might want to change. 8 | 9 | You can then find more advanced configuration settings in [the configuration documentation](../01_Features/Configuration.md). 10 | For more information on which options are available, you can run: `umlwriter diagram:class --help` 11 | 12 | ```text 13 | Description: 14 | Generate class diagram statements of a given data source 15 | 16 | Usage: 17 | diagram:class [options] [--] [...] 18 | 19 | Arguments: 20 | paths Data source (file or directory) 21 | 22 | Options: 23 | -o, --output=OUTPUT Path to output image file 24 | --format=FORMAT Set output format (depending of each generator) 25 | --generator=GENERATOR Graph generator 26 | --executable=EXECUTABLE Generator external binary resource 27 | --bootstrap=BOOTSTRAP A PHP script that is included before graph run 28 | -c, --configuration=CONFIGURATION Read configuration from YAML file 29 | --without-constants Hide all class constants 30 | --without-properties Hide all class properties 31 | --without-methods Hide all class methods 32 | --hide-private Hide private methods/properties 33 | --hide-protected Hide protected methods/properties 34 | --no-statement Do not show diagram statements 35 | -h, --help Display help for the given command. When no command is given display help for the list command 36 | -q, --quiet Do not output any message 37 | -V, --version Display this application version 38 | --ansi|--no-ansi Force (or disable --no-ansi) ANSI output 39 | -n, --no-interaction Do not ask any interactive question 40 | -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/usage/docker.md: -------------------------------------------------------------------------------- 1 | 2 | # Docker CLI 3 | 4 | > [!IMPORTANT] 5 | > Docker image with `latest` tag use the PHP 8.1 runtime ! 6 | > So, uses the tag `v4.2` if you want a PHP 8.2 compatible version. 7 | 8 | > Please mount your source code to `/workdir` in the container. 9 | 10 | If you want to analyse a `src/` folder in your source code, after mounting it, please don't forget to specify a full path 11 | based on `/workdir`, i.e: `/workdir/src` 12 | 13 | ```shell 14 | docker run --rm -t -v "${PWD}":/workdir ghcr.io/llaville/umlwriter:latest diagram:class /workdir/src 15 | ``` 16 | 17 | And same way if you want to generate an image (whatever format: svg, png, ...), and be able to retrieve it, 18 | run following command : 19 | 20 | ```shell 21 | docker run --rm -t -v "${PWD}":/workdir ghcr.io/llaville/umlwriter:latest diagram:class /workdir/src --output /workdir/diagram.svg 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/usage/programmatically.md: -------------------------------------------------------------------------------- 1 | 2 | # Programmatically 3 | 4 | Repository contains an `examples` directory that have many use cases to generate either `Graphviz` or `PlantUML` format. 5 | 6 | Here is a basic example, that you may follow to produce your own UML diagram 7 | from any source code that is loadable with an autoloader : 8 | 9 | ```php 10 | 'LightSkyBlue', 40 | 'cluster.Bartlett\\UmlWriter\\Generator.graph.bgcolor' => 'BurlyWood', 41 | ]; 42 | 43 | // Get an instance of the Generator 44 | $generatorFactory = new GeneratorFactory(); 45 | /** @var GraphVizGenerator $generator */ 46 | $generator = $generatorFactory->createInstance($generatorId, $format); 47 | 48 | // Generate UML class diagram of all objects found in dataSource 49 | $renderer = new ClassDiagramRenderer(); 50 | /** @var \Graphp\Graph\Graph $graph */ 51 | $graph = $renderer($datasource(), $generator, $options); 52 | 53 | // You can either : 54 | // - produce the graph statements (depending on the Generator used) 55 | $statements = $generator->createScript($graph); 56 | 57 | // - produce the image in format selected 58 | $imagePath = $generator->createImageFile($graph); 59 | 60 | var_dump([$imagePath => $statements]); 61 | ``` 62 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "$APP_DEBUG" == 'true' ] && set -x 4 | set -e 5 | 6 | if [ "$APP_DEBUG" == 'true' ] 7 | then 8 | echo "> You will act as user: $(id -u -n)" 9 | echo "$(composer config --global --list)" 10 | /bin/sh -c "ls -l $(composer config --global home)" 11 | fi 12 | 13 | "$(composer config --global home)/vendor/bin/umlwriter" $@ 14 | -------------------------------------------------------------------------------- /examples/application/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/application/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://graphviz.gitlab.io/docs/attrs/rankdir/ 16 | 'graph.rankdir' => 'LR', 17 | // @link https://plantuml.com/en/color 18 | 'cluster.Psr\\Container.graph.bgcolor' => 'LightSkyBlue', 19 | 'cluster.Symfony\\Component\\Console.graph.bgcolor' => 'LightSkyBlue', 20 | 'cluster.Symfony\\Component\\Console\\Command.graph.bgcolor' => 'LightSkyBlue', 21 | 'cluster.Symfony\\Component\\Config\\Loader.graph.bgcolor' => 'LightSkyBlue', 22 | 'cluster.Symfony\\Contracts\\Service.graph.bgcolor' => 'LightSkyBlue', 23 | 'cluster.Bartlett\\UmlWriter\\Service.graph.bgcolor' => 'BurlyWood', 24 | 'cluster.Bartlett\\UmlWriter\\Console.graph.bgcolor' => 'BurlyWood', 25 | 'cluster.Bartlett\\UmlWriter\\Console\\Command.graph.bgcolor' => 'BurlyWood', 26 | 'cluster.Bartlett\\UmlWriter\\Config\\Loader.graph.bgcolor' => 'BurlyWood', 27 | 'cluster.Bartlett\\UmlWriter\\Generator.graph.bgcolor' => 'BurlyWood', 28 | ]; 29 | -------------------------------------------------------------------------------- /examples/configuration/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource1)->name('*.php'); 21 | $finder->append((new Finder())->in($dataSource2)->name('ConfigurationHandler.php')); 22 | 23 | return $finder; 24 | }; 25 | -------------------------------------------------------------------------------- /examples/configuration/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://plantuml.com/en/color 16 | 'cluster.Bartlett\\UmlWriter\\Config\\Loader.graph.bgcolor' => 'BurlyWood', 17 | 'cluster.Bartlett\\UmlWriter\\Service.graph.bgcolor' => 'BurlyWood', 18 | 'cluster.Symfony\\Component\\Config\\Loader.graph.bgcolor' => 'LightSkyBlue', 19 | ]; 20 | -------------------------------------------------------------------------------- /examples/console-commands/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/console-commands/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://plantuml.com/en/color 16 | 'cluster.Bartlett\\UmlWriter\\Console.graph.bgcolor' => 'BurlyWood', 17 | 'cluster.Bartlett\\UmlWriter\\Console\\Command.graph.bgcolor' => 'BurlyWood', 18 | ]; 19 | -------------------------------------------------------------------------------- /examples/custom-autoloader/bootstrap.php: -------------------------------------------------------------------------------- 1 | addClassMap( 18 | [ 19 | 'Name\\Space\\Foo' => __DIR__ . '/reflection-properties.php', 20 | 'Name\\Space\\Bar' => __DIR__ . '/reflection-properties.php', 21 | ] 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /examples/custom-autoloader/datasource.php: -------------------------------------------------------------------------------- 1 | in(__DIR__)->name('*.php'); 17 | 18 | return $finder; 19 | }; 20 | -------------------------------------------------------------------------------- /examples/custom-autoloader/options.php: -------------------------------------------------------------------------------- 1 | 'white', 15 | ]; 16 | -------------------------------------------------------------------------------- /examples/custom-autoloader/reflection-properties.php: -------------------------------------------------------------------------------- 1 | set(GeneratorFactoryInterface::class, fn() => new MyGeneratorFactory()); 22 | 23 | $application = new Application($container); 24 | $application->run(); 25 | -------------------------------------------------------------------------------- /examples/custom-generator/batch.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 24 | 25 | $generatorFactory = new MyGeneratorFactory(); 26 | // creates instance of Name\Space\MyGenerator 27 | $generator = $generatorFactory->createInstance('mygenerator'); 28 | 29 | $renderer = new ClassDiagramRenderer(); 30 | // generates UML class diagram of all objects found in dataSource 31 | $graph = $renderer($finder, $generator); 32 | 33 | $script = $generator->createScript($graph); 34 | 35 | echo $script, PHP_EOL; 36 | -------------------------------------------------------------------------------- /examples/custom-generator/bootstrap.php: -------------------------------------------------------------------------------- 1 | addClassMap( 18 | [ 19 | 'Name\\Space\\MyGenerator' => __DIR__ . '/my-generator.php', 20 | 'Name\\Space\\MyGeneratorFactory' => __DIR__ . '/my-generator-factory.php', 21 | ] 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /examples/custom-generator/datasource.php: -------------------------------------------------------------------------------- 1 | in(__DIR__)->name('*.php'); 17 | 18 | return $finder; 19 | }; 20 | -------------------------------------------------------------------------------- /examples/custom-generator/my-generator-factory.php: -------------------------------------------------------------------------------- 1 | options); 26 | } 27 | 28 | public function getName(): string 29 | { 30 | return 'mygenerator'; 31 | } 32 | 33 | public function createScript(Graph $graph): string 34 | { 35 | return 'TODO: Implement createScript() method.'; 36 | } 37 | 38 | public function createImageFile(Graph $graph, string $cmdFormat): string 39 | { 40 | return '/image_generation_not_implemented'; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/custom-generator/options.php: -------------------------------------------------------------------------------- 1 | 'white', 15 | ]; 16 | -------------------------------------------------------------------------------- /examples/formatter/bootstrap.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://plantuml.com/en/color 16 | 'cluster.Bartlett\\GraphUml\\Formatter.graph.bgcolor' => 'LightSkyBlue', 17 | 'cluster.Bartlett\\GraphUml.graph.bgcolor' => 'BurlyWood', 18 | ]; 19 | -------------------------------------------------------------------------------- /examples/from-yaml/.umlwriter.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | generator: graphviz 3 | 4 | graph: 5 | name: G 6 | overlap: 'false' 7 | rankdir: LR 8 | bgcolor: transparent 9 | 10 | node: 11 | fillcolor: 'white' 12 | 13 | edge: ~ 14 | 15 | cluster: 16 | Bartlett\UmlWriter\Console: 17 | graph: 18 | bgcolor: BurlyWood 19 | node: 20 | fillcolor: '#FEFECE' 21 | style: filled 22 | Symfony\Component\Console: 23 | graph: 24 | bgcolor: LightSteelBlue 25 | node: 26 | fillcolor: '#FEFECE' 27 | style: filled 28 | 29 | paths: 30 | - src/ 31 | 32 | show_constants: true 33 | show_properties: true 34 | show_methods: true 35 | show_private: false 36 | show_protected: false 37 | -------------------------------------------------------------------------------- /examples/from-yaml/bootstrap.php: -------------------------------------------------------------------------------- 1 | toArray(); 18 | 19 | $finder = new Finder(); 20 | $finder->name('*.php'); 21 | 22 | foreach ($config['paths'] as $path) { 23 | if (is_dir($path)) { 24 | $finder->in($path); 25 | } else { 26 | $finder->in(dirname($path)); 27 | } 28 | } 29 | 30 | return $finder; 31 | }; 32 | -------------------------------------------------------------------------------- /examples/from-yaml/options.php: -------------------------------------------------------------------------------- 1 | toFlat(); 15 | -------------------------------------------------------------------------------- /examples/generator/bootstrap.php: -------------------------------------------------------------------------------- 1 | addClassMap( 18 | [ 19 | 'Name\\Space\\MyGeneratorFactory' => __DIR__ . '/my-generator-factory.php', 20 | 'Name\\Space\\MyGenerator' => __DIR__ . '/my-generator.php', 21 | ] 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /examples/generator/datasource.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/generator/my-generator-factory.php: -------------------------------------------------------------------------------- 1 | options); 25 | } 26 | 27 | public function getName(): string 28 | { 29 | return 'mygenerator'; 30 | } 31 | 32 | public function createScript(Graph $graph): string 33 | { 34 | return 'TODO: Implement createScript() method.' . PHP_EOL; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/generator/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://plantuml.com/en/color 16 | 'cluster.Name\\Space.graph.bgcolor' => 'LightSkyBlue', 17 | ]; 18 | -------------------------------------------------------------------------------- /examples/graphviz.php: -------------------------------------------------------------------------------- 1 | ', PHP_EOL; 12 | echo ' ', PHP_EOL; 13 | echo ' ', PHP_EOL; 14 | echo ' ', PHP_EOL; 15 | echo '=====================================================================', PHP_EOL; 16 | exit(); 17 | } 18 | 19 | $example = $_SERVER['argv'][1] ?? null; 20 | $folder = $_SERVER['argv'][2] ?? sys_get_temp_dir(); 21 | $format = $_SERVER['argv'][3] ?? 'svg'; 22 | $writeGraphStatement = $_SERVER['argv'][4] ?? false; 23 | 24 | $baseDir = __DIR__ . DIRECTORY_SEPARATOR . $example . DIRECTORY_SEPARATOR; 25 | $available = is_dir($baseDir) && file_exists($baseDir); 26 | 27 | if (empty($example) || !$available) { 28 | throw new RuntimeException(sprintf('Example "%s" does not exists.', $example)); 29 | } 30 | 31 | use Bartlett\GraphUml\Generator\GraphVizGenerator; 32 | use Bartlett\UmlWriter\Generator\GeneratorFactory; 33 | use Bartlett\UmlWriter\Service\ClassDiagramRenderer; 34 | 35 | $resources = [ 36 | $baseDir . 'bootstrap.php', // autoloader or any other resource to include before run this script 37 | $baseDir . 'datasource.php', // list of files or classes to parse 38 | $baseDir . 'options.php', // all options to customize the Graph 39 | ]; 40 | 41 | $isAutoloadFound = false; 42 | 43 | foreach ($resources as $resource) { 44 | if (file_exists($resource)) { 45 | $variable = basename($resource, '.php'); 46 | $$variable = require $resource; 47 | } 48 | if (isset($bootstrap) && !$isAutoloadFound) { 49 | $isAutoloadFound = true; 50 | $bootstrap(); 51 | } 52 | } 53 | 54 | $generatorName = basename(__FILE__, '.php'); 55 | 56 | $generatorFactory = new GeneratorFactory(); 57 | /** @var GraphVizGenerator $generator */ 58 | $generator = $generatorFactory->createInstance($generatorName, $format); 59 | 60 | $renderer = new ClassDiagramRenderer(); 61 | // generates UML class diagram of all objects found in dataSource (in graphviz format) 62 | $graph = $renderer($datasource(), $generator, $options); 63 | 64 | if ($writeGraphStatement) { 65 | // writes graphviz statements to file 66 | $output = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $example . '.html.gv'; 67 | file_put_contents($output, $generator->createScript($graph)); 68 | } 69 | 70 | $output = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $example . '.graphviz.' . $format; 71 | $cmdFormat = '%E -T%F %t -o ' . $output; 72 | $target = $generator->createImageFile($graph, $cmdFormat); 73 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 74 | -------------------------------------------------------------------------------- /examples/plantuml.php: -------------------------------------------------------------------------------- 1 | ', PHP_EOL; 12 | echo ' ', PHP_EOL; 13 | echo ' ', PHP_EOL; 14 | echo ' ', PHP_EOL; 15 | echo '=====================================================================', PHP_EOL; 16 | exit(); 17 | } 18 | 19 | $example = $_SERVER['argv'][1] ?? null; 20 | $folder = $_SERVER['argv'][2] ?? sys_get_temp_dir(); 21 | $format = $_SERVER['argv'][3] ?? 'svg'; 22 | $writeGraphStatement = $_SERVER['argv'][4] ?? false; 23 | 24 | $baseDir = __DIR__ . DIRECTORY_SEPARATOR . $example . DIRECTORY_SEPARATOR; 25 | $available = is_dir($baseDir) && file_exists($baseDir); 26 | 27 | if (empty($example) || !$available) { 28 | throw new RuntimeException(sprintf('Example "%s" does not exists.', $example)); 29 | } 30 | 31 | use Bartlett\GraphPlantUml\PlantUmlGenerator; 32 | use Bartlett\UmlWriter\Generator\GeneratorFactory; 33 | use Bartlett\UmlWriter\Service\ClassDiagramRenderer; 34 | 35 | $resources = [ 36 | $baseDir . 'bootstrap.php', // autoloader or any other resource to include before run this script 37 | $baseDir . 'datasource.php', // list of files or classes to parse 38 | $baseDir . 'options.php', // all options to customize the Graph 39 | ]; 40 | 41 | $isAutoloadFound = false; 42 | 43 | foreach ($resources as $resource) { 44 | if (file_exists($resource)) { 45 | $variable = basename($resource, '.php'); 46 | $$variable = require $resource; 47 | } 48 | if (isset($bootstrap) && !$isAutoloadFound) { 49 | $isAutoloadFound = true; 50 | $bootstrap(); 51 | } 52 | } 53 | 54 | $generatorName = basename(__FILE__, '.php'); 55 | 56 | $generatorFactory = new GeneratorFactory(); 57 | /** @var PlantUmlGenerator $generator */ 58 | $generator = $generatorFactory->createInstance($generatorName); 59 | 60 | $renderer = new ClassDiagramRenderer(); 61 | // generates UML class diagram of all objects found in dataSource (in PlantUML format) 62 | $graph = $renderer($datasource(), $generator, $options); 63 | 64 | if ($writeGraphStatement) { 65 | // writes graphviz statements to file 66 | $output = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $example . '.puml'; 67 | file_put_contents($output, $generator->createScript($graph)); 68 | } 69 | 70 | $target = $generator->createImageFile($graph); 71 | 72 | $from = $target; 73 | $target = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $example . '.plantuml.' . $format; 74 | if (!rename($from, $target)) { 75 | $target = null; 76 | } 77 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 78 | -------------------------------------------------------------------------------- /examples/public-architecture/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/public-architecture/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | ]; 16 | -------------------------------------------------------------------------------- /examples/public-methods-only/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/public-methods-only/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | 'show_constants' => false, 16 | 'show_properties' => false, 17 | ]; 18 | -------------------------------------------------------------------------------- /examples/services/bootstrap.php: -------------------------------------------------------------------------------- 1 | in($dataSource)->name('*.php')->notName('ConfigurationHandler.php'); 20 | 21 | return $finder; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/services/options.php: -------------------------------------------------------------------------------- 1 | false, 14 | 'show_protected' => false, 15 | // @link https://plantuml.com/en/color 16 | 'cluster.Bartlett\\UmlWriter\\Service.graph.bgcolor' => 'BurlyWood', 17 | ]; 18 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | site_name: UMLWriter 3 | site_url: https://llaville.github.io/umlwriter 4 | repo_url: https://github.com/llaville/umlwriter # https://squidfunk.github.io/mkdocs-material/setup/adding-a-git-repository/#repository 5 | site_author: Laurent Laville 6 | edit_uri: "" # hide edit button -- https://squidfunk.github.io/mkdocs-material/setup/adding-a-git-repository/#edit-button 7 | theme: 8 | name: material 9 | palette: # Color palette toggle -- https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#color-palette-toggle 10 | # editorconfig-checker-disable 11 | - scheme: default 12 | primary: red 13 | toggle: 14 | icon: material/lightbulb-outline 15 | name: Switch to dark mode 16 | - scheme: slate 17 | toggle: 18 | icon: material/lightbulb 19 | name: Switch to light mode 20 | # editorconfig-checker-enable 21 | features: 22 | - navigation.instant # Instant loading -- https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/#instant-loading 23 | - navigation.tabs # Navigation tabs -- https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/#navigation-tabs 24 | - navigation.indexes # Section index pages -- https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/#section-index-pages 25 | - navigation.top # Back-To-Top button -- https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/#back-to-top-button 26 | markdown_extensions: 27 | - pymdownx.highlight # https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#highlight 28 | - pymdownx.superfences # https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown-extensions/#superfences 29 | nav: 30 | - "Home": README.md 31 | - "Installation": installation.md 32 | - "Getting-Started": usage/README.md 33 | - "Architecture": architecture/README.md 34 | - "Features": 35 | - "Configuration": 01_Features/Configuration.md 36 | - "Services": 01_Features/Services.md 37 | - "Commands": 38 | - "Class diagrams": 02_Console_Commands/diagram_class.md 39 | - "Cookbook": 40 | - "Application diagram": 03_Cookbook/01_UmlWriter_public_architecture.md 41 | - "Application diagram with public methods only": 03_Cookbook/02_UmlWriter_public_methods_only.md 42 | - "Use a custom class autoloader": 03_Cookbook/03_Custom_autoloader.md 43 | - "Contributors": 44 | - "Generators": 90_For_Developers/1_Generators.md 45 | - "Creating a new generator": 90_For_Developers/2_Creating_a_Generator.md 46 | -------------------------------------------------------------------------------- /patches/graph-graphviz_add_subgraph_cluster-42.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/GraphViz.php b/src/GraphViz.php 2 | index fcddeb0..f97fcdb 100644 3 | --- a/src/GraphViz.php 4 | +++ b/src/GraphViz.php 5 | @@ -273,13 +273,29 @@ class GraphViz 6 | } 7 | 8 | // only cluster vertices into groups if there are at least 2 different groups 9 | - if (count($groups) > 1) { 10 | + if (count($groups) > 0) { 11 | + // add subgraph cluster attributes 12 | + $clusters = array( 13 | + 'graph' => 'graphviz.cluster.%s.graph.', 14 | + 'node' => 'graphviz.cluster.%s.node.', 15 | + 'edge' => 'graphviz.cluster.%s.edge.', 16 | + ); 17 | $indent = str_repeat($this->formatIndent, 2); 18 | $gid = 0; 19 | // put each group of vertices in a separate subgraph cluster 20 | foreach ($groups as $group => $vertices) { 21 | - $script .= $this->formatIndent . 'subgraph cluster_' . $gid++ . ' {' . self::EOL . 22 | - $indent . 'label = ' . $this->escape($group) . self::EOL; 23 | + $script .= $this->formatIndent . 'subgraph cluster_' . $gid . ' {' . self::EOL; 24 | + foreach ($clusters as $key => $prefix) { 25 | + foreach (array($group, $gid) as $clusterId) { 26 | + $layout = $this->getAttributesPrefixed($graph, sprintf($prefix, $clusterId)); 27 | + if (!empty($layout)) { 28 | + $script .= $indent . $key . ' ' . $this->escapeAttributes($layout) . self::EOL; 29 | + break; 30 | + } 31 | + } 32 | + } 33 | + $script .= $indent . 'label = ' . $this->escape($group) . self::EOL; 34 | + $gid++; 35 | foreach ($vertices as $vertex) { 36 | $vid = $vids[\spl_object_hash($vertex)]; 37 | $layout = $this->getLayoutVertex($vertex, $vid); 38 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | tests/ 20 | 21 | 22 | 23 | 24 | src/ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /resources/build.php: -------------------------------------------------------------------------------- 1 | dirname(__DIR__), 37 | 'output' => $target, 38 | '--depth' => 2, 39 | '--orientation' => 'LR', 40 | ]); 41 | $status = $export->run($input, new NullOutput()); 42 | echo ($status != 0 ? 'no' : $target) . ' file generated' . PHP_EOL; 43 | exit($status); 44 | } 45 | 46 | $baseDir = __DIR__ . DIRECTORY_SEPARATOR . $script . DIRECTORY_SEPARATOR; 47 | $available = is_dir($baseDir) && file_exists($baseDir); 48 | 49 | if (empty($script) || !$available) { 50 | throw new LogicException(sprintf('Unable to build a graph for unknown script "%s"', $script)); 51 | } 52 | 53 | $resources = [ 54 | $baseDir . '/datasource.php', 55 | $baseDir . '/options.php', 56 | ]; 57 | 58 | foreach ($resources as $resource) { 59 | if (file_exists($resource)) { 60 | $variable = basename($resource, '.php'); 61 | $$variable = require $resource; 62 | } 63 | } 64 | 65 | $generatorFactory = new GeneratorFactory(); 66 | /** @var GraphVizGenerator $generator */ 67 | $generator = $generatorFactory->createInstance('graphviz', $format); 68 | 69 | $renderer = new ClassDiagramRenderer(); 70 | // generates UML class diagram of all objects found in dataSource (in graphviz format) 71 | $graph = $renderer($datasource(), $generator, $options ?? []); 72 | 73 | // writes graph statements to file 74 | $output = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $script . '.html.gv'; 75 | file_put_contents($output, $generator->createScript($graph)); 76 | 77 | $output = rtrim($folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $script . '.graphviz.' . $format; 78 | $cmdFormat = '%E -T%F %t -o ' . $output; 79 | $target = $generator->createImageFile($graph, $cmdFormat); 80 | echo (empty($target) ? 'no' : $target) . ' file generated' . PHP_EOL; 81 | -------------------------------------------------------------------------------- /resources/gh-pages-hook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 4 | 5 | ASSETS_IMAGE_DIR="docs/assets/images" 6 | 7 | php $SCRIPT_DIR/build.php graph-composer $ASSETS_IMAGE_DIR 8 | php $SCRIPT_DIR/../examples/graphviz.php configuration $ASSETS_IMAGE_DIR svg 1 9 | php $SCRIPT_DIR/../examples/graphviz.php console-commands $ASSETS_IMAGE_DIR svg 1 10 | php $SCRIPT_DIR/../examples/graphviz.php custom-autoloader $ASSETS_IMAGE_DIR svg 1 11 | php $SCRIPT_DIR/../examples/graphviz.php formatter $ASSETS_IMAGE_DIR svg 1 12 | php $SCRIPT_DIR/../examples/graphviz.php generator $ASSETS_IMAGE_DIR svg 1 13 | php $SCRIPT_DIR/../examples/graphviz.php public-architecture $ASSETS_IMAGE_DIR svg 1 14 | php $SCRIPT_DIR/../examples/graphviz.php public-methods-only $ASSETS_IMAGE_DIR svg 1 15 | php $SCRIPT_DIR/../examples/graphviz.php services $ASSETS_IMAGE_DIR svg 1 16 | -------------------------------------------------------------------------------- /src/Config/Loader/YamlFileLoader.php: -------------------------------------------------------------------------------- 1 | 30 | */ 31 | public function load(mixed $resource, string $type = null): array 32 | { 33 | try { 34 | $configs = Yaml::parseFile($resource, Yaml::PARSE_CONSTANT); 35 | } catch (ParseException $e) { 36 | throw new InvalidArgumentException( 37 | sprintf('The file "%s" does not contain valid YAML: ', $resource) . $e->getMessage(), 38 | 0, 39 | $e 40 | ); 41 | } 42 | 43 | if (null !== $configs && !is_array($configs)) { 44 | throw new InvalidArgumentException(sprintf('Unable to load file "%s".', $resource)); 45 | } 46 | 47 | return $configs ?? []; 48 | } 49 | 50 | /** 51 | * @inheritDoc 52 | */ 53 | public function supports($resource, string $type = null): bool 54 | { 55 | return is_string($resource) 56 | && in_array(pathinfo($resource, PATHINFO_EXTENSION), ['yml', 'yaml']); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Console/Application.php: -------------------------------------------------------------------------------- 1 | getInstalledVersion(false) 47 | ); 48 | 49 | $this->setCommandLoader($this->createCommandLoader($container)); 50 | } 51 | 52 | /** 53 | * @inheritDoc 54 | */ 55 | public function getHelp(): string 56 | { 57 | return sprintf( 58 | '%s%s version %s', 59 | self::$logo, 60 | $this->getName(), 61 | $this->getVersion() 62 | ); 63 | } 64 | 65 | /** 66 | * @inheritDoc 67 | */ 68 | public function getLongVersion(): string 69 | { 70 | return $this->getInstalledVersion(); 71 | } 72 | 73 | /** 74 | * @inheritDoc 75 | */ 76 | public function doRun(InputInterface $input, OutputInterface $output): int 77 | { 78 | $this->container->set(InputInterface::class, $input); // @phpstan-ignore-line 79 | $this->container->set(OutputInterface::class, $output); // @phpstan-ignore-line 80 | 81 | return parent::doRun($input, $output); 82 | } 83 | 84 | /** 85 | * @inheritDoc 86 | */ 87 | public function run(InputInterface $input = null, OutputInterface $output = null): int 88 | { 89 | if (null === $input) { 90 | if ($this->container->has(InputInterface::class)) { 91 | $input = $this->container->get(InputInterface::class); 92 | } else { 93 | $input = new ArgvInput(); 94 | } 95 | } 96 | 97 | if (null === $output) { 98 | if ($this->container->has(OutputInterface::class)) { 99 | $output = $this->container->get(OutputInterface::class); 100 | } else { 101 | $output = new ConsoleOutput(); 102 | } 103 | } 104 | 105 | return parent::run($input, $output); 106 | } 107 | 108 | /** 109 | * @see https://symfony.com/doc/current/console/lazy_commands.html#containercommandloader 110 | */ 111 | private function createCommandLoader(ContainerInterface $container): CommandLoaderInterface 112 | { 113 | return new ContainerCommandLoader( 114 | $container, 115 | [ 116 | ClassDiagramCommand::getDefaultName() => ClassDiagramCommand::class, 117 | ] 118 | ); 119 | } 120 | 121 | private function getInstalledVersion(bool $withRef = true): string 122 | { 123 | $packageName = 'bartlett/umlwriter'; 124 | 125 | $version = InstalledVersions::getPrettyVersion($packageName); 126 | if (!$withRef) { 127 | return $version; 128 | } 129 | $commitHash = InstalledVersions::getReference($packageName); 130 | return sprintf('%s@%s', $version, substr($commitHash, 0, 7)); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Console/Command/ClassDiagramCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Generate class diagram statements of a given data source') 65 | ->addArgument('paths', InputArgument::IS_ARRAY, 'Data source (file or directory)') 66 | ->addOption('output', 'o', InputOption::VALUE_REQUIRED, 'Path to output image file') 67 | ->addOption('format', '', InputOption::VALUE_REQUIRED, 'Set output format (depending of each generator)') 68 | ->addOption('generator', null, InputOption::VALUE_REQUIRED, 'Graph generator') 69 | ->addOption('executable', null, InputOption::VALUE_REQUIRED, 'Generator external binary resource') 70 | ->addOption('bootstrap', null, InputOption::VALUE_REQUIRED, 'A PHP script that is included before graph run') 71 | ->addOption('configuration', 'c', InputOption::VALUE_REQUIRED, 'Read configuration from YAML file') 72 | ->addOption('without-constants', '', InputOption::VALUE_NONE, 'Hide all class constants') 73 | ->addOption('without-properties', '', InputOption::VALUE_NONE, 'Hide all class properties') 74 | ->addOption('without-methods', '', InputOption::VALUE_NONE, 'Hide all class methods') 75 | ->addOption('hide-private', '', InputOption::VALUE_NONE, 'Hide private methods/properties') 76 | ->addOption('hide-protected', '', InputOption::VALUE_NONE, 'Hide protected methods/properties') 77 | ->addOption('no-statement', '', InputOption::VALUE_NONE, 'Do not show diagram statements') 78 | ; 79 | } 80 | 81 | /** 82 | * @throws ReflectionException 83 | */ 84 | protected function execute(InputInterface $input, OutputInterface $output): int 85 | { 86 | $io = new SymfonyStyle($input, $output); 87 | 88 | $parameters = $this->handleConfiguration($input, $io); 89 | 90 | $paths = array_filter($parameters, function ($key) { 91 | return str_starts_with($key, 'paths.'); 92 | }, ARRAY_FILTER_USE_KEY); 93 | 94 | if (empty($paths)) { 95 | $io->caution('Not enough arguments (missing data source paths)'); 96 | return 1; 97 | } 98 | 99 | try { 100 | $generator = $this->generatorFactory->createInstance( 101 | $parameters['generator'], 102 | $parameters['format'], 103 | $parameters['executable'] 104 | ); 105 | } catch (Throwable $e) { 106 | $io->error($e->getMessage()); 107 | return 1; 108 | } 109 | 110 | $finder = $this->handleSourceLocator($paths); 111 | 112 | $io->title('UML Class Diagram Generation'); 113 | $io->definitionList( 114 | ['Path(s)' => implode(', ', $paths)], 115 | ['Generator' => $parameters['generator']], 116 | ['Configuration' => $parameters['__from'] ?? ''] 117 | ); 118 | unset($parameters['__from']); 119 | 120 | $graph = $this->renderer->__invoke($finder, $generator, $parameters); 121 | $script = $generator->createScript($graph); 122 | 123 | if ($output->isVerbose()) { 124 | $this->handleContext($output, $io, $parameters); 125 | } 126 | 127 | $exitCode = $this->handleOutput($graph, $generator, $input->getOption('output'), $parameters['format'], $io); 128 | 129 | if (0 === $exitCode) { 130 | if (!$input->getOption('no-statement')) { 131 | $io->section('Graph statements'); 132 | $io->writeln($script); 133 | } 134 | $io->success('UML classes were generated.'); 135 | } 136 | return $exitCode; 137 | } 138 | 139 | /** 140 | * @param array $parameters 141 | */ 142 | private function handleContext(OutputInterface $output, SymfonyStyle $io, array $parameters): void 143 | { 144 | $io->section('Configuration'); 145 | 146 | array_walk($parameters, function (&$value, $key) { 147 | if (is_bool($value)) { 148 | $value = var_export($value, true); 149 | } 150 | }); 151 | $io->horizontalTable( 152 | array_keys($parameters), 153 | [array_values($parameters)] 154 | ); 155 | 156 | $io->section('Entities summary'); 157 | 158 | $metaData = $this->renderer->getMetadata(); 159 | $io->definitionList( 160 | ['classes' => count($metaData['classes'])] 161 | ); 162 | if ($output->isVeryVerbose()) { 163 | $io->comment($metaData['classes']); 164 | } 165 | $io->definitionList( 166 | ['interfaces' => count($metaData['interfaces'])] 167 | ); 168 | if ($output->isVeryVerbose()) { 169 | $io->comment($metaData['interfaces']); 170 | } 171 | $io->definitionList( 172 | ['namespaces' => count($metaData['namespaces'])] 173 | ); 174 | if ($output->isVeryVerbose()) { 175 | $io->comment($metaData['namespaces']); 176 | } 177 | } 178 | 179 | private function handleOutput(Graph $graph, GeneratorInterface $generator, ?string $target, ?string $format, SymfonyStyle $io): int 180 | { 181 | if (null === $target && null === $format) { 182 | // do not generate image file 183 | return 0; 184 | } 185 | 186 | $path = $generator->createImageFile($graph, ''); 187 | 188 | if ($target !== null) { 189 | if (is_dir($target)) { 190 | $target = rtrim($target, '/') . '/umlwriter.' . $format; 191 | } 192 | if (!@rename($path, $target)) { 193 | $io->error(sprintf('Cannot write diagram into %s', $target)); 194 | return 1; 195 | } 196 | $path = realpath($target); 197 | } 198 | $io->note(sprintf('Image built into %s', $path)); 199 | 200 | return 0; 201 | } 202 | 203 | /** 204 | * @return array 205 | */ 206 | private function handleConfiguration(InputInterface $input, SymfonyStyle $io): array 207 | { 208 | $configFilename = $input->getOption('configuration'); 209 | $configHandler = new ConfigurationHandler($configFilename); 210 | 211 | try { 212 | $parameters = $configHandler->toFlat(); 213 | $parameters['__from'] = $configFilename ?? 'Default values and/or command line arguments'; 214 | 215 | if ($input->getOption('without-constants')) { 216 | $parameters['show_constants'] = false; 217 | } 218 | if ($input->getOption('without-properties')) { 219 | $parameters['show_properties'] = false; 220 | } 221 | if ($input->getOption('without-methods')) { 222 | $parameters['show_methods'] = false; 223 | } 224 | if ($input->getOption('hide-private')) { 225 | $parameters['show_private'] = false; 226 | } 227 | if ($input->getOption('hide-protected')) { 228 | $parameters['show_protected'] = false; 229 | } 230 | } catch (InvalidArgumentException $exception) { 231 | $io->caution($exception->getMessage()); 232 | $parameters = []; 233 | } 234 | 235 | $bootstrap = $input->getOption('bootstrap'); 236 | if (!empty($bootstrap)) { 237 | $parameters['bootstrap'] = $bootstrap; 238 | if (file_exists($bootstrap)) { 239 | include $bootstrap; 240 | } 241 | } 242 | 243 | $parameters['generator'] = $input->getOption('generator') ?? $parameters['generator'] ?? 'graphviz'; 244 | $parameters['executable'] = $input->getOption('executable') ?? $parameters['executable'] ?? 'dot'; 245 | $parameters['format'] = $input->getOption('format') ?? $parameters['format'] ?? 'svg'; 246 | 247 | $paths = $input->getArgument('paths'); 248 | foreach ($paths as $index => $path) { 249 | $parameters['paths.' . $index] = $path; 250 | } 251 | 252 | return $parameters; 253 | } 254 | 255 | /** 256 | * @param string[] $paths 257 | */ 258 | private function handleSourceLocator(array $paths): Finder 259 | { 260 | $filter = function (SplFileInfo $file) use ($paths) { 261 | foreach ($paths as $path) { 262 | if (is_dir($path)) { 263 | if (str_starts_with($file->getPath(), rtrim($path, '/'))) { 264 | return true; 265 | } 266 | } else { 267 | if ($file->getPathname() === $path) { 268 | return true; 269 | } 270 | } 271 | } 272 | return false; 273 | }; 274 | 275 | $finder = new Finder(); 276 | $finder->files(); 277 | $finder->name('*.php'); 278 | 279 | foreach ($paths as $path) { 280 | if (is_dir($path)) { 281 | $finder->in($path); 282 | } else { 283 | $finder->in(dirname($path)); 284 | } 285 | } 286 | $finder->filter($filter); 287 | 288 | return $finder; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/Generator/GeneratorFactory.php: -------------------------------------------------------------------------------- 1 | new GraphVizGenerator(new GraphViz(), 'dot', $format), 29 | 'plantuml' => new PlantUmlGenerator('vendor/bin/plantuml', $format), 30 | default => throw new LogicException(sprintf('Provider "%s" is not supported', $provider)) 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Generator/GeneratorFactoryInterface.php: -------------------------------------------------------------------------------- 1 | */ 38 | private array $metaData; 39 | 40 | /** 41 | * @param array $parameters 42 | * @throws ReflectionException 43 | */ 44 | public function __invoke(Finder|Generator $datasource, GeneratorInterface $generator, array $parameters = []): Graph 45 | { 46 | $this->metaData = [ 47 | 'classes' => [], 48 | 'interfaces' => [], 49 | 'namespaces' => [], 50 | ]; 51 | 52 | $defaults = (new ConfigurationHandler())->toFlat(); 53 | $options = array_merge($defaults, $parameters); 54 | $this->initGraph($options); 55 | 56 | $builder = new ClassDiagramBuilder($generator, $this->graph, $options); 57 | 58 | $astLocator = (new BetterReflection())->astLocator(); 59 | 60 | foreach ($datasource as $source) { 61 | $classes = []; 62 | if ($source instanceof SplFileInfo) { 63 | $filename = $source->getRealPath(); 64 | $reflector = new DefaultReflector(new SingleFileSourceLocator($filename, $astLocator)); 65 | $classes = $reflector->reflectAllClasses(); 66 | } elseif (is_string($source)) { 67 | $reflector = new DefaultReflector(new AutoloadSourceLocator($astLocator)); 68 | $classes = [$reflector->reflectClass($source)]; 69 | } 70 | 71 | foreach ($classes as $class) { 72 | if ($class->isAnonymous()) { 73 | continue; 74 | } 75 | if ($class->isInterface()) { 76 | $this->metaData['interfaces'][] = $class->getName(); 77 | } else { 78 | $this->metaData['classes'][] = $class->getName(); 79 | } 80 | $builder->createVertexClass($class->getName()); 81 | } 82 | } 83 | 84 | return $this->graph; 85 | } 86 | 87 | /** 88 | * Returns list of entities found in data source. 89 | * 90 | * @return array 91 | */ 92 | public function getMetadata(): array 93 | { 94 | $this->metaData['namespaces'] = array_unique($this->metaData['namespaces']); 95 | return $this->metaData; 96 | } 97 | 98 | /** 99 | * @param array $parameters 100 | */ 101 | private function initGraph(array $parameters): void 102 | { 103 | $this->graph = new Graph(); 104 | 105 | $attributes = array_filter($parameters, function ($key) { 106 | return (str_starts_with($key, 'graph.') 107 | || str_starts_with($key, 'node.') 108 | || str_starts_with($key, 'edge.') 109 | || str_starts_with($key, 'cluster.') 110 | ); 111 | }, ARRAY_FILTER_USE_KEY); 112 | 113 | $this->graph->setAttributes($attributes); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Service/ConfigurationHandler.php: -------------------------------------------------------------------------------- 1 | */ 32 | private array $configStore; 33 | private bool $initialized; 34 | private OptionsResolver $optionsResolver; 35 | 36 | public function __construct(?string $filename = null) 37 | { 38 | $this->filename = $filename; 39 | $this->initialized = false; 40 | 41 | $this->optionsResolver = new OptionsResolver(); 42 | $this->optionsResolver->setDefaults(self::getDefaults()); 43 | } 44 | 45 | /** 46 | * @return array 47 | */ 48 | public static function getDefaults(): array 49 | { 50 | return [ 51 | 'generator' => 'graphviz', 52 | 'graph' => [ 53 | 'name' => 'G', 54 | 'overlap' => 'false', 55 | 'rankdir' => 'TB', 56 | 'bgcolor' => 'transparent', 57 | ], 58 | 'node' => [ 59 | 'fontname' => 'Verdana', 60 | 'fontsize' => 8, 61 | 'shape' => 'none', 62 | 'margin' => 0, 63 | 'fillcolor' => '#FEFECE', 64 | 'style' => 'filled', 65 | ], 66 | 'edge' => [ 67 | 'fontname' => 'Verdana', 68 | 'fontsize' => 8, 69 | ], 70 | 'cluster' => null, 71 | 'paths' => [], 72 | 'label_format' => 'html', 73 | 'show_constants' => ClassDiagramBuilderInterface::OPTIONS_DEFAULTS['show_constants'], 74 | 'show_properties' => ClassDiagramBuilderInterface::OPTIONS_DEFAULTS['show_properties'], 75 | 'show_methods' => ClassDiagramBuilderInterface::OPTIONS_DEFAULTS['show_methods'], 76 | 'show_private' => ClassDiagramBuilderInterface::OPTIONS_DEFAULTS['show_private'], 77 | 'show_protected' => ClassDiagramBuilderInterface::OPTIONS_DEFAULTS['show_protected'], 78 | ]; 79 | } 80 | 81 | /** 82 | * @return array 83 | */ 84 | public function toArray(): array 85 | { 86 | if (!$this->initialized) { 87 | $this->initialize(); 88 | } 89 | return $this->configStore; 90 | } 91 | 92 | /** 93 | * @return array 94 | */ 95 | public function toFlat(): array 96 | { 97 | if (!$this->initialized) { 98 | $this->initialize(); 99 | } 100 | return $this->flatten($this->configStore); 101 | } 102 | 103 | private function initialize(): void 104 | { 105 | if (isset($this->filename)) { 106 | $paths = [realpath(dirname($this->filename))]; 107 | $fileLocator = new FileLocator($paths); 108 | try { 109 | $resource = basename($this->filename); 110 | $this->filename = $fileLocator->locate($resource); 111 | $loaderResolver = new LoaderResolver([new YamlFileLoader($fileLocator)]); 112 | $loader = $loaderResolver->resolve($resource); 113 | $configs = $loader->load($this->filename); 114 | $options = $configs['parameters']; 115 | } catch (FileLocatorFileNotFoundException $exception) { 116 | throw new InvalidArgumentException($exception->getMessage(), 0, $exception); 117 | } 118 | } else { 119 | $options = []; 120 | } 121 | $this->configStore = $this->optionsResolver->resolve($options); 122 | $this->initialized = true; 123 | } 124 | 125 | /** 126 | * Flattens a nested array of configurations. 127 | * 128 | * The scheme used is: 129 | * 'key' => ['key2' => ['key3' => 'value']] 130 | * Becomes: 131 | * 'key.key2.key3' => 'value' 132 | * 133 | * @see https://github.com/symfony/translation/blob/master/Loader/ArrayLoader.php 134 | * @param array $configs 135 | * @return array 136 | */ 137 | private function flatten(array $configs): array 138 | { 139 | $result = []; 140 | foreach ($configs as $key => $value) { 141 | if (is_array($value)) { 142 | foreach ($this->flatten($value) as $k => $v) { 143 | $result[$key . '.' . $k] = $v; 144 | } 145 | } else { 146 | $result[$key] = $value; 147 | } 148 | } 149 | return $result; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Service/ContainerService.php: -------------------------------------------------------------------------------- 1 | 33 | */ 34 | private array $internalServices = [ 35 | ClassDiagramCommand::class => null, 36 | ClassDiagramRenderer::class => null, 37 | GeneratorFactoryInterface::class => null, 38 | ]; 39 | 40 | /** 41 | * Services allowed at runtime 42 | * @var array 43 | */ 44 | private array $runtimeServices = [ 45 | InputInterface::class => null, 46 | OutputInterface::class => null, 47 | ]; 48 | 49 | public function __construct() 50 | { 51 | $this->runtimeServices[GeneratorFactoryInterface::class] = function () { 52 | return new GeneratorFactory(); 53 | }; 54 | 55 | $this->internalServices[ClassDiagramRenderer::class] = function () { 56 | return new ClassDiagramRenderer(); 57 | }; 58 | $this->internalServices[ClassDiagramCommand::class] = function () { 59 | return new ClassDiagramCommand( 60 | $this->get(ClassDiagramRenderer::class), 61 | $this->get(GeneratorFactoryInterface::class) 62 | ); 63 | }; 64 | } 65 | 66 | public function set(string $id, mixed $service): void 67 | { 68 | if (!array_key_exists($id, $this->runtimeServices)) { 69 | throw new class ( 70 | sprintf('The "%s" runtime service is not expected.', $id) 71 | ) extends RuntimeException implements ContainerExceptionInterface { 72 | }; 73 | } 74 | 75 | $this->runtimeServices[$id] = $service; 76 | } 77 | 78 | public function get(string $id): mixed 79 | { 80 | if (isset($this->runtimeServices[$id])) { 81 | return call_user_func($this->runtimeServices[$id]); 82 | } 83 | 84 | if (isset($this->internalServices[$id])) { 85 | return call_user_func($this->internalServices[$id]); 86 | } 87 | 88 | throw new class ( 89 | sprintf('The "%s" service is not registered in the service container.', $id) 90 | ) extends RuntimeException implements NotFoundExceptionInterface { 91 | }; 92 | } 93 | 94 | public function has(string $id): bool 95 | { 96 | return isset($this->internalServices[$id]) || isset($this->runtimeServices[$id]); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/FeatureTest.php: -------------------------------------------------------------------------------- 1 | createInstance($name); 35 | 36 | $fixtures = new Finder(); 37 | $fixtures->in(self::FIXTURE_DIR)->name('*.php')->sortByName(); 38 | 39 | foreach ($fixtures as $file) { 40 | $fixture = $file->getRelativePathname(); 41 | $finder = new Finder(); 42 | $finder->in(self::FIXTURE_DIR)->name($fixture); 43 | yield $fixture => [$fixture, $finder, $generator]; 44 | } 45 | } 46 | 47 | /** 48 | * Data Provider to test generation of graph statements with Graphviz generator 49 | */ 50 | public static function graphvizProvider(): Generator 51 | { 52 | return self::provider('graphviz'); 53 | } 54 | 55 | /** 56 | * Data Provider to test generation of graph statements with PlantUML generator 57 | */ 58 | public static function plantumlProvider(): Generator 59 | { 60 | return self::provider('plantuml'); 61 | } 62 | 63 | /** 64 | * Tests graph statements generation with the Graphviz generator 65 | * 66 | * @dataProvider graphvizProvider 67 | * @throws ReflectionException 68 | */ 69 | public function testGraphvizGenerator(string $fixture, Finder $finder, GeneratorInterface $generator): void 70 | { 71 | $configHandler = new ConfigurationHandler(null); 72 | $parameters = $configHandler->toFlat(); 73 | $renderer = new ClassDiagramRenderer(); 74 | $graph = $renderer($finder, $generator, $parameters); 75 | $script = $generator->createScript($graph); 76 | 77 | $this->assertStringEqualsFile( 78 | self::FIXTURE_DIR . DIRECTORY_SEPARATOR . basename($fixture, '.php') . '.gv', 79 | $script, 80 | 'Failed asserting that two graphs statements are equal.' 81 | ); 82 | } 83 | 84 | /** 85 | * Tests graph statements generation with the PlantUML generator 86 | * 87 | * @dataProvider plantumlProvider 88 | * @throws ReflectionException 89 | */ 90 | public function testPlantumlGenerator(string $fixture, Finder $finder, GeneratorInterface $generator): void 91 | { 92 | $configHandler = new ConfigurationHandler(null); 93 | $parameters = $configHandler->toFlat(); 94 | $renderer = new ClassDiagramRenderer(); 95 | $graph = $renderer($finder, $generator, $parameters); 96 | $script = $generator->createScript($graph); 97 | 98 | $this->assertStringEqualsFile( 99 | self::FIXTURE_DIR . DIRECTORY_SEPARATOR . basename($fixture, '.php') . '.puml', 100 | $script, 101 | 'Failed asserting that two graphs statements are equal.' 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/PlantUMLIssueTest.php: -------------------------------------------------------------------------------- 1 | in(self::ISSUE_DIR)->name('gh-7.php'); 37 | 38 | $generatorFactory = new GeneratorFactory(); 39 | // creates instance of Bartlett\GraphPlantUml\PlantUmlGenerator 40 | $generator = $generatorFactory->createInstance('plantuml'); 41 | 42 | $renderer = new ClassDiagramRenderer(); 43 | $graph = $renderer($finder, $generator); 44 | $script = $generator->createScript($graph); 45 | 46 | $this->assertStringEqualsFile(self::ISSUE_DIR . DIRECTORY_SEPARATOR . 'gh-7.puml', $script); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | addClassMap( 5 | [ 6 | // Fixture(s) resource(s) 7 | 'FixtureOne\\OneClass' => __DIR__ . '/fixtures/001_simpleClass.php', 8 | 'FixtureTwo\\OneClass' => __DIR__ . '/fixtures/002_simpleClassExtends.php', 9 | 'FixtureTwo\\TwoClass' => __DIR__ . '/fixtures/002_simpleClassExtends.php', 10 | 'FixtureThree\\OneInterface' => __DIR__ . '/fixtures/003_simpleClassImplements.php', 11 | 'FixtureThree\\TwoInterface' => __DIR__ . '/fixtures/003_simpleClassImplements.php', 12 | 'FixtureThree\\OneClass' => __DIR__ . '/fixtures/003_simpleClassImplements.php', 13 | 'FixtureThree\\TwoClass' => __DIR__ . '/fixtures/003_simpleClassImplements.php', 14 | 'FixtureFour\\OneClass' => __DIR__ . '/fixtures/004_Method.php', 15 | 'FixtureFive\\ParentClass' => __DIR__ . '/fixtures/005_InheritMethod.php', 16 | 'FixtureFive\\ExtendingClass' => __DIR__ . '/fixtures/005_InheritMethod.php', 17 | 'FixtureSix\\OneClass' => __DIR__ . '/fixtures/006_Constant.php', 18 | 'FixtureSeven\\ParentClass' => __DIR__ . '/fixtures/007_InheritConstant.php', 19 | 'FixtureSeven\\ExtendingClass' => __DIR__ . '/fixtures/007_InheritConstant.php', 20 | 'FixtureEight\\OneClass' => __DIR__ . '/fixtures/008_Property.php', 21 | // Issue(s) resource(s) 22 | 'ltta\\model\\BackupProject' => __DIR__ . '/issues/gh-7.php', 23 | ] 24 | ); 25 | -------------------------------------------------------------------------------- /tests/fixtures/001_simpleClass.gv: -------------------------------------------------------------------------------- 1 | graph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureOne" 7 | "FixtureOne\\OneClass" [shape="none" label=< 8 | 9 | 10 | 11 | 12 |

OneClass
>] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/fixtures/001_simpleClass.php: -------------------------------------------------------------------------------- 1 | > { 7 | -- 8 | } 9 | } 10 | @enduml 11 | -------------------------------------------------------------------------------- /tests/fixtures/002_simpleClassExtends.gv: -------------------------------------------------------------------------------- 1 | digraph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureTwo" 7 | "FixtureTwo\\OneClass" [shape="none" label=< 8 | 9 | 10 | 11 | 12 |

OneClass
>] 13 | "FixtureTwo\\TwoClass" [shape="none" label=< 14 | 15 | 16 | 17 | 18 |

TwoClass
>] 19 | } 20 | "FixtureTwo\\TwoClass" -> "FixtureTwo\\OneClass" [arrowhead="empty" style="filled"] 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/002_simpleClassExtends.php: -------------------------------------------------------------------------------- 1 | > { 7 | -- 8 | } 9 | class TwoClass << class >> { 10 | -- 11 | } 12 | } 13 | FixtureTwo.TwoClass --|> FixtureTwo.OneClass 14 | @enduml 15 | -------------------------------------------------------------------------------- /tests/fixtures/003_simpleClassImplements.gv: -------------------------------------------------------------------------------- 1 | digraph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureThree" 7 | "FixtureThree\\OneInterface" [shape="none" label=< 8 | 9 | 10 | 11 | 12 |
«interface»
OneInterface
>] 13 | "FixtureThree\\TwoInterface" [shape="none" label=< 14 | 15 | 16 | 17 | 18 |
«interface»
TwoInterface
>] 19 | "FixtureThree\\OneClass" [shape="none" label=< 20 | 21 | 22 | 23 | 24 |

OneClass
>] 25 | "FixtureThree\\TwoClass" [shape="none" label=< 26 | 27 | 28 | 29 | 30 |

TwoClass
>] 31 | } 32 | "FixtureThree\\TwoInterface" -> "FixtureThree\\OneInterface" [arrowhead="empty" style="dashed"] 33 | "FixtureThree\\OneClass" -> "FixtureThree\\OneInterface" [arrowhead="empty" style="dashed"] 34 | "FixtureThree\\TwoClass" -> "FixtureThree\\TwoInterface" [arrowhead="empty" style="dashed"] 35 | } 36 | -------------------------------------------------------------------------------- /tests/fixtures/003_simpleClassImplements.php: -------------------------------------------------------------------------------- 1 | > { 7 | -- 8 | } 9 | interface TwoInterface << interface >> { 10 | -- 11 | } 12 | class OneClass << class >> { 13 | -- 14 | } 15 | class TwoClass << class >> { 16 | -- 17 | } 18 | } 19 | FixtureThree.TwoInterface ..|> FixtureThree.OneInterface 20 | FixtureThree.OneClass ..|> FixtureThree.OneInterface 21 | FixtureThree.TwoClass ..|> FixtureThree.TwoInterface 22 | @enduml 23 | -------------------------------------------------------------------------------- /tests/fixtures/004_Method.gv: -------------------------------------------------------------------------------- 1 | graph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureFour" 7 | "FixtureFour\\OneClass" [shape="none" label=< 8 | 9 | 10 | 11 | 19 |

OneClass
12 | 13 | 14 | 15 | 16 | 17 | 18 |
+ zeroMethod()
+ objectTypeHint(oneClass : FixtureFour\\OneClass)
+ objectTypeHintAndDocComment(oneClass : FixtureFour\\OneClass)
# scalarParameters(int : int, float : float, bool : bool)
– typeHintWinsOverDocComment(oneClass : FixtureFour\\OneClass)
+ parametersWithValues(int = 1, float = 12.1, string = 'foo', bool = true)
>] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/004_Method.php: -------------------------------------------------------------------------------- 1 | > { 7 | -- 8 | +zeroMethod() 9 | +objectTypeHint(oneClass : FixtureFour.OneClass) 10 | +objectTypeHintAndDocComment(oneClass : FixtureFour.OneClass) 11 | #scalarParameters(int : int, float : float, bool : bool) 12 | –typeHintWinsOverDocComment(oneClass : FixtureFour.OneClass) 13 | +parametersWithValues(int = 1, float = 12.1, string = 'foo', bool = true) 14 | } 15 | } 16 | @enduml 17 | -------------------------------------------------------------------------------- /tests/fixtures/005_InheritMethod.gv: -------------------------------------------------------------------------------- 1 | digraph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureFive" 7 | "FixtureFive\\ParentClass" [shape="none" label=< 8 | 9 | 10 | 11 | 15 |

ParentClass
12 | 13 | 14 |
+ someParentMethod()
+ methodToOverride()
>] 16 | "FixtureFive\\ExtendingClass" [shape="none" label=< 17 | 18 | 19 | 20 | 23 |

ExtendingClass
21 | 22 |
+ methodToOverride()
>] 24 | } 25 | "FixtureFive\\ExtendingClass" -> "FixtureFive\\ParentClass" [arrowhead="empty" style="filled"] 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/005_InheritMethod.php: -------------------------------------------------------------------------------- 1 | > { 7 | -- 8 | +someParentMethod() 9 | +methodToOverride() 10 | } 11 | class ExtendingClass << class >> { 12 | -- 13 | +methodToOverride() 14 | } 15 | } 16 | FixtureFive.ExtendingClass --|> FixtureFive.ParentClass 17 | @enduml 18 | -------------------------------------------------------------------------------- /tests/fixtures/006_Constant.gv: -------------------------------------------------------------------------------- 1 | graph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureSix" 7 | "FixtureSix\\OneClass" [shape="none" label=< 8 | 9 | 10 | 18 | 30 | 35 |

OneClass
11 | 12 | 13 | 14 | 15 | 16 | 17 |
+ «static» STRING_CONSTANT : string = "string" {readOnly}
+ «static» INTEGER_CONSTANT : int = 7654 {readOnly}
+ «static» FLOAT_CONSTANT : float = 7654.321 {readOnly}
+ «static» LF_CONSTANT : string = "\\n" {readOnly}
+ «static» CR_CONSTANT : string = "\\r" {readOnly}
+ «static» TAB_CONSTANT : string = "\\t" {readOnly}
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
+ «static» NOVALUE_STATIC
+ «static» STRING_STATIC = "string"
+ «static» INTEGER_STATIC = 7654
+ «static» FLOAT_STATIC = 7654.321
+ «static» LF_STATIC = "\\n"
+ «static» CR_STATIC = "\\r"
+ «static» TAB_STATIC = "\\t"
+ «static» PUBLIC_STATIC
# «static» PROTECTED_STATIC
– «static» PRIVATE_STATIC
31 | 32 | 33 | 34 |
+ «static» staticPublic()
# «static» staticProtected()
– «static» staticPrivate()
>] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/fixtures/006_Constant.php: -------------------------------------------------------------------------------- 1 | > { 7 | +{static} STRING_CONSTANT : string = "string" {readOnly} 8 | +{static} INTEGER_CONSTANT : int = 7654 {readOnly} 9 | +{static} FLOAT_CONSTANT : float = 7654.321 {readOnly} 10 | +{static} LF_CONSTANT : string = "\\n" {readOnly} 11 | +{static} CR_CONSTANT : string = "\\r" {readOnly} 12 | +{static} TAB_CONSTANT : string = "\\t" {readOnly} 13 | 14 | +{static} NOVALUE_STATIC 15 | +{static} STRING_STATIC = "string" 16 | +{static} INTEGER_STATIC = 7654 17 | +{static} FLOAT_STATIC = 7654.321 18 | +{static} LF_STATIC = "\\n" 19 | +{static} CR_STATIC = "\\r" 20 | +{static} TAB_STATIC = "\\t" 21 | +{static} PUBLIC_STATIC 22 | #{static} PROTECTED_STATIC 23 | –{static} PRIVATE_STATIC 24 | -- 25 | +{static}staticPublic() 26 | #{static}staticProtected() 27 | –{static}staticPrivate() 28 | } 29 | } 30 | @enduml 31 | -------------------------------------------------------------------------------- /tests/fixtures/007_InheritConstant.gv: -------------------------------------------------------------------------------- 1 | digraph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureSeven" 7 | "FixtureSeven\\ParentClass" [shape="none" label=< 8 | 9 | 10 | 14 | 15 | 16 |

ParentClass
11 | 12 | 13 |
+ «static» PARENT_CONSTANT : bool = true {readOnly}
+ «static» INHERIT_CONSTANT : bool = true {readOnly}
>] 17 | "FixtureSeven\\ExtendingClass" [shape="none" label=< 18 | 19 | 20 | 23 | 24 | 25 |

ExtendingClass
21 | 22 |
+ «static» PARENT_CONSTANT : bool = false {readOnly}
>] 26 | } 27 | "FixtureSeven\\ExtendingClass" -> "FixtureSeven\\ParentClass" [arrowhead="empty" style="filled"] 28 | } 29 | -------------------------------------------------------------------------------- /tests/fixtures/007_InheritConstant.php: -------------------------------------------------------------------------------- 1 | > { 7 | +{static} PARENT_CONSTANT : bool = true {readOnly} 8 | +{static} INHERIT_CONSTANT : bool = true {readOnly} 9 | 10 | -- 11 | } 12 | class ExtendingClass << class >> { 13 | +{static} PARENT_CONSTANT : bool = false {readOnly} 14 | 15 | -- 16 | } 17 | } 18 | FixtureSeven.ExtendingClass --|> FixtureSeven.ParentClass 19 | @enduml 20 | -------------------------------------------------------------------------------- /tests/fixtures/008_Property.gv: -------------------------------------------------------------------------------- 1 | graph { 2 | graph [name="G" overlap="false" rankdir="TB" bgcolor="transparent"] 3 | node [fontname="Verdana" fontsize=8 shape="none" margin=0 fillcolor="#FEFECE" style="filled"] 4 | edge [fontname="Verdana" fontsize=8] 5 | subgraph cluster_0 { 6 | label = "FixtureEight" 7 | "FixtureEight\\OneClass" [shape="none" label=< 8 | 9 | 10 | 17 | 18 |

OneClass
11 | 12 | 13 | 14 | 15 | 16 |
– stringProperty : string = "string"
# intProperty : int = 654
+ booleanProperty : bool = true
# arrayProperty : array = […]
+ floatProperty : float = 654.123
>] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/008_Property.php: -------------------------------------------------------------------------------- 1 | > { 7 | –stringProperty : string = "string" 8 | #intProperty : int = 654 9 | +booleanProperty : bool = true 10 | #arrayProperty : array = […] 11 | +floatProperty : float = 654.123 12 | -- 13 | } 14 | } 15 | @enduml 16 | -------------------------------------------------------------------------------- /tests/issues/gh-7.php: -------------------------------------------------------------------------------- 1 | a = $a; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/issues/gh-7.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | skinparam backgroundColor transparent 4 | top to bottom direction 5 | namespace ltta.model { 6 | class BackupProject << class >> { 7 | –a 8 | -- 9 | +__construct(a : string) 10 | } 11 | } 12 | @enduml 13 | -------------------------------------------------------------------------------- /vendor-bin/graph-composer/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "repositories": [ 3 | { 4 | "type": "vcs", 5 | "url": "https://github.com/llaville/graph-composer" 6 | } 7 | ], 8 | "minimum-stability": "dev", 9 | "require-dev": { 10 | "clue/graph-composer": "v2.x-dev" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /vendor-bin/php-cs/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "squizlabs/php_codesniffer": "^3" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vendor-bin/phplint/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "overtrue/phplint": "^9.5" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vendor-bin/phpstan/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "phpstan/phpstan": "^1.10" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vendor-bin/phpunit/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "phpunit/phpunit": "^10.5" 4 | } 5 | } 6 | --------------------------------------------------------------------------------