refactor: Cleanup git state - commit all staged changes

Major refactoring cleanup:
- Add new controller architecture (class-controller-*.php)
- Add new settings-v2 UI (views/settings-v2/)
- Add new CSS architecture (agentic-sidebar.css, tokens)
- Add esbuild build pipeline (scripts/build.js, package.json)
- Add composer dependencies (vendor/)
- Add frontend src directory (assets/js/src/index.jsx)
- Add documentation files
- Remove old/obsolete files (class-settings.php, old CSS)

This commits all pending changes from previous refactoring efforts.
This commit is contained in:
Dwindi Ramadhana
2026-06-17 05:27:58 +07:00
parent d3f142222c
commit 690991c526
7963 changed files with 941566 additions and 67372 deletions

View File

@@ -0,0 +1,23 @@
======================================
Contribute to the phpDocumentor Guides
======================================
Go to the mono-repository
=========================
This project is developed in the mono-repository `phpDocumentor Guides <https://github.com/phpDocumentor/guides>`__.
The repository you are currently in gets auto-created by splitting the mono-repository. You **must not** contribute
to this repository directly but always to the mono-repository linked above.
Create Issues
=============
* If you find something missing or something is wrong in this library, you are welcome to write an issue
describing the problem: `Issues on GitHub <https://github.com/phpDocumentor/guides/issues>`__.
* If you can, please try to fix the problem yourself.
Make changes (create pull requests)
===================================
See the `Contribution chapter <https://docs.phpdoc.org/components/guides/guides/contributions/index.html>`__ in the
`Documentation` <https://docs.phpdoc.org/components/guides/guides/index.html>`__.

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2010 Mike van Riel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,37 @@
.. image:: https://poser.pugx.org/phpdocumentor/guides-graphs/require/php
:alt: PHP Version Require
:target: https://packagist.org/packages/phpdocumentor/guides-graphs
.. image:: https://poser.pugx.org/phpdocumentor/guides-graphs/v/stable
:alt: Latest Stable Version
:target: https://packagist.org/packages/phpdocumentor/guides-graphs
.. image:: https://poser.pugx.org/phpdocumentor/guides-graphs/v/unstable
:alt: Latest Unstable Version
:target: https://packagist.org/packages/phpdocumentor/guides-graphs
.. image:: https://poser.pugx.org/phpdocumentor/guides-graphs/d/total
:alt: Total Downloads
:target: https://packagist.org/packages/phpdocumentor/guides-graphs
.. image:: https://poser.pugx.org/phpdocumentor/guides-graphs/d/monthly
:alt: Monthly Downloads
:target: https://packagist.org/packages/phpdocumentor/guides-graphs
====================
phpDocumentor Guides
====================
This repository is part of `phpDocumentor's Guides library <https://github.com/phpDocumentor/guides>`__, a framework
designed to take hand-written documentation in code repositories and create an AST (abstract syntax tree) from it.
This AST is then fed to a renderer, which produces the desired output, such as HTML.
The package `phpdocumentor/guides-graphs <https://packagist.org/packages/phpdocumentor/guides-graphs>`__ provides
`Plantuml <https://github.com/plantuml/plantuml>`__ support for restructured text rendered by the phpDocumentor's
Guides library. Using this package is optional.
:Mono-Repository: https://github.com/phpDocumentor/guides
:Documentation: https://docs.phpdoc.org/components/guides/guides/index.html
:Packagist: https://packagist.org/packages/phpdocumentor/guides-graphs
:Contribution: https://github.com/phpDocumentor/guides/tree/main/CONTRIBUTING.rst

View File

@@ -0,0 +1,39 @@
{
"name": "phpdocumentor/guides-graphs",
"description": "Provides Plantuml support for restructured text rendered by the phpDocumentor's Guides library.",
"type": "library",
"license": "MIT",
"homepage": "https://www.phpdoc.org",
"config": {
"sort-packages": true
},
"autoload": {
"psr-4": {
"phpDocumentor\\Guides\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"phpDocumentor\\Guides\\": [
"tests/unit/"
]
}
},
"minimum-stability": "stable",
"require": {
"php": "^8.1",
"phpdocumentor/guides": "^1.0 || ^2.0",
"phpdocumentor/guides-restructured-text": "^1.0 || ^2.0",
"jawira/plantuml-encoding": "^1.0",
"symfony/process": "^5.4 || ^6.3 || ^7.0 || ^8.0",
"twig/twig": "~2.0 || ^3.0"
},
"suggest": {
"jawira/plantuml": "To render graphs locally using plant uml"
},
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
use phpDocumentor\Guides\Graphs\Directives\UmlDirective;
use phpDocumentor\Guides\Graphs\Nodes\UmlNode;
use phpDocumentor\Guides\Graphs\Renderer\DiagramRenderer;
use phpDocumentor\Guides\Graphs\Renderer\PlantumlRenderer;
use phpDocumentor\Guides\Graphs\Renderer\PlantumlServerRenderer;
use phpDocumentor\Guides\Graphs\Renderer\TestRenderer;
use phpDocumentor\Guides\Graphs\Twig\UmlExtension;
use phpDocumentor\Guides\NodeRenderers\TemplateNodeRenderer;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
use function Symfony\Component\DependencyInjection\Loader\Configurator\tagged_iterator;
return static function (ContainerConfigurator $container): void {
$container->services()
->defaults()
->autowire()
->autoconfigure()
->set(UmlDirective::class)
->tag('phpdoc.guides.directive')
->set('phpdoc.guides.', TemplateNodeRenderer::class)
->tag('phpdoc.guides.noderenderer.html')
->arg('$template', 'body/uml.html.twig')
->arg('$nodeClass', UmlNode::class)
->set(PlantumlRenderer::class)
->arg('$plantUmlBinaryPath', '%guides.graphs.plantuml_binary%')
->tag('phpdoc.guides.graph.renderer', ['alias' => 'plantuml'])
->set(TestRenderer::class)
->tag('phpdoc.guides.graph.renderer', ['alias' => 'testrender'])
->set(PlantumlServerRenderer::class)
->arg(
'$plantumlServerUrl',
'%guides.graphs.plantuml_server%',
)
->tag('phpdoc.guides.graph.renderer', ['alias' => 'plantuml-server'])
->alias(DiagramRenderer::class, PlantumlServerRenderer::class)
->set(UmlExtension::class)
->arg('$renderers', tagged_iterator('phpdoc.guides.graph.renderer', 'alias'))
->arg('$rendererAlias', param('guides.graphs.renderer'))
->tag('twig.extension');
};

View File

@@ -0,0 +1,8 @@
<figure class="uml-diagram{% if node.classesString %} {{ node.classesString }}{% endif %}"
{%- if node.hasOption('width') %} style="width: {{ node.option('width') }}"{% endif -%}
>
{{ uml(node.value) }}
{% if node.caption %}
<figcaption>{{ node.caption }}</figcaption>
{% endif %}
</figure>

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use function assert;
final class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('Graphs');
$rootNode = $treeBuilder->getRootNode();
assert($rootNode instanceof ArrayNodeDefinition);
$rootNode->children()
->scalarNode('renderer')
->defaultValue('plantuml-server')
->info('Render engine to use for generating graphs')
->end()
->scalarNode('plantuml_server')
->defaultValue('https://www.plantuml.com/plantuml')
->info('URL of the PlantUML server to use')
->end()
->scalarNode('plantuml_binary')
->defaultValue('plantuml')
->info('Path to your local PlantUML binary')
->end();
return $treeBuilder;
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use function dirname;
final class GraphsExtension extends Extension implements PrependExtensionInterface
{
/** @param mixed[] $configs */
public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->processConfiguration(
$this->getConfiguration($configs, $container),
$configs,
);
$container->setParameter('guides.graphs.renderer', $config['renderer']);
$container->setParameter('guides.graphs.plantuml_binary', $config['plantuml_binary']);
$container->setParameter('guides.graphs.plantuml_server', $config['plantuml_server']);
$loader = new PhpFileLoader(
$container,
new FileLocator(dirname(__DIR__, 3) . '/resources/config'),
);
$loader->load('guides-graphs.php');
}
public function prepend(ContainerBuilder $container): void
{
$container->prependExtensionConfig('guides', [
'base_template_paths' => [dirname(__DIR__, 3) . '/resources/template/html'],
]);
}
}

View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Directives;
use phpDocumentor\Guides\Graphs\Nodes\UmlNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface;
use phpDocumentor\Guides\RestructuredText\Directives\BaseDirective;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use Psr\Log\LoggerInterface;
use Webmozart\Assert\Assert;
use function dirname;
use function explode;
use function implode;
use function sprintf;
use function str_replace;
/**
* Renders a uml diagram, example:
*
* .. uml::
* skinparam activityBorderColor #516f42
* skinparam activityBackgroundColor #a3dc7f
* skinparam shadowing false
*
* start
* :Boot the application;
* :Parse files into an AST;
* :Transform AST into artifacts;
* stop
*/
final class UmlDirective extends BaseDirective
{
public function __construct(
private readonly LoggerInterface $logger,
private readonly DocumentNameResolverInterface $documentNameResolver,
) {
}
public function getName(): string
{
return 'uml';
}
/** {@inheritDoc} */
public function process(
BlockContext $blockContext,
Directive $directive,
): Node|null {
$value = implode("\n", $blockContext->getDocumentIterator()->toArray());
if (empty($value)) {
$value = $this->loadExternalUmlFile($blockContext, $directive->getData());
if ($value === null) {
return null;
}
}
$node = new UmlNode($value);
$node->setClasses(explode(' ', (string) $directive->getOption('classes')->getValue()));
if ($directive->hasOption('caption')) {
$node->setCaption((string) $directive->getOption('caption')->getValue());
}
return $node;
}
private function loadExternalUmlFile(BlockContext $blockContext, string $path): string|null
{
$parser = $blockContext->getDocumentParserContext()->getParser();
$parserContext = $parser->getParserContext();
$fileName = $this->documentNameResolver->absoluteUrl(
dirname($blockContext->getDocumentParserContext()->getContext()->getCurrentAbsolutePath()),
$path,
);
if (!$parserContext->getOrigin()->has($fileName)) {
$message =
sprintf('Tried to include "%s" as a diagram but the file could not be found', $fileName);
$this->logger->error($message, $parserContext->getLoggerInformation());
return null;
}
$value = $parserContext->getOrigin()->read($fileName);
Assert::string($value);
return str_replace(['@startuml', '@enduml'], '', $value);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Nodes;
use phpDocumentor\Guides\Nodes\TextNode;
final class UmlNode extends TextNode
{
private string $caption = '';
public function setCaption(string $caption): void
{
$this->caption = $caption;
}
public function getCaption(): string
{
return $this->caption;
}
}

View File

@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Renderer;
use phpDocumentor\Guides\RenderContext;
interface DiagramRenderer
{
public function render(RenderContext $renderContext, string $diagram): string|null;
}

View File

@@ -0,0 +1,131 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Renderer;
use phpDocumentor\Guides\RenderContext;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Exception\RuntimeException;
use Symfony\Component\Process\Process;
use function array_merge;
use function file_get_contents;
use function file_put_contents;
use function is_dir;
use function mkdir;
use function sys_get_temp_dir;
use function tempnam;
use function unlink;
final class PlantumlRenderer implements DiagramRenderer
{
private readonly string $tempDirectory;
public function __construct(
private readonly LoggerInterface $logger,
private readonly string $plantUmlBinaryPath,
string|null $tempDirectory = null,
) {
$this->tempDirectory = $tempDirectory ?? sys_get_temp_dir() . '/phpdocumentor';
}
public function render(RenderContext $renderContext, string $diagram): string|null
{
$output = <<<PUML
@startuml
skinparam ArrowColor #516f42
skinparam activityBorderColor #516f42
skinparam activityBackgroundColor #ffffff
skinparam activityDiamondBorderColor #516f42
skinparam activityDiamondBackgroundColor #ffffff
skinparam shadowing false
$diagram
@enduml
PUML;
if (!$this->ensureDirectoryExists($this->tempDirectory)) {
$this->logger->error(
'Failed to create temp directory: ' . $this->tempDirectory,
$renderContext->getLoggerInformation(),
);
return null;
}
$pumlFileLocation = tempnam($this->tempDirectory, 'pu_');
if ($pumlFileLocation === false) {
$this->logger->error(
'Failed to create temporary file for diagram',
$renderContext->getLoggerInformation(),
);
return null;
}
file_put_contents($pumlFileLocation, $output);
try {
$process = new Process([$this->plantUmlBinaryPath, '-tsvg', $pumlFileLocation], __DIR__, null, null, 600.0);
$process->run();
if (!$process->isSuccessful()) {
$this->logger->error(
'Generating the class diagram failed',
array_merge(
['error' => $process->getErrorOutput()],
$renderContext->getLoggerInformation(),
),
);
return null;
}
} catch (RuntimeException $e) {
$this->logger->error(
'Generating the class diagram failed',
array_merge(
['error' => $e->getMessage()],
$renderContext->getLoggerInformation(),
),
);
return null;
}
$svg = file_get_contents($pumlFileLocation . '.svg') ?: null;
@unlink($pumlFileLocation);
@unlink($pumlFileLocation . '.svg');
return $svg;
}
/**
* Ensures the directory exists, handling race conditions safely.
*
* @return bool True if directory exists or was created, false on failure
*/
private function ensureDirectoryExists(string $directory): bool
{
if (is_dir($directory)) {
return true;
}
// Attempt to create the directory (suppress warning if concurrent process creates it)
if (@mkdir($directory, 0o755, true)) {
return true;
}
// mkdir failed - check if another process created it (race condition)
return is_dir($directory);
}
}

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Renderer;
use phpDocumentor\Guides\RenderContext;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use function Jawira\PlantUml\encodep;
use function sprintf;
final class PlantumlServerRenderer implements DiagramRenderer
{
public function __construct(
private readonly HttpClientInterface $httpClient,
private readonly string $plantumlServerUrl,
private readonly LoggerInterface $logger,
) {
}
public function render(RenderContext $renderContext, string $diagram): string|null
{
$encodedDiagram = encodep($diagram);
$url = $this->plantumlServerUrl . '/svg/' . $encodedDiagram;
try {
$response = $this->httpClient->request(
'GET',
$url,
);
if ($response->getStatusCode() !== 200) {
$this->logger->warning(
sprintf(
'Failed to render diagram using url: %s. The server returned status code %s. ',
$url,
$response->getStatusCode(),
),
$renderContext->getLoggerInformation(),
);
return null;
}
return $response->getContent();
} catch (TransportExceptionInterface) {
$this->logger->warning(
sprintf(
'Failed to render diagram using url: %s. ',
$url,
),
$renderContext->getLoggerInformation(),
);
return null;
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Renderer;
use phpDocumentor\Guides\RenderContext;
use function md5;
final class TestRenderer implements DiagramRenderer
{
public function render(RenderContext $renderContext, string $diagram): string|null
{
return md5($diagram);
}
}

View File

@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/
namespace phpDocumentor\Guides\Graphs\Twig;
use phpDocumentor\Guides\Graphs\Renderer\DiagramRenderer;
use phpDocumentor\Guides\RenderContext;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use function assert;
final class UmlExtension extends AbstractExtension
{
private DiagramRenderer $diagramRenderer;
/** @param iterable<string, DiagramRenderer> $renderers */
public function __construct(iterable $renderers, string $rendererAlias)
{
foreach ($renderers as $alias => $renderer) {
if ($alias !== $rendererAlias) {
continue;
}
$this->diagramRenderer = $renderer;
}
}
/** @return TwigFunction[] */
public function getFunctions(): array
{
return [
new TwigFunction('uml', $this->uml(...), ['is_safe' => ['html'], 'needs_context' => true]),
];
}
/** @param array{env: RenderContext} $context */
public function uml(array $context, string $source): string|null
{
$renderContext = $context['env'];
assert($renderContext instanceof RenderContext);
return $this->diagramRenderer->render($renderContext, $source);
}
}