How can I use Laravel file validation to a multiple file inside a loop?
Usually in a single file validation, I can just do like
$validator = Validator::make($request->all(),[
'image' => 'image|max_width:1000|max_height:1000'
]);
if($validator->fails()){
//validation fails
}
but now I want to validate multiple files in a single process, like
//store to a variable
$file = $request->file('image');
if($file){ //if request file image exist
foreach($request->file('image') as $i){
//here, validate each file image, but it just I don't know how
}
}
Now for the front end side, to elaborate about the process of sending multiple files in one post.
$(document).on("change",'input[type="file"]',function(){
if($(this).val()!==""){
var files = this.files;
handleFileUpload(files);
$(this).val("");
}
});
function handleFileUpload(files)
{
//create a formData
var fd = new FormData();
//loop through e
for (var i = 0; i < files.length; i++)
{
//append each file object to the formData
fd.append('image[]', files[i]);
}
//this function is where ajax request will be process
sendFileToServer(fd);
}
and so in the back end if I dump the request, I get these
array(2) { [0]=> object(Illuminate\Http\UploadedFile)#214 (7) {
["test":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
bool(false)
["originalName":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
string(50) "12400457_643171672489204_2452820305362127031_n.jpg"
["mimeType":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
string(10) "image/jpeg"
["size":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
int(18413)
["error":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
int(0) ["pathName":"SplFileInfo":private]=> string(25)
"C:\wamp64\tmp\phpBAE4.tmp" ["fileName":"SplFileInfo":private]=>
string(11) "phpBAE4.tmp" } [1]=>
object(Illuminate\Http\UploadedFile)#217 (7) {
["test":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
bool(false)
["originalName":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
string(39) "13296200_702501119889592_55691535_n.jpg"
["mimeType":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
string(10) "image/jpeg"
["size":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
int(95383)
["error":"Symfony\Component\HttpFoundation\File\UploadedFile":private]=>
int(0) ["pathName":"SplFileInfo":private]=> string(25)
"C:\wamp64\tmp\phpBAE5.tmp" ["fileName":"SplFileInfo":private]=>
string(11) "phpBAE5.tmp" } }
any ideas, clues, help please on how to use Laravel file validation on a multiple files inside a loop?
PS: I'm running on Laravel 5.2
Try sending the image file input field as an array and then using array validation. If you're using Laravel 5.2 you can use Array Validation and ditch the foreach loop for building the rules.
Firstly, you would need to set up your file input as an array...
If you're using one input field:
<input type="file" name="image[]" multiple>
Your request would then come through looking something like this:
array:2 [▼
"_token" => "oX3sTXPDnNiVj9mX20VOHe2xo1Ahx6sWzU4VHZxh"
"image" => array:2 [▼
0 => UploadedFile {#147 ▶}
1 => UploadedFile {#146 ▶}
]
]
Then using array validation your rules would be declared in the validator by utilising the asterix symbol to indicate an array field:
$validator = Validator::make($request->all(),[
'image.*' => 'image|max_width:1000|max_height:1000'
]);
Check the docs here for more info: https://laravel.com/docs/5.2/validation#validating-arrays
You can try the following:
foreach($this->input('image') as $key => $value){
$rules['image.'.$key] = 'image|max_width:1000|max_height:1000';
}
Related
I'm trying to cast an entity property into an array so that it autoserializes.
The Entity is set up as follows
\App\Entities\Submission.php
<?php
namespace App\Entities;
use CodeIgniter\Entity;
class Submission extends Entity
{
protected $casts =[
'field2' => 'array'
];
}
Then in a controller I create a new entity, filling it using the constructor
<?php
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
?>
Dumping the submission at this point (var_dump()) shows field2 being an array, it's not serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
array(2) {
[0]=>
int(0)
[1]=>
int(1)
}
}
if I do
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
$submission->field2 = $submission->field2;
and then var_dump, field2 is correctly serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
For some reason, it seems like filling using the constructor does not autoserialize, I have to manually set the field. Am I doing something wrong?
The problem this caused is that when I tried inserting that entity into the Database, it threw an error saying
"mysqli_sql_exception Operand should contain 1 column(s)"
which went away when I flattened the array (first by dropping all but one values to test and then by using what I've done above)
================
EDIT 11/05: This turned out to be an issue on the core code. fill() (and the constructor) were not configured to use __set() so autoserialization was not happening. See the PR on Codeigniter's Github page here.
I'll be accepting Kulshreshth K's answer because, for now, this provides an adequate workaround but in the future it will most likely not be needed.
Add this in your Entity:
public function __construct($arr) {
$this->field2 = $arr['field2'];
}
Controller:
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
var_dump($submission)
Result:
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
As per CI documentation you need to set it after initialize its model anyway:
<?php namespace App\Entities;
use CodeIgniter\Entity;
class User extends Entity
{
protected $casts => [
'options' => 'array',
'options_object' => 'json',
'options_array' => 'json-array'
];
}
$user = $userModel->find(15);
$options = $user->options;
$options['foo'] = 'bar';
$user->options = $options;
$userModel->save($user);
Let's say I have an array (it really could have any depth):
$arr = array(
"lvl1" => array(
"lvl2 => ...
)
)
Now in a function I need to access it like this:
$path = array("lvl1", "lvl2", ...); // array of ordered indexes
$tmp = $arr;
foreach($path as $lvl){
...// other read-only/copy stuff happening on the array, no editing
$tmp = $tmp[$lvl];
}
At this point, just out of curiosity (no real optimization here), am I making copies of copies everytime? Or is it just using references automatically?
TL;DR If you are using PHP 7 the array won't be copied internally unless you change it. This is called copy-on-write.
To understand how PHP works under the hood you can read Reference Counting Basics:
A PHP variable is stored in a container called a "zval".
PHP is smart enough not to copy the actual variable container when it is not necessary.
Let's try to illustrate this on your simplified example using debug_zval_dump:
$array = [
'lvl1' => [
'lvl2' => [
'lvl3' => [
],
],
],
];
$path = ['lvl1', 'lvl2', 'lvl3'];
$tmp = $array;
foreach ($path as $lvl) {
debug_zval_dump($array);
$tmp = $tmp[$lvl];
}
debug_zval_dump($array);
If you run this code you will get the following output:
array(1) refcount(4){
["lvl1"]=>
array(1) refcount(1){
["lvl2"]=>
array(1) refcount(1){
["lvl3"]=>
array(0) refcount(1){
}
}
}
}
array(1) refcount(3){
["lvl1"]=>
array(1) refcount(2){
["lvl2"]=>
array(1) refcount(1){
["lvl3"]=>
array(0) refcount(1){
}
}
}
}
array(1) refcount(3){
["lvl1"]=>
array(1) refcount(1){
["lvl2"]=>
array(1) refcount(2){
["lvl3"]=>
array(0) refcount(1){
}
}
}
}
array(1) refcount(3){
["lvl1"]=>
array(1) refcount(1){
["lvl2"]=>
array(1) refcount(1){
["lvl3"]=>
array(0) refcount(2){
}
}
}
}
Pay attention to refcount: it changes, so internally PHP assigns by reference until you actually change the assigned value. You can read about this in the blog post by nikic:
The important difference to PHP 5 is that all variables were able to share the same array, even though some were PHP references and some weren’t. Only once some kind of modification is performed the array will be separated.
I am developing a web application in laravel 5.3. The problem i am getting is that attributes doesn't add up in stdClass object, however you can see my code where i am explicitly setting/adding a new attributes in a object.
problematic code
1- $sender = Sender::where('id', $this->senderId)->first();
2- if ($sender != null) {
3- var_dump($sender->bundle);
4- $sender->bundle->latitude = $this->lat;
5- $sender->bundle->longitude = $this->long;
6- $sender->bundle->location = $response->formattedAddress();
7- var_dump($sender->bundle);
8- $sender->save();
9- error_log('resolved');
10- } else {
11- error_log('no sender');
12- }
In above code you can clearly see that i am setting some new properties for bundle object.
$sender->bundle->latitude = $this->lat;
$sender->bundle->longitude = $this->long;
$sender->bundle->location = $response->formattedAddress();
but in output you can clearly see that it doesn't get add up. The code basically runs in laravel queue. In above code $sender is laravel eloquent model and the attribute bundle is being json_decode via laravel mutators.
mutator code
public function setBundleAttribute($value) {
$this->attributes['bundle'] = json_encode($value);
}
public function getBundleAttribute($value) {
return json_decode($value);
}
output of above problematic code
object(stdClass)#686 (3) { #output of line 3
["city"]=>
string(0) ""
["province"]=>
string(0) ""
["country"]=>
string(0) ""
}
object(stdClass)#686 (3) { #output of line 7
["city"]=>
string(0) ""
["province"]=>
string(0) ""
["country"]=>
string(0) ""
}
[2017-07-25 16:11:03] Processed: App\Jobs\LocationResolverQueue
resolved
Problem Solved
laravel Accessors & Mutators cause the problem.
Accessor and Mutator get called whenever we get or set property respectively, in my case the mutator was calling whenever i try to access $sender->bundle->property however accessor didn't get called because i was setting a $sender->bundle->property rather than $sender->bundle
i solved problem like
$sender = Sender::where('id', $this->senderId)->first();
if ($sender != null) {
$temp = $sender->bundle;
$temp->latitude = $this->lat;
$temp->longitude = $this->long;
$temp->location = $response->formattedAddress();
$sender->bundle = $temp;
$sender->save();
}
In Laravel im using this code in my controller to get files from directory:
public function galleryImages($album) {
$images = File::allFiles('gallery/'.$album);
return View::make('galleryimages', ['images' => $images]);
}
and in my 'galleryimages' view is:
#foreach($images as $image)
<img src="???"> <-- how to get file url here?
#endforeach
Now how can I get pathName of $image variable? Var_dump of $image is returning:
object(Symfony\Component\Finder\SplFileInfo)#247 (4) {
["relativePath":"Symfony\Component\Finder\SplFileInfo":private]=> string(0) ""
["relativePathname":"Symfony\Component\Finder\SplFileInfo":private]=> string(11) "garden5.jpg"
["pathName":"SplFileInfo":private]=> string(25) "gallery/Album/garden5.jpg"
["fileName":"SplFileInfo":private]=> string(11) "garden5.jpg" }
I was trying $image->pathName, but it doesn't work.
You have to use the getter method
$image->getPathname()
The Symfony class extends from SplFileInfo. You can find the reference to all its methods on php.net
I am working with a series of forms that have subforms embedded into them and I am trying to work out if I can make getValues return the values without the array notation on the subform.
ie:
$form = new Zend_Form();
$subForm = new Zend_Form_SubForm();
$form->addSubForm( $subForm, 'contact' );
$form->addElement(new Zend_Form_Element_Text('name'));
$subForm->addElement( new Zend_Form_Element_Text('phone') );
var_dump($form->getValues());
Gives me the output:
array(2) {
["name"]=>
NULL
["contact"]=>
array(1) {
["phone"]=>
NULL
}
}
But I would actually like the output to be:
array(2) {
["name"]=>
NULL
["phone"]=>
NULL
}
Any easy way of doing this without overriding Zend_Form functions?
You can do it quite simply by using:
$subform->setIsArray(false);
Something like this may be a start:
$data = array();
foreach ($form->getSubForms() as $subform) {
$data += $subform->getValues();
}