ClassVisitor.php 4.25 KiB
<?php
/*
 * © 2016 IRSTEA
 * Guillaume Perréal <guillaume.perreal@irstea.fr>
 * Tous droits réservés.
 */
namespace Irstea\PlantUmlBundle\Model;
use Irstea\PlantUmlBundle\Model\Node\Class_;
use Irstea\PlantUmlBundle\Model\Node\Interface_;
use Irstea\PlantUmlBundle\Model\Node\Trait_;
use ReflectionClass;
/**
 * Description of Visitor
 * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
class ClassVisitor implements ClassVisitorInterface, UmlComponentInterface
    /**
     * @var UmlNodeInterface[]
    protected $nodes = [];
    /**
     * @var UmlComponentInterface[]
    protected $arrows = [];
    /**
     * @var string[]
    protected $namespaces = [];
    public function visitClass($className)
        assert('is_string($className)', $className);
        if (isset($this->nodes[$className])) {
            return $this->nodes[$className];
        return $this->doVisitClass($className);
    /**
     * @param string $className
     * @return UmlNodeInterface
    protected function doVisitClass($className)
        $reflection = new ReflectionClass($className);
        return $this->visitClassReflection($reflection);
    /**
     * @param ReflectionClass $class
     * @return UmlNodeInterface
    protected function visitClassReflection(ReflectionClass $class)
        if ($class->isTrait()) {
            $node  = new Trait_($class->getName());
        } elseif ($class->isInterface()) {
            $node  = new Interface_($class->getName());
        } else {
            $node = new Class_($class->getName(), $class->isAbstract(), $class->isFinal());
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
} $this->nodes[$class->getName()] = $node; $this->visitNamespace($class->getNamespaceName()); $parentClass = $class->getParentClass(); $traitNames = $class->getTraitNames(); $indirectInterfaces = array_filter( array_map( function ($i) { return $i->getInterfaceNames(); }, $class->getInterfaces() ) ); $interfaceNames = $class->getInterfaceNames(); if (!empty($indirectInterfaces)) { $indirectInterfaces = call_user_func_array('array_merge', $indirectInterfaces); $interfaceNames = array_diff($interfaceNames, $indirectInterfaces); } if ($parentClass) { $traitNames = array_diff($traitNames, $parentClass->getTraitNames()); $interfaceNames = array_diff($interfaceNames, $parentClass->getInterfaceNames()); $this->visitRelations($node, [$parentClass->getName()], 'Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass'); } $this->visitRelations($node, $interfaceNames, 'Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface'); $this->visitRelations($node, $traitNames, 'Irstea\PlantUmlBundle\Model\Arrow\UsesTrait'); return $node; } protected function visitRelations(UmlNodeInterface $source, array $classNames, $relationClass) { foreach ($classNames as $className) { $target = $this->visitClass($className); $this->arrows[] = new $relationClass($source, $target); } } protected function visitNamespace($namespaceName) { $current =& $this->namespaces; foreach(explode('\\', $namespaceName) as $part) { if (!isset($current[$part])) { $current[$part] = []; } $current = &$current[$part]; } } public function outputTo($stream) { $this->outputNamespacesTo($stream, $this->namespaces); foreach ($this->nodes as $node) { $node->outputTo($stream); } foreach ($this->arrows as $arrow) { $arrow->outputTo($stream); } } protected function outputNamespacesTo($stream, $namespaces) { foreach($namespaces as $name => $children) { fputs($stream, "namespace "); /*while(count($children) == 1) { fputs($stream, $name.'.'); list($name, $children) = each($children); }*/
141142143144145146147
fputs($stream, "$name {\n"); $this->outputNamespacesTo($stream, $children); fputs($stream, "}\n"); } } }