Proper implementation for multiple validation - php

Here's my code:
I'm trying to implement it on ServiceProvider but I don't have any luck.
//Contact.php
class Contact extends \Eloquent {
protected $fillable = array('email', 'name', 'subject', 'msg');
public static $rules = array(
'email' => 'required|email',
'name' => 'required',
'subject' => 'required',
'msg' => 'required'
);
public static function validate($input) {
return Validator::make($input, static::$rules);
}
}
//Registration .php
class Registration extends \Eloquent {
protected $fillable = array('name', 'address', 'birthdate', 'gender', 'civil_status', 'nationality', 'contact_number', 'email', 'invited');
protected $guarded = array('id');
public static $rules = array(
"name" => "required|alpha_spaces",
"address" => "required",
"contact_number" => "required|numeric",
"email" => "required|email|unique:registrations"
);
public static function validate($input) {
return Validator::make($input, static::$rules);
}
}
class HomeController extends BaseController
{
public function postContactForm()
{
return Contact::validate(Input::all());
}
public function postRegistrationForm()
{
return Registration ::validate(Input::all());
}
}
Is the a way that I can implement it like this?
$this->validate-check(Input::all());
I'm trying to refactor my code and also still new using laravel 4 as well.
Thanks,

Aldren,
I think a Service Provider is a bit overkill for this task. You can create something like a Validation Service. Let me explain:
Say you put your custom files under app/src and use composer to autoload the classes there.
Create an abstract Validator class. This way you can extend this class for every model you need to validate:
<?php namespace Foo\Services\Validation;
abstract class Validator {
protected $errors;
public function check($validator)
{
if ($validator->fails()) {
$this->errors = $validator->messages();
return false;
}
return true;
}
public function isValidForCreation($input)
{
$validator = \Validator::make($input, static::$insertRules);
return $this->check($validator);
}
public function isValidForUpdate($input)
{
$validator = \Validator::make($input, static::$updateRules);
return $this->check($validator);
}
public function errors()
{
return $this->errors;
}
}
Now, lets say you want to validate your Contact model input, right ? You can then create a ContactValidator class that extends our Validator abstract class:
<?php namespace Foo\Services\Validation;
class ContactValidator extends Validator
{
static $insertRules = [
'name' => 'required'
];
static $updateRules = [
'name' => 'required'
];
}
All right, so now we have our boilerplate done. Now lets go to ContactsController to implement our new ContactValidator.
First of all, we need to inject our validator inside the controller. IMHO the best way to do it is in the controllers constructor.
So, lets go:
<?php
use Foo\Services\Validation\ContactValidator as Validator;
class ContactsController extends \BaseController {
protected $validator;
function __construct(Validator $validator)
{
$this->validator = $validator;
}
Great! Now we have it injected. Next, we have to make sure our ContactValidator is invoked when I try to store a Contact. Lets say your method is called store().
public function store()
{
if(!$this->validator->isValidForCreation(Input::all()))
{
return Redirect::back()->withErrors($this->validator->errors())->withInput();
}
else
{
//store your data here.
}
}
You can use either $this->validator->isValidForCreation or $this->validator->isValidForUpdate to check your input against the Validator Service.
I hope you can understand everything and if you have any doubts please let me know.
Cheers and good coding :D

Thanks for the input GustavoR, I get what you want to explain right here. But is it possible to implement the $this->validator in one controller?
use Foo\Services\Validation\MainValidator as Validator;
class HomeController extends BaseController
{
protected $validator;
public function __construct(Validator $validator)
{
$this->validator = $validator;
}
public function postContactForm()
{
return ( $this->validator->isValidForCreation(Input::all()) );
}
public function postRegistrationForm()
{
return ( $this->validator->isValidForCreation(Input::all()) );
}
}
Again, thanks for the input :)

Related

inline validator function not working for model in yii2

I am creating offer for products thats why I have implemented several model at create function in controller
public function actionCreate()
{
$model = new Offer();
$wmodel = new Wmoffer();
$pmodel = new Product();
$ummodel = new Unitofmeasurement();
$qvmodel = new OfferingValue();
$blmodel = new OfferLocation();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// code manipulation
}else{
return $this->render('create', [
'model' => $model,
'wmodel' => $wmodel,
'pmodel' => $pmodel,
'qvmodel' => $qvmodel,
'blmodel' => $blmodel,
'ummodel' => $ummodel
]);
}
all of my model extends by ActiveRecord aspect Wmoffer() this model looks like as below
use Yii;
use yii\base\Model;
use yii\web\UploadedFile;
use yii\helpers\FileHelper;
class Wmoffer extends Model
{
public $bIsProductOrService;
public $iCatalogueID;
public $imageProduct;
public $nHasCurrencyValue;
public $nHasCurrencyValueMRP;
public $BusinesslocationIds;
public function rules()
{
// validation rules
Now i need to implement inline validator for start,end date comparison [Start Date should be greater than End Date ]
i have tried this and this but this is not working i know something is missing which causes this
Any suggestions will be appreciable. Thanks
You should check $model->errors value after calling $model->validate() to look for validation errors.
Your dates validator method can be something like:
public function validateDates($attribute, $params) {
if ($this->hasErrors()) {
return;
}
if ($this->dateStart > $this->dateEnd)) {
$this->addError($attribute, 'Start date can not be greater than end date');
}
}
Add it to rules() in your backend models.

Error on insert data into database using laravel5

I am new in laravel5 Framework. when I insert data into database using laravel5 at that time I get error like....
FatalErrorException in ClientFormRequest.php line 10:
Cannot make static method Symfony\Component\HttpFoundation\Request::create() non static in class App\Http\Requests\ClientFormRequest
my all files are below...
app/Http/Controller/RegisterController.php
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientFormRequest;
use Illuminate\Http\Request;
class RegisterController extends Controller {
public function create()
{
return view('Client.client');
}
public function store(ClientFormRequest $request)
{
return \Redirect::route('Client.client')
->with('message', 'Record Inserted!');
}
}
app/Http/Requests/ClientFormRequest.php
<?php namespace App\Http\Requests;
use Stringy\create;
use App\User;
use Validator;
use App\Http\Requests\ClientFormRequest;
class ClientFormRequest 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()
{
}
public function validator(array $data)
{
return Validator::make($data, [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
]);
}
public function create(array $data)
{
return client::create([
'fullname' => $data['fullname'],
'email' => $data['email'],
]);
}
}
Routes
Route::get('client', 'RegisterController#create');
Route::post('contact_store', 'RegisterController#store');
First of all, i would suggest you to watch Laravel 5 Fundamentals repeatedly since it is free. Other series also give great information.
Secondly, I would suggest you to use at least Sublime Text and some useful packages to be able to inspect the depth nested relations of system files (Namespaces, Interfaces, Inheritance Tree etc...). If you can't/might not, this friend will serve you anytime Laravel API
Third, AFAIK, Laravel Request is build onto the Symfony' Request Component. Since you are trying to overload one of its core function as non static, you are getting this error.
In addition, to be honest, i wouldn't put my user/client model creation logic into the requests. Laravel provides an good example for this kind of misconception. In the App\Services folder, you will find a registrar service for Laravel oem user model.
Let's inspect the problem with different cases.
but first, basic...
Lets assume that all logic should be put inside the controller.
RegisterController.php
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Request;
class RegisterController extends Controller {
public function create()
{
return view('Client.client');
}
public function store()
{
$data = Request::all(); //requested data via Facade
//prepare validatation
$validation = Validator::make($data, [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
]);
//validate
if ($validation->fails())
{
return redirect()->back()->withErrors($v->errors());
}
// create the client
Client::create([
'fullname' => Request::input('fullname'),
'email' => Request::input('email'),
]);
return \Redirect::route('Client.client')
->with('message', 'Record Inserted!');
}
}
Second Solution
You might be willing to separate the validation logic and apply some dependency injection.
RegisterController.php
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientFormRequest;
class RegisterController extends Controller {
public function create()
{
return view('Client.client');
}
public function store(ClientFormRequest $request)
{
// create the client
Client::create([
'fullname' => $request->input('fullname'),
'email' => $request->input('email'),
]);
return \Redirect::route('Client.client')
->with('message', 'Record Inserted!');
}
}
ClientFormRequest.php
use Stringy\create;
use App\User;
use Validator;
use App\Http\Requests\ClientFormRequest;
class ClientFormRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
return [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users'
];
}
}
Third Solution
You might be willing to take things further and even separate the object creation logic as an service to use it anywhere. Now your request file would stay the same. However,
RegisterController.php
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientFormRequest;
use App\Services\ClientRegistrar;
class RegisterController extends Controller {
private $registrar;
public function __construct(ClientRegistrar $registrarService)
{
$this->registrar = $registrarService;
}
public function create()
{
return view('Client.client');
}
public function store(ClientFormRequest $request)
{
$newClient = $this->registrar->create($request->all());
return \Redirect::route('Client.client')
->with('message', 'Record Inserted!')->compact('newClient');
}
}
App\Services\ClientRegistrar.php
use App\Client;
use Validator;
use Illuminate\Contracts\Auth\Registrar as RegistrarContract;
class ClientRegistrar implements RegistrarContract {
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
public function validator(array $data)
{
return Validator::make($data, [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
]);
}
/**
* Create a new client instance after a valid registration.
*
* #param array $data
* #return Client
*/
public function create(array $data)
{
// create the client
return Client::create([
'fullname' => $data['fullname'],
'email' => $data['email'],
]);
}
}
To My Conclusion
There is no correct and best way to solve a problem. Stay with the best applicable and appropriate way for you and your project scale.
You also might be interested in;
Jeffrey Way's Laravel Auto Validate on Save
The error message tells you that you are overriding the create method in the ClientFormRequest class. So remove the method there. Instead create the new Client in your Controller.
Below I updated your classes to reflect the changes.
ClientFormRequest
class ClientFormRequest extends Request {
public function authorize()
{
return true;
}
public function rules()
{
}
public function validator(array $data)
{
return Validator::make($data, [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
]);
}
}
RegisterController
class RegisterController extends Controller {
public function create()
{
return view('Client.client');
}
public function store(ClientFormRequest $request)
{
// ClientFormRequest was valid
// create the client
Client::create([
'fullname' => $request->input('fullname'),
'email' => $request->input('email'),
]);
return Redirect::route('Client.client')
->with('message', 'Record Inserted!');
}
}

How add Custom Validation Rules when using Form Request Validation in Laravel 5

I am using form request validation method for validating request in laravel 5.I would like to add my own validation rule with form request validation method.My request class is given below.I want to add custom validation numeric_array with field items.
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array|numericarray']
];
My cusotom function is given below
Validator::extend('numericarray', function($attribute, $value, $parameters) {
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
How can use this validation method with about form request validation in laravel5?
While the above answer is correct, in a lot of cases you might want to create a custom validation only for a certain form request. You can leverage laravel FormRequest and use dependency injection to extend the validation factory. I think this solution is much simpler than creating a service provider.
Here is how it can be done.
use Illuminate\Validation\Factory as ValidationFactory;
class UpdateMyUserRequest extends FormRequest {
public function __construct(ValidationFactory $validationFactory)
{
$validationFactory->extend(
'foo',
function ($attribute, $value, $parameters) {
return 'foo' === $value;
},
'Sorry, it failed foo validation!'
);
}
public function rules()
{
return [
'username' => 'foo',
];
}
}
Using Validator::extend() like you do is actually perfectly fine you just need to put that in a Service Provider like this:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ValidatorServiceProvider extends ServiceProvider {
public function boot()
{
$this->app['validator']->extend('numericarray', function ($attribute, $value, $parameters)
{
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
}
public function register()
{
//
}
}
Then register the provider by adding it to the list in config/app.php:
'providers' => [
// Other Service Providers
'App\Providers\ValidatorServiceProvider',
],
You now can use the numericarray validation rule everywhere you want
The accepted answer works for global validation rules, but many times you will be validating certain conditions that are very specific to a form. Here's what I recommend in those circumstances (that seems to be somewhat intended from Laravel source code at line 75 of FormRequest.php):
Add a validator method to the parent Request your requests will extend:
<?php namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Validator;
abstract class Request extends FormRequest {
public function validator(){
$v = Validator::make($this->input(), $this->rules(), $this->messages(), $this->attributes());
if(method_exists($this, 'moreValidation')){
$this->moreValidation($v);
}
return $v;
}
}
Now all your specific requests will look like this:
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class ShipRequest extends Request {
public function rules()
{
return [
'shipping_country' => 'max:60',
'items' => 'array'
];
}
// Here we can do more with the validation instance...
public function moreValidation($validator){
// Use an "after validation hook" (see laravel docs)
$validator->after(function($validator)
{
// Check to see if valid numeric array
foreach ($this->input('items') as $item) {
if (!is_int($item)) {
$validator->errors()->add('items', 'Items should all be numeric');
break;
}
}
});
}
// Bonus: I also like to take care of any custom messages here
public function messages(){
return [
'shipping_country.max' => 'Whoa! Easy there on shipping char. count!'
];
}
}
Custom Rule Object
One way to do it is by using Custom Rule Object, this way you can define as many rule as you want without need to make changes in Providers and in controller/service to set new rules.
php artisan make:rule NumericArray
In NumericArray.php
namespace App\Rules;
class NumericArray implements Rule
{
public function passes($attribute, $value)
{
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
}
public function message()
{
return 'error message...';
}
}
Then in Form request have
use App\Rules\NumericArray;
.
.
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array', new NumericArray]
];
Alternatively to Adrian Gunawan's solution this now also can be approached like:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreBlogPost extends FormRequest
{
public function rules()
{
return [
'title' => ['required', 'not_lorem_ipsum'],
];
}
public function withValidator($validator)
{
$validator->addExtension('not_lorem_ipsum', function ($attribute, $value, $parameters, $validator) {
return $value != 'lorem ipsum';
});
$validator->addReplacer('not_lorem_ipsum', function ($message, $attribute, $rule, $parameters, $validator) {
return __("The :attribute can't be lorem ipsum.", compact('attribute'));
});
}
}
You need to override getValidatorInstance method in your Request class, for example this way:
protected function getValidatorInstance()
{
$validator = parent::getValidatorInstance();
$validator->addImplicitExtension('numericarray', function($attribute, $value, $parameters) {
foreach ($value as $v) {
if (!is_int($v)) {
return false;
}
}
return true;
});
return $validator;
}
You don't need to extend the validator to validate array items, you can validate each item of a array with "*" as you can see in
Array Validation
protected $rules = [
'shipping_country' => ['max:60'],
'items' => ['array'],
'items.*' => 'integer'
];
All answers on this page will solve you the problem, but... But the only right way by the Laravel conventions is solution from Ganesh Karki
One example:
Let’s take an example of a form to fill in Summer Olympic Games events – so year and city. First create one form.
<form action="/olimpicyear" method="post">
Year:<br>
<input type="text" name="year" value=""><br>
City:<br>
<input type="text" name="city" value=""><br><br>
<input type="submit" value="Submit">
</form>
Now, let’s create a validation rule that you can enter only the year of Olympic Games. These are the conditions
Games started in 1896
Year can’t be bigger than current year
Number should be divided by 4
Let’s run a command:
php artisan make:rule OlympicYear
Laravel generates a file app/Rules/OlympicYear.php. Change that file to look like this:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class OlympicYear implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
// Set condition that should be filled
return $value >= 1896 && $value <= date('Y') && $value % 4 == 0;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
// Set custom error message.
return ':attribute should be a year of Olympic Games';
}
}
Finally, how we use this class? In controller's store() method we have this code:
public function store(Request $request)
{
$this->validate($request, ['year' => new OlympicYear]);
}
If you want to create validation by Laravel conventions follow tutorial in link below. It is easy and very well explained. It helped me a lot. Link for original tutorial is here Tutorial link.
For me works the solution that give us lukasgeiter, but with a difference that we create a class with our custom validations ,like this, for laravel 5.2.* The next example is for add a validation to a range of date in where the second date has to be equals or more big that the first one
In app/Providers create ValidatorExtended.php
<?php
namespace App\Providers;
use Illuminate\Validation\Validator as IlluminateValidator;
class ValidatorExtended extends IlluminateValidator {
private $_custom_messages = array(
"after_or_equal" => ":attribute debe ser una fecha posterior o igual a
:date.",
);
public function __construct( $translator, $data, $rules, $messages = array(),
$customAttributes = array() ) {
parent::__construct( $translator, $data, $rules, $messages,
$customAttributes );
$this->_set_custom_stuff();
}
protected function _set_custom_stuff() {
//setup our custom error messages
$this->setCustomMessages( $this->_custom_messages );
}
/**
* La fecha final debe ser mayor o igual a la fecha inicial
*
* after_or_equal
*/
protected function validateAfterOrEqual( $attribute, $value, $parameters,
$validator) {
return strtotime($validator->getData()[$parameters[0]]) <=
strtotime($value);
}
} //end of class
Ok. now lets create the Service Provider. Create ValidationExtensionServiceProvider.php inside app/Providers, and we code
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class ValidationExtensionServiceProvider extends ServiceProvider {
public function register() {}
public function boot() {
$this->app->validator->resolver( function( $translator, $data, $rules,
$messages = array(), $customAttributes = array() ) {
return new ValidatorExtended( $translator, $data, $rules, $messages,
$customAttributes );
} );
}
} //end of class
Now we to tell Laravel to load this Service Provider, add to providers array at the end in config/app.php and
//Servicio para extender validaciones
App\Providers\ValidationExtensionServiceProvider::class,
now we can use this validation in our request in function rules
public function rules()
{
return [
'fDesde' => 'date',
'fHasta' => 'date|after_or_equal:fDesde'
];
}
or in Validator:make
$validator = Validator::make($request->all(), [
'fDesde' => 'date',
'fHasta' => 'date|after_or_equal:fDesde'
], $messages);
you have to notice that the name of the method that makes the validation has the prefix validate and is in camel case style validateAfterOrEqual but when you use the rule of validation every capital letter is replaced with underscore and the letter in lowercase letter.
All this I take it from https://www.sitepoint.com/data-validation-laravel-right-way-custom-validators// here explain in details. thanks to them.

Unset child object static variable from abstract parent class php

I am using Laravel and it's Validators.
I have the following code in my controller:
class ResellerController extends BaseController{
public function add() {
//some code before
$userValidator = new App\Services\Validators\UserCreateValidator();
//HERE I WANT TO REMOVE THE company KEY FROM THE RULES IN THE USERS CREATE VALIDATOR
$userValidator->removeRule('company');
//code execution continues
}
}
The UserCreateValidator extends a parent Validator class:
namespace App\Services\Validators;
class UserCreateValidator extends Validator {
public static $rules = array(
'firstName' => 'required',
'lastName' => 'required',
'email' => 'required|email|unique:users',
'company' => 'required'
);
}
And here is the base Validator class:
namespace App\Services\Validators;
abstract class Validator {
/**
* Validation rules
* #var array
*/
public static $rules;
//THIS CODE DOES NOT WORK IN THE CONTROLLER UP
public static function removeRule($ruleKey){
if(is_array($ruleKey))
{
foreach($ruleKey as $key)
{
if(!array_key_exists($key, static::$rules)) continue;
unset(static::$rules[$key]);
}
return true;
}
if(!array_key_exists($ruleKey, static::$rules)) //return false;
unset(static::$rules['company']);
return true;
}
}
The unsettting of the static::$rules[$key] in ResellerController does not work.
I can see in a XDEBUG session (after this line gets executed) that the static::$rules['company'] is still present in the UserCreateValidator as property.
I thought that Late Static Binding should solve this problem?
What is wrong?
The problem is solved. It was in the commented part in the:
if(!array_key_exists($ruleKey, static::$rules)) //return false;
The unsetting is working fine after I uncomment the return false.
Silly mistake :)

Model binding from input form

I'm working with Laravel and it seems in examples that they decide to implement validation inside controller, and I don't like it at all. What I want to ask is if there is some kind of bind method that can bind posted input fields to object that I created so that I can make sure my controllers are not messy.
I will try to explain what I want in code, I think it will be much clearer.
What I have
public function postRegister() {
$validation = Validator::make(Input::all(), array(
'email' => 'required|email',
'password' => 'required|min:6',
'name' => 'required|alpha',
'gender' => 'required|in:male,female'
));
if ($validation->fails()) {
Input::flashExcept('password');
return Redirect::to('register')->withErrors($validation)->withInput();
}
// Register user...
}
What I want to have
class UserRegisterDto {
public $email;
public $password;
public $name;
public $gender;
protected $errors;
public function isValid() {
// Validate it here, set errors if there are some
return $validator->isValid();
}
public function getErrors() {
return $this->errors;
}
}
public function postRegister() {
$user = Input::bind('UserRegisterDto'); // This is made-up function, I wonder if something like this exists
if ($user->isValid()) {
// Register user...
}
}
Ardent can help you to keep the controllers clean: https://github.com/laravelbook/ardent
"Ardent models use Laravel's built-in Validator class. Defining validation rules for a model is simple and is typically done in your model class as a static variable"

Categories