Open latysh opened 10 years ago
I had a similar one and found the issue with debugging the javascript in my "constraints".
Can you add your form?
Hi,
My manual form looks like this
<form name="pepperstone_applicationbundle_user" method="post" action="/app_dev.php/registration/step1/check"
class="form-horizontal formView step1form" novalidate="novalidate">
<div class="form-group">
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_email">username</label>
<input type="email" id="pepperstone_applicationbundle_user_email"
name="pepperstone_applicationbundle_user[email]" required="required" class="form-control input-lg"
value="altynbek.usenov@gmail.com"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_change_password_first">enter.new.password</label>
<input type="password" id="pepperstone_applicationbundle_user_change_password_first"
name="pepperstone_applicationbundle_user[change_password][first]" required="required"
class="form-control input-lg"/>
<span class="help-block"> </span>
</div>
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_change_password_second">confirm.new.password</label>
<input type="password" id="pepperstone_applicationbundle_user_change_password_second"
name="pepperstone_applicationbundle_user[change_password][second]" required="required"
class="form-control input-lg"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_first_name">First name</label>
<input type="text" id="pepperstone_applicationbundle_user_first_name"
name="pepperstone_applicationbundle_user[first_name]" required="required" maxlength="255"
class="form-control input-lg" value="Altynbek"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_last_name">Last name</label>
<input type="text" id="pepperstone_applicationbundle_user_last_name"
name="pepperstone_applicationbundle_user[last_name]" required="required" maxlength="255"
class="form-control input-lg" value="Usenov"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_phone">Phone</label>
<input type="text" id="pepperstone_applicationbundle_user_phone"
name="pepperstone_applicationbundle_user[phone]" required="required" maxlength="255"
class="form-control input-lg" value="0404205605"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_address">Address</label>
<input type="text" id="pepperstone_applicationbundle_user_address"
name="pepperstone_applicationbundle_user[address]" required="required" maxlength="255"
class="form-control input-lg" value="1/522 South road"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_city">City</label>
<input type="text" id="pepperstone_applicationbundle_user_city"
name="pepperstone_applicationbundle_user[city]" required="required" maxlength="255"
class="form-control input-lg" value="Moorabbin"/>
<span class="help-block"> </span>
</div>
<!-- Text input-->
<div class="col-md-12 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_state">State</label>
<input type="text" id="pepperstone_applicationbundle_user_state"
name="pepperstone_applicationbundle_user[state]" required="required" maxlength="255"
class="form-control input-lg" value="VIC"/>
<span class="help-block"> </span>
</div>
<!-- Text input short-->
<div class="col-md-3 mgnBtm20">
<label class="control-label required" for="pepperstone_applicationbundle_user_zip_code">Zip code</label>
<input type="text" id="pepperstone_applicationbundle_user_zip_code"
name="pepperstone_applicationbundle_user[zip_code]" required="required" maxlength="255"
class="form-control input-lg " value="3189"/>
<span class="help-block"> </span>
</div>
</div>
<!-- buttons-->
<div class="form-group btnWrapper">
<div class="col-md-6 col-xs-12 pull-right text-right">
<button type="submit" id="pepperstone_applicationbundle_user_submit"
name="pepperstone_applicationbundle_user[submit]" class="btn btn-lg btn-success flexBtn">
Update.and.proceed
</button>
</div>
</div>
</div><!--/contentvieport-->
<ul class="record_actions">
</ul>
<input type="hidden" id="pepperstone_applicationbundle_user__token"
name="pepperstone_applicationbundle_user[_token]" value="8ZAF1uxjybgTL5kQLIJPb7dFDMQD5ghgII6rtJtS_L0"/>
</form>
And this is what generated from {{ form(form, { 'attr': {'class': 'form-horizontal formView step1form', novalidate: 'novalidate'} }) }}
<form name="pepperstone_applicationbundle_user" method="post" action="/app_dev.php/registration/step1/check"
class="form-horizontal formView step1form" novalidate="novalidate">
<div id="pepperstone_applicationbundle_user" class="form-horizontal formView step1form" novalidate="novalidate">
<div><label for="pepperstone_applicationbundle_user_email" class="required">username</label><input type="email"
id="pepperstone_applicationbundle_user_email"
name="pepperstone_applicationbundle_user[email]"
required="required"
value="altynbek.usenov@gmail.com"/>
</div>
<div><label for="pepperstone_applicationbundle_user_change_password_first"
class="required">enter.new.password</label> <input type="password"
id="pepperstone_applicationbundle_user_change_password_first"
name="pepperstone_applicationbundle_user[change_password][first]"
required="required"/></div>
<div><label for="pepperstone_applicationbundle_user_change_password_second" class="required">confirm.new.password</label>
<input type="password" id="pepperstone_applicationbundle_user_change_password_second"
name="pepperstone_applicationbundle_user[change_password][second]" required="required"/></div>
<div><label for="pepperstone_applicationbundle_user_first_name" class="required">First name</label><input
type="text" id="pepperstone_applicationbundle_user_first_name"
name="pepperstone_applicationbundle_user[first_name]" required="required" maxlength="255"
value="Altynbek"/></div>
<div><label for="pepperstone_applicationbundle_user_last_name" class="required">Last name</label><input
type="text" id="pepperstone_applicationbundle_user_last_name"
name="pepperstone_applicationbundle_user[last_name]" required="required" maxlength="255"
value="Usenov"/></div>
<div><label for="pepperstone_applicationbundle_user_phone" class="required">Phone</label><input type="text"
id="pepperstone_applicationbundle_user_phone"
name="pepperstone_applicationbundle_user[phone]"
required="required"
maxlength="255"
value="0404205605"/>
</div>
<div><label for="pepperstone_applicationbundle_user_address" class="required">Address</label><input type="text"
id="pepperstone_applicationbundle_user_address"
name="pepperstone_applicationbundle_user[address]"
required="required"
maxlength="255"
value="1/522 South road"/>
</div>
<div><label for="pepperstone_applicationbundle_user_city" class="required">City</label><input type="text"
id="pepperstone_applicationbundle_user_city"
name="pepperstone_applicationbundle_user[city]"
required="required"
maxlength="255"
value="Moorabbin"/>
</div>
<div><label for="pepperstone_applicationbundle_user_state" class="required">State</label><input type="text"
id="pepperstone_applicationbundle_user_state"
name="pepperstone_applicationbundle_user[state]"
required="required"
maxlength="255"
value="VIC"/>
</div>
<div><label for="pepperstone_applicationbundle_user_zip_code" class="required">Zip code</label><input
type="text" id="pepperstone_applicationbundle_user_zip_code"
name="pepperstone_applicationbundle_user[zip_code]" required="required" maxlength="255" value="3189"/>
</div>
<div>
<button type="submit" id="pepperstone_applicationbundle_user_submit"
name="pepperstone_applicationbundle_user[submit]">Submit
</button>
</div>
<input type="hidden" id="pepperstone_applicationbundle_user__token"
name="pepperstone_applicationbundle_user[_token]" value="8ZAF1uxjybgTL5kQLIJPb7dFDMQD5ghgII6rtJtS_L0"/>
</div>
</form>
Am I right we are talking here about an user registration with UniqueEntity?
Perhaps using an existing UserBundle like FOSUserBundle?
Yes you are right. We use FOSUserBundle. Email is unique field... Is the problem related to it?
Yes it is, I will write later a complete answer, what issue you are encountering and how you can get around it.
Okay, so lets go ...
The point why the validation doesn't work is FOSUserBundle stores username and email twice in DB (username and username_canonical; same for email and email_canonical). The UniqueEntity constraints validates against the *_canonical field.
If you have a look on the generated form you will see it contains email, that is the reason why the JsFormValidator can't match them.
Why does it work on the normal way? It uses the validator.initializer in Initializer class:
public function initialize($object)
{
if ($object instanceof UserInterface) {
$this->userManager->updateCanonicalFields($object);
}
}
So the fields are filled before the validation is done (on the normal way).
How I got this working for me: Yes it is like a kind of a hack, but it works for me.
You need to extend the JsFormValidatorFactory and overwrite the method parseConstraints
:
protected function parseConstraints(array $constraints)
{
$result = array();
foreach ($constraints as $item) {
// Translate messages if need and add to result
foreach ($item as $propName => $propValue) {
if (false !== strpos(strtolower($propName), 'message')) {
$item->{$propName} = $this->translateMessage($propValue);
}
}
if ($item instanceof \Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity) {
if (! is_array($item->fields) && strpos($item->fields, 'Canonical') !== false) {
$item->fields = $item->errorPath;
}
$item = new UniqueEntity($item, $this->currentElement->getConfig()->getDataClass());
}
$result[get_class($item)][] = $item;
}
return $result;
}
You see I overwrite the field name if it contains Canonical with the errorPath (it is the field contained by the form).
In general the form is working, now. But you should also extend the AjaxController to revert the change and validate against the right fields.
Overwrite the method checkUniqueEntityAction
:
public function checkUniqueEntityAction(Request $request)
{
$data = $request->request->all();
if ($data['entityName'] === '<User entity name with namespace>' && isset($data['errorPath']) && ($data['errorPath'] === 'email' || $data['errorPath'] === 'username')) {
$data['data'][$data['errorPath'] . 'Canonical'] = $data['data'][$data['errorPath']];
unset($data['data'][$data['errorPath']]);
$request->request->replace($data);
}
return parent::checkUniqueEntityAction($request);
}
Overwrite the Factory parameter:
parameters:
fp_js_form_validator.factory.class: <your namespace>\JsFormValidatorFactory
Overwrite the routing:
fp_js_form_validator:
routing:
check_unique_entity: <your route>
Thanks mate, Now it works, exactly as I wanted it to work.
The only issue left with repeated form type. It is not caught by showErrors ((
I also got this same error when the input for the unique constraint wasn't in the form because of the buggy javascript. I opened a PR #78 to fix it
@CSchulz or @latysh can you recheck it now?
I will do it the next days.
I am surprised that it seems to be such a minor change, nevertheless good work @kick-the-bucket .
One more PR #79 for the same line - apparantly the name wasn't the right one to search for...
Symfony 2.4.8
Error appears when I try to validate form on a custom event based on here https://github.com/formapro/JsFormValidatorBundle/blob/master/Resources/doc/3_12.md
Form elements generated manually, tried to generate form elements by {{ form(form) }} still the same error.
Everything works fine when I submit the form. But I want to validate form field when the value is changed to show whether it is correct value or not.
What can be the issue?