Skip to content

Commit

Permalink
refactor - extract class storage and string generation in separate class
Browse files Browse the repository at this point in the history
  • Loading branch information
Nono1971 committed Jul 22, 2016
1 parent cc9a35a commit d7595a4
Show file tree
Hide file tree
Showing 18 changed files with 1,416 additions and 255 deletions.
1 change: 0 additions & 1 deletion .travis.yml
@@ -1,7 +1,6 @@
language: php

php:
- 5.4
- 5.5
- 5.6
- 7
Expand Down
273 changes: 23 additions & 250 deletions lib/Onurb/Doctrine/ORMMetadataGrapher/YUMLMetadataGrapher.php
Expand Up @@ -20,6 +20,8 @@
namespace Onurb\Doctrine\ORMMetadataGrapher;

use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Onurb\Doctrine\ORMMetadataGrapher\YumlMetadataGrapher\ClassStore;
use Onurb\Doctrine\ORMMetadataGrapher\YumlMetadataGrapher\StringGenerator;

/**
* Utility to generate yUML compatible strings from metadata graphs
Expand All @@ -32,23 +34,14 @@
class YUMLMetadataGrapher implements YUMLMetadataGrapherInterface
{
/**
* Temporary array where already visited collections are stored
*
* @var array
* @var ClassStore
*/
private $visitedAssociations = array();
protected $classStore;

/**
* indexed array of ClassMetadata
*
* @var ClassMetadata[]
* @var StringGenerator
*/
private $metadata = array();

/**
* @var array
*/
private $classStrings = array();
protected $stringGenerator;

/**
* Generate a yUML compatible `dsl_text` to describe a given array
Expand All @@ -60,20 +53,27 @@ class YUMLMetadataGrapher implements YUMLMetadataGrapherInterface
*/
public function generateFromMetadata(array $metadata)
{
$this->storeClasses($metadata);
$this->classStore = new ClassStore($metadata);
$this->stringGenerator = new StringGenerator($this->classStore);

$this->visitedAssociations = array();
// $this->storeClasses($metadata);
$str = array();

foreach ($metadata as $class) {
if ($parent = $this->getParent($class)) {
$str[] = $this->getClassString($parent) . '^' . $this->getClassString($class);
if ($parent = $this->classStore->getParent($class)) {
$str[] = $this->stringGenerator->getClassString($parent) . '^'
. $this->stringGenerator->getClassString($class);
}

$associations = $class->getAssociationNames();

if (empty($associations) && !isset($this->visitedAssociations[$class->getName()])) {
$str[] = $this->getClassString($class);
if (empty($associations)
&& !isset(
$this->stringGenerator->getAssociationLogger()
->getVisitedAssociations()[$class->getName()]
)
) {
$str[] = $this->stringGenerator->getClassString($class);

continue;
}
Expand All @@ -83,240 +83,13 @@ public function generateFromMetadata(array $metadata)
continue;
}

if ($this->visitAssociation($class->getName(), $associationName)) {
$str[] = $this->getAssociationString($class, $associationName);
if ($this->stringGenerator->getAssociationLogger()
->visitAssociation($class->getName(), $associationName)
) {
$str[] = $this->stringGenerator->getAssociationString($class, $associationName);
}
}
}
return implode(',', $str);
}

/**
* @param ClassMetadata $class1
* @param string $association
* @return string
*/
private function getAssociationString(ClassMetadata $class1, $association)
{
$targetClassName = $class1->getAssociationTargetClass($association);
$class2 = $this->getClassByName($targetClassName);
$isInverse = $class1->isAssociationInverseSide($association);
$class1Count = $class1->isCollectionValuedAssociation($association) ? 2 : 1;

if (null === $class2) {
return $this->makeSingleClassString($class1, $isInverse, $association, $class1Count, $targetClassName);
}

$class1SideName = $association;
$class2SideName = $this->getClassReverseAssociationName($class1, $association);
$class2Count = 0;
$bidirectional = false;

if (null !== $class2SideName) {
if ($isInverse) {
$class2Count = $class2->isCollectionValuedAssociation($class2SideName) ? 2 : 1;
$bidirectional = true;
} elseif ($class2->isAssociationInverseSide($class2SideName)) {
$class2Count = $class2->isCollectionValuedAssociation($class2SideName) ? 2 : 1;
$bidirectional = true;
}
}

$this->visitAssociation($targetClassName, $class2SideName);

return $this->makeDoubleClassString(
$class1,
$class2,
$bidirectional,
$isInverse,
$class2SideName,
$class2Count,
$class1SideName,
$class1Count
);
}

/**
* Returns the $class2 association name for $class1 if reverse related (or null if not)
*
* @param ClassMetadata $class1
* @param string $association
*
* @return string|null
*/
private function getClassReverseAssociationName(ClassMetadata $class1, $association)
{
if ($class1->getAssociationMapping($association)['isOwningSide']) {
return $class1->getAssociationMapping($association)['inversedBy'];
}

return $class1->getAssociationMapping($association)['mappedBy'];
}

/**
* Build the string representing the single graph item
*
* @param ClassMetadata $class
*
* @return string
*/
private function getClassString(ClassMetadata $class)
{
$className = $class->getName();
if (!isset($this->classStrings[$className])) {
$this->visitAssociation($className);

$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 {
$fields[] = $fieldName;
}
}

if (!empty($fields)) {
$classText .= '|' . implode(';', $fields);
}

$classText .= ']';

$this->classStrings[$className] = $classText;
}

return $this->classStrings[$className];
}

/**
* Retrieve a class metadata instance by name from the given array
*
* @param string $className
*
* @return ClassMetadata|null
*/
private function getClassByName($className)
{
return isset($this->metadata[$className]) && !empty($this->metadata[$className])?
$this->metadata[$className]: null;
}

/**
* store metadata in an associated array to get classes
* faster into $this->getClassByName()
*
* @param ClassMetadata[] $metadata
*/
private function storeClasses($metadata)
{
foreach ($metadata as $class) {
$this->metadata[$class->getName()] = $class;
}
}

/**
* 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
* @param string|null $association
*
* @return bool true if the association was visited before
*/
private function visitAssociation($className, $association = null)
{
if (null === $association) {
if (isset($this->visitedAssociations[$className])) {
return false;
}

$this->visitedAssociations[$className] = array();

return true;
}

if (isset($this->visitedAssociations[$className][$association])) {
return false;
}

if (!isset($this->visitedAssociations[$className])) {
$this->visitedAssociations[$className] = array();
}

$this->visitedAssociations[$className][$association] = true;

return true;
}

/**
* @param ClassMetadata $class1
* @param boolean $isInverse
* @param string $association
* @param int $class1Count
* @param string $targetClassName
* @return string
*/
private function makeSingleClassString(
ClassMetadata $class1,
$isInverse,
$association,
$class1Count,
$targetClassName
) {
return $this->getClassString($class1) . ($isInverse ? '<' : '<>') . '-' . $association . ' '
. ($class1Count > 1 ? '*' : ($class1Count ? '1' : '')) . ($isInverse ? '<>' : '>')
. '[' . str_replace('\\', '.', $targetClassName) . ']';
}

/**
* @param ClassMetadata $class1
* @param ClassMetadata $class2
* @param boolean $bidirectional
* @param boolean $isInverse
* @param string $class2SideName
* @param integer $class2Count
* @param string $class1SideName
* @param integer $class1Count
*
* @return string
*/
private function makeDoubleClassString(
ClassMetadata $class1,
ClassMetadata $class2,
$bidirectional,
$isInverse,
$class2SideName,
$class2Count,
$class1SideName,
$class1Count
) {
return $this->getClassString($class1) . ($bidirectional ? ($isInverse ? '<' : '<>') : '')
. ($class2SideName ? $class2SideName . ' ' : '') . ($class2Count > 1 ? '*' : ($class2Count ? '1' : ''))
. '-' . $class1SideName . ' ' . ($class1Count > 1 ? '*' : ($class1Count ? '1' : ''))
. (($bidirectional && $isInverse) ? '<>' : '>') . $this->getClassString($class2);
}
}

0 comments on commit d7595a4

Please sign in to comment.