1
0
mirror of synced 2025-01-31 04:21:44 +03:00

DDC-1439 - Fix validate mapping some more

This commit is contained in:
Benjamin Eberlei 2011-10-31 20:49:28 +01:00
parent d444f0e06b
commit 11f82bd41f
2 changed files with 245 additions and 145 deletions

View File

@ -50,7 +50,7 @@ class SchemaValidator
} }
/** /**
* Checks the internal consistency of mapping files. * Checks the internal consistency of all mapping files.
* *
* There are several checks that can't be done at runtime or are too expensive, which can be verified * There are several checks that can't be done at runtime or are too expensive, which can be verified
* with this command. For example: * with this command. For example:
@ -69,11 +69,29 @@ class SchemaValidator
$classes = $cmf->getAllMetadata(); $classes = $cmf->getAllMetadata();
foreach ($classes AS $class) { foreach ($classes AS $class) {
if ($ce = $this->validateClass($class)) {
$errors[$class->name] = $ce;
}
}
return $errors;
}
/**
* Validate a single class of the current
*
* @param ClassMetadataInfo $class
* @return array
*/
public function validateClass(ClassMetadataInfo $class)
{
$ce = array(); $ce = array();
/* @var $class ClassMetadata */ $cmf = $this->em->getMetadataFactory();
foreach ($class->associationMappings AS $fieldName => $assoc) { foreach ($class->associationMappings AS $fieldName => $assoc) {
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) { if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.'; $ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
return $ce;
} }
if ($assoc['mappedBy'] && $assoc['inversedBy']) { if ($assoc['mappedBy'] && $assoc['inversedBy']) {
@ -139,59 +157,62 @@ class SchemaValidator
} }
} }
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) { foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']); if (!isset($targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
if (!isset($targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " . $ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'."; "have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
break; break;
} }
$fieldName = $targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']]; $fieldName = $targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetClass->identifier)) { if (!in_array($fieldName, $targetMetadata->identifier)) {
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " . $ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
"has to be a primary key column."; "has to be a primary key column.";
} }
} }
if (count($targetClass->identifier) != count($assoc['joinTable']['inverseJoinColumns'])) { if (count($targetMetadata->getIdentifierColumnNames()) != count($assoc['joinTable']['inverseJoinColumns'])) {
$ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " . $ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to match to ALL identifier columns of the target entity '". $targetClass->name . "'"; "have to contain to ALL identifier columns of the target entity '". $targetMetadata->name . "', " .
"however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), $assoc['relationToTargetKeyColumns'])) .
"' are missing.";
} }
if (count($class->identifier) != count($assoc['joinTable']['joinColumns'])) { if (count($class->getIdentifierColumnNames()) != count($assoc['joinTable']['joinColumns'])) {
$ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " . $ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
"have to match to ALL identifier columns of the source entity '". $class->name . "'"; "have to contain to ALL identifier columns of the source entity '". $class->name . "', " .
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $assoc['relationToSourceKeyColumns'])) .
"' are missing.";
} }
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) { } else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($assoc['joinColumns'] AS $joinColumn) { foreach ($assoc['joinColumns'] AS $joinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']); if (!isset($targetMetadata->fieldNames[$joinColumn['referencedColumnName']])) {
if (!isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " . $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'."; "have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
break; break;
} }
$fieldName = $targetClass->fieldNames[$joinColumn['referencedColumnName']]; $fieldName = $targetMetadata->fieldNames[$joinColumn['referencedColumnName']];
if (!in_array($fieldName, $targetClass->identifier)) { if (!in_array($fieldName, $targetMetadata->identifier)) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
"has to be a primary key column."; "has to be a primary key column.";
} }
} }
if (count($class->identifier) != count($assoc['joinColumns'])) { if (count($class->getIdentifierColumnNames()) != count($assoc['joinColumns'])) {
$ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " . $ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " .
"have to match to ALL identifier columns of the source entity '". $class->name . "'"; "have to match to ALL identifier columns of the source entity '". $class->name . "', " .
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $assoc['joinColumns'])) .
"' are missing.";
} }
} }
} }
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) { if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
foreach ($assoc['orderBy'] AS $orderField => $orientation) { foreach ($assoc['orderBy'] AS $orderField => $orientation) {
if (!$targetClass->hasField($orderField)) { if (!$targetMetadata->hasField($orderField)) {
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " . $ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
$orderField . " that is not a field on the target entity " . $targetClass->name; $orderField . " that is not a field on the target entity " . $targetMetadata->name;
} }
} }
} }
@ -212,12 +233,7 @@ class SchemaValidator
} }
} }
if ($ce) { return $ce;
$errors[$class->name] = $ce;
}
}
return $errors;
} }
/** /**

View File

@ -71,4 +71,88 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmTestCase
)); ));
$this->validator->validateMapping(); $this->validator->validateMapping();
} }
/**
* @group DDC-1439
*/
public function testInvalidManyToManyJoinColumnSchema()
{
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
$ce = $this->validator->validateClass($class1);
$this->assertEquals(
array(
"The inverse join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key4' are missing.",
"The join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity1', however 'key2' are missing."
),
$ce
);
}
/**
* @group DDC-1439
*/
public function testInvalidToOneJoinColumnSchema()
{
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
$ce = $this->validator->validateClass($class2);
$this->assertEquals(
array(
"The referenced column name 'id' does not have a corresponding field with this column name on the class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.",
"The join columns of the association 'assoc' have to match to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key3, key4' are missing."
),
$ce
);
}
}
/**
* @Entity
*/
class InvalidEntity1
{
/**
* @Id @Column
*/
protected $key1;
/**
* @Id @Column
*/
protected $key2;
/**
* @ManyToMany (targetEntity="InvalidEntity2")
* @JoinTable (name="Entity1Entity2",
* joinColumns={@JoinColumn(name="key1", referencedColumnName="key1")},
* inverseJoinColumns={@JoinColumn(name="key3", referencedColumnName="key3")}
* )
*/
protected $entity2;
}
/**
* @Entity
*/
class InvalidEntity2
{
/**
* @Id @Column
* @GeneratedValue(strategy="AUTO")
*/
protected $key3;
/**
* @Id @Column
* @GeneratedValue(strategy="AUTO")
*/
protected $key4;
/**
* @ManyToOne(targetEntity="InvalidEntity1")
*/
protected $assoc;
} }