How to validate a JSON Request object in laravel validation? - laravel

How will I validate the current entries from here , this is the json response inside the Chrome Devtools after submitting the form thru axios ?
And this is in my UpdateProfileRequest.php
public function rules()
{
return [
'username' => 'required|unique:users|min:3',
'password' => 'required|min:8|confirmed',
'confirm_password' => 'required|',
'current_password' => 'required|u',
'country_id' => 'required|integer',
'display_name' => 'required|min:5',
'email' => 'required|unique:users,email_address',
'phone_number' => 'required|alpha_num',
'image' => 'mimes:jpg,png,gif'
];
This is the whole response from the request
This is inside my UpdateProfile.vue
<div>
<div v-if="user != null">
<form class="bg-white m-auto h-full p-4 w-full" id="setup-billing-form" #submit.prevent="submitProfile()" method="POST">
<div class="flex inline-block">
<div id="input-group" class="w-3/5">
<label for="name" class="block uppercase tracking-wide text-black-v2 text-xs font-bold mb-2">Username
</label>
<input v-model="form.username" type="text" class="hover:bg-grey-lightest bg-grey-lighter w-full mb-2 p-2 leading-normal" id="pin" name="pin" autocomplete="name" placeholder="Your Username" required>
</div>
<div id="input-group" class="ml-2 w-3/5">
<label for="name" class="block uppercase tracking-wide text-black-v2 text-xs font-bold mb-2">Email
</label>
this is is inside my axios request
submitProfile(){
let data = new FormData();
axios.put(this.endpoint, {
form : this.form ,
image : this.image
}).then(response => {
console.log(response.data);
}).catch(error => {
console.log(error);
});
},
Now, I want to ask if how do I validate those requests inside my UpdateProfileRequest, should I add the form. to each of those requests ?

Two Methods:
1. just use form.username to validate
$rule = [
'form.username' => 'required|unique:users|min:3',
'form.password' => 'required|min:8|confirmed',
'form.confirm_password' => 'required|',
'form.current_password' => 'required|u',
'form.country_id' => 'required|integer',
'form.display_name' => 'required|min:5',
'form.email' => 'required|unique:users,email_address',
'form.phone_number' => 'required|alpha_num',
'image' => 'mimes:jpg,png,gif'
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
}
2. Flatten the object to request:
It seems that you new a formdata without using it.
And pass the data with keys form and image.
You need to flatten your object before put it:
submitProfile(){
// if you use formdata
// let form = new FormData(this.form);
// let form = form.append('image', this.image);
let form = Object.assign({}, this.form); // clone this.form
form['image'] = this.image;
axios.put(this.endpoint, form).then(response => {
console.log(response.data);
}).catch(error => {
console.log(error);
});
},
This request that you can directly validate by
'username', 'password', ... without prefix form.
and if you want to insert the datas, you can just use $request->except('image').

Related

Sending images through Laravel Guzzle Client

I am trying to upload multiple images using guzzlehttp client. I load images as a file and loads only one image with the code below.
$clientPAimages = new Client();
$imagesPA = Req::file('images');
foreach($imagesPA as $image){
$bodyImages[] = [
'name' => 'image',
'contents' => fopen($image->getRealPath(), 'r'),
'filename' => $image->getClientOriginalName(),
'headers' => [
'Content-Type' => '<Content-type header>'
]
];
}
$responsePA3 = $clientPAimages->request('POST', 'link/images', [
'multipart' => $bodyImages
]);
$responsePA3->getBody();
Does anyone have any idea how to solve this i.e. how to save multiple images?
I was in this kind of situation, when i needed to send multiple images from the laravel app to the node.js app. Your code seems ok, but may you've something wrong in your blade, for example usage of enctype="multipart/form-data" in the form, or name="images[]" as an input property, or something like that.
Anyway i'll share here the snippet, which worked well for me before, so i guess it can be useful.
Specifications for this snippet was:
"laravel/framework": "^8.12",
"guzzlehttp/guzzle": "^7.0.1",
create.blade.php
<form action="http://internal.site/upload" method="post" enctype="multipart/form-data">
#csrf
<input id="ss_images"
name="images[]"
type="file"
multiple="multiple"
class="input"
accept=".jpeg,.bmp,.png,.jpg,.gif"
/>
<div class="mt-3">
<label class="{{ $errors->has('name') ? 'has-error' : '' }}">
{{ $errors->has('name') ? $errors->first('name') : "Name" }}
</label>
<input value="{{ old('name') }}" type="text" class="input" placeholder="Name" name="name">
</div>
<div class="mt-3">
<label class="{{ $errors->has('description') ? 'has-error' : '' }}">
{{ $errors->has('description') ? $errors->first('description') : "Description" }}
</label>
<textarea class="input" placeholder="Description" name="description">{{ old('description') }}</textarea>
</div>
</form>
ItemController.php
use GuzzleHttp\Client;
// ...
public function upload(Request $request)
{
$data = $request->only([
'name',
'description',
]);
$multipart = [];
if($request->hasFile('images')) {
foreach ($request->file('images') as $k => $image) {
$multipart[] = [
'name' => 'file',
'contents' => fopen($image->getRealPath(), 'r'),
// ... some additional fields
];
}
}
// adding some text-oriented data if need
$multipart[] = [
'name' => 'data',
'contents' => json_encode($data, true),
];
$client = new Client();
$url = "http://external.site/link/images";
$response = $client->request('POST', $url, [
'multipart' => $multipart
]);
$res_json = $response->getBody()->getContents();
$res = json_decode($res_json, true);
return redirect()->back()->with([
'success' => $res['success'],
'flash_message' => $res['message'],
]);
}
Enjoy!!

Reactivity not working Laravel, Inertia.js, Vue3

I am using inertiajs and vue3 on my laravel project.
Problem:
When I try to login with an invalid credential toast message appears and disappears with animation as intended.
But after correct login toast message appear without animation, and doesn't disappear after a certain interval. Also same happens on logout
Toast Component
<template>
<transition
enter-active-class="transition-all ease-out duration-200"
enter-from-class="transform opacity-0 top-32 scale-95"
enter-to-class="transform opacity-100 top-22 scale-100"
leave-active-class="transition-all top-22 ease-in duration-200"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform top-12 opacity-0 scale-95">
<div v-if="toast && show == true" class="absolute flex flex-col max-w-lg top-20 right-2 shadow-lg rounded pl-4 pr-2 pt-0 pb-2
bg-white/95 dark:bg-gray-800/95"
:class="{
'bg-green-600 dark:bg-green-600 shadow-green-600/40': toast.type == 'success',
'bg-red-600 dark:bg-red-600 shadow-red-600/40': toast.type == 'error'
}">
<div class="flex mb-2">
<div class="font-semibold"
:class="{
'text-white dark:text-white': toast.type == 'success',
'text-red-200 dark:text-red-200 hover:text-red-50 dark:hover:text-red-50': toast.type == 'error'
}">
{{toast.header}}
</div>
<button #click.prevent="show = false" class="focus:outline-none ml-auto"
:class="{
'text-green-200 dark:text-green-200 hover:text-green-50 dark:hover:text-green-50': toast.type == 'success',
'text-red-200 dark:text-red-200 hover:text-red-50 dark:hover:text-red-50': toast.type == 'error'
}" >
<XCircleIcon class="w-6 h-6" />
</button>
</div>
<div class="flex mr-6 items-center">
<div class="mr-2">
<CheckCircleIcon v-if="toast.type == 'success'" class="w-6 h-6"
:class="{
'text-green-50 dark:text-green-50': toast.type == 'success',
}" />
<XCircleNoFillIcon v-if="toast.type == 'error'" class="w-6 h-6"
:class="{
'text-red-50 dark:text-red-50': toast.type == 'error'
}" />
</div>
<div class="flex-1"
:class="{
'text-green-50 dark:text-green-50': toast.type == 'success',
'text-red-50 dark:text-red-50': toast.type == 'error'
}">
{{toast.message}}
</div>
</div>
</div>
</transition>
</template>
<script>
import { defineComponent, computed, reactive, watch, ref } from 'vue'
import { usePage } from '#inertiajs/inertia-vue3'
import CheckCircleIcon from '#/Icons/CheckCircle.vue'
import XCircleIcon from '#/Icons/XCircle.vue'
import XCircleNoFillIcon from '#/Icons/XCircleNoFill.vue'
export default defineComponent({
components: {
CheckCircleIcon, XCircleIcon, XCircleNoFillIcon,
},
setup() {
const toast = ref(computed(() => usePage().props.value.toast))
const show = ref(true)
watch(toast, () => {
setTimeout(() => {
show.value = true
}, 10);
hideToast()
})
function hideToast() {
setTimeout(() => {
console.log( toast.value.duration)
show.value = false
}, toast.value.duration);
}
return { toast, show }
},
})
</script>
AuthController
// Sign in
public function store(Request $request)
{
$credentials = Validator::make($request->all(), [
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', Rules\Password::defaults()],
]);
if($credentials->fails()) {
return back()
->withInput()
->withErrors($credentials)
->with([
'toast' => [
'duration' => '6000',
'type' => 'error',
'header' => 'Validation Error.',
'message' => 'Please resolve the issues.',
]
]);
}
if (!Auth::attempt($credentials->validated(), $request->remember ? true : false)) {
return back()
->withInput()
->withErrors(['email' => 'Invalid credentials'])
->with([
'toast' => [
'duration' => '1000',
'type' => 'error',
'header' => 'Failed!',
'message' => 'Invalid credentials.',
]
]);
}
$request->session()->regenerate();
return redirect()
->intended(RouteServiceProvider::HOME)
->with([
'toast' => [
'duration' => '5000',
'type' => 'success',
'header' => 'Signed in.',
'message' => 'Welcome back, ' . Auth::user()->name,
]
]);
}

Save arrangement to Livewire

I need to save an array generated when I select several input type checkboxes, and I don't know how to do it Laravel Livewire. So, in this section, I select the checkboxes and send them by wire "documentos."
<input wire:model.defer="documentos" name="documentos" type="checkbox" value="Acta"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
<label for="acta" class="form-check-label">Acta</label>
<br></br>
<input wire:model.defer="documentos" name="documentos" type="checkbox" value="Documento Ideas"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
<label for="ideas" class="form-check-label">Documento Ideas</label>
<input wire:model.defer="documentos" name="documentos" type="checkbox" value="Plan Inversion"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
<label for="plan" class="form-check-label">Plan Inversion</label>
</div>
I have the save function in this section, but it only saves one value.
public function guardar()
{
$data = [
['id' => $this->use_id],
[
'tarea_paso' => $this->tarea_paso,
'descripcion_paso' => $this->descripcion_paso,
'fecha_inicio' => $this->fecha_inicio,
'fecha_fin' => $this->fecha_fin,
'id_responsable' => $this->id_responsable,
'documentos' => $this->documentos,
'acta' => $this->acta,
'ideas' => $this->ideas,
'plan' => $this->plan,
'acciones' => $this->acciones,
'poais_id' => $this->metodologia_id,
]
];
}
try this
$data = [
'tarea_paso' => $this->tarea_paso,
'descripcion_paso' => $this->descripcion_paso,
'fecha_inicio' => $this->fecha_inicio,
'fecha_fin' => $this->fecha_fin,
'id_responsable' => $this->id_responsable,
'documentos' => $this->documentos,
'acta' => $this->acta,
'ideas' => $this->ideas,
'plan' => $this->plan,
'acciones' => $this->acciones,
'poais_id' => $this->metodologia_id,
];
Model::where('id', $this->use_id)->update($data);

send an email with attachment using a form

I can't understand what the problem may be:
I state that the code without the part of the attachment works
function submit(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'file' => 'mimes:pdf,doc,docx'
]);
$data = array(
'name_data' => $request->name,
'cognome_data' => $request->cognome,
'luogo_data' => $request->luogo,
'date_data' => $request->date,
'telefono_data' => $request->telefono,
'email_data' => $request->email,
'citta_data' => $request->citta,
'provincia_data' => $request->provincia,
'studio_data' => $request->studio,
'lingua_data' => $request->lingua,
'livello_data' => $request->livello,
'lingua2_data' => $request->lingua2,
'livello2_data' => $request->livello2,
'file_data' => $request->file,
'agree_data' => $request->agree
);
Mail::send('mail', $data, function($message) use ($request,$data){
$message->to('pipo#gmail.com', 'piooi')->subject('Send mail ' . $request->name);
$message->from($request->email, $request->name);
if ( isset($data['file_data']))
{
$message->attach($data['file_data']->getRealPath(), array(
'as' => $data['file_data']->getClientOriginalName(),
'mime' => $data['file_data']->getMimeType()));
}
});
Session::flash('success', 'Mail spedita con sucesso');
}
}
I put the piece of the form in question:
<form class="text-left form-email"action="#" enctype="multipart/form-data" method="POST">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupFileAddon01">Curriculum Vitae:</span>
</div>
<div class="custom-file">
<input type="file" class="custom-file-input" id="file" name="file"
aria-describedby="inputGroupFileAddon01">
<label class="custom-file-label" for="inputGroupFile01">Seleziona il file</label>
</div>
</div>
the error that gives the summit is the following:
local.ERROR: Call to a member function getRealPath() on null {"exception":"[object] (Error(code: 0):
Change your mail part to this and see if it works
Mail::send('mail', $data, function($message) use ($request,$data){
$message->to('pipo#gmail.com', 'piooi')->subject('Send mail ' . $request->name);
$message->from($request->email, $request->name);
if($request->hasFile('file')){
$message->attach($request->file->getRealPath(), array(
'as' => $request->file->getClientOriginalName(),
'mime' => $request->file->getMimeType())
);
}
});

Laravel checkbox validation, always empty?

I have a checkboxes like this:
<div class="form-group">
<div style="display:none ;" class="weekday_message form-control alert-warning"></div>
<label id="weekday2" for="weekday" class="col-md-4 control-label">Weekday</label>
<div class="required form-field" name="weekday" id="weekday">
<input class="weekday" type="checkbox" name="weekdays[]" value="MO">Monday
<input class="weekday" type="checkbox" name="weekdays[]" value="TU">Tuesday
<input class="weekday" type="checkbox" name="weekdays[]" value="WE">Wednesday
<input class="weekday" type="checkbox" name="weekdays[]" value="TH">Thursday
<input class="weekday" type="checkbox" name="weekdays[]" value="FR">Friday
<input class="weekday" type="checkbox" name="weekdays[]" value="SA">Saturday
<input class="weekday" type="checkbox" name="weekdays[]" value="SU">Sunday
</div>
<span class="help-block">
<strong></strong>
</span>
</div>
My validation:
public function rules()
{
return [
'startdate' => 'required|date',
'endate' => 'nullable|date',
'startime' => ['required', new Time],
'endtime' => ['required', new Time],
'title' => 'required',
'entity_id' => 'required',
'type' => 'required|exists:entities,type',
'description' => 'required',
'frequency' => 'required',
'interval' => 'nullable|numeric',
'monthday' => 'nullable|numeric|min:1|max:3',
'weekdays' => 'array|max:3',
'month' => 'nullable|numeric',
'until' => 'nullable|date',
'tags' => 'nullable',
];
}
and controller:
public function storeEvent(EventRequest $request)
{
$test = ($request->input('weekdays'));
dd($test);
$weekday_string = implode(",", $request->input('weekdays'));
$request->merge(array('weekday', $weekday_string));
dd($request->all());
$event = DirtyEvent::create($request->all());
$geoloc_id = Entity::find($event->entity_id)
->first();
$user_id = Auth::id();
// Save Geoloc + user id into newly created event
$event->_geoloc()->associate($geoloc_id);
$event->users()->associate($user_id);
$event->save();
Now, validation seems to pass because it does data dump, however both dd($test) as well as $request->all() are giving me back empty weekdays, like it would not be defined. What could be the possible cause of this?
If you want to make sure you have always at least one weekday selected you should change:
'weekdays' => 'array|max:3',
into:
'weekdays' => 'array|required|max:3',
Also I suppose you don't send data using standard HTML form because you set for example name for divs so maybe you forget to attach weekdays or have bug in code elsewhere?
Your HTML says weekday (singular) but your rules set says weekdays (plural).
There needs to be at least one checkbox selected to make the input weekdays to be included in the request. You can use a default value in case none was selected by adding a hidden input before the checkboxes.
<input type="hidden" name="weekdays" value="defaultValue">

Resources