Request Validation Not Working for PUT method In Laravel 8 - laravel

My Route
Route::put('dataedit/{id}', [empDataController::class, 'empDataEdit'])->middleware('guest')->name('emp.data.edit');
My Controller
public function empDataEdit(empDataValidation $request, $id){
$id = Crypt::decrypt($id);
$DataAddCheck = EmpData::find($id)->update($request->all());
if($DataAddCheck){
return back()->with('successMsg', 'Data Added Successfully');
}
else{
return back()->with('successMsg', 'Something Went Wrong Try Again!');
}
}
Note : I add use App\Http\Requests\empDataValidation; in controller Top.
My Request Validation
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class empDataValidation extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'empName' => ['required'],
];
}
}
My blade (Just Important part)
<form id="msform" method="post" enctype="multipart/form-data"
action="{{ route('emp.data.edit', Crypt::encrypt($data->id)) }}">
#csrf
#method('PUT')
Note: When I use Request $request in controller It works Fine but when I use empDataValidation $request It not working, In my create controller empDataValidation $requestworks fine. Please help to solve this issue.

Related

Setting a Flash error message with FormRequest

I am attempting to set and pass a flash message, when a form validation fails. When the validation passes, I am able to set Flash message in the controller.
I have tried to override the protected failedValidation() but I get an error.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Validator;
class UserRequest extends FormRequest {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'first_name' => 'required|string|min:2|max:50',
'last_name' => 'required|string|min:2|max:50',
'date_of_birth' => 'required|date',
'gender' => 'required|in:male,female'
];
}
/**
* Handle a failed validation attempt.
*/
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
Flash::error("Profile could not be saved!");
// alert()->error('oops ... error');
return parent::failedValidation($validator);
} }
error:
Symfony\Component\Debug\Exception\FatalThrowableError Class
'App\Http\Requests\Flash' not found
I am setting my view in app.blade.php as follows
<div class="flash-message">
#foreach (['danger', 'warning', 'success', 'info'] as $msg)
#if(Session::has('alert-' . $msg))
<p class="alert alert-{{ $msg }}">{{ Session::get('alert-' . $msg) }} ×</p>
#endif
#endforeach
</div> <!-- end .flash-message -->
you need to add use Flash; in the controller at the top after namespace declaration where you want to use the flash library methods.

Laravael - Language switcher not working

I am trying to dynamically display the texts in two languages - English or German. But I am failing the task because nothing happens.
I have done the following:
Middleware:
public function handle($request, Closure $next) {
if (!\Session::has('locale')) {
\Session::put('locale', \Config::get('app.locale'));
}
app()->setLocale(\Session::get('locale'));
return $next($request);
}
}
Controller:
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Session;
use App;
use Illuminate\Http\Request;
class LanguageController extends Controller {
protected $langs = ['en', 'de'];
public function changeLanguage($lang) {
if (in_array($lang, $this->langs)) {
App::setLocale($lang);
Session::put('locale', $lang);
}
return redirect()->back();
}
}
Kernel:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\LanguageMiddleware::class,
];
View:
<div class="dropdown">
<button class="dropbtn">{{trans('translations.lang')}}</button>
<div class="dropdown-content">
#if(Session::get('locale')=='en')
Deutsch
#else
English
#endif
</div>
</div>
Route:
Route::get('lang/{id}', 'LanguageController#changeLanguage');
Using Laravel 5.4
Thanks in advance :)
you can define and middleware like this :
namespace App\Http\Middleware;
use Closure;
/**
* Class LocaleMiddleware.
*/
class LocaleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
protected $languages = ['en','de'];
public function handle($request, Closure $next)
{
if(!session()->has('locale'))
{
session()->put('locale', $request->getPreferredLanguage($this->languages));
}
app()->setLocale(session('locale'));
return $next($request);
}
}
on your controller create method for change
public function changeLanguage($languague)
{
if(Session::has(locale)){
session()->set('locale', $language);}
else{
session()->set('locale', 'en');
}
return redirect()->back();
}
Route look like
Route::get('lang/{languague}', 'LanguageController#changeLanguage');
in your route command you send $id but in your controller's function you have enter $lang and not $id. the error can come for that.
you must have this
public function changeLanguage($id) {

Laravel Form Request issue with validation

I am trying to use form request in my REST API built using laravel 5.2. My controller is
public function save(SbcEntityFormRequest $request)
{
$requestData = Input::all();
try {
list($success, $message) = $this->sbcService->saveSbcEntity($requestData);
if ($success) {
return $this->successJsonResponse($request, ['id' => $message]);
}
return $this->errorJsonResponse($request, Response::HTTP_BAD_REQUEST, [$message]);
} catch (Exception $e) {
AppLog::write($e);
$message = [config('messages.save_failed')];
return $this->errorJsonResponse($request, Response::HTTP_BAD_REQUEST, $message);
}
}
My form request is
namespace App\Http\Requests;
use Illuminate\Http\Request;
class SbcEntityFormRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'logo' => 'Required',
'bio' => 'Required|Max:150'
];
}
}
My validation rules are never called. I put a die statement in authorize() function and it is neither called. When I printed $request->all() in the controller it shows empty array. Any Idea on what is wrong here?

How to update specific fields in a PUT request?

I have a settings table where I store things like website title, social network links and other things... I make then all acessible by seting a cache variable.
Now, my question is, how can I update this table? By example... If I have the following blade form:
{!! Form::model(config('settings'), ['class' => 's-form', 'route' => ['setting.update']]) !!}
{{ method_field('PUT') }}
<div class="s-form-item text">
<div class="item-title required">Nome do site</div>
{!! Form::text('title', null, ['placeholder' => 'Nome do site']) !!}
</div>
<div class="s-form-item text">
<div class="item-title required">Descrição do site</div>
{!! Form::text('desc', null, ['placeholder' => 'Descrição do site']) !!}
</div>
<div class="s-form-item s-btn-group s-btns-right">
Voltar
<input class="s-btn" type="submit" value="Atualizar">
</div>
{!! Form::close() !!}
In the PUT request how can I search in the table by the each name passed and update the table? Here are the another files:
Route
Route::put('/', ['as' => 'setting.update', 'uses' => 'Admin\AdminConfiguracoesController#update']);
Controller
class AdminConfiguracoesController extends AdminBaseController
{
private $repository;
public function __construct(SettingRepository $repository){
$this->repository = $repository;
}
public function geral()
{
return view('admin.pages.admin.configuracoes.geral.index');
}
public function social()
{
return view('admin.pages.admin.configuracoes.social.index');
}
public function analytics()
{
return view('admin.pages.admin.configuracoes.analytics.index');
}
public function update($id, Factory $cache, Setting $setting)
{
// Update?
$cache->forget('settings');
return redirect('admin');
}
}
Repository
class SettingRepository
{
private $model;
public function __construct(Setting $model)
{
$this->model = $model;
}
public function findByName($name){
return $this->model->where('name', $name);
}
}
Model
class Setting extends Model
{
protected $table = 'settings';
public $timestamps = false;
protected $fillable = ['value'];
}
ServiceProvider
class SettingsServiceProvider extends ServiceProvider
{
public function boot(Factory $cache, Setting $settings)
{
$settings = $cache->remember('settings', 60, function() use ($settings)
{
return $settings->lists('value', 'name')->all();
});
config()->set('settings', $settings);
}
public function register()
{
//
}
}
Migration
class CreateSettingsTable extends Migration
{
public function up()
{
Schema::create('settings', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100)->unique();
$table->text('value');
});
}
public function down()
{
Schema::drop('settings');
}
}
Ok, step by step.
First, let's think about what we really want to achieve and look at the implementation in the second step.
Looking at your code, I assume that you want to create an undefined set of views that contain a form for updating certain settings. For the user, the settings seem to be structured in groups, e.g. "General", "Social", "Analytics", but you don't structure your settings in the database like that. Your settings is basically a simple key/value-store without any relation to some settings group.
When updating, you want a single update method that handles all settings, disregarding which form the update request is sent from.
I hope I'm correct with my assumptions, correct me if I'm not.
Okay cool, but, come on, how do I implement that?
As always, there are probably a thousand ways you can implement something like this. I've written a sample application in order to explain how I would implement it, and I think it's pretty Laravelish (what a word!).
1. How should my data be stored?
We already talked about it. We want a basic key/value-store that persists in the database. And because we work with Laravel, let's create a model and a migration for that:
php artisan make:model Setting --migration
This will create a model and the appropriate migration. Let's edit the migration to create our key/value columns:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSettingsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('settings', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('value');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('settings');
}
}
In the Setting model, we have to add the name column to the fillable array. I'll explain why we need to below. Basically, we want to use some nice Laravel APIs and therefore we have to make the name-attribute fillable.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Setting extends Model {
/**
* #var array
*/
protected $fillable = ['name'];
}
2. How do I want to access the settings data?
We discussed this in your last question, so I won't go into detail about this and I pretend that this code already exists. I'll use a repository in this example, so I will update the SettingsServiceProvider during development.
3. Creating the repositories
To make the dependencies more loosely coupled, I will create an Interface (Contract in the Laravel world) and bind it to a concrete implementation. I can then use the contract with dependency injection and Laravel will automatically resolve the concrete implementation with the Service Container. Maybe this is overkill for your app, but I love writing testable code, no matter how big my application will be.
app/Repositories/SettingRepositoryInterface.php:
<?php
namespace App\Repositories;
interface SettingRepositoryInterface {
/**
* Update a setting or a given set of settings.
*
* #param string|array $key
* #param string $value
*
* #return void
*/
public function update($key, $value);
/**
* List all available settings (name => value).
*
* #return array
*/
public function lists();
}
As you can see, we will use the repository for updating settings and listing our settings in a key/value-array.
The concrete implementation (for Eloquent in this example) looks like this:
app/Repositories/EloquentSettingRepository.php
<?php
namespace App\Repositories;
use App\Setting;
class EloquentSettingRepository implements SettingRepositoryInterface {
/**
* #var \App\Setting
*/
private $settings;
/**
* EloquentSettingRepository constructor.
*
* #param \App\Setting $settings
*/
public function __construct(Setting $settings)
{
$this->settings = $settings;
}
/**
* Update a setting or a given set of settings.
* If the first parameter is an array, the second parameter will be ignored
* and the method calls itself recursively over each array item.
*
* #param string|array $key
* #param string $value
*
* #return void
*/
public function update($key, $value = null)
{
if (is_array($key))
{
foreach ($key as $name => $value)
{
$this->update($name, $value);
}
return;
}
$setting = $this->settings->firstOrNew(['name' => $key]);
$setting->value = $value;
$setting->save();
}
/**
* List all available settings (name => value).
*
* #return array
*/
public function lists()
{
return $this->settings->lists('value', 'name')->all();
}
}
The DocBlocks should pretty much explain how the repository is implemented. In the update method, we make use of the firstOrNew method. Thats why we had to update the fillable-array in our model.
Now let's bind the interface to that implementation. In app/Providers/SettingsServiceProvider.php, add this to the register-method:
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
\App\Repositories\SettingRepositoryInterface::class,
\App\Repositories\EloquentSettingRepository::class
);
}
We could have added this to the AppServiceProvider, but since we have a dedicated service provider for our settings we will use it for our binding.
Now that we have finished the repository, we can update the existing code in the boot-method of our SettingsServiceProvider so that it uses the repository instead of hardcoding App\Setting.
/**
* Bootstrap the application services.
*
* #param \Illuminate\Contracts\Cache\Factory $cache
* #param \App\Repositories\SettingRepositoryInterface $settings
*/
public function boot(Factory $cache, SettingRepositoryInterface $settings)
{
$settings = $cache->remember('settings', 60, function() use ($settings)
{
return $settings->lists();
});
config()->set('settings', $settings);
}
4. Routes and controller
In this simple example, the homepage will show a form to update some settings. Making a PUT/PATCH-request on the same route will trigger the update method:
<?php
get('/', ['as' => 'settings.index', 'uses' => 'Admin\SettingsController#index']);
put('/', ['as' => 'settings.update', 'uses' => 'Admin\SettingsController#update']);
The index-method of our controller will return a view that contains the form. I've commented the update method throughout to explain what each line does:
app/Http/Controllers/Admin/SettingsController.php:
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Contracts\Cache\Factory;
use Illuminate\Http\Request;
use App\Repositories\SettingRepositoryInterface;
class SettingsController extends AdminBaseController {
/**
* #var \App\Repositories\SettingRepositoryInterface
*/
private $settings;
/**
* SettingsController constructor.
*
* #param \App\Repositories\SettingRepositoryInterface $settings
*/
public function __construct(SettingRepositoryInterface $settings)
{
$this->settings = $settings;
}
/**
* Shows the setting edit form.
*
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index()
{
return view('settings.index');
}
/**
* Update the settings passed in the request.
*
* #param \Illuminate\Http\Request $request
* #param \Illuminate\Contracts\Cache\Factory $cache
*
* #return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request, Factory $cache)
{
// This will get all settings as a key/value array from the request.
$settings = $request->except('_method', '_token');
// Call the update method on the repository.
$this->settings->update($settings);
// Clear the cache.
$cache->forget('settings');
// Redirect to some page.
return redirect()->route('settings.index')
->with('updated', true);
}
}
Note the first statement in the update method. It will fetch all POST-data from the request, except the method and CSRF token. $settings is now an associative array with your settings sent by the form.
5. And last, the views
Sorry for the Bootstrap classes, but i wanted to style my example app real quick :-)
I guess that the HTML is pretty self-explanatory:
resources/views/settings/index.blade.php:
#extends('layout')
#section('content')
<h1>Settings example</h1>
#if(Session::has('updated'))
<div class="alert alert-success">
Your settings have been updated!
</div>
#endif
<form action="{!! route('settings.update') !!}" method="post">
{!! method_field('put') !!}
{!! csrf_field() !!}
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" id="title" name="title" placeholder="Title" value="{{ config('settings.title', 'Application Title') }}">
</div>
<div class="form-group">
<label for="Facebook">Facebook</label>
<input type="text" class="form-control" id="facebook" name="facebook" placeholder="Facebook URL" value="{{ config('settings.facebook', 'Facebook URL') }}">
</div>
<div class="form-group">
<label for="twitter">Twitter</label>
<input type="text" class="form-control" id="twitter" name="twitter" placeholder="Twitter URL" value="{{ config('settings.twitter', 'Twitter URL') }}">
</div>
<input type="submit" class="btn btn-primary" value="Update settings">
</form>
#stop
As you can see, when I try to get a value from the config, I also give it a default value, just in case it has not been set yet.
You can now create different forms for different setting groups. The form action should always be the settings.update route.
When I run the app, I can see the form with the default values:
When I type some values, hit the update button and Laravel redirects me to the form again, I can see a success message and my settings that now persist in the database.
You can inject the Request class. Lets update the title:
// Injecting Illuminate\Http\Request object
public function update(Request $request, $id, Factory $cache, Setting $setting)
{
$newTitle = $request->get('title');
$cache->forget('settings');
return redirect('admin');
}
To change the value in db, then could do:
$titleSetting = App\Setting::where('name', 'title')->first();
$titleSetting->value = $newTitle;
$titleSetting->save();
The whole code looks like:
public function update(Request $request, $id)
{
$newTitle = $request->get('title');
\Cache::forget('settings');
$titleSetting = App\Setting::where('name', 'title')->first();
$titleSetting->value = $newTitle;
$titleSetting->save();
return redirect('admin');
}

Laravel 5 how to validate route parameters?

I want to validate the route parameters in the "form request" but don't know how to do it.
Below is the code sample, I am trying with:
Route
// controller Server
Route::group(['prefix' => 'server'], function(){
Route::get('checkToken/{token}',['as'=>'checkKey','uses'=> 'ServerController#checkToken']);
});
Controller
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests;
class ServerController extends Controller {
public function checkToken( \App\Http\Requests\CheckTokenServerRequest $request) // OT: - why I have to set full path to work??
{
$token = Token::where('token', '=', $request->token)->first();
$dt = new DateTime;
$token->executed_at = $dt->format('m-d-y H:i:s');
$token->save();
return response()->json(json_decode($token->json),200);
}
}
CheckTokenServerRequest
namespace App\Http\Requests;
use App\Http\Requests\Request;
class CheckTokenServerRequest extends Request {
//autorization
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
}
}
But when I try to validate a simple url http://myurl/server/checkToken/222, I am getting the response: no " token " parameter set.
Is it possible to validate the parameters in a separate "Form request", Or I have to do all in a controller?
ps. Sorry for my bad English.
For Laravel < 5.5:
The way for this is overriding all() method for CheckTokenServerRequest like so:
public function all()
{
$data = parent::all();
$data['token'] = $this->route('token');
return $data;
}
EDIT
For Laravel >= 5.5:
Above solution works in Laravel < 5.5. If you want to use it in Laravel 5.5 or above, you should use:
public function all($keys = null)
{
$data = parent::all($keys);
$data['token'] = $this->route('token');
return $data;
}
instead.
Override the all() function on the Request object to automatically apply validation rules to the URL parameters
class SetEmailRequest
{
public function rules()
{
return [
'email' => 'required|email|max:40',
'id' => 'required|integer', // << url parameter
];
}
public function all()
{
$data = parent::all();
$data['id'] = $this->route('id');
return $data;
}
public function authorize()
{
return true;
}
}
Access the data normally from the controller like this, after injecting the request:
$setEmailRequest->email // request data
$setEmailRequest->id, // url data
If you dont want to specify each route param and just put all route params you can override like this:
Laravel < 5.5:
public function all()
{
return array_merge(parent::all(), $this->route()->parameters());
}
Laravel 5.5 or above:
public function all($keys = null)
{
// Add route parameters to validation data
return array_merge(parent::all(), $this->route()->parameters());
}
The form request validators are used for validating HTML form data that are sent to server via POST method. It is better that you do not use them for validating route parameters. route parameters are mostly used for retrieving data from data base so in order to ensure that your token route parameter is correct change this line of your code, from
$token = Token::where('token', '=', $request->token)->first();
to
$token = Token::where('token', '=', $request->input(token))->firstOrFail();
firstOrFail() is a very good function, it sends 404 to your user, if the user insert any invalid token.
you get no " token " parameter set because Laravel assumes that your "token" parameter is a POST data which in your case it is not.
if you insist on validating your "token" parameter, by form request validators you gonna slow down your application, because you perform two queries to your db,
one in here
$token = Token::where('token', '=', $request->token)->first();
and one in here
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
I suggest to use firsOrFail to do both validating and retrieving at once.
A trait can cause this validation to be relatively automagic.
Trait
<?php
namespace App\Http\Requests;
/**
* Class RouteParameterValidation
* #package App\Http\Requests
*/
trait RouteParameterValidation{
/**
* #var bool
*/
private $captured_route_vars = false;
/**
* #return mixed
*/
public function all(){
return $this->capture_route_vars(parent::all());
}
/**
* #param $inputs
*
* #return mixed
*/
private function capture_route_vars($inputs){
if($this->captured_route_vars){
return $inputs;
}
$inputs += $this->route()->parameters();
$inputs = self::numbers($inputs);
$this->replace($inputs);
$this->captured_route_vars = true;
return $inputs;
}
/**
* #param $inputs
*
* #return mixed
*/
private static function numbers($inputs){
foreach($inputs as $k => $input){
if(is_numeric($input) and !is_infinite($inputs[$k] * 1)){
$inputs[$k] *= 1;
}
}
return $inputs;
}
}
Usage
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyCustomRequest extends FormRequest{
use RouteParameterValidation;
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(){
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules(){
return [
//
'any_route_param' => 'required'//any rule(s) or custom rule(s)
];
}
}
For \App\Http\Requests\CheckTokenServerRequest you can add use App\Http\Requests\CheckTokenServerRequest; at the top.
If you pass the token by url you can use it likes a variable in controller.
public function checkToken($token) //same with the name in url
{
$_token = Token::where('token', '=', $token)->first();
$dt = new DateTime;
$_token->executed_at = $dt->format('m-d-y H:i:s');
$_token->save();
return response()->json(json_decode($token->json),200);
}
$request->merge(['id' => $id]);
...
$this->validate($request, $rules);
or
$request->merge(['param' => $this->route('param')]);
...
$this->validate($request, $rules);
You just missing the underscore before token. Replace with
_token
wherever you check it against the form generated by laravel.
public function rules()
{
return [
'_token' => ['required','exists:Tokens,token,executed_at,null']
];
FormRequest has a method validationData() that defines what data to use for validation. So just override that one with route parameters in your form request class:
/**
* Use route parameters for validation
* #return array
*/
protected function validationData()
{
return $this->route()->parameters();
}
or leave most of the all logic in place and override input method from trait \Illuminate\Http\Concerns\InteractsWithInput
/**
* Retrieve an input item from the request.
*
* #param string|null $key
* #param string|array|null $default
* #return string|array|null
*/
public function input($key = null, $default = null)
{
return data_get(
$this->getInputSource()->all() + $this->query->all() + $this->route()->parameters(), $key, $default
);
}

Resources