Laravel broken translator (affects validation messages) - laravel

I have a problem with validation in Laravel. It used to work properly but now it does not. I do not know when the problem started.
The problem appears using the Validator class or a custom request file.
For example:
$validator = Validator::make($request->all(), [
'username' => 'required',
]);
If username is missing will produce an error bag containing the following error text:
validation.required
which is useless as far as validation feedback goes. If another field does not satisfy the minimum length, the error bag will contain:
validation.required
validation.min
Instead it should use the descriptions in the lang/en/validation.php file: 'The :attribute field is required.' i.e. 'The username field is required.'
It seems like the lang file is completely ignored. I checked it, and it contains a valid array. I don't know how to troubleshoot this. Can you please help?
I print out the errors as follows:
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $message)
<li>{{ $message }}</li>
#endforeach
</ul>
</div>
#endif
Example of message bag as seen from the debugger:
UPDATE: I found the original cause of the problem.
# vendor/laravel/framework/src/Illuminate/Translation/Translator.php
public function get( ..
this function fails to retrieve the translated line.
Because the load() function fails to load the contents of lang/en/validation.php
Because it's looking for it in the wrong path (/resources/lang/).
Because there exists a /resource/lang folder, which was put there by a third party package (outdated, that was the path in laravel 8).

The problem was in fact with the translation subsystem.
It's been caused by a third party plugin which created a /resources/lang folder. This was the lang folder location in Laravel 8, and it still takes precedence over the new location /lang. But the necessary files were not there and the translation failed without raising any exception (!!!).
Removing the /resources/lang folder resolved my issue.

Related

Problem accessing a route that has no parameter in Laravel 8

I have a problem accessing my route, I have a "pedidos" view where it contains some information, features and links. In one of these links I have a href with the route "pedidos.imports", every time I click on this link the route gives me an error. The route has already been created, the view too and I have the function in my controller. The only solution I found was to change the order of the routes, but that doesn't seem like the best thing to do. It could be a trivial error, but I can't solve it, even though I've already worked with several errors throughout my project.
Here's the error:
App\Http\Controllers\ReserveController::show(): Argument #1 ($id) must be of type int, string given, called in
C:\xampp\htdocs\ApLabRequest\vendor\laravel\framework\src\Illuminate\Routing\Controller.php on line 54
Link:
<a style="font-size: 20px;" href="{{route('pedidos.imports')}}" class="btn btn-info form-control">
<i class="fas fa-upload"></i>
Importar
</a>
Route:
Route::resource('pedidos', ReserveController::class)->middleware('auth');
Route::get('pedidos/imports', [ReserveController::class, 'imports'])->name('pedidos.imports')->middleware('auth');
Controller:
public function imports()
{
$deeps = Deep::get();
$clients = Client::with('properties')->orderBy('name')->get();
$kinds = Kind::get();
$materials = Material::get();
$cultures = Culture::get();
$paymentMethods = PaymentMethod::get();
return view('reserves.imports', compact('deeps', 'clients', 'kinds', 'materials', 'cultures', 'paymentMethods'));
}
"Solution" I found:
Route::get('pedidos/imports', [ReserveController::class, 'imports'])->name('pedidos.imports')->middleware('auth');
Route::resource('pedidos', ReserveController::class)->middleware('auth');
One thing I realized is that all the routes I created so far had some parameter, but in this new route I don't need a parameter and it doesn't even make sense to have it (for me). Summarizing what I'm trying to implement, this route returns a view where I will import an excel file and save these values in the database.

Laravel: How to log errors in form request input

I am using Laravel's form request to validate some complex input. If there is an error, Laravel returns the user to the previous page (which is fine), but I also want it to log the errors for me. How do I do that?
I attempted to use the form's withValidator method as follows, but got an error re 'maximum nesting level reached'.
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($validator->fails()) {
foreach($validator->errors()->all() as $error) {
logger($error);
}
}
});
}
Calling $validator->fails() in the after callback will end in an endless loop as it calls $validator->after() in the process. It re-evaluates and does not use a previous result.
Use $validator->errors() instead and check if it is empty.
Best way to validate on laravel is to use Laravel Request
As mentioned in the Laravel Documentation,
If the incoming request parameters do not pass the given validation rules, Laravel will automatically redirect the user back to their previous location.
In addition, all of the validation errors will be present in the $error variable.
The $errors variable is bound to the view by the Illuminate\View\Middleware\ShareErrorsFromSession middleware, which is provided by the web middleware group. When this middleware is applied an $errors variable will always be available in your views, allowing you to conveniently assume the $errors variable is always defined and can be safely used.
To view the errors, you can add the following snippet inside your view which is returned when the validation is failed:
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

Backpack for Laravel - Upload CSV and Store as JSON in Database

I have successfully configured Backpack for Laravel to handle all of the CRUD ops for my app except for one particular field. I need to import a CSV, convert it to JSON and then store the JSON in my database to later display as an HTML table.
I created a custom field in Backpack, which does in fact create a field to upload the file, but I can't figure out how to point it to a custom method to handle the logic to handle the conversion and storing of the CSV.
I have combed the documentation but I don't see any mention of anything like this. https://backpackforlaravel.com/docs/3.4/crud-fields#creating-a-custom-field-type
//Placed in the Controller CrudPanel Configuration
$this->crud->addField([
// CSV to JSON
'label' => "Specs Table",
'name' => "specifications_table",
'type' => 'csv2json', //custom field name
], 'update/create/both');
//Placed in csv2json.blade.php file
<div #include('crud::inc.field_wrapper_attributes') >
<label>{!! $field['label'] !!}</label>
<input
type="file"
name="{{ $field['name'] }}"
value="{{ old($field['name']) ? old($field['name']) : (isset($field['value']) ? $field['value'] : (isset($field['default']) ? $field['default'] : '' )) }} "
#include('crud::inc.field_attributes')
>
{{-- HINT --}}
#if (isset($field['hint']))
<p class="help-block">{!! $field['hint'] !!}</p>
#endif
</div>
If you need extra logic for a custom field type, it's always a good idea (imho) to do it inside the model, as an accessor for that particular model attribute.
Take the image field type as an example: it requires you to have a setImageAttribute() accessor, where the actual uploading and storing is done.
You could add a new method on your model:
public function setSpecificationsTableAttribute($value) {
// read $value
// convert it to JSON
// $this->attributes['specifications_table'] = $fileConvertedToJson;
}
Hope it helps.

Session Flash Messages not showing anywhere despite coding

I am following strict practices as per 5.2 docs, yet the validation is driving me insane.
1) This is a code snippet that I have in the controller right after the $property->save(); function
Session::flash('success', 'property table filled');
Session::flash('errors', 'These are the errors');
etc
Second issue is that the Validate method, if there are errors, it reverts back to the Create Form Page, but instead of binding the existing data in the Fields, it wipes everything out, so that I have to start the Form from scratch. Besides, it does not display any error messages
public function store(Request $request){
$this->validate($request, array(
'country' => 'bail|required|max:100',
'region' => 'bail|required|max:100',
etc
According to the documentation, this alone should, in case of fail to pass, revert back to the Create method above (the one that shows the Form to Create the Post) and issue a set of errors.
Since I am using a Resource Controller, all of the Routes are included in one line, and also, all of the Controllers and stuff are inside the Web Middleware:
Route::group(['middleware' =>'web'], function(){
Route::auth();
Route::get('/', function () {
return view('welcome');
});
Route::get('/home', 'HomeController#index');
Route::resource('property', 'PropertyController');
});
This is the flawless snippet I have in the partials which is included in the Layout, so that it will display messages (success or fail) for every page that has a session:
#if(Session::has('success'))
<div class="alert alert-success" role="success">
<strong>Success: </strong> {{Session::get('success')}}
</div>
#endif
<div class="row">
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
If instead, the storing of the data in the table database was successful, it still won't echo out any success flash session message.
Question:
Were there any errors in the submitted data, why doesn't display anything and why does it empty me all of the fields. The effect of emptying the fields is the same thing that would happen not when you refresh the Page, (filled fields stay filled) but when you click and press in the URL box of the browser.
Well, this is one of the cases where you get the answer but you dont know exactly why it works.
While I already had the Resource Controller Method inside the Web Middleware in the routes file, it turns out that I did not have to place the (or rather it was not enough) this:
Session::flash('success', 'property table filled');
Session::flash('errors', 'Posting failed');
in the Property Controller (and then this controller inside the Web Middleware in the Routes File), but actually those two lines on their own right in there in th Routes File
Session::flash('success', 'property table filled');
Session::flash('errors', 'Posting failed');
This is so much so that if I remove them from the Controller, this still works, but if I remove them from the Routes File, it doesn't.

Updated Selected Columns in Laravel 5.1 or Create a Custom Patch/PUT update function

I am working on a system and it's working perfectly. Now, i need to create a custom update method which will only update selected columns. The main update works fine but we only need to update a few columns, not every field. So i added two new functions on my EmployeeController on top of the basic index, create, update, store, destroy and delete.
public function editphoto($EmployeeID)
{
$employee=Employee::find($EmployeeID);
return view('employees.editphoto',compact('employee'));
}
public function updatephoto($EmployeeID)
{
return view('hello');
}
On my routes.php file, i added two new routes
Route::resource('employees', 'EmployeesController');
Route::get('employees/{employee}/editphoto', 'EmployeesController#editphoto')->name('employees.editphoto');
Route::get('employees/{employee}', 'EmployeesController#updatephoto')->name('employees.updatephoto');
On my new editphoto.blade.php view
{!! Form::model($employee,['method' => 'PUT','route'=>['employees.updatephoto',$employee->EmployeeID]]) !!}
{!! Form::label('GrandFathersName', 'Grand Fathers Name') !!}
{!! Form::text('GrandFathersName',null,['class'=>'form-control']) !!}
<a class="btn btn-success pull-left form-control" href="{{ URL::route('employees.index') }}">Cancel</a>
{!! Form::close() !!}
When i click the update button on this form, it tries to validate the data, which is actually on the update function of the controller. But i should have gotten a view with a text 'hello'
I thought it was the PATCH method that was causing it to go to the update method, so i tried to change it and even remove it, but it either throws an error or the same thing.
Here is the route list.
I've tried the solution on Add new methods to a resource controller in Laravel even though it is for laravel 4. I didn't try the second answer, although it was not marked as a solution. Besides, You can see that i have added the proper routes on the Controller.
So, how can i create a new update method with a PATCH action request or how can i update the data with a new method with a PUT or any other action request?
Your problem is that the employees.update route already defined by the Route::resource matches the incoming URL path and HTTP verb when you try to update the photo.
There is no difference between the path employees/{employees} defined by the resource and employees/{employee} defined by you, because the path variable name doesn't matter when matching, so it will always match the route registered first. The solution is easy in this case, just use a different path definition for updating the photo, for example:
Route::put('employees/{employee}/updatephoto', 'EmployeesController#updatephoto')->name('employees.updatephoto');
With this change alone your edit photo form should now work.

Resources