I am currently doing a small project to learn some laravel validation and ran into a problem.
The API endpoint is api/test/schoolbook?start= and my validation is
'start' => ['date_format:Y-m-d H:i:s']
While this works like a charm and sorts the schoolbooks by a start year, i think my validation has some error. It validates if start is equal to the defined date format, all good. but if i now parse just ?start=without any thing, it still goes through, but doesn't throw an error message (it just returns everything without sorting)
Is there a way i can validate this better and prevent the query string parameter to be empty?
If start is not passed, it should return all the records, so i cant make it required really.
So the scenarios are:
?start=date is passed in the right format and returns all the schoolbooks by the passed date,
?start=date is not passed and returns all the records in the database
?start= should also return 'has to be in date format validation'
Thank you!
The Controller:
public function findSchoolbook(
SchoolBookRequest $request,
) : JsonResponse {
$schoolbook = $this->schoolkbool->sort($paramBag);
$response = $this->transformer()->paginator($schoolbook);
return $this->response($response);
}
The ParamBg method i use
private function getParamBag(SchoolBookRequest $request) : ParamBag
{
return ParamBag::create()
->setPage($request->get('page'))
->setPerPage($request->get('per_page'))
->setStartDate($request->get('start_at'))
}
The Request
class SchoolBookRequest extends Request
{
public function rules() : array
{
return [
'start_at' => ['date_format:Y-m-d H:i:s']
];
}
}
This should only filter in start date when present in the request:
private function getParamBag(SchoolBookRequest $request) : ParamBag
{
$parambag = ParamBag::create()
->setPage($request->get('page'))
->setPerPage($request->get('per_page'))
if ($request->has('start_at')) {
$parambag = $parambag->setStartDate($request->get('start_at'));
}
return $parambag;
}
Related
In my blade form, I have an input field that asks for a hour value, lets say input_stage_hour
I am trying to convert this to minutes AFTER validation, but BEFORE it hits my controller ... In my form request im using the passedValidation method to convert hours to minutes, then in my controller i am filling my model using $request->validated()
The problem is, it is passing through the original value and not the converted value.
My cut down form request is below;
public function rules()
{
return [
'input_stage_hour' => ['required', 'numeric', 'integer'],
];
}
protected function passedValidation()
{
$this->replace([
'input_stage_hour' => intval($this->input_stage_hour) * 60,
]);
}
If I pass a value like 2 into the input_stage_hour and then dd($request->validated()) in my controller, it still shows the value 2 instead of 120
The data that comes from that validated method on the FormRequest is coming from the Validator not the FormRequest itself. So if you really wanted to do this with the FormRequest and be able to call that validated method you would have to adjust the data the Validator is holding or adjust the validated method.
Example attempting to adjust the data the Validator is holding:
protected function passedValidation()
{
$data = $this->validator->getData();
$this->validator->setData(
['input_stage_hour' => $data['input_stage_hour'] * 60] + $data
);
}
If you wanted to override the validated method:
public function validated()
{
$data = parent::validated();
return ['input_stage_hour' => $data['input_stage_hour'] * 60] + $data;
}
I'm trying to escape a value from a field according to another field, but it never get escaped. Here's a part of my code. However if 'samename' is true or false, 'res_title' never get escaped. It always end up in my database. I've also tried with 'unless_if', but stil got the same result.
return [
'samename' => 'required|boolean',
'res_title' => 'exclude_if:samename,false'
];
So here is how I process the request, I use Postman :
{
"samename": true,
"res_title": "test"
}
Also, here is my controller :
public function store(DmLogRequest $req)
{
$log = new DmLog();
$log->samename = $req->samename;
$log->res_title = $req->res_title;
$log->save();
return response()->json($log);
}
I don't remember this is always been so freakin' hard to do in Laravel, but how to return back to form page blade.php instead of displaying the errors as JSON object on the browser?
Controller
public function create()
{
return view('view.to.form');
}
public function store(CreateModelRequest $request)
{
Model::create($request->validated());
}
// CreateModelRequest
protected function failedValidation(Validator $validator)
{
return back()->withErrors($validator);
}
I've tried countless other "solutions" as well, but no matter what,
the failed form request return raw JSON to the browser:
{
message: 'The given data was invalid',
errors: {
first_name: ['The first name field is required.'],
last_name: ['The last name field is required.'],
email: ['The email field is required.'],
},
}
}
Ok, I found one way to return back to the form but damn this is awful:
// Controller's store method
$validator = Validator::make($request->all(), [
// rules
]);
if ($validator->fails()) {
return back()->withErrors($validator->errors());
}
I'd like to extract that code into Request class but apparently we can't return a view and therefore we can't use them outside of API endpoints. Please, correct me if I'm wrong.
I just start learning Laravel 5, and I want to know what the proper way to handle submitted forms. I found many tutorials where we create two separate actions, where first render form, and the second actually handle form. I am came from Symfony2, where we create a single action for both, render and handle submitted form, so I want to know I need to create two separate actions because thats Laravel-way, or I can place all logic into single action, I do this like the folowing, but I dont like code what I get:
public function create(Request $request)
{
if (Input::get('title') !== null) {
$v = Validator::make($request->all(), [
'title' => 'required|unique:posts',
'content' => 'required',
]);
if ($v->fails()) {
return redirect()->back()->withErrors($v->errors());
}
$post = new Post(Input::all());
if ($post->save()) {
return redirect('posts');
}
}
return view('add_post');
}
So can somebody give me advice how I need do this properly? Thanks!
One of the most important reason to create two actions is to avoid duplicate form submissions . You can read more about Post/Redirect/Get pattern.
Another important reason is the way you keep the code cleaner. Take a look at this first change:
public function showForm(){
return view('add_post');
}
public function create(Request $request)
{
$v = Validator::make($request->all(), [
'title' => 'required|unique:posts',
'content' => 'required',
]);
if ($v->fails()) {
return redirect()->back()->withErrors($v->errors());
}
$post = new Post(Input::all());
if ($post->save()) {
return redirect('posts');
}
return redirect()->route('show_form')->withMessage();
}
The first thing that you can notice is that create() function is not rendering any view, it is used to manage the creation logic (as the name itself suggests). That is OK if you plan to stay in low-profile, but what happens when you do need to add some others validations or even better, re-utilize the code in other controllers. For example, your form is a help tool to publish a comment and you want to allow only "authors-ranked" users to comment. This consideration can be manage more easily separating the code in specific actions instead making an if-if-if-if spaghetti. Again...
public function showForm(){
return view('add_post');
}
public function create(PublishPostRequest $request)
{
$post = new Post($request->all());
$post->save()
return redirect('posts');
}
Take a look on how PublishPostRequest request takes place in the appropriated function. Finally, in order to get the best of Laravel 5 you could create a request class to keep all the code related with validation and authorization inside it:
class PublishPostRequest extends Request{
public function rules(){
return [
'title' => 'required|unique:posts',
'content' => 'required',
]
}
public function authorize(){
$allowedToPost = \Auth::user()->isAuthor();
// if the user is not an author he can't post
return $allowedToPost;
}
}
One nice thing about custom request class class is that once is injected in the controller via function parameter, it runs automatically, so you do not need to worry about $v->fails()
I want to get the parameter passed in the validation rule.
For certain validation rules that I have created, I'm able to get the parameter from the validation rule, but for few rules it's not getting the parameters.
In model I'm using the following code:
public static $rules_sponsor_event_check = array(
'sponsor_id' => 'required',
'event_id' => 'required|event_sponsor:sponsor_id'
);
In ValidatorServiceProvider I'm using the following code:
Validator::extend('event_sponsor', function ($attribute, $value, $parameters) {
$sponsor_id = Input::get($parameters[0]);
$event_sponsor = EventSponsor::whereIdAndEventId($sponsor_id, $value)->count();
if ($event_sponsor == 0) {
return false;
} else {
return true;
}
});
But here I'm not able to get the sponsor id using the following:
$sponsor_id = Input::get($parameters[0]);
As a 4th the whole validator is passed to the closure you define with extends. You can use that to get the all data which is validated:
Validator::extend('event_sponsor', function ($attribute, $value, $parameters, $validator) {
$sponsor_id = array_get($validator->getData(), $parameters[0], null);
// ...
});
By the way I'm using array_get here to avoid any errors if the passed input name doesn't exist.
http://laravel.com/docs/5.0/validation#custom-validation-rules
The custom validator Closure receives three arguments: the name of the
$attribute being validated, the $value of the attribute, and an array
of $parameters passed to the rule.
Why Input::get( $parameters ); then? you should check $parameters contents.
Edit.
Ok I figured out what are you trying to do. You are not going to read anything from input if the value you are trying to get is not being submitted. Take a look to
dd(Input::all());
You then will find that
sponsor_id=Input::get($parameters[0]);
is working in places where sponsor_id was submited.