diff --git a/Command/EntitySchemaCommand.php b/Command/EntitySchemaCommand.php index be44af3bf365debb205c4c7aaf00372c4731ba33..a47536c8067b9d4ef32ede948d63628529321af8 100644 --- a/Command/EntitySchemaCommand.php +++ b/Command/EntitySchemaCommand.php @@ -8,11 +8,12 @@ namespace Irstea\PlantUmlBundle\Command; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; +use Irstea\PlantUmlBundle\Doctrine\AssociationDecorator; +use Irstea\PlantUmlBundle\Doctrine\EntityDecorator; 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\NullDecorator; use Irstea\PlantUmlBundle\Model\Filter\Whitelist; use Irstea\PlantUmlBundle\Writer\OutputWriter; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; @@ -55,7 +56,11 @@ class EntitySchemaCommand extends ContainerAwareCommand ); $decorator = new FilteringDecorator( - new InheritanceDecorator(), + new CompositeDecorator([ + new InheritanceDecorator(), + new EntityDecorator($factory), + new AssociationDecorator($factory), + ]), new Whitelist($classes) ); diff --git a/Doctrine/AbstractDoctrineDecorator.php b/Doctrine/AbstractDoctrineDecorator.php new file mode 100644 index 0000000000000000000000000000000000000000..6494d51580210b78859e410a3556d85acfa7ddf6 --- /dev/null +++ b/Doctrine/AbstractDoctrineDecorator.php @@ -0,0 +1,45 @@ +<?php + +/* + * © 2016 IRSTEA + * Guillaume Perréal <guillaume.perreal@irstea.fr> + * Tous droits réservés. + */ + +namespace Irstea\PlantUmlBundle\Doctrine; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\ClassMetadataFactory; +use Irstea\PlantUmlBundle\Model\ClassVisitorInterface; +use Irstea\PlantUmlBundle\Model\DecoratorInterface; +use Irstea\PlantUmlBundle\Model\NodeInterface; +use ReflectionClass; + +/** + * Description of AbstractDoctrineDecorator + * + * @author Guillaume Perréal <guillaume.perreal@irstea.fr> + */ +abstract class AbstractDoctrineDecorator implements DecoratorInterface +{ + /** + * @var ClassMetadataFactory + */ + protected $metadataFactory; + + public function __construct(ClassMetadataFactory $metadataFactory) + { + $this->metadataFactory = $metadataFactory; + } + + public function decorate(ReflectionClass $class, NodeInterface $node, ClassVisitorInterface $visitor) + { + $className = $class->getName(); + if ($this->metadataFactory->hasMetadataFor($className)) { + $this->decorateEntity($this->metadataFactory->getMetadataFor($className), $node, $visitor); + } + return $this; + } + + abstract protected function decorateEntity(ClassMetadata $metadata, NodeInterface $node, ClassVisitorInterface $visitor); +} \ No newline at end of file diff --git a/Doctrine/AssociationDecorator.php b/Doctrine/AssociationDecorator.php new file mode 100644 index 0000000000000000000000000000000000000000..a5027fd207c167f7e283c9ad4c31578bae854ebe --- /dev/null +++ b/Doctrine/AssociationDecorator.php @@ -0,0 +1,78 @@ +<?php + +/* + * © 2016 IRSTEA + * Guillaume Perréal <guillaume.perreal@irstea.fr> + * Tous droits réservés. + */ + +namespace Irstea\PlantUmlBundle\Doctrine; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Irstea\PlantUmlBundle\Model\Arrow\BaseArrow; +use Irstea\PlantUmlBundle\Model\ClassVisitorInterface; +use Irstea\PlantUmlBundle\Model\NodeInterface; +use ReflectionClass; + +/** + * Description of RelationDecorator + * + * @author Guillaume Perréal <guillaume.perreal@irstea.fr> + */ +class AssociationDecorator extends AbstractDoctrineDecorator +{ + protected function decorateEntity(ClassMetadata $metadata, NodeInterface $node, ClassVisitorInterface $visitor) + { + $associations = $metadata->getAssociationMappings(); + if(empty($associations)) { + return; + } + + foreach($associations as $association) { + $this->visitAssociation($node, $visitor, $association); + } + } + + protected function visitAssociation(NodeInterface $node, ClassVisitorInterface $visitor, array $association) + { + if (!$association['isOwningSide']) { + return; + } + + $target = $visitor->visitClass($association['targetEntity']); + if ($target === false) { + return; + } + + $link = "-->"; + if ($association["isCascadeRemove"]) { + $link = "o".$link; + } + + $leftLabel = ""; + $rightLabel = ""; + switch($association["type"]) { + case ClassMetadata::ONE_TO_ONE: + $leftLabel = '1'; + $rightLabel = '1'; + break; + case ClassMetadata::ONE_TO_MANY: + $leftLabel = '1'; + $rightLabel = '*'; + break; + case ClassMetadata::MANY_TO_MANY: + $leftLabel = '*'; + $rightLabel = '*'; + break; + case ClassMetadata::MANY_TO_ONE: + $leftLabel = '*'; + $rightLabel = '1'; + break; + } + $link = sprintf('"%s" %s "%s"', $leftLabel, $link, $rightLabel); + + $node->addArrow( + new BaseArrow($node, $target, $link, $association["fieldName"]." >") + ); + } +} diff --git a/Doctrine/EntityDecorator.php b/Doctrine/EntityDecorator.php new file mode 100644 index 0000000000000000000000000000000000000000..64d65222d6ad86d2bb7f7570cab533665d5e11cb --- /dev/null +++ b/Doctrine/EntityDecorator.php @@ -0,0 +1,32 @@ +<?php + +/* + * © 2016 IRSTEA + * Guillaume Perréal <guillaume.perreal@irstea.fr> + * Tous droits réservés. + */ + +namespace Irstea\PlantUmlBundle\Doctrine; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Irstea\PlantUmlBundle\Model\ClassVisitorInterface; +use Irstea\PlantUmlBundle\Model\NodeInterface; + +/** + * Description of EntityDecorator + * + * @author Guillaume Perréal <guillaume.perreal@irstea.fr> + */ +class EntityDecorator extends AbstractDoctrineDecorator +{ + protected function decorateEntity(ClassMetadata $metadata, NodeInterface $node, ClassVisitorInterface $visitor) + { + if ($metadata->isMappedSuperclass) { + $node->addStereotype('mappedSuperClass'); + } elseif($metadata->isEmbeddedClass) { + $node->addStereotype('embedded'); + } else { + $node->addStereotype('entity'); + } + } +} diff --git a/Model/Node/BaseNode.php b/Model/Node/BaseNode.php index ced060790c03aab280d08813728aed19b89f0b58..1b19d52af3b597eb6c471069f61d83a32cf20131 100644 --- a/Model/Node/BaseNode.php +++ b/Model/Node/BaseNode.php @@ -59,9 +59,9 @@ class BaseNode implements NodeInterface */ function __construct(NamespaceInterface $namespace, $name, $nodeType, array $classifiers = [], array $stereotypes = []) { - $this->namespace = $namespace; + $this->namespace = $namespace; - $pos = strrpos($name, '\\'); + $pos = strrpos($name, '\\'); $this->name = substr($name, $pos + 1); $this->alias = str_replace('\\', '.', $name)."_node"; @@ -70,6 +70,18 @@ class BaseNode implements NodeInterface $this->stereotypes = $stereotypes; } + public function addClassifier($classifier) + { + $this->classifiers[] = $classifier; + return $this; + } + + public function addStereotype($stereotype) + { + $this->stereotypes[] = $stereotype; + return $this; + } + public function outputTo(WriterInterface $writer) { $this diff --git a/Model/NodeInterface.php b/Model/NodeInterface.php index bf2ba6e2d2d8097468b055c906eb962fb9fb33bc..7a27509249fc34d7d94b327a2c8937101d960739 100644 --- a/Model/NodeInterface.php +++ b/Model/NodeInterface.php @@ -21,4 +21,16 @@ interface NodeInterface extends WritableNodeInterface * @return self */ public function addArrow(ArrowInterface $arrow); + + /** + * @param string $classifier + * @return string + */ + public function addClassifier($classifier); + + /** + * @param string $stereotype + * @return string + */ + public function addStereotype($stereotype); }