Skip to content
Browse files

Adding support for inherited associations duplication removal

  • Loading branch information...
1 parent cfa8829 commit b2c9507603d4f4442fa1f3ead87e14abb80b8073 @Ocramius Ocramius committed
View
64 src/DoctrineORMModule/Yuml/MetadataGrapher.php
@@ -38,6 +38,11 @@ class MetadataGrapher
protected $visitedAssociations = array();
/**
+ * @var \Doctrine\Common\Persistence\Mapping\ClassMetadata[]
+ */
+ private $metadata;
+
+ /**
* Generate a YUML compatible `dsl_text` to describe a given array
* of entities
*
@@ -47,10 +52,17 @@ class MetadataGrapher
*/
public function generateFromMetadata(array $metadata)
{
+ $this->metadata = $metadata;
$this->visitedAssociations = array();
- $str = array();
+ $str = array();
foreach ($metadata as $class) {
+ $parent = $this->getParent($class);
+
+ if ($parent) {
+ $str[] = $this->getClassString($parent) . '^' . $this->getClassString($class);
+ }
+
$associations = $class->getAssociationNames();
if (empty($associations) && !isset($this->visitedAssociations[$class->getName()])) {
@@ -60,8 +72,12 @@ public function generateFromMetadata(array $metadata)
}
foreach ($associations as $associationName) {
+ if ($parent && in_array($associationName, $parent->getAssociationNames())) {
+ continue;
+ }
+
if ($this->visitAssociation($class->getName(), $associationName)) {
- $str[] = $this->getAssociationString($metadata, $class, $associationName);
+ $str[] = $this->getAssociationString($class, $associationName);
}
}
}
@@ -69,10 +85,10 @@ public function generateFromMetadata(array $metadata)
return implode(',', $str);
}
- private function getAssociationString(array $metadata, ClassMetadata $class1, $association)
+ private function getAssociationString(ClassMetadata $class1, $association)
{
$targetClassName = $class1->getAssociationTargetClass($association);
- $class2 = $this->getClassByName($targetClassName, $metadata);
+ $class2 = $this->getClassByName($targetClassName);
$isInverse = $class1->isAssociationInverseSide($association);
$class1Count = $class1->isCollectionValuedAssociation($association) ? 2 : 1;
@@ -126,18 +142,25 @@ private function getAssociationString(array $metadata, ClassMetadata $class1, $a
/**
* Build the string representing the single graph item
*
- * @param ClassMetadata $class
+ * @param ClassMetadata $class
*
* @return string
*/
private function getClassString(ClassMetadata $class)
{
- $className = $class->getName();
- $classText = '[' . str_replace('\\', '.', $className);
+ $this->visitAssociation($class->getName());
- $fields = array();
+ $className = $class->getName();
+ $classText = '[' . str_replace('\\', '.', $className);
+ $fields = array();
+ $parent = $this->getParent($class);
+ $parentFields = $parent ? $parent->getFieldNames() : array();
foreach ($class->getFieldNames() as $fieldName) {
+ if (in_array($fieldName, $parentFields)) {
+ continue;
+ }
+
if ($class->isIdentifier($fieldName)) {
$fields[] = '+' . $fieldName;
} else {
@@ -158,13 +181,12 @@ private function getClassString(ClassMetadata $class)
* Retrieve a class metadata instance by name from the given array
*
* @param string $className
- * @param ClassMetadata[] $metadata
*
* @return ClassMetadata|null
*/
- private function getClassByName($className, $metadata)
+ private function getClassByName($className)
{
- foreach ($metadata as $class) {
+ foreach ($this->metadata as $class) {
if ($class->getName() === $className) {
return $class;
}
@@ -174,6 +196,24 @@ private function getClassByName($className, $metadata)
}
/**
+ * Retrieve a class metadata's parent class metadata
+ *
+ * @param ClassMetadata $class
+ *
+ * @return ClassMetadata|null
+ */
+ private function getParent($class)
+ {
+ $className = $class->getName();
+
+ if (!class_exists($className) || (!$parent = get_parent_class($className))) {
+ return null;
+ }
+
+ return $this->getClassByName($parent);
+ }
+
+ /**
* Visit a given association and mark it as visited
*
* @param string $className
@@ -181,7 +221,7 @@ private function getClassByName($className, $metadata)
*
* @return bool true if the association was visited before
*/
- private function visitAssociation($className, $association)
+ private function visitAssociation($className, $association = null)
{
if (null === $association) {
if (isset($this->visitedAssociations[$className])) {
View
90 tests/DoctrineORMModuleTest/Yuml/MetadataGrapherTest.php
@@ -301,9 +301,95 @@ public function testDrawManyToManyAssociationWithoutKnownInverseSide()
$class1->expects($this->any())->method('isCollectionValuedAssociation')->will($this->returnValue(true));
$class1->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+ $this->assertSame('[A]<>-b *>[B]', $this->grapher->generateFromMetadata(array($class1)));
+ }
+
+ /**
+ * @covers \DoctrineORMModule\Yuml\MetadataGrapher
+ */
+ public function testDrawInheritance()
+ {
+ $class1 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $class2 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $child = get_class($this->getMock('stdClass'));
+ $class1->expects($this->any())->method('getName')->will($this->returnValue('stdClass'));
+ $class1->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class1->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+ $class2->expects($this->any())->method('getName')->will($this->returnValue($child));
+ $class2->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class2->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+
+ $this->assertSame(
+ '[stdClass]^[' . str_replace('\\', '.', $child) . ']',
+ $this->grapher->generateFromMetadata(array($class2, $class1))
+ );
+ }
+
+ /**
+ * @covers \DoctrineORMModule\Yuml\MetadataGrapher
+ */
+ public function testDrawInheritedFields()
+ {
+ $class1 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $class2 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $child = get_class($this->getMock('stdClass'));
+
+ $class1->expects($this->any())->method('getName')->will($this->returnValue('stdClass'));
+ $class1->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class1->expects($this->any())->method('getFieldNames')->will($this->returnValue(array('inherited')));
+
+ $class2->expects($this->any())->method('getName')->will($this->returnValue($child));
+ $class2->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class2->expects($this->any())->method('getFieldNames')->will($this->returnValue(array('inherited', 'field2')));
+
+ $this->assertSame(
+ '[stdClass|inherited]^[' . str_replace('\\', '.', $child) . '|field2]',
+ $this->grapher->generateFromMetadata(array($class2, $class1))
+ );
+ }
+
+ /**
+ * @covers \DoctrineORMModule\Yuml\MetadataGrapher
+ */
+ public function testDrawInheritedAssociations()
+ {
+ $class1 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $class2 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $class3 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $class4 = $this->getMock('Doctrine\\Common\\Persistence\\Mapping\\ClassMetadata');
+ $child = get_class($this->getMock('stdClass'));
+
+ $class1->expects($this->any())->method('getName')->will($this->returnValue('stdClass'));
+ $class1->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array('a')));
+ $class1->expects($this->any())->method('getAssociationTargetClass')->will($this->returnValue('A'));
+ $class1->expects($this->any())->method('isAssociationInverseSide')->will($this->returnValue(false));
+ $class1->expects($this->any())->method('isCollectionValuedAssociation')->will($this->returnValue(true));
+ $class1->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+
+ $class2->expects($this->any())->method('getName')->will($this->returnValue($child));
+ $class2->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array('a', 'b')));
+ $class2
+ ->expects($this->any())
+ ->method('getAssociationTargetClass')
+ ->will($this->returnCallback(function ($assoc) {
+ return strtoupper($assoc);
+ }));
+ $class2->expects($this->any())->method('isAssociationInverseSide')->will($this->returnValue(false));
+ $class2->expects($this->any())->method('isCollectionValuedAssociation')->will($this->returnValue(true));
+ $class2->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+
+ $class3->expects($this->any())->method('getName')->will($this->returnValue('A'));
+ $class3->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class3->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+
+ $class4->expects($this->any())->method('getName')->will($this->returnValue('B'));
+ $class4->expects($this->any())->method('getAssociationNames')->will($this->returnValue(array()));
+ $class4->expects($this->any())->method('getFieldNames')->will($this->returnValue(array()));
+
+ $childName = str_replace('\\', '.', $child);
$this->assertSame(
- '[A]<>-b *>[B]',
- $this->grapher->generateFromMetadata(array($class1))
+ '[stdClass]<>-a *>[A],[stdClass]^[' . $childName . '],[' . $childName . ']<>-b *>[B]',
+ $this->grapher->generateFromMetadata(array($class1, $class2))
);
}
}

0 comments on commit b2c9507

Please sign in to comment.
Something went wrong with that request. Please try again.