In my registration form, I have a checkbox where a user can accept to receive newsletters.
In create function I want to display all passed data:
protected function create(array $data)
{
dd($data);
}
The name of my checkbox field is newsletter. When I do dd(), I don't get the value for the newsletter, only for: name, email and password.
If I add this newsletter to Validator then it is shown.
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'newsletter' => 'required',
]);
}
Now, when I do dd() it is passed, but I don't want this checkbox to be required. It should be optional. Should I change something in Validator or?
Regardless of the backend, when a checkbox is not checked, its value won't be sent as part of the request to the server. That's how browsers work and that's why you won't be seeing a newsletter field when dumping the request.
However, when you use Laravel's validator and mention the field in the rules, Laravel does it for you and sets its value. To not to make it required, use the sometimes rule.
That would do it just for the purpose of dumping the data. But when implementing the real logic, instead of dumping data, you'll hopefully be utilizing the given request instance, facade or helper which will return a falsy value for non-existent parameters. So, you're just fine without adding the additional rule.
Or, you can set a default value for the newsletter field making sure if the data is not there, new registrations will happen with the desired default state.
By the way, you wanna make sure that your controller method is accepting a Request instance instead of an array.
Your newsletter field is a checkbox. When a html form is submitted and the checkbox is not checked, this field will not be available in the posted data. If the checkbox is checked it will be available. This is default html behavior, nothing you can do about this.
To check if the checkbox has been checked in your code, you can use the following:
$checked = array_key_exists('newsletter', $data);
Related
I have a form in Laravel and the submission and validation works, but I'm doing custom validation to check the data against the database (for sanitization) as well.
The issue is, I only want to do this validation IF each of the fields is filled out. In other words, if an input isn't required thus not filled out, I don't want it to fail because of it not matching data in the database.
For instance, I have a form input on my blade:
<td>{!! Form::select('productNumber', $img->productNumber) !!}</td>
and in the controller I'm checking this against the service to make sure it's valid data
if(!$productCheckService->validGroupCode($request->productNumber))
return back()->withErrors("Invalid group: ".$request->productNumber);
This works if filled out, but if the field is empty I want to bypass that check. In other words, the field isn't required so the data validity check shouldn't be required on a possibly null/empty field
I'm doing this below but it still is failing if it's empty for some reason. Am I totally missing something? I would think that checking that it's not empty before the check should suffice.
if(!empty($request->productNumber))
if(!$productCheckService->validGroupCode($request->productNumber))
return back()->withErrors("Invalid group: ".$request->productNumber);
You can use Laravel 'sometimes' attributes, so if your field is not present in request array it will bypass from validation.
$v = Validator::make($data, [
'productNumber' => 'sometimes|required|number',
]);
how could one make the following validation:
something like exclude_if:field,value
The field under validation cannot be present if the field "field" is equal to value.
I thought of doing a custom validation, but I am not sure how to pass the value of the other field into the custom validation class.
A real world example for this case would be if we have let's say two checkboxes A and B, and we want to make sure that if A is checked then B cannot be checked.
Anybody? Thanks!
Laravel has this covered out of the body. Lets say you don't want additional_field to be required to be filled in if the field is greater than the value 100.
Firstly - do your static rules that never change:
$v = Validator::make($data, array(
'name' => 'required',
'field' => 'required|numeric',
));
Then you can validate a sometimes rule against the field rule:
$v->sometimes('additional_field', 'required, function($input)
{
return $input->field > 100;
});
You can read more about conditionally adding rules in the Laravel Docs here.
I'm currently building a form manager in PHP to validate large forms.
I'm wondering what is the best structure for that, because the number of fields will be different each time.
I'm already filtering the field to validate by using a prefix (ex : 'user_name', will be validated, but 'name' no).
My real problem is for the validation : I must check the type of the field (mail, zipcode, phone...)
AND check that the value for this type of field is valid.
I thought that I could use HTML5 Custom data" (ex: data-fieldtype="zipcode"), but i didn't know that the server can't get this attribute...
What's the way to go ?
I could use 2 inputs per field, one for the value and one for the type, but it looks really stupid !
Thanks if you can help.
EDIT :
Your answers are all interesting, i don't know which is best.
I will probably make a mix between your solutions, depending of the kind of form.
Thanks a lot.
Methinks, this shouldn't be played via the Browser without further thought: A malicious user would be able to manipulate a "INT ONLY" field into being freetext, and your application would suddenly have to deal with freetext in a field, that is thought to be validated as an integer (und thus e.g. safe for SQL).
You have two approaches:
Have your form validation structure stored in the DB, and submit a single hidden field, that carries the ID of the validation structure. On receiving the request, your script would request the structure from the DB, unserialize it, and work on it.
If you really need to go through the browser, serialize your validation structure, base64-encode it and use it as a single hidden field. For the reasons stated above, it is mandatory to authenticate this value, either hashing (concatenate with another string only known to the server, hash it, send the hash as a second hidden field, on next request verify the hash is correct) or by encryption (encrypt the serialized data before the browser roundtrip, decrypt afterwards, key known only to the server)
Both would make your prefix-trick unnecessary, increasing readability and maintainability.
If no framework is used, you can use an array of field => options.
$rules = [
'user_name' => 'required',
'user_email' => 'email required',
// ...
];
And then feed them to some validator class, where rules are methods and they're being called inside validate method dynamically:
class Validator {
public function __construct($data) { $this->data = $data; }
private function required($field) {}
private function email($email) {}
// etc
/** #method bool validate(array $rules) */
public function validate($rules) {}
}
Never ever validate on client-side only. Always validate serverside.
Usually you will have a base class for controller, and every other controller extends it.
Aa good approach is to have en every view controller (or the bootsrtap) a method check_params().
It should 1) get a copy or $_REQUEST, check every parameter needed, 2) delete $_REQUEST, 3) write back the checked and validated params.
abstract class controller_base {
public function __construct() { ...; $this->check_param();...}
protected final function check_param() {
foreach ($this->param_list() AS $name => $type) {...}
}
abstract public function param_list();
}
class controller_login extends controller_base {
public function param_list() {
return array('name' => 'string', 'password' => 'string');
}
}
The idea is that this way you
only use params that has been sanitized
you autmaticly delete every param not needed
you have a list in every controller that states the used params.
I was investigating CakePHP (2.3.4) Model::save method to insert new records and ran into a little snag:
//Two fields provided, email field intended to fail validation
$data = array('Member' => array(
'username' => 'hello',
'email' => 'world'
));
$this->Member->create();
var_dump($this->Member->save($data, true));
The above save() will return false and no data will be written to the database. However if I change the data to:
//One field provided, intended to pass validation
$data = array('Member' => array(
'username' => 'hello'
));
then save() will attempt to write a new record to database with a blank email field. I realize that skipping validation for unspecified fields might be a useful behavior during updates, but is there a CakePHP recommended way to handle partially empty data sets when creating new records? Thanks a lot.
Edit:
Thanks to Sam Delaney for the tip. In case anybody else gets stumped, this did the trick: CakePHP Data Validation: field 'required' key
This key accepts either a boolean, or create or update. Setting this key to true will make the field always required. While setting it to create or update will make the field required only for update or create operations. If ‘required’ is evaluated to true, the field must be present in the data array. For example, if the validation rule has been defined as follows:
I had originally baked the model and forgotten that required => true was left out of the validation rule. Setting it to true or 'create' would've avoided me blank records getting inserted due to gibberish data array.
IMHO what you've experienced is the desired behavior. Consider that you have the same two fields within a form and the user provides a value for only username. Both username and email field are submitted even though email is empty. Then on the server, you try to save the record only to find out that it has failed validation which you feedback to the user. On the other hand, perhaps in your system it is perfectly possible to create a user without requiring an email (for example root access account), CakePHP's validation implementation allows both of these scenarios.
If this flexibility isn't what you desire, just set the required attribute for your validation rule as true:
public $validate = array(
'email' => array(
'rule' => 'email',
'required' => true
)
);
This will satisfy your all or nothing requirement.
I have a pretty simple form with some fields from a doctrine model.
$this->widgetSchema['fields'] = new sfWidgetFormDoctrineChoice(array(
'model' => 'FieldModel',
'expanded' => true,
'multiple' => true,));
$this->validatorSchema['fields'] = new sfValidatorDoctrineChoice(array(
'model' => 'FieldModel',
'multiple' => true,));
The fields are rendered in the form as checkboxes and I'm able to check and save correctly. This 'fields'-field is converted to a json-structure and saved to the database as text. So far so good.
NOTE: The field 'fields' is stored as TEXT in the database, but the user should be able to select values from a list of checkboxes.
The problem arise when I want to have some of the checkboxes checked by default.
I tried to do:
$this->setDefault('fields', array('key1','key2','key3'));
Where 'keyX' correspond to the actual value of the primary key (string) for Field in the database.
If I do a
$this->getDefault('fields');
I get back exactly what I put in previously.
However, symfony is not outputing any of the checkboxes as checked. I have even tried to remove both the 'expanded' and 'multiple' options to the choice-widget so I get a simple SELECT-box and the provide only one value as default selected.
Setting default values for other widgets (text-inputs, choice, etc) work.
Btw; The Field-model is i18n. Don't know if that matters here, since both storing / retrieving works as expected.
Also; the form is rendered as part of another form by means of include_partial(). Can that sabotage anything? In the 'parent' form class:
$this->embedRelation('TheRelationThatBugsMe');
And then in the _form.php for the 'parent':
include_partial('the_relation_that_bugs_me/form', array('form' => $form['TheRelationThatBugsMe']));
Does anyone have an idea where I might have gone wrong, or at least can give me some pointers as to where I should start digging?
[UPDATE]
If I create a new field in the form 'fields2' (that does not exist as a field in the database) and use the exact same code to create widget, validator and set defaults, then the defaults are rendered correctly. How come it doesn't work setting defaults for a field mapped to a column in the database?
If you're calling setDefault before updateDefaultFromObject gets called in sfDoctrineForm, then the object's values will override form defaults if the object exists. updateDefaultsFromObject contains the relevant logic. You'll have to call setDefault later, or override the method.