Zend framework - how to allow empty field for form element - zend-framework

I'm using this construction for my element:
$freetext = $this->CreateElement('textarea', 'freetext')
->setLabel('Comments')
->setAttrib('class','input-textarea')
->setOptions(array('rows' => '2', 'cols'=>'30'))
->addValidator('StringLength', false, array(0,500))
->addFilter('HtmlEntities')
->addFilter('StripTags')
->setRequired(true);
I want to add an "allowEmpty" to this but can't find the correct syntax. I was hoping for something like:
... ->addValidator('allowEmpty', false, true)
But this does not work.
Edit: I've changed the setRequired() to true - I want to allow empty string as an acceptable value on a require field.
Regardless of usage, how do I add this option to my element?

->setRequired(false);
this is enough if you want to allow an empty string and save an empty string to database.
if you want the field to be optional and keep null value in database if nothing is given, add:
->addFilter(new Zend_Filter_Null)

$freetext = $this->CreateElement('textarea', 'freetext')
->addValidator('StringLength', false, array(10,500))
->setRequired(false);
Your code should already do that, the setRequired(false) method do what you're asking for, i.e. if the value is not submitted then validators won't be run.
Do you have any issue with the code you've written, some validation error messages or something else?
Update
I've changed the setRequired() to true - I want to allow empty string as an acceptable value on a require field.
What is the semantic in setRequired(true) and allowing the empty string as a valid value? Or better what do you require if the element can be empty?
What you've asked in the edit is a no sense, because if an element is required it MUST have a value different from the empty string. If you need to accept the empty string as a valid value just use setRequired(false). When you get form values with Zend_Form::getValues() or Zend_Form_Element::getValue() you'll obtain the empty string as result.
Anyway here it's the explanation of setRequired and setAllowEmpty from ZF manual:
Using the defaults, validating an Element without passing a value, or
passing an empty string for it, skips all validators and validates to
TRUE.
setAllowEmpty(false) leaving the two other mentioned flags
untouched, will validate against the validator chain you defined for
this Element, regardless of the value passed to isValid().
setRequired(true) leaving the two other mentioned flags untouched,
will add a 'NotEmpty' validator on top of the validator chain (if none
was already set)), with the $breakChainOnFailure flag set. This
behavior lends required flag semantic meaning: if no value is passed,
we immediately invalidate the submission and notify the user, and
prevent other validators from running on what we already know is
invalid data.
If you do not want this behavior, you can turn it off by passing a
FALSE value to setAutoInsertNotEmptyValidator($flag); this will
prevent isValid() from placing the 'NotEmpty' validator in the
validator chain.

Related

TYPO3 Fluid Form returns old values

Am running a form using fluid with two fields, username and password. When first run, correct data is sent to the action. When different data is resubmitted, original data is sent to the controller action instead of the new values. How do I solve this problem?
EDIT: I've discovered that an array containing the user-submitted form fields and their values are obtained from the request, serialized as is and the string stored in a hidden input field called '__referrer[arguments]', which is then submitted with the form back to the user. When the user resubmits the form again with new values, the user doesn't realize that the old values are in the form, in the form of a serialized string, which is submitted together with the new values. Turns out, this is ok if no errors are reported by the validators. In that case the data is simply passed to the controller action and processing continues. But if errors are collected, processing is not sent to the controller action but is sent to the error action. The error action unserializes the old data and forwards that data (instead of the the new values) to the intended action controller. See \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest().
EDIT: Steps to reproduce;
Create an action with one argument and create a form with one input element and a submit button. Create a validator for the element. Make it a string property. When all is said and done, start by sending a VALID value and let the form return. it will come back with no errors. but also if you look at it's hidden values, you find that the __referrer[arguments] has changes. That's because your previous values were serialized and are there. Now submit an INVALID value and check values entering your action. You'll be stunned they are the old ones.
This is weird. Currently if I disable the production of the __referrer[arguments] input field in the \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, everything works properly. How do I solve this? Please help.
Where things go wrong:
Here: \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::forwardToReferringRequest() . In this method, arguments are sought from __referrer internal arguments instead of the submitted values. Normally, if errors are found, only two elements are found in the arguments form variable: controller for controller name and action for action name. This is because they were submitted originally with the form and they will recycle without changing as long as the validator finds errors. Nothing else will be added to it. This is good... until it validates. When it validates, results are sent directly to the action controller and not through the error controller. When the process goes back to the form, the object or arguments submitted will be added to the form and returned to the user. Remember it validated. When you then send a wrong value next, it goes to the error controller, but the old values (that validated) and were serialized in the __referrer[arguments] are unserialized and forwarded to your action. And that's how you end up with old values in your action. This is because it assumes that the variable carries only two values inside it; the controller and action names only. It's wrong.
Assumption:
Form post values processing seem to be built under the presumption that once a form validates, you won't need it again.
News.
The values you send are sought from extbase arguments and serialized in \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::renderHiddenReferrerFields() method, added to the form just before presenting it to you. All TYPO3 has to do is skip your values and let the default values only be serialized. Just saw that the doc section of the function has this:
/**
* Renders hidden form fields for referrer information about
* the current controller and action.
*
* #return string Hidden fields with referrer information
* #todo filter out referrer information that is equal to the target (e.g. same packageKey)
*/
The #todo part is the news. Hope it's done in the next-patch since there are many scenarios where you want to resume the form such as in data entry.
Solution
Easiest solution: Initialize the empty argument in your action and hand the argument to the form. In my case, I use a DTO.
Example
public function accountLoginAction(DTO\Account\LoginDTO $accountLogin=null):ResponseInterface
{
if($accountLogin){
$this->repository->logon();
...
} else{
$accountLogin=DTO\Account\LoginDTO::getNewInstance();
}
$this->view->assign('object', $accountLogin);
return $this->response();
}
Hope it helps someone.

Given a Symfony 2.7 formType object with an added choice field, how can I access the choice strings?

I have created a form object in symfony, which is meant to process an api request. It is created in a controller via:
$myForm = new MyFormType($foo, $bar);
$form = $this->createForm($myForm, $entity, array('method' => 'POST', 'csrf_protection' => false));
Once these objects are created, I pass them into an external service which converts api data into data that's meant to be consumed by the form, like the following:
//I pass this in, so that, our api users don't have to pass in
//{uglyAPIVariable45: 721}, but rather {pretty_variable: "go left"}
$goodData = $this->convertOldData($form->getBuilderDataCopy(), $oldData);
One of the things this service does, is if the form has a choice, like a select tag, it attempts to convert any string passed to the api into the value in select tag. This way, if the user can pass over "East" if the select field has the options "North", "West", "South" and "East" associated with the values 0, 4, 5 and 10 and the converter should return 10. The user doesn't have to pass over one of those random values, they can just pass over the string. And if they passed over "Foo", it would return an error along with a description of what good choices they could pass over.
My problem is that, in production, I'm not able to get ahold of those values.
In development, I found that I could get my options using,
foreach($formBuilderDataCopy as $formElement){
$options = $formElement->getAttributes()['data_collector/passed_options']['choices'];
}
But when we moved to production, this code broke. The method, getAttributes, returned null suddenly. Admittedly, it seemed kind of janky to begin with, so I wanted to find a more valid approach to getting these choices, possibly even allowing me to bypass a different approach for 'choice', 'entity', 'timezone' et. al.
Unfortunately, looking through the source code and exploring it with get_class_methods and friends hasn't provided me with a solution this issue. Even when I get choices, the most I can get are values, but not the string options in the select box.
What's the appropriate approach to acquiring such information from my symphony forms?
As a side note, I have also tried:
$form->get('elementName')->getConfig()->getOption('choices');
But it also just returns a list of the ids to single numbers and not the strings that replace those numbers. e.g.
{3: 0, 5: 1, 10: 2, 11: 3...}
Create an entity Object for the form type. Then you can use the data as object. It must not been a doctrine entity.

Angular 2 - FormControl setValue 'onlySelf' parameter

Trying to understand what the 'onlySelf' parameter does when passing to setValue.
this.form.get('name').setValue('', { onlySelf: true })
The documentation says: "If onlySelf is true, this change will only affect the validation of this FormControl and not its parent component. This defaults to false."
However I'm struggling to understand this. Still fairly new to the using Angulars' model driven forms.
Angular2 by default will check for the form control/form group validity cascadingly up to the top level whenever there's an update to any form element value, unless you say no. onlySelf is the tool to help you do that.
Say you have a loginForm that has a username field and a password field, both of them are required, like this:
this.userNameControl = this.formBuilder.control('Harry', Validators.required);
this.passwordControl = this.formBuilder.control('S3cReT', Validators.required);
this.loginForm = this.formBuilder.group({
userName: this.userNameControl,
password: this.passwordControl
});
After this code, this.loginForm.valid is true.
If you set the value of a control using the default setting (onlySelf = false), Angular2 will update the control's validity as well as form group's validity. For example, this:
this.passwordControl.setValue('');
will result in
this.passwordControl.valid === false
this.loginForm.valid === false
However, this:
this.passwordControl.setValue('', { onlySelf: true });
will only change passwordControl's validity only:
this.passwordControl.valid === false
this.loginForm.valid === true
Put it this way, let's say that you have a form, called mainForm which is valid. It has four controls on it and all four have a value. Now, you decide to update the value of one of your controls, let's say you update it to some incorrect value and you specify onlySelf: true. If you try to call this.mainForm.valid, you will get the result that your form is valid even though your control is not valid, and it's invalid state should not allow the form to be submitted. But because the forms valid property is reporting true, you will be submitting inconsistent values to the backend.
It might be confusing why you would have this property, but there might be occasions when you don't want to invalidate the form because of one value or control. Probably you have some advanced checks on the server and you want to correct the value on the server or you might depend on a value from some external web service that might not be available at the time. I'm sure there are number of scenarios but this is something from top of my head.

bindFromRequest and asFormUrlEncoded return different values

I have a form where a field name is the same as one of the method/url parameters on the submit, say someInt. I.e. my form has #(dummyForm:Form[Dummy], someInt:Int) and dummyForm has a field "someInt" -> number and the controller is defined as def submit(someInt:Int) =.... Sample code here.
Let's say I submit the form with dummy.someInt value 222 and url parameter 555, I find the following:
request.body.asFormUrlEncoded shows one someInt, namely the value entered in the input field: (someInt,ArrayBuffer(222))
bindFromRequest, however somehow binds the form value to the url parameter value, 555 in this case
Is this expected behaviour? I would have thought bindFromRequest would be able to differentiate between the two? Is there a preferred way to prevent this type of conflict (besides having different names)?
(There is a workaround in this case. Instead of using the parameterless version of bindFromRequest, it seems to work as desired if you explicitly specify the asFormUrlEncoded set of values, i.e. bindFromRequest(request.body.asFormUrlEncoded.getOrElse(Map())). I am using Scala - have not tried to replicate in Java.)
In the bindFromRequest function, request.queryString is explicitly append to the list of values.

Get statuscode text in C#

I'm using a plugin and want to perform an action based on the records statuscode value. I've seen online that you can use entity.FormattedValues["statuscode"] to get values from option sets but when try it I get an error saying "The given key was not present in the dictionary".
I know this can happen when the plugin cant find the change for the field you're looking for, but i've already checked that this does exist using entity.Contains("statuscode") and it passes by that fine but still hits this error.
Can anyone help me figure out why its failing?
Thanks
I've not seen the entity.FormattedValues before.
I usually use the entity.Attributes, e.g. entity.Attributes["statuscode"].
MSDN
Edit
Crm wraps many of the values in objects which hold additional information, in this case statuscode uses the OptionSetValue, so to get the value you need to:
((OptionSetValue)entity.Attributes["statuscode"]).Value
This will return a number, as this is the underlying value in Crm.
If you open up the customisation options in Crm, you will usually (some system fields are locked down) be able to see the label and value for each option.
If you need the label, you could either do some hardcoding based on the information in Crm.
Or you could retrieve it from the metadata services as described here.
To avoid your error, you need to check the collection you wish to use (rather than the Attributes collection):
if (entity.FormattedValues.Contains("statuscode")){
var myStatusCode = entity.FormattedValues["statuscode"];
}
However although the SDK fails to confirm this, I suspect that FormattedValues are only ever present for numeric or currency attributes. (Part-speculation on my part though).
entity.FormattedValues work only for string display value.
For example you have an optionset with display names as 1, 2, 3,
The above statement do not recognize these values because those are integers. If You have seen the exact defintion of formatted values in the below link
http://msdn.microsoft.com/en-in/library/microsoft.xrm.sdk.formattedvaluecollection.aspx
you will find this statement is valid for only string display values. If you try to use this statement with Integer values it will throw key not found in dictionary exception.
So try to avoid this statement for retrieving integer display name optionset in your code.
Try this
string Title = (bool)entity.Attributes.Contains("title") ? entity.FormattedValues["title"].ToString() : "";
When you are talking about Option set, you have value and label. What this will give you is the label. '?' will make sure that the null value is never passed.