Why upload image fails using Laravel 9 CRUD? - laravel

I am creating a database for books. When I was testing CRUD without image upload(normal CRUD), it was working. But when I added book cover image file as part of data input I get error "
Argument #1 ($rules) must be of type array, Illuminate\Http\Request given, called in
". I didn't understand what caused it, is it because validation or path image folder will be stored in?
Here it is image of error.
Model/Buku.php
class Buku extends Model
{
use HasFactory;
protected $fillable = [
'cover',
'nama_buku',
'author',
'terbitan',
'barcode',
'ketersediaan',
];
}
I suspect the error is in controllers code but didn't know why normal CRUD succeed but image upload CRUD fails.
Controllers/BukuController.php
protected function store(Request $request)
{
$request->validate($request, [
'cover' => 'required|file|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
'nama_buku' => 'required',
'author' => 'required',
'terbitan' => 'required',
'barcode' => 'required',
'ketersediaan' => 'required',
]);
$input = $request->all();
if ($cover = $request->file('cover')) {
$destinationPath = 'cover/';
$profileImage = date('YmdHis') . "." . $cover->getClientOriginalExtension();
$cover->move($destinationPath, $profileImage);
$input['cover'] = "$profileImage";
}
Buku::create($input);
return redirect()->route('buku.index')->with('success','Buku has been created successfully.');
}
I don't know if the errors is actually from input so just in case here is views create blade
Views/create.blade.php
<form action="{{ route('buku.store') }}" method="POST" enctype="multipart/form-data">
#csrf
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Cover:</strong>
<input type="file" name="cover" placeholder="Cover Buku"
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100" />
#error('cover')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Nama Buku:</strong>
<input type="text" name="nama_buku" class="form-control" placeholder="Nama Buku">
#error('nama_buku')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Author:</strong>
<input type="text" name="author" class="form-control" placeholder="Author Buku">
#error('author')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Terbitan:</strong>
<input type="text" name="terbitan" class="form-control" placeholder="Terbitan Buku">
#error('terbitan')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Barcode:</strong>
<input type="text" name="barcode" placeholder="Barcode Buku" id="scanner" />
#error('barcode')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<div class="form-group">
<strong>Ketersediaan:</strong>
<input type="number" name="ketersediaan" class="form-control" placeholder="Ketersediaan Buku">
#error('ketersediaan')
<div class="alert alert-danger mt-1 mb-1">{{ $message }}</div>
#enderror
</div>
</div>
<button type="submit" class="btn btn-primary ml-3">Submit</button>
</div>
</form>
I also tried image upload code when I was still using Laravel 4, still get the same error. Did anyone know how to fix this?

The error states it pretty clearly. You pass a Request object where an array is expected.
Instead of using the object directly, you should use the all() method, which creates an array with all the posted fields in your request. Or in this case, you can leave the request->all() out, because the method is already called on the request object.
$request->validate($request,...)
$request->validate($request->all(),...)
$request->validate(['cover' => ....])
#########EDIT
It is also not recommended to insert all request data. You should only insert validated data.
$input = $request->all();
Buku::create($input);
You should use one of the two following approaches to only insert validated data: https://laravel.com/docs/10.x/validation#working-with-validated-input

Related

how to scroll to first validation error message in livewire laravel

I am new in livewire. i am working on registration process of user. Register form is quite big and validations also working fine to me. The problem is when user submits the form validations came but user not able to see because submit button is at bottom and form is at top.
When i manually scroll to top error message is displaying. So what i want when user submits the form its will automatically go to first error message. Here is my code:
<form wire:submit.prevent="userRegister">
<div class="row">
<div class="col-md-3">
<label>First Name *</label>
</div>
<div class="col-md-9">
<input type="text" wire:model="register.first_name" placeholder="Enter First Name" required>
#error('register.first_name') <span class="text-danger">{{ $message }}</span> #enderror
</div>
</div>
<div class="row">
<div class="col-md-3">
<label>Last Name *</label>
</div>
<div class="col-md-9">
<input type="text" wire:model="register.last_name" placeholder="Enter Last Name">
#error('register.last_name') <span class="text-danger">{{ $message }}</span> #enderror
</div>
</div>
<div class="row">
<div class="col-md-3">
<label>Test 1 Name *</label>
</div>
<div class="col-md-9">
<input type="text" wire:model="register.test1_name" placeholder="Enter Last Name">
</div>
</div>
<div class="row">
<div class="col-md-3">
<label>Test 2 Name *</label>
</div>
<div class="col-md-9">
<input type="text" wire:model="register.test2_name" placeholder="Enter Last Name">
</div>
</div>
<div class="row">
<div class="col-md-3">
<label>Test 3 Name *</label>
</div>
<div class="col-md-9">
<input type="text" wire:model="register.test3_name" placeholder="Enter Last Name">
</div>
</div>
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-9">
<!--<input type="submit" value="Edit" class="edt-sb">-->
<input wire:click="userRegister" type="submit" value="Submit" class="edt-sv">
</div>
</div>
</form>
My Register.php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Register extends Component
{
public $register;
protected $rules = [
'register.first_name' => 'bail|required|max:50',
'register.last_name' => 'bail|required|max:50',
];
protected $messages = [
'register.first_name.required' => 'Please enter first name',
];
public function userRegister(){
$this->validate();
}
I want when user submits the form it will immediately scroll to first error message. Currently my validations work perfects for me. Do i need to use alpine js? for this.
Livewire errors will be saved in $errors bag so probably you can add an id to each field in your form and use alpinejs to focus the first element with the id present in the errors bag, something like:
<div x-data="{
'errors': {{ json_encode(array_keys($errors->getMessages())) }},
focusField(input) {
fieldError = document.getElementById(input);
if (fieldError) {
fieldError.focus({preventScroll:false});
}
},
}"
x-init="() => { $watch('errors', value => focusField(value[0])) }">
<input id="register.test3_name" type="text" wire:model="register.test3_name" placeholder="Enter Last Name">
</div>
I nearly faced the same issue but with success message not error messages, for error messages I used updated(), they are shown on real time for user while filling the fields.
My Class Component :
class FormSubmissions extends Component
{
public $city;
public $fullname;
protected $rules = [
'city' => 'required',
'fullname' => 'required',
];
public $successMessage;
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function submitForm()
{
$submission = $this->validate();
$this->successMessage = trans('site.success');
$this->resetForm();
}
public function resetForm()
{
$this->city = '';
$this->fullname = '';
}
}
My Blade template :
<div id="formSection" class="form-wrapper">
#if ($successMessage)
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ $successMessage }}
<button wire:click="$set('successMessage', null)" type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<script>
var elmnt = document.getElementById("formSection");
elmnt.scrollIntoView();
</script>
#endif
<form wire:submit.prevent="submitForm" action="/" method="POST">
...
</div>
So the small script added with success message allowed me to scroll back to top of my form Section #formSection.
If you are using <x-jet-input-error/> component for displaying errors, you can just modify resources/views/vendor/jetstream/components/input-error.blade.php (make sure you have published livewire views) file to below code:
#props(['for'])
<span x-data="{hasError: '{{$errors->get($for)[0] ?? ''}}' }"
x-init="()=> { $watch('hasError', (value)=> {
let errorDiv = document.getElementsByClassName('invalid-feedback')[0];
if(errorDiv){
errorDiv.scrollIntoView({behavior: 'smooth', block: 'center', inline: 'nearest'});
}
})}">
#error($for)
<span {{ $attributes->merge(['class' => 'invalid-feedback d-block']) }} role="alert" style="font-size: inherit">
<strong>{{ $message }}</strong>
</span>
#enderror
</span>
Explanation : we use alpine to watch for changes in the validation message for the "$for" field. As soon as it changes (validation message shows up or vanishes), it looks for the error block and scrolls to it

Error: 405 - Method not allowed while trying to update in Laravel

Current, I am working on a project using Laravel-5.8. I have a code to update data:
Controller
public function store_external_respondent(StoreAppraisalRespondentExternalRequest $request)
{
$userCompany = Auth::user()->company_id;
$userEmployee = Auth::user()->employee_id;
DB::beginTransaction();
try {
$respondent = AppraisalRespondent::create([
'fullname' => $request->fullname,
'respondent_email' => $request->respondent_email,
'company_name' => $request->company_name,
'is_internal' => 1,
]);
DB::commit();
Session::flash('success', 'Appraisal Respondent created successfully');
return redirect()->route('appraisal.appraisal_respondents.index');
} catch (Exception $ex) {
DB::rollback();
Session::flash('error', 'Action failed! Please try again');
return back();
}
}
route/web.php:
Route::group(['prefix' => 'appraisal', 'as' => 'appraisal.', 'namespace' => 'Appraisal', 'middleware' => ['auth']], function () {
Route::post('appraisal/appraisal_respondents/update_external_respondent/{id?}', 'AppraisalRespondentsController#update_external_respondent')->name('appraisal_respondents.update_external_respondent');
});
When I did php artisan route:list, I got:
| | POST | appraisal/appraisal/appraisal_respondents/update_external_respondent/{id?} | appraisal.appraisal_respondents.update_external_respondent | App\Http\Controllers\Appraisal\AppraisalRespondentsController#update_external_respondent | web,auth
update view blade
<button type="button" class="btn btn-sm btn-info mr-1 edit-respondent-respondent" data-toggle="modal" data-target="#edit_respondent_external{{ $respondentexternal->id }}">Edit</button>
<div class="modal fade" id="edit_respondent_external{{ $respondentexternal->id }}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form action="{{route('appraisal.appraisal_respondents.update_external_respondent',['id'=>$respondentexternal->id])}}" method="post" id="edit_respondent-external-form">
{{ csrf_field() }}
<input type="hidden" name="appraisal_identity_id" value="{{$identities->id}}">
<input type="hidden" name="employee_id" value="{{$employees->id}}">
<input name="_method" type="hidden" value="PUT">
<div class="modal-header">
Update Respondent (External)
</div>
<div class="col-md-12">
<div class="form-group">
<label class="control-label"> FullName:<span style="color:red;">*</span></label>
<input type="text" name="fullname" placeholder="Enter external respondent fullname here" class="form-control" value="{{old('fullname',$respondentexternal->fullname)}}">
#error('fullname')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="control-label"> Company:<span style="color:red;">*</span></label>
<input type="text" name="company_name" placeholder="Enter external respondent company here" class="form-control" value="{{old('company_name',$respondentexternal->company_name)}}">
#error('company_name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="control-label"> Respondent Email:<span style="color:red;">*</span></label>
<input type="text" name="respondent_email" placeholder="Enter external respondent email here" class="form-control" value="{{old('respondent_email',$respondentexternal->respondent_email)}}">
#error('respondent_email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" id="edit_respondent_external_btn-submit" class="btn btn-success btn-ok">Save</button>
</div>
</form>
</div>
</div>
</div>
When I submitted, I got this error:
405
Method Not Allowed.
Sorry, the page you are looking for could not be found. Go Back
In the console I have:
POST http://localhost:8888/myapp/appraisal/appraisal/appraisal_respondents/update_external_respondent/2 405 (Method Not Allowed)
How do I resolve this?
Also Why is appraisal repeated twice in
POST http://localhost:8888/myapp/appraisal/appraisal/appraisal_respondents/update_external_respondent/2 405 (Method Not Allowed)
Thanks
// STEP 1
Route::post('appra....
// STEP 2
<input name="_method" type="hidden" value="PUT">
So what's wrong?
please use {{method_field('check_your_route_type')}} below {{ csrf_field() }}
e.g : Route::put('url' ... should use {{method_field('PUT')}}

Laravel - Session flash did not display the content of the error message

I am using session flash in my Laravel-5.8 project.
Controller
<?php
namespace App\Http\Controllers\Appraisal;
use App\Http\Controllers\Controller;
use App\Models\Appraisal\AppraisalSkill;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Exception;
use Illuminate\Support\Facades\Validator;
use Session;
class AppraisalSkillsController extends Controller
{
public function create()
{
abort_unless(\Gate::allows('skill_create'), 403);
return view('appraisal.skills.create');
}
public function store(Request $request)
{
abort_unless(\Gate::allows('skill_create'), 403);
$this->validate($request, [
'skill_name' => 'required|unique:appraisal_skills,company_id',
]);
$skill = AppraisalSkill::create([
'skill_name' => $request->skill_name,
'description' => $request->description,
'company_id' => Auth::user()->company_id,
'created_by' => Auth::user()->id,
'created_at' => date("Y-m-d H:i:s"),
'is_active' => 1,
]);
Session::flash('success', 'Appraisal Skill is created successfully');
return redirect()->route('appraisal.skills.index');
}
}
view/partials/_messages.blade.php
#if (count($errors) > 0)
<div class="alert alert-danger alert-block" role="alert">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Errors: </strong>
<ul>
#foreach ($errors as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
#if (Session::has('success'))
<div class="alert alert-success" role="alert">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Success: </strong>{{Session::get('success')}}
</div>
#endif
view
<div class="container-fluid">
<div class="panel-heading clearfix">
<div class="float-right">
<div class="btn-group btn-group-sm" role="group">
<a href="{{ route("appraisal.skills.index") }}" class="btn bg-navy margin" title=" Back">
<span> Back to List</span>
</a>
</div>
</div>
</div>
<br>
#include('partials._messages')
<br>
<div class="card">
<div class="card-header">
Create Skill
</div>
<div class="card-body">
<form action="{{route('appraisal.skills.store')}}" method="post" class="form-horizontal" enctype="multipart/form-data">
{{csrf_field()}}
<div class="form-body">
<div class="row">
<div class="col-md-6">
<div class="form-group row">
<label class="control-label text-right col-md-3">Skill Name<span style="color:red;">*</span></label>
<div class="col-md-9 controls">
<input type="text" name="skill_name" placeholder="Enter skill name here" class="form-control" value="{{old('skill_name')}}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group row">
<label class="control-label text-right col-md-3">Description</label>
<div class="col-md-9">
<textarea rows="2" name="description" class="form-control" placeholder="Enter Description here" value="{{old('description')}}"></textarea>
</div>
</div>
</div>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">{{ trans('global.save') }}</button>
<button type="button" onclick="window.location.href='{{route('appraisal.skills.index')}}'" class="btn btn-default">Cancel</button>
</div>
</form>
</div>
</div>
</div>
When I click on save submit button, I expect that if there is any error it should display the detail of the error. But, rather it only display Error: without the details.
The success message is working, but the error message is not working as expected
How do I get this resolved?
Thank you.
There is a little mistake when looping through the errors. Change line #foreach ($errors as $error) to #foreach ($errors->all() as $error) . It should work now!

Add [title] to fillable property to allow mass assignment on [App\Profile]

I am trying to create edit profile, but when I click on edit profile button I'm getting below error:
Illuminate \ Database \ Eloquent \ MassAssignmentException Add [title]
to fillable property to allow mass assignment on [App\Profile]
show.blade.php :
<#extends('layouts.app')
#section('content')
<div class="container">
<div class="row">
<div class="col-4">
<img src="https://scontent-cdt1-1.cdninstagram.com/vp/dcca3b442819fc8b9b63f09b2ebde320/5DA9E3CB/t51.2885-19/s150x150/40101184_290824334847414_1758201800999043072_n.jpg?_nc_ht=scontent-cdt1-1.cdninstagram.com" class="rounded-circle">
</div>
<div class="col-8">
<div class="d-flex align-items-baseline">
<div class="h4 mr-3 pt-2">{{ $user->username }}</div>
<button class="btn btn-primary">S'abonner</button>
</div>
<div class="d-flex">
<div class="mr-3">{{ $user->posts->count() }} article(s) en vente
</div>
Modifier Profile
<div class="mt-3">
<div class="font-weight-bold">
{{ $user->profile->title }}
</div>
<div class="font-weight-bold">
{{ $user->profile->description }}
</div>
</div>
</div>
</div>
<div class="row mt-5">
#foreach ($user->posts as $post)
<div class="col-4">
<img src="{{ asset('storage') . '/' . $post->image }}" class="w-100">
</div>
#endforeach
</div>
</div>
#endsection
ProfileController :
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function show(User $user)
{
return view('profile.show', compact('user'));
}
public function edit(User $user)
{
return view('profile.edit', compact('user'));
}
public function update(User $user)
{
$data = request()->validate([
'title' => 'required',
'description' => 'required'
]);
$user->profile->update($data);
return redirect()->route('profile.show', ['user' => $user]);
}
}
edit.blade.php :
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Modifier profile</div>
<div class="card-body">
<form method="POST" action="{{ route('profile.update', ['user' => $user]) }}" enctype="multipart/form-data">
#csrf
#method('PATCH')
<div class="form-group">
<label for="title">Titre</label>
<div class="col-md-6">
<input id="title" type="text" class="form-control #error('title') is-invalid #enderror" name="title" value="{{ old('title') ?? $user->profile->title }}" autocomplete="title" autofocus>
#error('title')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group">
<label for="description">Description</label>
<div class="col-md-6">
<textarea id="description" type="text" class="form-control #error('description') is-invalid #enderror" name="description" autocomplete="description" autofocus>{{ old('description') ?? $user->profile->description }}</textarea>
#error('description')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group">
<div class="custom-file">
<input type="file" name="image" class="custom-file-input #error('image') is-invalid #enderror" id="validatedCustomFile" >
<label class="custom-file-label" for="validatedCustomFile">Choisir une image</label>
#error('image')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
Modifier profile
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#endsection
Profile.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
protected $guarder = [];
public function user()
{
return $this->belongsTo('App\User');
}
}
What am I doing wrong here and how can I get rid of this error?
You have a spelling error, instead of $guarder add this in your model:
protected $guarded = [];
I won't advise using empty guarded but use $fillable instead.
In the same controller model, free access to database fields with
protected $guarded = [];
or
protected $fillable = [];

Posting data over post route - Page expired

I'm attempting to post data to my database using Laravel, but I can't seem to do so. The post route sends to a an expired page.
Here is the route
Route::post('/expenses', 'PropertyExpenseController#store')->middleware('auth');
This is the create and store functions which render the form, and process the form.
public function create($id){
$property = PropertyAdvert::where('id', $id)->first();
return view('/pages/expenses/create', compact('property'));
}
public function store(Request $request){
$PropertyExpenses = PropertyExpenses::create([
"property_id" => $request->property_id,
"user_id" => Auth::user()->id,
"expenseDescription" => $request->description,
"cost" => $request->amount,
"date" => $request->date,
"category" => $request->category
]);
return "Expense Log";
}
This is the view page, where the form is loaded. All the data is got in the controller via the names on the input elements.
<form method="POST" action="/expenses">
<span name="property_id" class="text-muted">{{$property->id}}</span>
<div class="row mt-4 justify-content-center">
<div class="col-md-6">
<label class="" for"description">Expense Description<label>
</div>
</div>
<div class="row form-group justify-content-center">
<div class="col-md-4">
<input class="form-control " type="text" name="description">
</div>
</div>
<div class="row mt-4 justify-content-center">
<div class="col-md-6">
<label for"amount">Amount<label>
</div>
</div>
<div class="row form-group justify-content-center">
<div class="col-md-4 input-group">
<span class="input-group-addon mr-1 mt-1">€</span>
<input class="form-control" type="text" name="amount">
</div>
</div>
<div class="row mt-4 justify-content-center">
<div class="col-md-6">
<label for"category">Category<label>
</div>
</div>
<div class="row form-group justify-content-center">
<div class="col-md-4">
<select class="form-control" id="category" name="category">
<option>Mortgage Payment</option>
<option>Maintainence</option>
<option>Management Fee</option>
</select>
</div>
</div>
<div class="row mt-4 justify-content-center">
<div class="col-md-6">
<label for"description">Date<label>
</div>
</div>
<div class="row form-group justify-content-center">
<div class="col-md-4">
<input class="form-control" type="date" name="date">
</div>
</div>
<input type="submit" class="btn btn-primary" value="Log Expense">
</form>
THis is the model, with the fillable array.
class PropertyExpense extends Model
{
protected $fillable = ['property_id'. 'user_id', 'expenseDescription', 'cost', 'date', 'category'];
public function property(){
return $this->belongsTo('App\PropertyAdverts');
}
}
In your form, you need a CSRF Token field.
<input type="hidden" name="_token" value="{{ csrf_token() }}">
Read more here.

Resources