Browse Source

[Validator] Added abstract method Constraint::targets() to define whether constraints can be put onto properties, classes or both

Bernhard Schussek 14 năm trước cách đây
mục cha
commit
eed3c9a48c
44 tập tin đã thay đổi với 409 bổ sung99 xóa
  1. 27 0
      src/Symfony/Component/Validator/Constraint.php
  2. 8 0
      src/Symfony/Component/Validator/Constraints/All.php
  3. 8 0
      src/Symfony/Component/Validator/Constraints/AssertFalse.php
  4. 8 0
      src/Symfony/Component/Validator/Constraints/AssertTrue.php
  5. 8 0
      src/Symfony/Component/Validator/Constraints/AssertType.php
  6. 8 0
      src/Symfony/Component/Validator/Constraints/Blank.php
  7. 8 0
      src/Symfony/Component/Validator/Constraints/Choice.php
  8. 8 0
      src/Symfony/Component/Validator/Constraints/Collection.php
  9. 8 0
      src/Symfony/Component/Validator/Constraints/Country.php
  10. 8 0
      src/Symfony/Component/Validator/Constraints/Date.php
  11. 8 0
      src/Symfony/Component/Validator/Constraints/DateTime.php
  12. 8 0
      src/Symfony/Component/Validator/Constraints/Email.php
  13. 8 0
      src/Symfony/Component/Validator/Constraints/File.php
  14. 8 0
      src/Symfony/Component/Validator/Constraints/Ip.php
  15. 8 0
      src/Symfony/Component/Validator/Constraints/Language.php
  16. 8 0
      src/Symfony/Component/Validator/Constraints/Locale.php
  17. 8 0
      src/Symfony/Component/Validator/Constraints/Max.php
  18. 8 0
      src/Symfony/Component/Validator/Constraints/MaxLength.php
  19. 8 0
      src/Symfony/Component/Validator/Constraints/Min.php
  20. 8 0
      src/Symfony/Component/Validator/Constraints/MinLength.php
  21. 8 0
      src/Symfony/Component/Validator/Constraints/NotBlank.php
  22. 8 0
      src/Symfony/Component/Validator/Constraints/NotNull.php
  23. 8 0
      src/Symfony/Component/Validator/Constraints/Null.php
  24. 8 0
      src/Symfony/Component/Validator/Constraints/Regex.php
  25. 8 0
      src/Symfony/Component/Validator/Constraints/Time.php
  26. 8 0
      src/Symfony/Component/Validator/Constraints/Url.php
  27. 8 0
      src/Symfony/Component/Validator/Constraints/Valid.php
  28. 4 2
      src/Symfony/Component/Validator/Mapping/ClassMetadata.php
  29. 7 0
      src/Symfony/Component/Validator/Mapping/MemberMetadata.php
  30. 13 0
      tests/Symfony/Tests/Component/Validator/Fixtures/ClassConstraint.php
  31. 5 0
      tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintA.php
  32. 8 1
      tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintB.php
  33. 5 0
      tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintC.php
  34. 10 11
      tests/Symfony/Tests/Component/Validator/Fixtures/Entity.php
  35. 5 0
      tests/Symfony/Tests/Component/Validator/Fixtures/FailingConstraint.php
  36. 13 0
      tests/Symfony/Tests/Component/Validator/Fixtures/PropertyConstraint.php
  37. 9 0
      tests/Symfony/Tests/Component/Validator/Mapping/ClassMetadataTest.php
  38. 10 12
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/AnnotationLoaderTest.php
  39. 4 2
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/StaticMethodLoaderTest.php
  40. 6 6
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php
  41. 6 6
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/YamlFileLoaderTest.php
  42. 38 37
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/constraint-mapping.xml
  43. 22 22
      tests/Symfony/Tests/Component/Validator/Mapping/Loader/constraint-mapping.yml
  44. 9 0
      tests/Symfony/Tests/Component/Validator/Mapping/MemberMetadataTest.php

+ 27 - 0
src/Symfony/Component/Validator/Constraint.php

@@ -28,8 +28,24 @@ use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
  */
 abstract class Constraint
 {
+    /**
+     * The name of the group given to all constraints with no explicit group
+     * @var string
+     */
     const DEFAULT_GROUP = 'Default';
 
+    /**
+     * Marks a constraint that can be put onto classes
+     * @var string
+     */
+    const CLASS_CONSTRAINT = 'class';
+
+    /**
+     * Marks a constraint that can be put onto properties
+     * @var string
+     */
+    const PROPERTY_CONSTRAINT = 'property';
+
     /**
      * @var array
      */
@@ -173,4 +189,15 @@ abstract class Constraint
     {
         return get_class($this) . 'Validator';
     }
+
+    /**
+     * Returns whether the constraint can be put onto classes, properties or
+     * both
+     *
+     * This method should return one or more of the constants
+     * Constraint::CLASS_CONSTRAINT and Constraint::PROPERTY_CONSTRAINT.
+     *
+     * @return string|array  One or more constant values
+     */
+    abstract public function targets();
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/All.php

@@ -24,4 +24,12 @@ class All extends \Symfony\Component\Validator\Constraint
     {
         return array('constraints');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/AssertFalse.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class AssertFalse extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should be false';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/AssertTrue.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class AssertTrue extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should be true';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/AssertType.php

@@ -31,4 +31,12 @@ class AssertType extends \Symfony\Component\Validator\Constraint
     {
         return array('type');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Blank.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Blank extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should be blank';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Choice.php

@@ -29,4 +29,12 @@ class Choice extends \Symfony\Component\Validator\Constraint
     {
         return 'choices';
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Collection.php

@@ -23,4 +23,12 @@ class Collection extends \Symfony\Component\Validator\Constraint
     {
         return array('fields');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Country.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Country extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid country';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Date.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Date extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid date';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/DateTime.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class DateTime extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid datetime';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Email.php

@@ -15,4 +15,12 @@ class Email extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid email address';
     public $checkMX = false;
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/File.php

@@ -19,4 +19,12 @@ class File extends \Symfony\Component\Validator\Constraint
     public $notReadableMessage = 'The file is not readable';
     public $maxSizeMessage = 'The file is too large ({{ size }}). Allowed maximum size is {{ limit }}';
     public $mimeTypesMessage = 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Ip.php

@@ -45,4 +45,12 @@ class Ip extends \Symfony\Component\Validator\Constraint
             throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s"', implode('", "', self::$versions)));
         }
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Language.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Language extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid language';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Locale.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Locale extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid locale';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Max.php

@@ -31,4 +31,12 @@ class Max extends \Symfony\Component\Validator\Constraint
     {
         return array('limit');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/MaxLength.php

@@ -32,4 +32,12 @@ class MaxLength extends \Symfony\Component\Validator\Constraint
     {
         return array('limit');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Min.php

@@ -31,4 +31,12 @@ class Min extends \Symfony\Component\Validator\Constraint
     {
         return array('limit');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/MinLength.php

@@ -32,4 +32,12 @@ class MinLength extends \Symfony\Component\Validator\Constraint
     {
         return array('limit');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/NotBlank.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class NotBlank extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should not be blank';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/NotNull.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class NotNull extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should not be null';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Null.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Null extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value should be null';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Regex.php

@@ -32,4 +32,12 @@ class Regex extends \Symfony\Component\Validator\Constraint
     {
         return array('pattern');
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Time.php

@@ -14,4 +14,12 @@ namespace Symfony\Component\Validator\Constraints;
 class Time extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid time';
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Url.php

@@ -15,4 +15,12 @@ class Url extends \Symfony\Component\Validator\Constraint
 {
     public $message = 'This value is not a valid URL';
     public $protocols = array('http', 'https');
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 8 - 0
src/Symfony/Component/Validator/Constraints/Valid.php

@@ -28,4 +28,12 @@ class Valid extends \Symfony\Component\Validator\Constraint
             throw new ConstraintDefinitionException('The constraint Valid does not accept any options');
         }
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
 }

+ 4 - 2
src/Symfony/Component/Validator/Mapping/ClassMetadata.php

@@ -96,8 +96,10 @@ class ClassMetadata extends ElementMetadata
      */
     public function addConstraint(Constraint $constraint)
     {
-        if ($constraint instanceof Valid) {
-            throw new ConstraintDefinitionException('The constraint Valid can only be put on properties or getters');
+        if (!in_array(Constraint::CLASS_CONSTRAINT, (array)$constraint->targets())) {
+            throw new ConstraintDefinitionException(sprintf(
+            		'The constraint %s cannot be put on classes',
+                    get_class($constraint)));
         }
 
         $constraint->addImplicitGroupName($this->getDefaultGroup());

+ 7 - 0
src/Symfony/Component/Validator/Mapping/MemberMetadata.php

@@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Mapping;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\Constraints\Valid;
 use Symfony\Component\Validator\Exception\ValidatorException;
+use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
 
 abstract class MemberMetadata extends ElementMetadata
 {
@@ -42,6 +43,12 @@ abstract class MemberMetadata extends ElementMetadata
      */
     public function addConstraint(Constraint $constraint)
     {
+        if (!in_array(Constraint::PROPERTY_CONSTRAINT, (array)$constraint->targets())) {
+            throw new ConstraintDefinitionException(sprintf(
+            		'The constraint %s cannot be put on properties or getters',
+                    get_class($constraint)));
+        }
+
         if ($constraint instanceof Valid) {
             $this->cascaded = true;
         } else {

+ 13 - 0
tests/Symfony/Tests/Component/Validator/Fixtures/ClassConstraint.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace Symfony\Tests\Component\Validator\Fixtures;
+
+use Symfony\Component\Validator\Constraint;
+
+class ClassConstraint extends Constraint
+{
+    public function targets()
+    {
+        return self::CLASS_CONSTRAINT;
+    }
+}

+ 5 - 0
tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintA.php

@@ -13,4 +13,9 @@ class ConstraintA extends Constraint
     {
         return 'property2';
     }
+
+    public function targets()
+    {
+        return array(self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT);
+    }
 }

+ 8 - 1
tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintB.php

@@ -4,4 +4,11 @@ namespace Symfony\Tests\Component\Validator\Fixtures;
 
 use Symfony\Component\Validator\Constraint;
 
-class ConstraintB extends Constraint {}
+class ConstraintB extends Constraint {
+
+    public function targets()
+    {
+        return array(self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT);
+    }
+
+}

+ 5 - 0
tests/Symfony/Tests/Component/Validator/Fixtures/ConstraintC.php

@@ -12,4 +12,9 @@ class ConstraintC extends Constraint
     {
         return array('option1');
     }
+
+    public function targets()
+    {
+        return array(self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT);
+    }
 }

+ 10 - 11
tests/Symfony/Tests/Component/Validator/Fixtures/Entity.php

@@ -6,23 +6,22 @@ require_once __DIR__.'/EntityParent.php';
 require_once __DIR__.'/EntityInterface.php';
 
 /**
- * @validation:NotNull
  * @Symfony\Tests\Component\Validator\Fixtures\ConstraintA
- * @validation:Min(3)
- * @validation:Choice({"A", "B"})
- * @validation:Set({
- *   @validation:All({@validation:NotNull, @validation:Min(3)}),
- *   @validation:All(constraints={@validation:NotNull, @validation:Min(3)})
- * })
- * @validation:Collection(fields={
- *   "foo" = {@validation:NotNull, @validation:Min(3)},
- *   "bar" = @validation:Min(5)
- * })
  * @validation:GroupSequence({"Foo", "Entity"})
  */
 class Entity extends EntityParent implements EntityInterface
 {
     /**
+     * @validation:NotNull
+     * @validation:Min(3)
+     * @validation:Set({
+     *   @validation:All({@validation:NotNull, @validation:Min(3)}),
+     *   @validation:All(constraints={@validation:NotNull, @validation:Min(3)})
+     * })
+     * @validation:Collection(fields={
+     *   "foo" = {@validation:NotNull, @validation:Min(3)},
+     *   "bar" = @validation:Min(5)
+     * })
      * @validation:Choice(choices={"A", "B"}, message="Must be one of %choices%")
      */
     protected $firstName;

+ 5 - 0
tests/Symfony/Tests/Component/Validator/Fixtures/FailingConstraint.php

@@ -7,4 +7,9 @@ use Symfony\Component\Validator\Constraint;
 class FailingConstraint extends Constraint
 {
     public $message = '';
+
+    public function targets()
+    {
+        return array(self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT);
+    }
 }

+ 13 - 0
tests/Symfony/Tests/Component/Validator/Fixtures/PropertyConstraint.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace Symfony\Tests\Component\Validator\Fixtures;
+
+use Symfony\Component\Validator\Constraint;
+
+class PropertyConstraint extends Constraint
+{
+    public function targets()
+    {
+        return self::PROPERTY_CONSTRAINT;
+    }
+}

+ 9 - 0
tests/Symfony/Tests/Component/Validator/Mapping/ClassMetadataTest.php

@@ -18,10 +18,12 @@ use Symfony\Component\Validator\Mapping\PropertyMetadata;
 use Symfony\Tests\Component\Validator\Fixtures\Entity;
 use Symfony\Tests\Component\Validator\Fixtures\ConstraintA;
 use Symfony\Tests\Component\Validator\Fixtures\ConstraintB;
+use Symfony\Tests\Component\Validator\Fixtures\PropertyConstraint;
 
 require_once __DIR__.'/../Fixtures/Entity.php';
 require_once __DIR__.'/../Fixtures/ConstraintA.php';
 require_once __DIR__.'/../Fixtures/ConstraintB.php';
+require_once __DIR__.'/../Fixtures/PropertyConstraint.php';
 
 class ClassMetadataTest extends \PHPUnit_Framework_TestCase
 {
@@ -42,6 +44,13 @@ class ClassMetadataTest extends \PHPUnit_Framework_TestCase
         $this->metadata->addConstraint(new Valid());
     }
 
+    public function testAddConstraintRequiresClassConstraints()
+    {
+        $this->setExpectedException('Symfony\Component\Validator\Exception\ConstraintDefinitionException');
+
+        $this->metadata->addConstraint(new PropertyConstraint());
+    }
+
     public function testAddPropertyConstraints()
     {
         $this->metadata->addPropertyConstraint('firstName', new ConstraintA());

+ 10 - 12
tests/Symfony/Tests/Component/Validator/Mapping/Loader/AnnotationLoaderTest.php

@@ -57,13 +57,12 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
 
         $expected = new ClassMetadata('Symfony\Tests\Component\Validator\Fixtures\Entity');
         $expected->setGroupSequence(array('Foo', 'Entity'));
-        $expected->addConstraint(new NotNull());
         $expected->addConstraint(new ConstraintA());
-        $expected->addConstraint(new Min(3));
-        $expected->addConstraint(new Choice(array('A', 'B')));
-        $expected->addConstraint(new All(array(new NotNull(), new Min(3))));
-        $expected->addConstraint(new All(array('constraints' => array(new NotNull(), new Min(3)))));
-        $expected->addConstraint(new Collection(array('fields' => array(
+        $expected->addPropertyConstraint('firstName', new NotNull());
+        $expected->addPropertyConstraint('firstName', new Min(3));
+        $expected->addPropertyConstraint('firstName', new All(array(new NotNull(), new Min(3))));
+        $expected->addPropertyConstraint('firstName', new All(array('constraints' => array(new NotNull(), new Min(3)))));
+        $expected->addPropertyConstraint('firstName', new Collection(array('fields' => array(
             'foo' => array(new NotNull(), new Min(3)),
             'bar' => new Min(5),
         ))));
@@ -122,13 +121,12 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
         $expected->mergeConstraints($expected_parent);
 
         $expected->setGroupSequence(array('Foo', 'Entity'));
-        $expected->addConstraint(new NotNull());
         $expected->addConstraint(new ConstraintA());
-        $expected->addConstraint(new Min(3));
-        $expected->addConstraint(new Choice(array('A', 'B')));
-        $expected->addConstraint(new All(array(new NotNull(), new Min(3))));
-        $expected->addConstraint(new All(array('constraints' => array(new NotNull(), new Min(3)))));
-        $expected->addConstraint(new Collection(array('fields' => array(
+        $expected->addPropertyConstraint('firstName', new NotNull());
+        $expected->addPropertyConstraint('firstName', new Min(3));
+        $expected->addPropertyConstraint('firstName', new All(array(new NotNull(), new Min(3))));
+        $expected->addPropertyConstraint('firstName', new All(array('constraints' => array(new NotNull(), new Min(3)))));
+        $expected->addPropertyConstraint('firstName', new Collection(array('fields' => array(
             'foo' => array(new NotNull(), new Min(3)),
             'bar' => new Min(5),
         ))));

+ 4 - 2
tests/Symfony/Tests/Component/Validator/Mapping/Loader/StaticMethodLoaderTest.php

@@ -11,9 +11,11 @@
 
 namespace Symfony\Tests\Component\Validator\Mapping\Loader;
 
+require_once __DIR__.'/../../Fixtures/ConstraintA.php';
+
 use Symfony\Component\Validator\Mapping\ClassMetadata;
 use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
-use Symfony\Component\Validator\Constraints\NotNull;
+use Symfony\Tests\Component\Validator\Fixtures\ConstraintA;
 
 class StaticMethodLoaderTest extends \PHPUnit_Framework_TestCase
 {
@@ -75,6 +77,6 @@ class BaseStaticLoaderDocument
 {
     static public function loadMetadata(ClassMetadata $metadata)
     {
-        $metadata->addConstraint(new NotNull());
+        $metadata->addConstraint(new ConstraintA());
     }
 }

+ 6 - 6
tests/Symfony/Tests/Component/Validator/Mapping/Loader/XmlFileLoaderTest.php

@@ -49,13 +49,13 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
         $loader->loadClassMetadata($metadata);
 
         $expected = new ClassMetadata('Symfony\Tests\Component\Validator\Fixtures\Entity');
-        $expected->addConstraint(new NotNull());
         $expected->addConstraint(new ConstraintA());
-        $expected->addConstraint(new Min(3));
-        $expected->addConstraint(new Choice(array('A', 'B')));
-        $expected->addConstraint(new All(array(new NotNull(), new Min(3))));
-        $expected->addConstraint(new All(array('constraints' => array(new NotNull(), new Min(3)))));
-        $expected->addConstraint(new Collection(array('fields' => array(
+        $expected->addPropertyConstraint('firstName', new NotNull());
+        $expected->addPropertyConstraint('firstName', new Min(3));
+        $expected->addPropertyConstraint('firstName', new Choice(array('A', 'B')));
+        $expected->addPropertyConstraint('firstName', new All(array(new NotNull(), new Min(3))));
+        $expected->addPropertyConstraint('firstName', new All(array('constraints' => array(new NotNull(), new Min(3)))));
+        $expected->addPropertyConstraint('firstName', new Collection(array('fields' => array(
             'foo' => array(new NotNull(), new Min(3)),
             'bar' => array(new Min(5)),
         ))));

+ 6 - 6
tests/Symfony/Tests/Component/Validator/Mapping/Loader/YamlFileLoaderTest.php

@@ -67,13 +67,13 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
         $loader->loadClassMetadata($metadata);
 
         $expected = new ClassMetadata('Symfony\Tests\Component\Validator\Fixtures\Entity');
-        $expected->addConstraint(new NotNull());
         $expected->addConstraint(new ConstraintA());
-        $expected->addConstraint(new Min(3));
-        $expected->addConstraint(new Choice(array('A', 'B')));
-        $expected->addConstraint(new All(array(new NotNull(), new Min(3))));
-        $expected->addConstraint(new All(array('constraints' => array(new NotNull(), new Min(3)))));
-        $expected->addConstraint(new Collection(array('fields' => array(
+        $expected->addPropertyConstraint('firstName', new NotNull());
+        $expected->addPropertyConstraint('firstName', new Min(3));
+        $expected->addPropertyConstraint('firstName', new Choice(array('A', 'B')));
+        $expected->addPropertyConstraint('firstName', new All(array(new NotNull(), new Min(3))));
+        $expected->addPropertyConstraint('firstName', new All(array('constraints' => array(new NotNull(), new Min(3)))));
+        $expected->addPropertyConstraint('firstName', new Collection(array('fields' => array(
             'foo' => array(new NotNull(), new Min(3)),
             'bar' => array(new Min(5)),
         ))));

+ 38 - 37
tests/Symfony/Tests/Component/Validator/Mapping/Loader/constraint-mapping.xml

@@ -8,51 +8,52 @@
 
     <!-- CLASS CONSTRAINTS -->
 
-    <!-- Constraint without value -->
-    <constraint name="NotNull" />
-
     <!-- Custom constraint -->
     <constraint name="Symfony\Tests\Component\Validator\Fixtures\ConstraintA" />
-    
-    <!-- Constraint with single value -->
-    <constraint name="Min">3</constraint>
-    
-    <!-- Constraint with multiple values -->
-    <constraint name="Choice">
-      <value>A</value>
-      <value>B</value>
-    </constraint>
-    
-    <!-- Constraint with child constraints -->
-    <constraint name="All">
+
+    <!-- PROPERTY CONSTRAINTS -->
+
+    <property name="firstName">
+  
+      <!-- Constraint without value -->
       <constraint name="NotNull" />
+      
+      <!-- Constraint with single value -->
       <constraint name="Min">3</constraint>
-    </constraint>
-    
-    <!-- Option with child constraints -->
-    <constraint name="All">
-      <option name="constraints">
+      
+      <!-- Constraint with multiple values -->
+      <constraint name="Choice">
+        <value>A</value>
+        <value>B</value>
+      </constraint>
+      
+      <!-- Constraint with child constraints -->
+      <constraint name="All">
         <constraint name="NotNull" />
         <constraint name="Min">3</constraint>
-      </option>
-    </constraint>
-    
-    <!-- Value with child constraints -->
-    <constraint name="Collection">
-      <option name="fields">
-        <value key="foo">
+      </constraint>
+      
+      <!-- Option with child constraints -->
+      <constraint name="All">
+        <option name="constraints">
           <constraint name="NotNull" />
           <constraint name="Min">3</constraint>
-        </value>
-        <value key="bar">
-          <constraint name="Min">5</constraint>
-        </value>
-      </option>
-    </constraint>
-
-    <!-- PROPERTY CONSTRAINTS -->
-
-    <property name="firstName">
+        </option>
+      </constraint>
+      
+      <!-- Value with child constraints -->
+      <constraint name="Collection">
+        <option name="fields">
+          <value key="foo">
+            <constraint name="NotNull" />
+            <constraint name="Min">3</constraint>
+          </value>
+          <value key="bar">
+            <constraint name="Min">5</constraint>
+          </value>
+        </option>
+      </constraint>
+      
       <!-- Constraint with options -->
       <constraint name="Choice">
         <!-- Option with single value -->

+ 22 - 22
tests/Symfony/Tests/Component/Validator/Mapping/Loader/constraint-mapping.yml

@@ -1,33 +1,33 @@
 Symfony\Tests\Component\Validator\Fixtures\Entity:
   constraints:
-    # Constraint without value
-    - NotNull: ~
     # Custom constraint
     - Symfony\Tests\Component\Validator\Fixtures\ConstraintA: ~
-    # Constraint with single value
-    - Min: 3
-    # Constraint with multiple values
-    - Choice: [A, B]
-    # Constraint with child constraints
-    - All:
-        - NotNull: ~
-        - Min: 3
-    # Option with child constraints
-    - All:
-        constraints:
+      
+  properties:
+    firstName:
+      # Constraint without value
+      - NotNull: ~
+      # Constraint with single value
+      - Min: 3
+      # Constraint with multiple values
+      - Choice: [A, B]
+      # Constraint with child constraints
+      - All:
           - NotNull: ~
           - Min: 3
-    # Value with child constraints
-    - Collection:
-        fields:
-          foo:
+      # Option with child constraints
+      - All:
+          constraints:
             - NotNull: ~
             - Min: 3
-          bar:
-            - Min: 5
-      
-  properties:
-    firstName:
+      # Value with child constraints
+      - Collection:
+          fields:
+            foo:
+              - NotNull: ~
+              - Min: 3
+            bar:
+              - Min: 5
       # Constraint with options
       - Choice: { choices: [A, B], message: Must be one of %choices% }
         

+ 9 - 0
tests/Symfony/Tests/Component/Validator/Mapping/MemberMetadataTest.php

@@ -13,9 +13,11 @@ namespace Symfony\Tests\Component\Validator\Mapping;
 
 require_once __DIR__.'/../Fixtures/ConstraintA.php';
 require_once __DIR__.'/../Fixtures/ConstraintB.php';
+require_once __DIR__.'/../Fixtures/ClassConstraint.php';
 
 use Symfony\Tests\Component\Validator\Fixtures\ConstraintA;
 use Symfony\Tests\Component\Validator\Fixtures\ConstraintB;
+use Symfony\Tests\Component\Validator\Fixtures\ClassConstraint;
 use Symfony\Component\Validator\Constraints\Valid;
 use Symfony\Component\Validator\Mapping\MemberMetadata;
 
@@ -50,6 +52,13 @@ class MemberMetadataTest extends \PHPUnit_Framework_TestCase
         $this->assertFalse($this->metadata->isCascaded());
     }
 
+    public function testAddConstraintRequiresClassConstraints()
+    {
+        $this->setExpectedException('Symfony\Component\Validator\Exception\ConstraintDefinitionException');
+
+        $this->metadata->addConstraint(new ClassConstraint());
+    }
+
     public function testSerialize()
     {
         $this->metadata->addConstraint(new ConstraintA(array('property1' => 'A')));