Laravel 4 , adding custom validation using extend - php

I am trying to use the Extend function that the validation offer,
Here is what I have:
1). HomeController.php :
$rules = array(
'first_name'=>'required|regex:/^[a-z ,."-]+$/i|min:2',
'last_name'=>'required|regex:/^[a-z ,."-]+$/i|min:2',
'gender'=>'required|alpha|gendercheck',
'email'=>'required|email|unique:users,email,'.Input::get('id').',id',
'zip'=>'required|zipcheck|max:10',
);
2). Then to use the extend method I add it to routes.php:
Validator::extend('zipcheck', function($field,$value,$parameters){
// List of regular expressions to use, if a custom one isn't specified.
$countryRegs = array(
"US"=>"/^[\d]{5}(-[\d]{4})?$/",
"GB"=>"/^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$/",
"DE"=>"/\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b/",
"CA"=>"/^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])\ {0,1}(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$/",
"FR"=>"/^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$/",
"IT"=>"/^(V-|I-)?[0-9]{5}$/",
"AU"=>"/^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$/",
"NL"=>"/^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$/",
"ES"=>"/^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$/",
"DK"=>"/^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$/",
"SE"=>"/^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$/",
"BE"=>"/^[1-9]{1}[0-9]{3}$/"
);
// get country submitted..
$country = Input::get('country');
// check country if in the array..
if (key_exists($country , $countryRegs))
return preg_match($countryRegs[$country], $value);
else // other countries make sure no special characters in there
return preg_match('/^[a-z0-9- ]+$/i' , $value);
});
The problem is I want to keep my code organized and I dont want to add the validation extend to my routes.php
What is the best way where I can have those in its own class and call those from my HomeController and still it will work?
Thanks

There are lots of ways to do this. The way I like is make a file /app/validators.php (So it is in the same location as routes.php and filters.php)
Then go to app/start/global.php and add this at the bottom after the filters require:
require app_path().'/validators.php';
You can now declare all your extended validators in the validators.php file -and Laravel will use them.

There are several ways to do. Personally I like to extends validation by a ValidationService (I think it is much cleaner).
1) We assume you use PSR-4 to load you own company directory in composer.json:
{
"autoload": {
"psr-4": {
"Acme\\": "app/Acme"
}
...
},
}
You have to run composer dumpautoload.
2) Create your validation service provider:
app/Acme/Extension/Validation/ValidationServiceProvider.php
<?php
namespace Acme\Extension\Validation;
use Illuminate\Support\ServiceProvider;
class ValidationServiceProvider extends ServiceProvider {
public function register() {
}
public function boot() {
$this->app->validator->resolver(function($translator, $data, $rules, $messages) {
return new CustomValidator($translator, $data, $rules, $messages);
});
}
}
3) Register your service provider in app/config/app.php for autoloading:
<?php
return array(
'providers' => array(
...
'Acme\Extension\Validation\ValidationServiceProvider',
),
);
4) Create your custom validation rule(s):
app/Acme/Extension/Validation/CustomValidator.php
<?php
namespace Acme\Extension\Validation;
use Illuminate\Validation\Validator as IlluminateValidator;
class CustomValidator extends IlluminateValidator {
public function validateAlphaNumSpace($attribute, $value) {
return preg_match('/^([a-z\x20])+$/i', $value);
}
public function validateZip($attribute, $value, $parameters) {
...
}
}
5) You are ready to use your custom rule(s). For example if I want to use my AlphaNumSpace rule (useful in many cases because original AlphaNum rule doesn't allow space!):
$rules = [
'name' => 'required|alpha_num_space',
'zipcode' => 'required|zip',
];

Related

Defining methods which can be used in multiple controllers (in short library) in laravel 5

I want to define some methods which can be used in multiple place or multiple controllers. Basically these methods will be like libraries which will perform multiple queries.
My main aim is to avoid writing common logic multiple times by creating some libraries.
Please help me with it.
Thanks in advance :)
Depends what are you trying to do. Here are some options:
By default all your controllers extend App\Http\Controllers\Controller class. Just put all the shared logic between controllers there.
For complex queries to the database you can create a Repository and and inject in the controllers.
class UserRepository {
public function getActiveUsers() {
return Users::with('role')
->where('...')
->someQueryScopes()
->anotherQueryScope()
->yetAnotherScope();
}
}
class SomeController extends Controller {
public function index(UserRepository $repository) {
$users = $repository->getActiveUsers();
return view('users.index')->withUsers($users);
}
}
Yet another option is to create a Service classes for business logic and inject them in the constructor or relevant methods
class UserCreatorService {
public function create($email, $password){
$user = User::create(['email' => $email, 'password' => $password]);
$user->addRole('Subscriber');
Event::fire(new UserWasCreated($user));
return $user;
}
}
class RegisterController extends Controller {
public function store(Request $request, UserCreatorService $service) {
$user = $service->create($request->input('email'), $request->input('password'));
return view('home')->withUser($user);
}
}
it's simple, build your own library in your app folder then create new file MyLibrary.php
namespace App;
Class MyLibrary {
public static function sum($a, $b) {
return $a + $b;
}
}
then create alias in your config/app.php
'MyLibrary' => App\MyLibrary::class,
and finally you can call it in anywhere your controller
$result = MyLibrary::sum(4, 5); // your $result now have value of 9
You can make a folder named lib and inside that a functions.php file and in composer.json
...
"autoload": {
"files": [
"app/lib/functions.php"
],
...
and run composer dump-autoload
Use helper classes and create common functions in them.
Create a folder named helper in app folder and create a helper class in it. And then use that helper class's function in multiple controller or views as you want.

Custom validator in Laravel 5

I am upgrading my Laravel application from 4 to 5. However, I have a custom validator that I cannot get to work.
In L4, I made a validators.php file and included it in global.php using require app_path().'/validators.php';.
I tried doing somewhat the same in L5. I dropped a validator in app/Validators/Validators.php, and updated my composer.json.
"files": [
"app/Validators/Validators.php"
]
However, now nothing renders on any page. What've I done wrong?
Try the following:
Make a bind class where you can implement each rule you want extending Validator class.
Make a service provider that extends ServiceProvider.
Add your custom validator provider at config/app.php file.
You can create the bind at Services folder like this:
namespace MyApp\Services;
class Validator extends \Illuminate\Validation\Validator{
public function validateFoo($attribute, $value, $parameters){
return $value == "foo"
}
}
Then, use a service provider to extends the core:
namespace MyApp\Providers;
use MyApp\Services\Validator;
use Illuminate\Support\ServiceProvider;
class ValidatorServiceProvider extends ServiceProvider{
public function boot()
{
\Validator::resolver(function($translator, $data, $rules, $messages)
{
return new Validator($translator, $data, $rules, $messages);
});
}
public function register()
{
}
}
Finally, import your service provider at config/app.php like so:
'providers' => [
...
...
'MyApp\Providers\ValidatorServiceProvider';
]
so here's what I did on adding a custom validation. this is for laravel 5.1
run PHP Artisan make:request MyFormValidationRequest file is created under app\Requests\MyFormValidationRequest.php
Here's the initial code:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class MyFormValidationRequest 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 [
//
];
}
}
IMPORTANT: Change the return value of authorize() method to true, if you're not doing any authentication. it's initial value is false. else you get a white page with a "Forbidden" error message.
I added a rule under the function rules(), here's what it looks like
public function rules() {
return [
'activeuntil' => 'today_onwards'
];
}
today_onwards is my new validation.
I created a folder named 'Services' under App folder
I created a file named 'ValidatorExtended.php' under App\Services folder , here's the code below:
<?php
namespace App\Services;
use Illuminate\Validation\Validator;
use Carbon\Carbon;
class ValidatorExtended extends Validator {
private $_custom_messages = array(
"today_onwards" => "The :attribute must be today onwards",
);
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 );
}
protected function validateTodayOnwards( $attribute, $value ) {
$now = strtotime('-1 day');
$valueDateFormat = strtotime($value);
if($valueDateFormat > $now){
return true;
}
else {
return false;
}
}
}
Note: the validateTodayOnwards method is where you put your logic.
the name of the method should always start in "validate" then the name of your new validation key which should be in title case,
Another note your validation key should be separated by underscore and all small letters, in this case, "today_onwards". the underscore should be put before all first capital letters in the method name. I hope I explained it good.
TodayOnwards method is equivalent to validation name of "today_onwards",
another example, if I created validateOldPassword, your validation key should be "old_password".
I added below code in app\Providers\AppServiceProvider.php inside boot() method.
Validator::resolver(function($translator, $data, $rules, $messages = array(), $customAttributes = array())
{
return new ValidatorExtended($translator, $data, $rules, $messages, $customAttributes);
});
Don't forget to add below library, one is the Validator class and the other is your own class which is the "ValidatorExtended".
use App\Services\ValidatorExtended;
use Illuminate\Support\Facades\Validator;
Here's what the whole file looks like, [app\Providers\AppServiceProvider.php]
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\ValidatorExtended;
use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
Validator::resolver(function($translator, $data, $rules, $messages = array(), $customAttributes = array())
{
return new ValidatorExtended($translator, $data, $rules, $messages, $customAttributes);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
That's it. done. you created your own custom validation.
Additionally, if you want to use it in your controller, below is the code:
class testController extends Controller
{
public function updatePass(MiscValidation $request){
//code here
}
}
Instead of using Request Class you use your own class which is an extension of the Request class.

Laravel does not load subfolder from /app/models

I'm trying to arrange things properly in my app, so I created a folder called "validators" in my "/app/models" directory to keep my custom validation rules there. I expected it to be auto-loaded, but it's not. Here's the code of my validator:
class AuthValidator extends \Illuminate\Validation\Validator
{
public function validateActive($input, $value, $parameters)
{
if ( $input === "email" )
{
return User::where("email", $value)->first()->confirmed();
} else
{
return true;
}
}
}
Validator::resolver(function($translator, $data, $rules, $messages)
{
$messages['active'] = "You need to confirm your email first";
return new AuthValidator($translator, $data, $rules, $messages);
});
It works fine, if i put it in /app/models/User.php file, so the problem is not in the class definition.
I tried to make a separated "/app/validators" directory and put it into composer.json and /app/start/global.php files for autoloading. Still doesn't load, even though I did "artisan dump-autoload" and "composer dump-autoload" both.
Every time I try to use my custom rule "active", Laravel says "Method [validateActive] does not exist.".
I also tried to write "echo '123'; exit;" in the beginning of my file and it didn't work, so the file is obviously just not loaded.
It's especially weird, because other custom models are loaded.
UPD: I use the standard files structure and right now composer.json is not edited.
Did you add a namespace?
This worked for me:
app/models/validators/AuthValidator.php:
namespace app\models\validators;
class AuthValidator
{
function test()
{
dd("message from AuthValidator");
}
}
In controller:
use app\models\validators\AuthValidator;
class WelcomeController extends Controller {
public function __construct(AuthValidator $av)
{
$av->test();
}
}
It autoloaded, I didn't have to add it in composer.json

Laravel 4 custom validation - [method] does not exist

I am trying to implement and use a couple of my own custom validation methods in a class called WBValidation that extends Illuminate\Validation\Validator
I have this method validateCombinedRequired:
class WBValidation extends Illuminate\Validation\Validator{
public function validateCombinedRequired($attribute,$value,$parameters){
return ( $this->validateRequired($attribute,$value) )
and ( $this->validateRequired($parameters[0],$this->data[$parameters[0]]) );
}
}
I have placed this class in the libraries folder. For the framework to automatically pick up this class, it might be getting picked up because I can see it in autoload_classmap.php ( I might be wrong ).
When I try to use it in my model, I am getting this error which says BadMethodCallException","message":"Method [validateCombinedRequired] does not exist:
class UserModel extends Eloquent{
protected $table='user';
public static function VerifyUserAdd($data){
$rules = array('password'=>'required|combined_required:repassword');
// stuff
return Validator::make($data,$rules,$errormessages);
}
}
Is there anything else I should be doing? Please help me!
You need to register your custom Validator extension:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new WBValidation($translator, $data, $rules, $messages);
});
I suggest reading the documentation as it covers several was of adding your own custom validation rules.

How to add a custom input filter to Zend Framework 2?

I am using Zend Framework 2, and I have created a new input filter that will be used throughout my application. I know that I need to add the new filter to the FilterPluginManager's list so that I can call it when I create inputs. This is the code that I believe I need to use:
\Zend\Filter\FilterPluginManager::setInvokableClass('myFilter', 'Namespace\Filters\MyFilter');
However, I can't find where this should go. Should this be in the bootstrap, or one of the config files, or somewhere else?
this is the answer you want
https://packages.zendframework.com/docs/latest/manual/en/modules/zend.service-manager.quick-start.html
class Module
{
public function getServiceConfig()
{
return array(
'invokables' => array(
'UserInputFiler' => 'SomeModule\InputFilter\User',
),
);
}
}
In your Module, implement InputFilterProviderInterface and provide a Factory for the InputFilterPluginManager (AbstractPluginManager):
namespace YourModule;
use Zend\ModuleManager\Feature\InputFilterProviderInterface;
class Module implements InputFilterProviderInterface
{
public function getInputFilterConfig()
{
return [
'factories'=>[
'your_input_filter_name'=>\YourModule\Factories\InputFilterFactory::class
]
];
}
}
Now implement the factory:
namespace YourModule\Factories;
use Zend\Filter\StringTrim;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Validator\StringLength;
class InputFilterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$filter = new InputFilter();
$nameFilter = new Input("name");
$nameFilter->getValidatorChain()->attach(new StringLength([
'min'=>3,
'max'=>16
]));
$nameFilter->getFilterChain()->attach(new StringTrim());
$filter->add($nameFilter);
return $filter;
}
}
Now in your Controller-factory or other factory where you need the InputFilter you can access the InputFilterPluginManager:
$inputFilterManager = $controllerManager->getServiceLocator()->get('InputFilterManager');
return new YourController(
$inputFilterManager->get('your_input_filter_name')
);
Update, you can also add the factory to the module.config.php
'input_filters'=>[
'factories'=>[
'your_input_filter_name'=>InputFilterFactory::class
]
],

Categories