Skip to content

Commit

Permalink
Merge branch 'release/0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
c0ntax committed Jan 25, 2018
2 parents ef05129 + 9b48c72 commit 530548a
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 104 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ Since this library is very much alpha, I haven't had time to add all the [valida
* Max
* Min
* Required
* Range
## Specific Validaton Notes
Sometimes there is not a 1-2-1 mapping of Symfony error messages to Parsley. This is because with Parsley, you supply only one error message for the validator which is then displayed at runtime, whereas with Symfony constraints, they can pick a specific error message based on what didn't validate. Listed here are any Symfony validators where I've had to pick a specific error message that you should override using the ConstraintErrorMessage directive (so that if server based validations kick in, they will still have a message that makes sense)
* Range
## Usage
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c0ntax/parsley-bundle",
"version": "0.3.0",
"version": "0.4.0",
"type": "symfony-bundle",
"description": "A bridge between Symfony and Parsley.js",
"license": "Apache-2.0",
Expand Down
6 changes: 3 additions & 3 deletions src/Directive/Field/Constraint/AbstractComparison.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ abstract class AbstractComparison extends AbstractConstraint
/**
* Min constructor.
*
* @param \DateTime|float|int $min
* @param \DateTime|float|int $value
* @param string|null $errorMessage
* @throws \InvalidArgumentException
*/
public function __construct($min, string $errorMessage = null)
public function __construct($value, string $errorMessage = null)
{
$this->setValue($min);
$this->setValue($value);
parent::__construct($errorMessage);
}

Expand Down
103 changes: 103 additions & 0 deletions src/Directive/Field/Constraint/Range.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
declare(strict_types = 1);

namespace C0ntax\ParsleyBundle\Directive\Field\Constraint;

/**
* Class Range
*
* @package C0ntax\ParsleyBundle\Directive\Field\Constraint
*/
class Range extends AbstractConstraint
{
/** @var int|float|\DateTime|\DateTimeImmutable */
private $min;

/** @var int|float|\DateTime|\DateTimeImmutable */
private $max;

/**
* Range constructor.
*
* @param int|float|\DateTime|\DateTimeImmutable $min
* @param int|float|\DateTime|\DateTimeImmutable $max
* @param null|string $errorMessageString
* @throws \InvalidArgumentException
*/
public function __construct($min, $max, ?string $errorMessageString = null)
{
$this->setMin($min);
$this->setMax($max);
parent::__construct($errorMessageString);
}

/**
* @return string
*/
public static function getConstraintId(): string
{
return 'range';
}

/**
* @return array
*/
public function getViewAttr(): array
{
$minValue = $this->createStringValue($this->getMin());
$maxValue = $this->createStringValue($this->getMax());

return $this->getMergedViewAttr('["'.$minValue.'", "'.$maxValue.'"]');
}

/**
* @param $value
* @return string
*/
private function createStringValue($value): string
{
if ($value instanceof \DateTime || $value instanceof \DateTimeImmutable) {
return $value->format('Y-m-d H:i:s');
} else {
return (string) $value;
}
}

/**
* @return \DateTime|\DateTimeImmutable|float|int
*/
private function getMin()
{
return $this->min;
}

/**
* @param \DateTime|\DateTimeImmutable|float|int $min
* @return Range
*/
private function setMin($min): Range
{
$this->min = $min;

return $this;
}

/**
* @return \DateTime|\DateTimeImmutable|float|int
*/
private function getMax()
{
return $this->max;
}

/**
* @param \DateTime|\DateTimeImmutable|float|int $max
* @return Range
*/
private function setMax($max): Range
{
$this->max = $max;

return $this;
}
}
65 changes: 34 additions & 31 deletions src/Factory/ConstraintFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@
namespace C0ntax\ParsleyBundle\Factory;

use C0ntax\ParsleyBundle\Contracts\ConstraintInterface;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Email;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Length;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Max;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\MaxLength;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Min;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\MinLength;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Pattern;
use C0ntax\ParsleyBundle\Directive\Field\Constraint\Required;
use C0ntax\ParsleyBundle\Directive\Field\Constraint as ParsleyConstraint;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints as SymfonyConstraint;
use Symfony\Component\Validator\Constraints\AbstractComparison;

/**
Expand All @@ -40,71 +34,80 @@ public static function createFromValidationConstraint(
): ?ConstraintInterface {
// TODO Change this to use the ViewInterface instead of the FormInterface as that makes a lot more sense!

if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Valid) {
if ($validationConstraint instanceof SymfonyConstraint\Valid) {
// This case is not an error. There just isn't a 'like-for-like' replacement
return null;
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\NotNull) {
return new Required($validationConstraint->message);
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\NotBlank) {
return new Required($validationConstraint->message);
} if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Length) {
} elseif ($validationConstraint instanceof SymfonyConstraint\NotNull) {
return new ParsleyConstraint\Required($validationConstraint->message);
} elseif ($validationConstraint instanceof SymfonyConstraint\NotBlank) {
return new ParsleyConstraint\Required($validationConstraint->message);
}
if ($validationConstraint instanceof SymfonyConstraint\Length) {
if ($validationConstraint->min !== null && $validationConstraint->max !== null) {
// TODO Pick a better message!
return new Length(
return new ParsleyConstraint\Length(
$validationConstraint->min,
$validationConstraint->max,
self::convertParameters($validationConstraint->exactMessage)
);
} elseif ($validationConstraint->min !== null) {
return new MinLength(
return new ParsleyConstraint\MinLength(
$validationConstraint->min,
self::convertParameters($validationConstraint->minMessage)
);
} else {
return new MaxLength(
return new ParsleyConstraint\MaxLength(
$validationConstraint->max,
self::convertParameters($validationConstraint->maxMessage)
);
}
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Regex) {
return new Pattern($validationConstraint->pattern, self::convertParameters($validationConstraint->message));
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\Email) {
return new Email(self::convertParameters($validationConstraint->message));
} elseif ($validationConstraint instanceof SymfonyConstraint\Regex) {
return new ParsleyConstraint\Pattern($validationConstraint->pattern, self::convertParameters($validationConstraint->message));
} elseif ($validationConstraint instanceof SymfonyConstraint\Email) {
return new ParsleyConstraint\Email(self::convertParameters($validationConstraint->message));
} elseif ($validationConstraint instanceof AbstractComparison) {
// This is an interesting case that requires the context of the form element. If any of these validations
// happen to contain a value that is a string, it is assumed that the string is a dateTime. We should
// only do dateTime evaluations if the field input type is 'date', otherwise Parsley just wont bother!

$innerType = $form->getConfig()->getType()->getInnerType();

if (is_string($validationConstraint->value) && !static::isFormHtml5DateType($form)) {
throw new \RuntimeException('Date evaluation called on a non-DateType field: '.$form->getName());
}

if ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\GreaterThanOrEqual) {
return new Min(
if ($validationConstraint instanceof SymfonyConstraint\GreaterThanOrEqual) {
return new ParsleyConstraint\Min(
static::convertMinMaxValue($validationConstraint->value),
self::convertParameters($validationConstraint->message)
);
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\GreaterThan) {
} elseif ($validationConstraint instanceof SymfonyConstraint\GreaterThan) {
// Bit of a trickey one as isn't an analogous Parsley
return new Min(
return new ParsleyConstraint\Min(
static::convertMinMaxValue($validationConstraint->value, true, true),
self::convertParameters($validationConstraint->message)
);
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\LessThanOrEqual) {
return new Max(
} elseif ($validationConstraint instanceof SymfonyConstraint\LessThanOrEqual) {
return new ParsleyConstraint\Max(
static::convertMinMaxValue($validationConstraint->value),
self::convertParameters($validationConstraint->message)
);
} elseif ($validationConstraint instanceof \Symfony\Component\Validator\Constraints\LessThan) {
} elseif ($validationConstraint instanceof SymfonyConstraint\LessThan) {
// Bit of a trickey one as isn't an analogous Parsley
return new Max(
return new ParsleyConstraint\Max(
static::convertMinMaxValue($validationConstraint->value, true, false),
self::convertParameters($validationConstraint->message)
);
}
} elseif ($validationConstraint instanceof SymfonyConstraint\Range) {
// No error message translation here

if (is_string($validationConstraint->min) && !static::isFormHtml5DateType($form)) {
throw new \RuntimeException('Date evaluation called on a non-DateType field: '.$form->getName());
}

return new ParsleyConstraint\Range(
static::convertMinMaxValue($validationConstraint->min),
static::convertMinMaxValue($validationConstraint->max)
);
}

throw new \RuntimeException('Unsupported Symfony Constraint: '.get_class($validationConstraint));
Expand Down
32 changes: 32 additions & 0 deletions tests/Directive/Field/Constraint/RangeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace C0ntax\ParsleyBundle\Tests\Directive\Field\Constraint;

use C0ntax\ParsleyBundle\Directive\Field\Constraint\Range;

class RangeTest extends \PHPUnit_Framework_TestCase
{

public function testGetConstraintId()
{
self::assertEquals('range', Range::getConstraintId());
}

public function testGetViewAttr()
{
$pattern = new Range(1, 10);
self::assertEquals(['data-parsley-range' => '["1", "10"]'], $pattern->getViewAttr());

$pattern = new Range(1, 10, 'Error message');
self::assertEquals(['data-parsley-range' => '["1", "10"]', 'data-parsley-range-message' => 'Error message'], $pattern->getViewAttr());

$minDate = (new \DateTime('now'))->sub(new \DateInterval('P2W'));
$maxDate = (new \DateTime('now'))->add(new \DateInterval('P2W'));

$minDateString = $minDate->format('Y-m-d H:i:s');
$maxDateString = $maxDate->format('Y-m-d H:i:s');

$pattern = new Range($minDate, $maxDate, 'Error message');
self::assertEquals(['data-parsley-range' => '["'.$minDateString.'", "'.$maxDateString.'"]', 'data-parsley-range-message' => 'Error message'], $pattern->getViewAttr());
}
}
Loading

0 comments on commit 530548a

Please sign in to comment.