ClassVisitor.php 3.43 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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_;
14
use Irstea\PlantUmlBundle\Writer\WriterInterface;
15
16
17
18
19
20
21
22
23
24
use ReflectionClass;

/**
 * Description of Visitor
 *
 * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
 */
class ClassVisitor implements ClassVisitorInterface, UmlComponentInterface
{
    /**
25
     * @var RootNamespace
26
     */
27
    protected $rootNamespace;
28

29
30
31
32
    public function __construct()
    {
        $this->rootNamespace = new RootNamespace();
    }
Guillaume Perréal's avatar
Guillaume Perréal committed
33

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    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());
        }
68

69
        $this->nodes[$class->getName()] = $node;
70
71
72

        $namespace = $this->rootNamespace->getNamespace($class->getNamespaceName());
        $namespace->addNode($node);
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

        $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());
92
            $this->visitRelations($node, $namespace, [$parentClass->getName()], 'Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass');
93
94
        }

95
96
        $this->visitRelations($node, $namespace, $interfaceNames, 'Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface');
        $this->visitRelations($node, $namespace, $traitNames, 'Irstea\PlantUmlBundle\Model\Arrow\UsesTrait');
97
98
99
100

        return $node;
    }

101
    protected function visitRelations(UmlNodeInterface $source, NamespaceInterface $namespace, array $classNames, $relationClass)
102
103
104
    {
        foreach ($classNames as $className) {
            $target = $this->visitClass($className);
105
            $namespace->addArrow(new $relationClass($source, $target));
106
107
108
        }
    }

109
    public function outputTo(WriterInterface $writer)
Guillaume Perréal's avatar
Guillaume Perréal committed
110
    {
111
        return $this->rootNamespace->outputTo($writer);
Guillaume Perréal's avatar
Guillaume Perréal committed
112
    }
113
}