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

Code before:
/**
 * MermaidDumper dumps a Mermaid flowchart describing role hierarchy.
 *
 * @author Damien Fernandes <your.email@example.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
     */
    public function dump(RoleHierarchyInterface $roleHierarchy): string
    {
        $hierarchy = $this->extractHierarchy($roleHierarchy);

        if ([] === $hierarchy) {
            return "graph {$this->direction}\n    classDef default fill:#e1f5fe;";
        }

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

        // Add role nodes
        foreach ($allRoles as $role) {

Review comment (suggestion):
```suggestion
            throw new \InvalidArgumentException(\sprintf(
```

Code after:

/**
 * 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));
    }

    private function extractHierarchy(RoleHierarchyInterface $roleHierarchy): array
    {
        if (!$roleHierarchy instanceof RoleHierarchy) {
            return [];
        }

        $reflection = new \ReflectionClass(RoleHierarchy::class);

        $hierarchyProperty = $reflection->getProperty('hierarchy');

        return $hierarchyProperty->getValue($roleHierarchy);
    }