Laravel withValidator() not working as expected - php

I have this formrequest that contains rules and a withValidator as a second layer of validation.
Note: I am aware that having it unique on the rules would supress the need for this example, but I'll need to do further validations here.
public function rules(Request $request) {
return [
"name" => "required|max:191",
"begin_date" => "required|after_or_equal:today|date_format:d-m-Y",
"end_date" => "required|after:begin_date|date_format:d-m-Y",
];
}
public function withValidator($factory) {
$result = User::where('name', $this->name)->get();
if (!$result->isEmpty()) {
$factory->errors()->add('User', 'Something wrong with this guy');
}
return $factory;
}
I am positive that it enters the if as I've placed a dd previously it to check if it's going inside. However, it proceeds to this method on the Controller and I don't want it to.
public function justATest(UserRequest $request) {
dd("HI");
}

I'm an idiot and didn't read the full doc.
It needs to specify with an after function,like this:
public function withValidator($factory) {
$result = User::where('name', $this->name)->get();
$factory->after(function ($factory) use ($result) {
if (!$result->isEmpty()) {
$factory->errors()->add('User', 'Something wrong with this guy');
}
});
return $factory;
}

I was facing this problem too.
I changed my withValidator to this:
public function withValidator($validator)
{
if (!$validator->fails()) {
$validator->after(function ($validator) {
if (Cache::has($this->mobile)) {
if (Cache::get($this->mobile) != $this->code) {
$validator->errors()->add('code', 'code is incorrect!');
} else {
$this->user = User::where('mobile', $this->mobile)->first();
}
} else {
$validator->errors()->add('code', 'code not found!');
}
});
}

Related

Why custom validation in Laravel 5.6 isn't working?

I created a custom rule with php artisan make:rule, set it in controller, but it not working. What the problem can be?
class CheckDeliveryDate implements Rule
{
public $client_id;
private $is_after_midday;
private $error_messge;
public function __construct(int $client_id)
{
$this->client_id = $client_id;
$this->is_after_midday = Carbon::now()->greaterThan(Carbon::now()->midDay());
$this->error_messge = 'Error';
}
public function passes($attribute, $value)
{
$delivery_date = Carbon::parse($value);
if ($delivery_date->isToday()) {
$this->error_messge = 'Error';
return false;
}
if ($delivery_date->endOfDay()->isPast()) {
$this->error_messge = 'Error';
return false;
}
return true;
}
public function message()
{
return $this->error_messge;
}
}
In controller i set method rules:
public function rules($client_id)
{
return [
'orders.*.positions.*.delivery_time' => [
'required',
'date',
new CheckDeliveryDate($client_id)
],
];
}
and when i store my order, validator->fails() return me "false".
$validator = Validator::make(
$request->all(),
$this->rules($client_id)
);
I tried set dd or dump in Rule, not working. Where is my mistake?
As stated on laravel documentation (https://laravel.com/docs/5.8/validation#custom-validation-rules) you are not supposed to pass the parameter to your custom rule instance. Laravel does it for you.
Thus:
new CheckDeliveryDate($client_id)
Becomes :
new CheckDeliveryDate
Have a nice day !
Wrong JSON format date. This is amazing mistake...

codeigniter restful api illegal string offset in several fields

I keep on getting this error in my codeigniter micro app restful api. When I post an item only the first letter is get saved with status code 400 being displayed.
here is my model file:
class Cities_model extends CI_Model {
public function __construct()
{
parent::__construct();
}
public function save($city)
{
$this->db->set($this->setCity($city, null))->insert('cities');
if ($this->db->affected_rows() > 0) {
return $this->db->insert_id;
}
return null;
}
public function update($id, $city)
{
$this->db->set($this->setCity($city))->where('id')->update('cities');
if ($this->db->affected_rows() === 1) {
return true;
}
return false;
}
private function setCity($city)
{
return array(
'id' => $city['id'],
'name' => $city['name']
);
}
}
As you can see setCity function treat $city variable as array. So you need to pass array to setCity function.
class Cities_model extends CI_Model {
public function __construct()
{
parent::__construct();
}
public function save($city)
{
$this->db->insert('cities',$this->setCity(array('name'=>$cit‌​y,'id'=> null)));
if ($this->db->affected_rows() > 0) {
return $this->db->insert_id();
}
return null;
}
public function update($id, $city)
{
$this->db->where('id',$id)->update('cities',$this->setCity(array('name'=>$cit‌​y,'id'=> $id)));
if ($this->db->affected_rows() === 1) {
return true;
}
return false;
}
private function setCity($city)
{
return array(
'id' => $city['id'],
'name' => $city['name']
);
}
}
another thing is, Codeignitor having method insert_id() to know last insert id.
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH . '/libraries/REST_Controller.php';
class Cities extends REST_Controller{
public function __construct() {
parent::__construct();
$this->load->model('cities_model');
}
public function index_get(){
$cities=$this->cities_model->get();
if(!is_null($cities))
{
$this->response(array('response'=>$cities),200);
}
else
{
$this->response(array('error'=>'cities cannot be found...'),404);
}
}
public function find_get($id){
if(!$id)
{
$this->respose(null,400);
}
$cit=$this->cities_model->get($id);
if(!is_null($cit))
{
$this->response(array('response'=> $cit),200);
}
else{
$this->response(array('error'=> 'data could not be found...'),404);
}
}
public function index_post(){
// Use validation library, instead of checking just for value.
$this->load->library('form_validation');
$this->form_validation->set_rules('city','City','trim|required');
if($this->form_validation->run() == FALSE)
{
// send back list of validation errors.
$this->response($this->validation_errors(),REST_Controller::HTTP_BAD_REQUEST);
}
$id=$this->cities_model->save($this->post('city'));
if(!is_null($id))
{
$this->response(array('response'=> $id),REST_Controller::HTTP_OK);
}
else
{
$this->response(array('error'=> 'sorry, data could not be saved...'),REST_Controller::HTTP_BAD_REQUEST);
}
}
public function index_put(){
// for put you need to pass id as parameter
// Use validation library, instead of checking just for value.
$this->load->library('form_validation');
$this->form_validation->set_rules('id','ID','trim|required|integer');
$this->form_validation->set_rules('city','City','trim|required');
if($this->form_validation->run() == FALSE)
{
// send back list of validation errors.
$this->response($this->validation_errors(),REST_Controller::HTTP_BAD_REQUEST);
}
$update=$this->cities_model->update($this->post('id'),$this->post('city'));
if(!is_null($update))
{
$this->response(array('response' => 'content updated successfully'),REST_Controller::HTTP_OK);
}
else
{
$this->response(array('error'=> 'sorry, technical error occurred, please try again later...'), REST_Controller::HTTP_BAD_REQUEST);
}
}
public function index_delete($id){
if(!$id)
{
$this->response(null,400);
}
$del=$this->cities_model->delete($id);
if(!is_null($del))
{
$this->response(array('response'=> 'item successfully deleted'),200);
}
else{
$this->response(array('error'=> 'delete operations could not be done...'),400);
}
}
}
here is the model file:
<?php
class Cities_model extends CI_Model
{
public function __construct()
{
parent::__construct();
}
public function get($id=null)
{
if(!is_null($id))
{
$query=$this->db->select('*')->from('cities')->where('id',$id)->get();
if($query->num_rows()===1)
{
return $query->row_array();
}
return null;
}
$sql=$this->db->select('*')->from('cities')->get();
if($sql->num_rows()>0)
{
return $sql->result_array();
}
return null;
}
public function save($city)
{
$this->db->insert('cities', array('name'=>$city));
if($this->db->affected_rows()>0)
{
return $this->db->insert_id();
}
return null;
}
public function update($id, $city)
{
$this->db->where('id',$id)->update('cities',$this->setCity(array('name'=>$cit‌​y,'id'=> $id)));
if ($this->db->affected_rows() === 1) {
return true;
}
return false;
}
private function setCity($city)
{
return array('id'=>$city['id'],
'name'=>$city['name']
);
}
public function delete($id)
{
$this->db->where('id',$id)->delete('cities');
if($this->db->affected_rows()===1)
{
return true;
}
return false;
}
}

Laravel 5.1 - Return First Error From FormRequest Validation

I have the following form request:
class FileRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
$rules = [];
if($this->file_type == 'image')
$rules['file'] = 'required|image|mimes:jpg,jpeg,gif|max:244|image_size:>=360,>=180';
else
$rules['file'] = 'required|mimes:doc,pdf,docx,txt,rtf|max:1000';
return $rules;
}
public function messages()
{
$messages = [
'file.image_size' => 'The image size is incorrect.'
];
return $messages;
}
public function response(array $errors)
{
$content = "<textarea data-type=\"application/json\">{\"ok\": false, \"message\": \"" . $errors[0] . "\" }</textarea>";
return response($content);
}
}
How do i return the first error from the errors array.
When I manually create a validator I'm able to do the following: $validator->errors()->first() but this doesn't work when using a FormRequest class. Doing errors[0] simply gives me an offset exception error.
I'm using an iframe submit which is why I need to return the response as above.
Any help appreciated.
You seem to need use the validator system from laravel.
After that you could use : $validator->messages() ; for have all the errors.
If you use $validator->messages()[0]; you gonna have the first message.
I suggest you something like that
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'file' =>'required|image|mimes:jpg,jpeg,gif|max:244|image_size:>=360,>=180';
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// Store the file
}
I've had to do the following:
$errors['file'][0]

Slim3 right way to set errors and check is user logged in

I'm a new user of Slim framework, I've a simple Slim 3 application, with sign in and sign up validation. But I'm not really sure if this is the right/best way to set errors and check if user is logged in -In order to redirect it to his account if session user.id exists.
I used a middleware: AuthMiddleware which includes:
class AuthMiddleware
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function __invoke($request, $response, $next)
{
if (isset($_SESSION['user.id']) && !empty($_SESSION['user.id'])) {
return $response->withRedirect($this->container->router->pathFor('user.index'));
}
$twig = $this->container->view->getEnvironment();
if (isset($_SESSION['validation'])) {
$twig->addGlobal('errors', $_SESSION['validation']['errors']);
$twig->addGlobal('values', $_SESSION['validation']['values']);
unset($_SESSION['validation']);
}
if (isset($_SESSION['auth.signup.success'])) {
$twig->addGlobal('auth_signup_success', $_SESSION['auth.signup.success']);
unset($_SESSION['auth.signup.success']);
}
if (isset($_SESSION['auth.signin.failed'])) {
$twig->addGlobal('auth_signin_failed', $_SESSION['auth.signin.failed']);
unset($_SESSION['auth.signin.failed']);
}
$response = $next($request, $response);
return $response;
}
}
And I used Twig for my views.
Session validation assigned in the validator.php which includes:
class Validator
{
protected $errors = [];
protected $values = [];
public function validate($request, $rules)
{
foreach ($rules as $field => $rule) {
$this->values[$field] = $request->getParam($field);
try {
$rule->setName(ucfirst($field))->assert($request->getParam($field));
} catch (NestedValidationException $e) {
$this->errors[$field] = $e->getMessages()[0];
}
}
if ($this->failed()) {
$_SESSION['validation'] = [
'errors' => $this->errors,
'values' => $this->values,
];
}
return $this;
}
public function failed()
{
return !empty($this->errors);
}
}
Using Respect\Validation. Also, is this the right use of Middlewares?
Thanks in advance.
try creating a separate file for the methods, and calling it from the middleware:
<?php
class AuthMiddleware extends Middleware {
public function __invoke($request, $response, $next) {
if (!$this->container->auth->check()) {
$this->container->flash->addMessage('danger', 'Please sign in to continue.');
return $response->withRedirect($this->container->router->pathFor('auth.signin'));
}
$response = $next($request, $response);
return $response;
}
}
while the Auth class would have those methods to check:
<?php
public function check () {
return isset($_SESSION['user']);
}
public function user() {
if (isset($_SESSION['user'])) {
return User::find($_SESSION['user'])->first();
} else {
return false;
}
}
Don't forget to include the Auth Class within your $app:
<?php
$container['auth'] = function ($container) {
return new \App\Auth\Auth();
};

Laravel 4 - redirect from a repository when not returning the called method

I am using a repository pattern in my Laravel 4 project but come across something which I think I am doing incorrectly.
I am doing user validation, before saving a new user.
I have one method in my controller for this:
public function addNewUser() {
$validation = $this->userCreator->validateUser($input);
if ( $validation['success'] === false )
{
return Redirect::back()
->withErrors($validation['errors'])
->withInput($input);
}
return $this->userCreator->saveUser($input);
}
Then the validateUser method is:
public function validate($input) {
$rules = array(
'first_name' => 'required',
'last_name' => 'required',
'email_address' => 'unique:users'
);
$messages = [
];
$validation = Validator::make($input, $rules, $messages);
if ($validation->fails())
{
$failed = $validation->messages();
$response = ['success' => false, 'errors' => $failed];
return $response;
}
$response = ['success' => true];
return $response;
}
This may be okay, but I dont like doing the if statement in my controller? I would rather be able to handle that in my validation class.
But to be able to redirect from the validation class, I need to return the method in the controller.
What if I then want to have 5 methods called, I cant return them all?
I would like to be able to simply call the methods in order, then in their respective class handle what I need to and if there is any errors redirect or deal with them. But if everything is okay, simply ignore it and move to the next function.
So example:
public function addNewUser()
{
$this->userCreator->validateUser($input);
$this->userCreator->formatInput($input);
$this->userCreator->sendEmails($input);
return $this->userCreator->saveUser($input);
}
If doing the if statement in the controller isn't as bad as I think then I can continue, but this seems incorrect?
For repository pattern, you can use this :-
setup your basemodel like this
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model{
protected static $rules=null;
protected $errors=null;
public function validateForCreation($data)
{
$validation=\Validator::make($data,static::$rules);
if($validation->fails())
{
$this->errors=$validation->messages();
return false;
}
return true;
}
/**
* #return errors
*/
public function getErrors() { return $this->errors; }
}
now in your repository, add these methods
protected $model;
protected $errors=null;
public function model(){ return $this->model; }
public function getErrors(){ return $this->errors; }
public function create($inputs)
{
if(!$this->model->validateForCreation($inputs))
{
$this->errors=$this->model->getErrors();
return false;
}
$new=$this->model->create($inputs);
return $new;
}
and the controller will look like this..
public function postCreate(Request $request)
{
$inputs=$request->all();
if($new=$this->repo->create($inputs))
{
return redirect()->back()
->with('flash_message','Created Successfully');
}
return redirect()->back()->withInput()->withErrors($this->repo->getErrors())
->with('flash_message','Whoops! there is some problem with your input.');
}

Categories