From bc58e9ca77e8fbfad438526404756f7ce47900ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Guillaume=20Perr=C3=A9al?= <guillaume.perreal@irstea.fr>
Date: Thu, 10 Mar 2016 17:22:21 +0100
Subject: [PATCH] =?UTF-8?q?S=C3=A9pare=20le=20d=C3=A9corateur=20inheritanc?=
 =?UTF-8?q?e=20en=20plusieurs=20morceaux.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 Command/GenerateCommand.php                   |  8 +++
 DependencyInjection/Configuration.php         |  4 +-
 Model/Decorator/AbstractRelationDecorator.php | 44 +++++++++++++++
 Model/Decorator/InheritanceDecorator.php      | 36 ++-----------
 Model/Decorator/InterfaceDecorator.php        | 54 +++++++++++++++++++
 Model/Decorator/TraitDecorator.php            | 42 +++++++++++++++
 6 files changed, 155 insertions(+), 33 deletions(-)
 create mode 100644 Model/Decorator/AbstractRelationDecorator.php
 create mode 100644 Model/Decorator/InterfaceDecorator.php
 create mode 100644 Model/Decorator/TraitDecorator.php

diff --git a/Command/GenerateCommand.php b/Command/GenerateCommand.php
index b17b5f0..dbc497a 100644
--- a/Command/GenerateCommand.php
+++ b/Command/GenerateCommand.php
@@ -15,7 +15,9 @@ use Irstea\PlantUmlBundle\Model\ClassVisitor;
 use Irstea\PlantUmlBundle\Model\Decorator\CompositeDecorator;
 use Irstea\PlantUmlBundle\Model\Decorator\FilteringDecorator;
 use Irstea\PlantUmlBundle\Model\Decorator\InheritanceDecorator;
+use Irstea\PlantUmlBundle\Model\Decorator\InterfaceDecorator;
 use Irstea\PlantUmlBundle\Model\Decorator\NullDecorator;
+use Irstea\PlantUmlBundle\Model\Decorator\TraitDecorator;
 use Irstea\PlantUmlBundle\Model\DecoratorInterface;
 use Irstea\PlantUmlBundle\Model\Filter\AcceptAllFilter;
 use Irstea\PlantUmlBundle\Model\Filter\Composite\AllFilter;
@@ -208,6 +210,12 @@ class GenerateCommand extends ContainerAwareCommand
                 case 'inheritance':
                     $decorators[] = new InheritanceDecorator();
                     break;
+                case 'interfaces':
+                    $decorators[] = new InterfaceDecorator();
+                    break;
+                case 'traits':
+                    $decorators[] = new TraitDecorator();
+                    break;
                 case 'entity':
                     $decorators[] = new EntityDecorator($this->entityManager->getMetadataFactory());
                     break;
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index e112708..2c8e19b 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -85,9 +85,9 @@ class Configuration implements ConfigurationInterface
                         ->addDefaultsIfNotSet()
                         ->children()
                             ->arrayNode('decorators')
-                                ->defaultValue(['inheritance', 'entity', 'associations', 'properties', 'methods'])
+                                ->defaultValue(['inheritance', 'traits', 'interfaces', 'entity', 'associations', 'properties', 'methods'])
                                 ->prototype('enum')
-                                    ->values(['inheritance', 'entity', 'associations', 'properties', 'methods'])
+                                    ->values(['inheritance', 'traits', 'interfaces', 'entity', 'associations', 'properties', 'methods'])
                                 ->end()
                             ->end()
                             ->append($this->buildFilterNode('include'))
diff --git a/Model/Decorator/AbstractRelationDecorator.php b/Model/Decorator/AbstractRelationDecorator.php
new file mode 100644
index 0000000..d91cd57
--- /dev/null
+++ b/Model/Decorator/AbstractRelationDecorator.php
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model\Decorator;
+
+use Irstea\PlantUmlBundle\Model\ArrowInterface;
+use Irstea\PlantUmlBundle\Model\ClassVisitorInterface;
+use Irstea\PlantUmlBundle\Model\DecoratorInterface;
+use Irstea\PlantUmlBundle\Model\NodeInterface;
+
+/**
+ * Description of InheritanceDecorator
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+abstract class AbstractRelationDecorator implements DecoratorInterface
+{
+    /**
+     * @param NodeInterface $source
+     * @param array $classNames
+     * @param ClassVisitorInterface $visitor
+     */
+    protected function visitRelations(NodeInterface $source, array $classNames, ClassVisitorInterface $visitor)
+    {
+        foreach ($classNames as $className) {
+            $target = $visitor->visitClass($className);
+            if ($target) {
+                $source->addArrow($this->buildRelation($source, $target));
+            }
+        }
+    }
+
+    /**
+     * @param NodeInterface $source
+     * @param NodeInterface $target
+     * @return ArrowInterface
+     */
+    abstract protected function buildRelation(NodeInterface $source, NodeInterface $target);
+}
diff --git a/Model/Decorator/InheritanceDecorator.php b/Model/Decorator/InheritanceDecorator.php
index ff901f0..0d5ef51 100644
--- a/Model/Decorator/InheritanceDecorator.php
+++ b/Model/Decorator/InheritanceDecorator.php
@@ -8,6 +8,7 @@
 
 namespace Irstea\PlantUmlBundle\Model\Decorator;
 
+use Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass;
 use Irstea\PlantUmlBundle\Model\ClassVisitor;
 use Irstea\PlantUmlBundle\Model\ClassVisitorInterface;
 use Irstea\PlantUmlBundle\Model\DecoratorInterface;
@@ -19,45 +20,18 @@ use ReflectionClass;
  *
  * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
  */
-class InheritanceDecorator implements DecoratorInterface
+class InheritanceDecorator extends AbstractRelationDecorator
 {
     public function decorate(ReflectionClass $class, NodeInterface $node, ClassVisitorInterface $visitor)
     {
         $parent = $class->getParentClass();
-        $traits = $class->getTraitNames();
-        $interfaces = $class->getInterfaceNames();
-
-        $indirectInterfaces = array_filter(
-            array_map(
-                function ($i) { return $i->getInterfaceNames(); },
-                $class->getInterfaces()
-            )
-        );
-
-        if (!empty($indirectInterfaces)) {
-            $indirectInterfaces = call_user_func_array('array_merge', $indirectInterfaces);
-            $interfaces = array_diff($interfaces, $indirectInterfaces);
-        }
-
         if ($parent) {
-            $traits = array_diff($traits, $parent->getTraitNames());
-            $interfaces = array_diff($interfaces, $parent->getInterfaceNames());
-            $this->visitRelations($node, [$parent->getName()], 'Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass', $visitor);
+            $this->visitRelations($node, [$parent->getName()], $visitor);
         }
-
-        $this->visitRelations($node, $interfaces, 'Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface', $visitor);
-        $this->visitRelations($node, $traits, 'Irstea\PlantUmlBundle\Model\Arrow\UsesTrait', $visitor);
-
-        return $this;
     }
 
-    protected function visitRelations(NodeInterface $source, array $classNames, $relationClass, ClassVisitorInterface $visitor)
+    protected function buildRelation(NodeInterface $source, NodeInterface $target)
     {
-        foreach ($classNames as $className) {
-            $target = $visitor->visitClass($className);
-            if ($target) {
-                $source->addArrow(new $relationClass($source, $target));
-            }
-        }
+        return new ExtendsClass($source, $target);
     }
 }
diff --git a/Model/Decorator/InterfaceDecorator.php b/Model/Decorator/InterfaceDecorator.php
new file mode 100644
index 0000000..a2e19a6
--- /dev/null
+++ b/Model/Decorator/InterfaceDecorator.php
@@ -0,0 +1,54 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model\Decorator;
+
+use Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface;
+use Irstea\PlantUmlBundle\Model\ClassVisitorInterface;
+use Irstea\PlantUmlBundle\Model\DecoratorInterface;
+use Irstea\PlantUmlBundle\Model\NodeInterface;
+use ReflectionClass;
+
+/**
+ * Description of InheritanceDecorator
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class InterfaceDecorator extends AbstractRelationDecorator
+{
+    public function decorate(ReflectionClass $class, NodeInterface $node, ClassVisitorInterface $visitor)
+    {
+        $interfaces = $class->getInterfaceNames();
+
+        $indirectInterfaces = array_filter(
+            array_map(
+                function ($i) { return $i->getInterfaceNames(); },
+                $class->getInterfaces()
+            )
+        );
+
+        if (!empty($indirectInterfaces)) {
+            $indirectInterfaces = call_user_func_array('array_merge', $indirectInterfaces);
+            $interfaces = array_diff($interfaces, $indirectInterfaces);
+        }
+
+        $parent = $class->getParentClass();
+        if ($parent) {
+            $interfaces = array_diff($interfaces, $parent->getInterfaceNames());
+        }
+
+        $this->visitRelations($node, $interfaces, $visitor);
+
+        return $this;
+    }
+
+    protected function buildRelation(NodeInterface $source, NodeInterface $target)
+    {
+        return new ImplementsInterface($source, $target);
+    }
+}
diff --git a/Model/Decorator/TraitDecorator.php b/Model/Decorator/TraitDecorator.php
new file mode 100644
index 0000000..c14d880
--- /dev/null
+++ b/Model/Decorator/TraitDecorator.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model\Decorator;
+
+use Irstea\PlantUmlBundle\Model\Arrow\UsesTrait;
+use Irstea\PlantUmlBundle\Model\ClassVisitorInterface;
+use Irstea\PlantUmlBundle\Model\DecoratorInterface;
+use Irstea\PlantUmlBundle\Model\NodeInterface;
+use ReflectionClass;
+
+/**
+ * Description of InheritanceDecorator
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class TraitDecorator extends AbstractRelationDecorator
+{
+    public function decorate(ReflectionClass $class, NodeInterface $node, ClassVisitorInterface $visitor)
+    {
+        $traits = $class->getTraitNames();
+
+        $parent = $class->getParentClass();
+        if ($parent) {
+            $traits = array_diff($traits, $parent->getTraitNames());
+        }
+
+        $this->visitRelations($node, $traits, $visitor);
+
+        return $this;
+    }
+
+    protected function buildRelation(NodeInterface $source, NodeInterface $target)
+    {
+        return new UsesTrait($source, $target);
+    }
+}
-- 
GitLab