In the Laravel Docs on validation they speak of 'nested parameters':
If your HTTP request contains "nested" parameters, you may specify them in your validation rules using "dot" syntax:
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
What would the HTML look like for this nesting? I googled around, and found nothing except things about form nesting. Also, the "dot" syntax, is this specific to Laravel?
The dot notation is for easily accessing array elements, and making their selectors more "fluent".
Validating author.name would be the equivalent of having checking the value of the input <input type="text" name="author[name]" />.
This makes having multi model forms or grouping related data much nicer =). You can then get all the data for that thing by doing something like $request->request('author'); and that would give you the collection/array of all the values submitted with author[*]. Laravel also uses it with its config accessors - so config.setting.parameter is the equivalent of config[setting][parameter]
Basically makes working with array data easier.
See https://github.com/glopezdetorre/dot-notation-access for some examples!
The Html form will look like Nothing More
Related
Is this secure or is it vulnerable to exploitation by user input?
$ids = explode(",", $_GET['ids']);
$results = $collection->find([
'arbitraryId' => ['$in' => $ids]
]);
In this particular case it's not injection-vulnerable per se, but may throw an error:
GET /?ids[]=1
This input will break your first line of code because PHP treats such params as arrays and would try to run explode() against it, which would cause
ErrorException: explode() expects parameter 2 to be string, array given
The the common practice is to validate the request first and proceed only on successful validation, otherwise return the 422 unprocessable entity status. Most frameworks give you convenient tools to easily accomplish this. To illustrate, in Laravel it would look something like this:
$this->validate($request, [
'ids' => 'string',
]);
// quits and returns 422 status automatically on validation failure
The big issue with what you are doing is that people could try random ID's and might luckily see a document that that user might not be allowed to see.
So if this is what you fear, then you should add a session flag that holds the user permission and add permissions to your documents.
//this would have been set at user login
$perms = $_SESSION['perms'];
//get the right documents
$results = $collection->find([
'_id' => ['$in' => $ids],
'perms' => ['$in' => $perms]
]);
Otherwise, if an id does not exist, then it would just return an empty array. There is really no injection here as long as we are talking about reading documents by id, unless you convert those IDs back to MongoID at query time. In this case you should at least validate the format of each id before converting to MongoID, using at least this regex
[a-z0-9]{24}
So, okay i tried a lot of rules from validation docs but all give me same error saying
Array to string conversion
Here is how I add the array:
$this->validate($request,[
'employee' => 'required|in:'.$employee->pluck('id')->toArray(),
],[
'employee.in' => 'employee does not exists',
]);
Any hint on how to achieve this?
i created a custom validator but still passing array seems to be not possible
Implode the array as a string and join it on commas.
'employee' => 'required|in:'.$employee->implode('id', ', '),
This will make the correct comma separated string that the validator expects when making an in comparison.
Edit
This still works, but is not the Laravelesque way of doing it anymore. See the answer by #nielsiano.
Update: You are now able to use the Rule class instead of imploding values yourself as described in the correct answer. Simply do:
['someProperty' => ['required', Rule::in(['needed', 'stuff'])]];
As mentioned in the 'validating arrays' section in the documentation: https://laravel.com/docs/5.6/validation#validating-arrays
How can I stop Lithium to flatten input values that are arrays before validation?
The Validator::check method in Lithium calls Set::flatten on the input before processing validators, see here:
http://li3.me/docs/lithium/util/Validator::check()
...
$values = Set::flatten($values);
...
The problem with this is that it assumes the values in $values are scalars. However, I am passing arrays to the model (which is a MongoDB document).
So
'users' => ['foo','bar']
will become
'users.0' => 'foo',
'users.1' => 'bar'
Which totally breaks validation, because it changes the property names.
I could actually just remove the flatten assignment, but I don't want to mess with the internals of the framework. Also I could convert the array to a JSON string, an object, etc. before validation, and convert it back later, but that just sounds lame :) On the other hand, I assume there should be an easy and nice way to skip flattening somehow.
Does anyone know how to validate nested input sets using the Laravel 4 validator?
I have a table with a set of line items, and each quantity field has the unique package id in square brackets in the name:
<input type="text" name="quantity[package_one]" />
<input type="text" name="quantity[package_two]" />
This results in a nested input array:
<?php
array(
'quantity' => array(
'package_one' => 3,
'package_two' => 12
)
);
Which is exactly what i want, but i'm unsure how to specify rules for these items using the validator class:
// Does not work :-(
Validator::make(Input::all(), array(
'quantity[package_one]' => 'numeric|required|min:1',
'quantity[package_two]' => 'numeric|required|min:1'
));
This does not seem to work, neither does nesting the rules under quantity. Obviously there are workarounds to this like building a custom array of input yourself before passing it to the validator etc, but what i'd like to know is:
is there a native, "Laravel" way of handling nested input like this?
Thanks in advance,
Dan.
The dirty way....
Controller
$input = Input::all();
$input = array_merge($input, $input['quantity']);
Validator::make(Input::all(), array(
'package_one' => 'numeric|required|min:1',
'package_two' => 'numeric|required|min:1'
));
Validator does not look into nested arrays. just bring that array to the outer one and you are done. (you can unset $input['quntity'] if you want after that)
loophole here is, it assumes that $input['quantity'] is present in the array. You need to validate this before putting into validation.
Works but not efficient.
You could make an extra Validator object just for the quantity input. It requires more code but i think it's more robust than merging in to one array
What's the standard way to get rid of the three <select> elements and allow users to just type dates in a regular <input type="text"> control?
Requirements include:
Date format must be D/M/Y
Existing dates must be printed correctly
Cannot break date validation
I cannot find any reasonable documentation on this, just hacks in forum threads written by users as clueless as me xD
Clarification: Please note the CakePHP tag. I already know how to handle dates in regular PHP. I need help about the precise CakePHP mechanism I can use to adjust the framework's default functionality (and I really mean adjust rather than override).
So far, I've added this to the model:
public $validate = array(
'fecha' => array(
array(
'rule' => 'notEmpty',
'required' => true,
),
array(
'rule' => array('date', 'dmy'),
),
)
);
... and I've composed the field like this inside the view:
echo $this->Form->input(
'Foo.fecha',
array(
'type' => 'text',
)
);
... but all I can do with this is reading and validating user input: it won't print previous date properly and it won't store new date properly.
Here's a summary of my findings. It seems that the appropriate mechanism is using Model Callback Methods to switch between two date formats:
Database format, e.g.: 2012-08-28
Display format, e.g.: 28/08/2012
Steps:
Add two utility methods to AppModel to convert between my custom format (aka "display format") and MySQL's default format (aka "DB format").
Add an afterFind() filter to my model that converts to display format when read from DB.
Render the form control as 'type' => 'text'.
Add a 'rule' => array('date', 'dmy') validation rule to the field inside the model.
Add a beforeSave() filter to my model that converts to DB format right before saving.
These steps can be encapsulated with a behaviour that implements the afterFind() and beforeSave() callbacks and possibly some others like beforeFind(). The behaviour can be applied directly to AppModel and will take care of traversing data arrays to convert dates between both formats (if the model has an attached table). The code is not trivial but can be done and it makes it all transparent.
Drawbacks:
Makes code MySQL-only (but, isn't it MySQL-only already?)
Makes it difficult to localize.
If you need to do date math, you find yourself with human-readable strings.
It would be more rock-solid to be able to use three formats:
Database format, e.g.: 2012-08-28
Display format, e.g.: 28/08/2012
PHP internal format, e.g. Unix timestamps or DateTime objects
Sadly, the CakePHP core is not designed for that and it all starts getting too complicate if you attemp to implement it this way.
The only possible way looks like letting the user typing whatever he wants do, then checking for its validity when he wants to submit the form or something. Or better, go for jQuery datepicker.
In case you'll write the input fields using the helper,
There's a type option for the input method of formhelper.
Try this , for instance:
<?php
echo $this->Form->input('birth_dt', array(
'type' => 'text',
'label' => 'Date of birth',
));
EDIT: (after reading your comment)
The solution if so , can be to validate the input value after the submit of the form
or using ajax vaildation.