Skip to content

Commit

Permalink
Merge pull request #105 from vaniocz/master
Browse files Browse the repository at this point in the history
PHP7 & Symfony3 compatibility
  • Loading branch information
66Ton99 committed Mar 29, 2016
2 parents 873b030 + 5d8615c commit 2cb04b4
Show file tree
Hide file tree
Showing 53 changed files with 395 additions and 457 deletions.
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
language: php

php: [5.3,5.4,5.5,5.6]
php: [5.5,5.6,7.0]

env:
- SF_VERSION='>=2.5.5,<2.6.0'
- SF_VERSION='~2.6.0'
- SF_VERSION='~2.7.0'
- SF_VERSION='~3.0.0'

before_script:
- export WEB_FIXTURES_HOST=http://localhost/index.php
Expand All @@ -30,6 +28,7 @@ before_script:
- sudo apt-get update > /dev/null
- sudo apt-get install -y --force-yes apache2 libapache2-mod-fastcgi > /dev/null
# enable php-fpm
- if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf; fi
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
- sudo a2enmod rewrite actions fastcgi alias
- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
Expand Down
52 changes: 40 additions & 12 deletions Factory/JsFormValidatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
use Fp\JsFormValidatorBundle\Form\Constraint\UniqueEntity;
use Fp\JsFormValidatorBundle\Model\JsConfig;
use Fp\JsFormValidatorBundle\Model\JsFormElement;
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\GetterMetadata;
use Symfony\Component\Validator\Mapping\PropertyMetadata;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

/**
* This factory uses to parse a form to a tree of JsFormElement's
Expand Down Expand Up @@ -91,7 +93,7 @@ public function __construct(
*/
protected function getMetadataFor($className)
{
return $this->validator->getMetadataFactory()->getMetadataFor($className);
return $this->validator->getMetadataFor($className);
}

/**
Expand Down Expand Up @@ -242,13 +244,15 @@ public function createJsModel(Form $form)
$model = new JsFormElement;
$model->id = $this->getElementId($form);
$model->name = $form->getName();
$model->type = $conf->getType()->getInnerType()->getName();
$model->type = get_class($conf->getType()->getInnerType());
$model->invalidMessage = $this->translateMessage(
$conf->getOption('invalid_message'),
$conf->getOption('invalid_message_parameters')
);
$model->transformers = $this->parseTransformers($form->getConfig()->getViewTransformers());
$model->cascade = $conf->getOption('cascade_validation');
$model->transformers = $this->normalizeViewTransformers(
$form,
$this->parseTransformers($conf->getViewTransformers())
);
$model->bubbling = $conf->getOption('error_bubbling');
$model->data = $this->getValidationData($form);
$model->children = $this->processChildren($form);
Expand Down Expand Up @@ -315,8 +319,8 @@ protected function getValidationData(Form $form)
$parent = $form->getParent();
if ($parent && null !== $parent->getConfig()->getDataClass()) {
$classMetadata = $metadata = $this->getMetadataFor($parent->getConfig()->getDataClass());
if ($classMetadata->hasMemberMetadatas($form->getName())) {
$metadata = $classMetadata->getMemberMetadatas($form->getName());
if ($classMetadata->hasPropertyMetadata($form->getName())) {
$metadata = $classMetadata->getPropertyMetadata($form->getName());
/** @var PropertyMetadata $item */
foreach ($metadata as $item) {
$this->composeValidationData(
Expand Down Expand Up @@ -444,8 +448,33 @@ protected function getValidationGroups(Form $form)
*/
protected function isProcessableElement($element)
{
return ($element instanceof Form)
&& ('hidden' !== $element->getConfig()->getType()->getName());
return ($element instanceof Form) && (!is_a($element->getConfig()->getType(), HiddenType::class, true));
}

/**
* Gets view transformers from the given form.
* Merges in an extra Choice(s)ToBooleanArrayTransformer transformer in case of expanded choice.
*
* @param FormInterface $form
* @param array $viewTransformers
*
* @return array
*/
protected function normalizeViewTransformers(FormInterface $form, array $viewTransformers)
{
$config = $form->getConfig();

// Choice(s)ToBooleanArrayTransformer was deprecated in SF2.7 in favor of CheckboxListMapper and RadioListMapper
if ($config->getType()->getInnerType() instanceof ChoiceType && $config->getOption('expanded')) {
$namespace = 'Symfony\Component\Form\Extension\Core\DataTransformer\\';
$transformer = $config->getOption('multiple')
? array('name' => $namespace . 'ChoicesToBooleanArrayTransformer')
: array('name' => $namespace . 'ChoiceToBooleanArrayTransformer');
$transformer['choiceList'] = array_values($config->getOption('choices'));
array_unshift($viewTransformers, $transformer);
}

return $viewTransformers;
}

/**
Expand All @@ -471,7 +500,6 @@ protected function parseTransformers(array $transformers)

$result[] = $item;
}

return $result;
}

Expand All @@ -495,7 +523,7 @@ protected function getTransformerParam(DataTransformerInterface $transformer, $p
} elseif (is_scalar($value) || is_array($value)) {
$result = $value;
} elseif ($value instanceof ChoiceListInterface) {
$result = $value->getChoices();
$result = array_values($value->getChoices());
}

return $result;
Expand Down
5 changes: 3 additions & 2 deletions Form/Extension/FormExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use Fp\JsFormValidatorBundle\Factory\JsFormValidatorFactory;
use Fp\JsFormValidatorBundle\Form\Subscriber\SubscriberToQueue;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -37,7 +38,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
}

/**
* @param OptionsResolverInterface $resolver
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
Expand All @@ -51,6 +52,6 @@ public function configureOptions(OptionsResolver $resolver)
*/
public function getExtendedType()
{
return 'form';
return FormType::class;
}
}
5 changes: 0 additions & 5 deletions Model/JsFormElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ class JsFormElement extends JsModelAbstract
*/
public $invalidMessage;

/**
* @var bool
*/
public $cascade = false;

/**
* @var bool
*/
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
[![Build Status](https://travis-ci.org/formapro/JsFormValidatorBundle.svg?branch=master)](https://travis-ci.org/formapro/JsFormValidatorBundle)
[![Total Downloads](https://poser.pugx.org/fp/jsformvalidator-bundle/downloads.png)](https://packagist.org/packages/fp/jsformvalidator-bundle)

This module enables validation of the Symfony 2.5.5+ forms on the JavaScript side.
This module enables validation of the 3.0+ forms on the JavaScript side.
It converts form type constraints into JavaScript validation rules.

If you have Symfony 2.5.4* or less* - you need to use [Version 1.2.*](https://github.com/formapro/JsFormValidatorBundle/tree/1.2)

* More details here: [Symfony2](https://github.com/symfony/symfony/commit/97243bcd024bbfa458d66a4263a50ee7f16bbe74), [PR #83](https://github.com/formapro/JsFormValidatorBundle/pull/83)

If you have Symfony 2.8.* or 2.7.* - you need to use [Version 1.3.*](https://github.com/formapro/JsFormValidatorBundle/tree/1.3)
If you have Symfony 2.6.* or less - you need to use [Version 1.2.*](https://github.com/formapro/JsFormValidatorBundle/tree/1.2)

## 1 Installation<a name="p_1"></a>

Expand Down
2 changes: 1 addition & 1 deletion Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<service id="fp_js_form_validator.extension" class="%fp_js_form_validator.extension.class%">
<argument type="service" id="fp_js_form_validator.factory" />
<tag name="form.type_extension" alias="form" />
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
</service>

<service id="fp_js_form_validator.factory" class="%fp_js_form_validator.factory.class%">
Expand Down
45 changes: 30 additions & 15 deletions Resources/public/js/FpJsFormValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ function FpJsFormElement() {
this.name = '';
this.type = '';
this.invalidMessage = '';
this.cascade = false;
this.bubbling = false;
this.disabled = false;
this.transformers = [];
Expand Down Expand Up @@ -46,6 +45,7 @@ function FpJsFormElement() {

this.validateRecursively = function () {
this.validate();

for (var childName in this.children) {
this.children[childName].validateRecursively();
}
Expand Down Expand Up @@ -470,17 +470,16 @@ var FpJsFormValidator = new function () {
this.validateElement = function (element) {
var errors = [];
var value = this.getElementValue(element);
for (var type in element.data) {

if (!this.checkParentCascadeOption(element) && 'entity' == type) {
for (var type in element.data) {
if ('entity' == type && element.parent && !this.shouldValidEmbedded(element)) {
continue;
}

if (element.parent && !this.checkParentCascadeOption(element.parent) && 'parent' == type) {
if ('parent' == type && element.parent && element.parent.parent && !this.shouldValidEmbedded(element.parent)) {
continue;
}


// Evaluate groups
var groupsValue = element.data[type]['groups'];
if (typeof groupsValue == "string") {
Expand All @@ -505,19 +504,32 @@ var FpJsFormValidator = new function () {
}
}
}

return errors;
};

this.checkParentCascadeOption = function (element) {
var result = true;
if (element.parent && !element.parent.cascade && 'collection' != element.parent.type) {
result = false;
} else if (element.parent) {
result = this.checkParentCascadeOption(element.parent);
this.shouldValidEmbedded = function (element) {
if (this.getElementValidConstraint(element)) {
return true;
} else if (
element.parent
&& 'Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType' == element.parent.type
) {
var validConstraint = this.getElementValidConstraint(element);

return !validConstraint || validConstraint.traverse;
}

return result;
return false;
};

this.getElementValidConstraint = function (element) {
if (element.data && element.data.form) {
for (var i in element.data.form.constraints) {
if (element.data.form.constraints[i] instanceof SymfonyComponentValidatorConstraintsValid) {
return element.data.form.constraints[i];
}
}
}
};

/**
Expand Down Expand Up @@ -569,7 +581,7 @@ var FpJsFormValidator = new function () {

if (i && undefined === value) {
value = this.getMappedValue(element);
} else if ('collection' == element.type) {
} else if ('Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType' == element.type) {
value = {};
for (var childName in element.children) {
value[childName] = this.getMappedValue(element.children[childName]);
Expand Down Expand Up @@ -609,7 +621,10 @@ var FpJsFormValidator = new function () {
}

var value;
if ('checkbox' == element.type || 'radio' == element.type) {
if (
'Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType' == element.type
|| 'Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType' == element.type
) {
value = element.domNode.checked;
} else if ('select' === element.domNode.tagName.toLowerCase()) {
value = [];
Expand Down
2 changes: 1 addition & 1 deletion Resources/public/js/constraints/Callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function SymfonyComponentValidatorConstraintsCallback () {
if (!this.callback) {
this.callback = [];
}
if (!this.methods) {
if (!this.methods.length) {
this.methods = [this.callback];
}

Expand Down
10 changes: 4 additions & 6 deletions Resources/public/js/constraints/Choice.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ function SymfonyComponentValidatorConstraintsChoice() {

if (this.multiple) {
if (invalidCnt) {
while (invalidCnt--) {
errors.push(this.multipleMessage.replace(
'{{ value }}',
FpJsBaseConstraint.formatValue(invalidList[invalidCnt])
));
}
errors.push(this.multipleMessage.replace(
'{{ value }}',
FpJsBaseConstraint.formatValue(invalidList[0])
));
}
if (!isNaN(this.min) && value.length < this.min) {
errors.push(this.minMessage);
Expand Down
13 changes: 1 addition & 12 deletions Resources/public/js/constraints/False.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,4 @@
* @constructor
* @author [email protected]
*/
function SymfonyComponentValidatorConstraintsFalse() {
this.message = '';

this.validate = function (value) {
var errors = [];
if ('' !== value && false !== value) {
errors.push(this.message.replace('{{ value }}', FpJsBaseConstraint.formatValue(value)));
}

return errors;
}
}
var SymfonyComponentValidatorConstraintsFalse = SymfonyComponentValidatorConstraintsIsFalse;
18 changes: 18 additions & 0 deletions Resources/public/js/constraints/IsFalse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//noinspection JSUnusedGlobalSymbols
/**
* Checks if value is (bool) false
* @constructor
* @author [email protected]
*/
function SymfonyComponentValidatorConstraintsIsFalse() {
this.message = '';

this.validate = function (value) {
var errors = [];
if ('' !== value && false !== value) {
errors.push(this.message.replace('{{ value }}', FpJsBaseConstraint.formatValue(value)));
}

return errors;
}
}
18 changes: 18 additions & 0 deletions Resources/public/js/constraints/IsNull.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//noinspection JSUnusedGlobalSymbols
/**
* Checks if value is null
* @constructor
* @author [email protected]
*/
function SymfonyComponentValidatorConstraintsIsNull() {
this.message = '';

this.validate = function(value) {
var errors = [];
if (null !== value) {
errors.push(this.message.replace('{{ value }}', FpJsBaseConstraint.formatValue(value)));
}

return errors;
}
}
Loading

0 comments on commit 2cb04b4

Please sign in to comment.