Repository: symfony/symfony
File: src/Symfony/Component/Security/Core/Dumper/MermaidDumper.php (PHP)

Code before:

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Security\Core\Dumper;

use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

/**
 * MermaidDumper dumps a Mermaid flowchart describing role hierarchy.
 *
 * @author Damien Fernandes <damien.fernandes24@gmail.com>
 */
class MermaidDumper
{
    public const DIRECTION_TOP_TO_BOTTOM = 'TB';
    public const DIRECTION_TOP_DOWN = 'TD';
    public const DIRECTION_BOTTOM_TO_TOP = 'BT';
    public const DIRECTION_RIGHT_TO_LEFT = 'RL';
    public const DIRECTION_LEFT_TO_RIGHT = 'LR';

    public const VALID_DIRECTIONS = [
        self::DIRECTION_TOP_TO_BOTTOM,
        self::DIRECTION_TOP_DOWN,
        self::DIRECTION_BOTTOM_TO_TOP,
        self::DIRECTION_RIGHT_TO_LEFT,
        self::DIRECTION_LEFT_TO_RIGHT,
    ];

    public function __construct(
        private readonly string $direction = self::DIRECTION_TOP_TO_BOTTOM,
    ) {
        if (!\in_array($direction, self::VALID_DIRECTIONS, true)) {
            throw new \InvalidArgumentException(\sprintf(
                'Direction "%s" is not valid, valid directions are: "%s".',
                $direction,
                implode('", "', self::VALID_DIRECTIONS)
            ));
        }
    }

    /**
     * Dumps the role hierarchy as a Mermaid flowchart.
     *
     * @param RoleHierarchyInterface $roleHierarchy The role hierarchy to dump

Review comment (suggestion):
those look like a perfect use case for a backed enum instead of using string constants in that class (and then redoing lots of manual validation)

Code after:

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Security\Core\Dumper;

use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

/**
 * MermaidDumper dumps a Mermaid flowchart describing role hierarchy.
 *
 * @author Damien Fernandes <damien.fernandes24@gmail.com>
 */
class MermaidDumper
{
    /**
     * Dumps the role hierarchy as a Mermaid flowchart.
     *
     * @param RoleHierarchyInterface $roleHierarchy The role hierarchy to dump
     * @param MermaidDirectionEnum   $direction     The direction of the flowchart
     */
    public function dump(RoleHierarchyInterface $roleHierarchy, MermaidDirectionEnum $direction = MermaidDirectionEnum::TOP_TO_BOTTOM): string
    {
        $hierarchy = $this->extractHierarchy($roleHierarchy);

        if (!$hierarchy) {
            return "graph {$direction->value}\n    classDef default fill:#e1f5fe;";
        }

        $output = ["graph {$direction->value}"];
        $allRoles = $this->getAllRoles($hierarchy);

        foreach ($allRoles as $role) {
            $output[] = $this->formatRoleNode($role);
        }

        foreach ($hierarchy as $parentRole => $childRoles) {
            foreach ($childRoles as $childRole) {
                $output[] = "    {$this->normalizeRoleName($parentRole)} --> {$this->normalizeRoleName($childRole)}";
            }
        }

        return implode("\n", array_filter($output));
    }