I use Ajax to send form data to a resource controller (Laravel 5). However I send my form fields with this call as an Array (no direct form field vars)
I have setup a Request with the rules which need to be validated.
However the default behaviour of this kind of validation is that it only looks at the direct field variables inside the Request object. So for instance if I would send: input name="firstname", I simply would have to set
public function rules()
{
return [
'firstname' => 'required|alpha|between:1,128'
];
}
But now, how can I validate an array inside the Request object? So for instance, what if I would send input name="nameArray['firstname']"?
So what I want to do is to modify the Request object before it is sent to the validation. Or maybe there is a better way to deal with this. I know one can loop through the object inside the rules method like this:
foreach($this->request->get('nameArray') as $key => $val)
{
}
But that doesn't help, as the Validator of Laravel will use the direct fields set in the Request object. So I can't change that here.
I want to get the individual form fields out of the array, and put them back directly in the Request object, so Validation can be done with the same way of setting the rules etc.
Btw, I use this method of Validation, by calling the Request method inside the resource controller where, in this example, I want to store the input.
public function store(CreateStudentRequest $request)
{
}
I would create a middleware for sanitizing the request object.
class SanitizeMiddleware
{
/**
* Run the request filter.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
// here do the sanitation needed to
// make the request object work with the validator
}
}
I would probably create the sanitation methods on its own class and just inject it through the controller to keep the code clean.
Also you can also do the sanitation in the Javascript side if that's easier for you.
Well indeed, Middleware seems to do the Job. Came across another method where the class Request was extended with new validator method. However, to me it looks the middleware functionality was meant for this.
The Class I created finally looks like this
class SanitizeFormRequest
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(isset($request['ajaxData']))
{
$input = $request['ajaxData'];
foreach ($input as $key => $value) {
$request->merge([$key => $value]);
}
}
return $next($request);
}
}
I registered it as $routeMiddleware inside the kernel.php
And applied on the concerning routes.
Route::group(array('middleware' => ['auth', 'form.request']), function(){
Thanks.
Related
i am using laravel 5 when i use laravel Route::resource function in my route.php file i can get my model collection inside a parameter of my method like this:
//**web.php** file
Route::resource('factors', 'FactorsController');
//called url localhost:8000/factors/1/edit
//**FactorsController**
/**
* #param Request $request
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function edit(Request $request, Factor $factor)
{
//$factor is a collection of Factor Model that contains id '1' information in factor table
return view('factors.edit', compact('factor'));
}
it is correct and works but when i make a custom url like this:
Route::get('factors/{id}/newEdit', 'FactorsController#newEdit');
i can't get the collection inside method parameters and it returns empty collection like this:
//called url localhost:8000/factors/1/newEdit
1)
//**FactorsController**
/**
* #param Request $request
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function newEdit(Request $request, Factor $factor)
{
return view('factors.newEdit', compact('factor'));
}
$factor is a empty collection of Factor Model but i want my selected row in database. when i use that like this works correct:
2)
//**FactorsController**
/**
* #param Request $request
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function newEdit(Request $request, $id)
{
$factor = Factor::find($id);
return view('factors.newEdit', compact('factor'));
}
but i don't want to call it like 2 i want to call it like 1
thanks for any help.
For model binding, you should have type-hinted variable names match a route segment name :
Route::get('factors/{factor}/newEdit', 'FactorsController#newEdit');
Since the $factor variable is type-hinted as the Factor model and the variable name matches the {factor} URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI.
I've extended the Illuminate\Http\Request class and am passing it along to my controller.
use Illuminate\Http\Request;
class MyRequest extends Request
{
...
}
Controller
class MyController
{
// Doesnt work
public function something(MyRequest $request) {
var_dump($request->session())
}
// Does work
public function something(Illuminate\Http\Request $request) {
var_dump($request->session())
}
}
So when I'm trying to get session $request->session() I get RuntimeException - Session store not set on request.
I feel it has something to do with not running middlewares on my custom request but I dont know how to make it work. Helping or pionting to the right direction would be much apreciated.
To give a little bit more info. I'm trying to make a wizard. Several pages where content of one page depends on choices on previous pages. I'm storing the data in session and on the final page I do "stuff" with it and clear the session storage of current user.
Because it a lot of lines of code and since session instace lives on request I though it would be elegant to hide all those line it in custom request and in controler simply call $myRequest->storeInputs()
This is what seemed to me as "most elegant" in this particular case so I would prefer to finish it this way but I'm also open to a different solution if there is a better aproach.
Summary: basically where should I hide all those lines which are storing and retriving data from sesison?
Solution: I actually solved it by extending FormRequest since it was solution which was the best fit for what I was trying to do. However I accepted the one offered answer since I believe it is generally better solution and I would use it if not for this very particullar case.
The classic Laravel request already got a bunch of settings you didn't catch on your custom request. To achieve that, you should setup a middleware (maybe global in your use-case) which replaces old request in Laravel's container by yours.
<?php
namespace App\Http\Middleware;
use App\Http\MyRequest;
use Closure;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\Request;
class CustomizeRequest
{
/**
* #var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* #var \App\Http\MyRequest
*/
protected $myRequest;
/**
* #param \Illuminate\Contracts\Foundation\Application $app
* #param \App\Http\MyRequest $myRequest
*/
public function __construct(Application $app, MyRequest $myRequest)
{
$this->app = $app;
$this->myRequest = $myRequest;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$this->app->instance(
'request', Request::createFrom($request, $this->myRequest)
);
return $next($this->myRequest);
}
}
I have created the form request for data validation,
I have also created the middleware for request modify which add the one key in the \Illuminate\Http\Request object from taking the value from query parameter
I want \Illuminate\Http\Request object data which is modified by the middleware to be attached with form request so I can further user in controller with the $request object
I have written middleware code to the baseformrequest(custom class) and called the method into my formrequest.
middleware code:
public function handle($request, Closure $next)
{
$requested_method = $request->route()->getActionMethod();
$required_with = [];
if($requested_method == 'show'){
if (!is_null($request->get('_with'))) {
$required_with = explode(',', $request->get('_with'));
}
}
$request->with = $request->get('_with');
return $next($request);
}
I expect all the modified request object can be accessible in My form request object, but I can't access in my Laravel controller
You can add custom attributes to the request object like this
$request->attributes->add(['with' => $required_with])
Then you can access it using
$request->get('with');
I wrote a very simple middleware, like this:
class CheckToken
{
private $token='xxx';
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! $request->tokenz == $this->token) {
return response('Unauthorized.', 401);
}
return $next($request);
}
}
Then I register it trough kernel.php, like this:
protected $routeMiddleware = [
.....
'CheckToken' => \App\Http\Middleware\CheckToken::class,
];
then Ive a very simple function in a controller guarded by this controller:
public function __construct()
{
$this->middleware('CheckToken');
}
public function push()
{
return view('home');
}
Now starts what is not clear to me:
how can i "protect" my page using this simple method?
I've tried to put this tag on the header of page but it seems to not works, maybe im in the wrong path:
<meta name="tokenz" content="xxx">
I put it even in the body but no results.
what ive misunderstood?
I believe you need to add the middleware call to the actual route:
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
This was extracted from the Laravel 5.7 documentation: Middleware - Assigning Middleware to Routes
sorry i can't create a comment. but just want to help.
does $request passed a tokenz?
you can use ?tokenz=blablabla
or you can change your method to get the tokenz
i wrote my own User-Role System, but i dont know how to implement the verification in my middleware routes.
The middleware class is calling on every request.
I recive the $request->user() but i can not access the attributes to verify if the user has the correct permissions.
My middleware controller looks like this:
namespace App\Http\Middleware;
use Closure;
use Activation;
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
class AccountMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Sentinel::findByCredentials([
'login' => $request->user()->attributes['email']
);
...
return $next($request);
}
}
It doesnt work.
If I trie to dump the $request->user() i can see all properties but there are protected.
What do i need to change, to make it work?
Accessing Eloquent model properties is done via accessors, in this case via the __get magic method. So you don't need to access them through the $attributes property array, all you need is this:
$request->user()->email;
The above will return the user email because the Illuminate\Database\Eloquent\Model::__get method already fetches the specified attribute automatically.
If you like, you can even define your own Accessors or Mutators to modify attribute values when reading or writing them to the database.