@noblemfd you mean you are logged in then when you import Excel you are logged out and redirected to Login page?
Maatwebsite import on failure redirects to Login Page
In my Laravel-5.8, I am importing from Excel into database using Maatwebsites-3.1:
public function importGrade(Request $request){
$request->validate([
'file' => 'required|max:10000|mimes:xlsx,xls',
]);
$path1 = $request->file('file')->store('import');
$path=storage_path('app').'/'.$path1;
$import = new GradeLevelsImport;
$import->import($path);
if ($import->failures()->isNotEmpty()) {
Session::flash('error', $import->failures());
return redirect()->route('hr.grades.index');
}
Session::flash('success', 'Grade Records Imported Successfully');
return redirect()->route('hr.grades.index');
}
On failure, it redirects me to the Login Page. The problem is coming from here:
if ($import->failures()->isNotEmpty()) {
Session::flash('error', $import->failures());
return redirect()->route('hr.grades.index');
}
Even when I changed it to:
if ($import->failures()->isNotEmpty()) {
Session::flash('error', $import->failures());
return back();
}
And even when I used:
return back()->withFailures($import->failures());
The problem still persists.
How do I get it resolved?
Thanks
@neilstee - I didn't log out. When I submitted import button, it redirects me to Login Page. That it, to login afresh.
But when I removed this:
if ($import->failures()->isNotEmpty()) {
Session::flash('error', $import->failures());
return redirect()->route('hr.grades.index');
}
It didn't redirect to Login Page. But I need it to display list of failures.
What is GradeLevelsImport?
@michaloravec - GradeLevelsImport is inside Imports folder. That's where I have the Maatwebsite Excel import code:
class GradeLevelsImport implements ToModel, WithHeadingRow, SkipsOnError, WithValidation, WithBatchInserts, SkipsOnFailure
{
public function model(array $row)
{
$grade_data = [
'grade_level_code' => $row['grade_level_code'] ?? '',
'grade_level_name' => $row['grade_level_name'] ?? '',
'company_id' => Auth::user()->company_id,
'created_by' => Auth::user()->id,
'created_at' => date("Y-m-d H:i:s"),
'is_active' => 1,
];
$grade = HrGrade::create($grade_data);
}
public function batchSize(): int
{
return 1000;
}
public function headingRow(): int
{
return 1;
}
}
And the code of GradeLevelsImport is?
@michaloravec - I've updated the code
All methods in interfaces (ToModel, WithHeadingRow, SkipsOnError, WithValidation, WithBatchInserts, SkipsOnFailure) must be implemented within a class.
@noblemfd can you try
if ($import->failures()->isNotEmpty()) {
return redirect()->route('hr.grades.index')->withFailures($import->failures());
}
@neilstee - The same issue
hmm calling the $import->failures()->isNotEmpty() seems the culprit here then
@neilstee - But when I dd('hello') inside it, it displays, Any other idea or method?
try this instead
!empty($import->failures())
oh so the condition is working fine.
then I guess passing the $import->failures seems the issue? can you try your old code but instead of passing $import->failures use some dummy string data.
@neilstee - The problem still persists
@neilstee - How do you mean by this "instead of passing $import->failures use some dummy string data"
@noblemfd then it has to do with the route. Can you check if your route is correct
I mean like this
if ($import->failures()->isNotEmpty()) {
// dd('test'); <- you said this is working so no problem on the if condition
return redirect()->route('hr.grades.index'); // how about this?
}
@neilstee - return redirect()->route('hr.grades.index'); also works.
But I need to find a way to display the failures
@noblemfd Yes, we're just narrowing down the errors.
So now we know that passing the $import->failures is the problem.
Can you do this
if ($import->failures()->isNotEmpty()) {
return redirect()->route('hr.grades.index')->with('errors', $import->failures);
}
Then on the blade file, you should check here how to print it correctly:
https://docs.laravel-excel.com/3.1/imports/validation.html#gathering-all-failures-at-the-end
if ($import->failures()->isNotEmpty()) {
return redirect()->route('hr.grades.index')->with('errors', $import->failures);
}
I got the same error.
But when I did it this way
try {
$import = new GradeLevelsImport;
$import->import($path);
Session::flash('success', 'Grade Records Imported Successfully');
return redirect()->route('hr.grades.index');
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
$failures = $e->failures();
foreach ($failures as $failure) {
$failure->row(); // row that went wrong
$failure->attribute(); // either heading key (if using heading row concern) or column index
$failure->errors(); // Actual error messages from Laravel validator
$failure->values(); // The values of the row that has failed.
}
Session::flash('error', $import->failures());
return redirect()->route('hr.grades.index');
}
and I did this on the blade:
@if (Session::has('failures'))
<table class="table table-danger">
<tr>
<th>
Row
</th>
<th>
Attribute
</th>
<th>
Error
</th>
<th>
Value
</th>
</tr>
@foreach(session()->get('failures') as $validation)
<tr>
<td>
{{$evalidation->row() ?? '' }}
</td>
<td>
{{$validation->attribute() ?? '' }}
</td>
<td>
<ul>
@foreach($validation->errors() as $e)
<li>{{$e ?? '' }}</li>
@endforeach
</ul>
</td>
<td>
{{$validation->value()[$validation->attribute()] }}
</td>
</tr>
@endforeach
</table>
@endif
It's always showing his success message, Session::flash('success', 'Grade Records Imported Successfully');
Yet if fails. It didn't get to the failure side.
I think it should be
Session::flash('error', $import->errors());
Ohh looks like this will solve your issue @noblemfd
Nice spot there @michaloravec !
dd($import->failures()); gives results
but dd($import->errors()); shows empty array
@noblemfd can you try converting to array like this $import->failures()->toArray?
and maybe share what's inside dd($import->failures());
@neilstee - toArray does not exist
@neilstee - dd($import->failures());
#items: array:198 [▼
0 => Maatwebsite\Excel\Validators\Failure {#1284 ▼
#row: 2
#attribute: "Grade Code"
#errors: array:1 [▼
0 => "The Grade Code has already been taken."
]
-values: array:2 [▼
"grade_code" => "CLX"
"grade_name" => "Class 1"
]
}
1 => Maatwebsite\Excel\Validators\Failure {#1280 ▼
#row: 3
#attribute: "Grade Code"
#errors: array:1 [▶]
-values: array:2 [▶]
}
2 => Maatwebsite\Excel\Validators\Failure {#1276 ▶}
3 => Maatwebsite\Excel\Validators\Failure {#1277 ▶}
@noblemfd from what I suggested earlier that try to pass some test data like this
if ($import->failures()->isNotEmpty()) {
return redirect()->route('hr.grades.index')->with('failures', []);
}
does this work?
@neilstee - The error is no more there. But it only displays the title of the errors, the content of the error not there.
Row | Attribute | Error | Value
@noblemfd yes because you are not passing any. can you do this then:
if ($import->failures()->isNotEmpty()) {
return redirect()->route('hr.grades.index')->with('failures', json_decode(json_encode($import->failures()), true));
}
Then on your blade file, change your variables to use array index instead of object property.
@neilstee - I really appreciate your effort. But now I got this error:
production.ERROR: Call to a member function row() on array
and it points to {{$validation->row() ?? '' }}
in
@if (Session::has('failures'))
<table class="table table-danger">
<tr>
<th>
Row
</th>
<th>
Attribute
</th>
<th>
Error
</th>
<th>
Value
</th>
</tr>
@foreach(session()->get('failures') as $validation)
<tr>
<td>
{{$validation->row() ?? '' }}
</td>
<td>
{{$validation->attribute() ?? '' }}
</td>
<td>
<ul>
@foreach($validation->errors() as $e)
<li>{{$e ?? '' }}</li>
@endforeach
</ul>
</td>
<td>
{{$validation->value()[$validation->attribute()] }}
</td>
</tr>
@endforeach
</table>
@endif
@noblemfd as I said earlier, you have to change the call on blade file.
From $validation->row()
it should be like this $validation['row']
@noblemfd Do you understand what is an array, a collection or an object?
When you have this code
return redirect()->route('hr.grades.index')->with('failures', []);
It's pretty clear that you get only
Row | Attribute | Error | Value
Because you send an empty array.
I'm really surprised that you didn't get any progress as programmer for the last year...
I suggest you to find someone who finnish your project instead of you...
@michaloravec - You are too forward and harsh in your approach. I showed you my dd($import->failures());
It is not empty. It was @neilstee that suggested
return redirect()->route('hr.grades.index')->with('failures', []);
If you are not sure of something, be calm.
Thanks
Calm down guys, we are trying to make ourselves to be better programmers here :)
@noblemfd I was actually surprised that you didn't get the point that I suggested on passing an empty array to the route that @michaloravec is pointing about. But I saw your effort when you implement the try and catch approach on the documentation so kudos on you.
@michaloravec I hope you can be kind to your words especially to those beginners/in need because that might demotivate them to work on themselves to strive to be better. We all started by not knowing something.
We are all learning here nonetheless not just to be a better programmer but to be a good person overall so let's all keep going :)
@neilstee - Thanks. Let me go over it again
@noblemfd you might have missed my previous reply but you can try to dd() the new value of $failures in your blade file. basically, we just transformed the object to an array that's why $validation->row() wouldn't work now.
I think it will be $validation['row'] instead but check what's inside the new $failures array
@neilstee He is not beginner...
35 000 experience, 9 lesson completed and 0 best replies.
We have suggested to him so many times to learn something on Laracasts.
At least to watch the basic series https://laracasts.com/series/laravel-6-from-scratch
And he never did it.
He create almost every single day a thread about the basic issue.
So what can I say.
Please or to participate in this conversation.