Cant get Yii Model custom rules to work - php

In a form i working on, i have this rules set which i want to validate. rate should be a a floating number. and price should be numbers with , and .
here is what i have so far
public function rules()
{
array('rate','type', 'type'=>'float', 'on' => 'loan-calculator'),
// EPriceValidator is a custom validation class
array('price', 'site.common.components.validate.EPriceValidator'),
}
In site.common.components.validate.EPriceValidator i have this
class EPriceValidator extends CRegularExpressionValidator
{
public $pattern = '/[^0-9,.]/';
}
when i change
array('price', 'site.common.components.validate.EPriceValidator'),
to
array('price', 'match', 'not' => true, 'pattern' => '/[^0-9,.]/'),
it works perfectly when validating on the fly. but i would rather put it into a class, this way i can reuse it thru out my site.
array('rate','type', 'type'=>'float', 'on' => 'loan-calculator'),
the code above on the other hand doesn't work at all. Any idea how i can fix these two problems? Or what am i'm doing wrong? Thanks

try something like this
class EPriceValidator extends CValidator
{
//Regular Expressions for numbers
private $pattern = '/[^0-9,.]/';
//Default error messages
private $err_msg = '{attribute} is an invalid.';
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* #param CModel $object the object being validated
* #param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
$pattern = $this->pattern;
// extract the attribute value from it's model object
$value = $object->$attribute;
if(!preg_match($pattern, $value))
{
$this->addError($object, $attribute, $this->err_msg);
}
}
/**
* Implementing Client Validation
*
* Returns the JavaScript needed for performing client-side validation.
* #param CModel $object the data object being validated
* #param string $attribute the name of the attribute to be validated.
* #return string the client-side validation script.
* #see CActiveForm::enableClientValidation
*/
public function clientValidateAttribute($object,$attribute)
{
// check the strength parameter used in the validation rule of our model
$pattern = $this->pattern;
//replace {attribute} with correct label
$params['{attribute}']=$object->getAttributeLabel($attribute);
$error_message = strtr($this->err_msg,$params);
return "
if(value.match(".$pattern.")) {
messages.push(".CJSON::encode($error_message).");
}
";
}
}
the validateAttribute() function overrides the CValidator class function for server side validation. And the clientValidateAttribute() function overrides the CValidator class function for client side validation.
for more information read this

Related

How can I create a custom validation rule and define it in Service Provider a form?

I'm making a form generator on a project, and we've decided to automatically upload files before the user submit their answers. The problem is then that we can't use a premade rule for the validation to check if the media as been uploaded if it's required, because the field will be empty at the submit. Plus, we also require a media if a radio button as a defined value (for example : do you need to rent a car? Yes/No; if yes, please upload a scan of your driving license).
I've read the documentation about custom validation rules, but the forms and ruleset are defined in a json stored in the db, so I can't call the rule like new CustomValidationRule. I wanted to create a shortcut to make it look like a "real" rule and that could be stored in my json with no problem.
Here is a code that is working to make my custom rule to do what I want.
AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
/**
* Boot the application events.
*
* #return void
*/
public function boot()
{
Validator::extend('media_required_if', function ($attribute, $value, $parameters, $validator) {
if ($validator->getData()[$parameters[0]] == $parameters[1]) {
$model = request()->route($parameters[2]);
$media = $model->getMedia('attachments', ['input_name' => $attribute]);
if (count($media) == 0) {
return false;
}
return true;
}
return true;
}, "The dropzone :attribute must contain at least a file.");
It is invoked like this in the ruleset media_required_if:rent_car,1,model. It's a rule can exclusively for an update, so I can have the model, check if media has been uploaded yet for this attribute (there can be more dropzones, all depending of other rules), and check if there is at least one file store. I need these 3 parameters.
But I don't think AppServiceProvider is the best place to store this rule, and I'd like to only keep the invokation here and the declaration with its snake case name.
Here's what I tried and is not working:
Validator::extend('media_required_if', new MediaRequiredIf, "The dropzone :attribute must contain at least a file.");
namespace App\Rules;
/// uses
class MediaRequiredIf implements DataAwareRule, InvokableRule, ValidatorAwareRule
{
protected $data = [];
protected $validator = [];
/**
* Run the validation rule.
*
* #param string $attribute
* #param mixed $value
* #param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
* #return void
*/
public function __invoke($attribute, $value, $fail)
{
dd($this->data, $this->validator);
// Here I want to put the code that works, but $this->data and $this->value aren't filled.
}
public function setData($data)
{
$this->data = $data;
return $this;
}
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
}
I don't understand but $this->data and $this->validator always return [], whatever I do.
I tried to follow the documentation but it's not really clear, and I also tried to follow older documentations (from 8.* to 5.2), but the code is really different and I don't want to make code that will be obsolete in a week. Is it even possible to do that?
Thanks a lot for your answers.
You can use required_if to check the driving licence.
Add a hidden input and check it after the file is uploaded. Then use exclude_if, so it will be excluded from validation.
https://laravel.com/docs/9.x/validation#conditionally-adding-rules

Lumen Custom Validation

I am trying to implement a custom validation rule within lumen and I am following the docs for lumen 5.6. It says to refer to laravel validation to see how to use the validation. I am currently trying to make a validation to check if the value is a true null or not. So $x === "" would mean it fails Here is my rule located in App\Rules folder I created.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class TrueNull implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if($value === "") {
return false;
} else {
return true;
}
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute cannot be an empty string.';
}
}
I copied this straight from lumen docs and make my modification to the passes function. Within my modal have
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
use App\Rules\TrueNull;
use Validator;
Then
public function validate($data)
{
// make a new validator object
$v = Validator::make($data,
[
'x' => ['regex:/^(?=.+)(?:[1-9]\d*|0)?(?:\.\d+)?$/', new TrueNull]
]
}
But the validation for TrueNull never happens am I missing a connection or something its really frustrating because the docs says this should work.
Here is my controller calling the update I am validating.
public function update(Request $request, $id)
{
/*
In middleware need to add community id to request.
*/
try {
$site = Site::findOrFail($id);
if ($site->validate($request->all())) {
$site->fill($request->all());
// save
$site->save();
} else {
return response()->json($site->errors(), 422);
}
} catch (Exception $e) {
return response()->json($e, 422);
}
return response()->json($site, 200);
}
For future reference I found a random snippet of code that offset the basic docs of Lumen. In my class for TrueNull instead of implements Rule I changed this to implements ImplicitRule and changed the use to \ImplicitRule and it is now catching that "" is not a null.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\ImplicitRule;
class TrueNull implements ImplicitRule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if($value === "") {
return false;
} else {
return true;
}
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute cannot be an empty string.';
}
}
The answer is greate by #Alexander Beyers but it doesn't work for Lumen 5.3. Here is how to create organised custom rules for the Lumen 5.3.
Create a Directory name Rules under app dir and Create the Following File:
namespace App\Rules;
use Illuminate\Support\Facades\Validator;
class AlphaSpace
{
public static function validate(){
//Extending the custom validation rule.
Validator::extend('alpha_spaces', function ($attribute, $value) {
// This will only accept alpha and spaces.
// If you want to accept hyphens use: /^[\pL\s-]+$/u.
return preg_match('/^[\pL\s]+$/u', $value);
});
}
}
Open the file resources/lang/en/validation and add the following under the Custom Validation:
Note:(under the Custom Validation is only for maintenance)
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'alpha_spaces' => 'The :attribute may only contain letters and spaces.',
Call the rule in app/Providers/AppServiceProvider::boot():
use HRM\Core\Rules\AlphaSpace;
class AppServiceProvider extends ServiceProvider
{
public function boot() {
AlphaSpace::validate();
}
// class will carry on with the stuffs!
Now you can use it anywhere you want to like this:
'first_name' => 'required|alpha_spaces|min:3|max:50',
'last_name' => 'required|alpha_spaces|min:3|max:50',
Version: Lumen 7.X
First, declare your rule in app/Providers/AppServiceProvider.php.
Create a boot() with your rule method as following (I registered a rule for phone number).
public function register()
{
//
}
public function boot()
{
app('validator')->extend('phone', function ($attribute, $value) {
return preg_match('%^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$%i', $value) && strlen($value) >= 10;
});
app('validator')->replacer('phone', function ($message, $attribute, $rule, $parameters) {
return 'Phone number has wrong format.';
});
}
Different part in opposite of Laravel, and most important is, that AppServiceProvider is not registered in Lumen by default.
You need to go to bootstrap/app.php and uncomment following line:
$app->register(App\Providers\AppServiceProvider::class);
Maybe you would like to do composer dumpautoload, just in case, but it should work without it.
Then, in your code:
$validator = Validator::make(
$request->all(),
[
'tel' => 'required|phone'
],
[
'tel.required' => 'Phone is required',
'tel.phone' => 'Phone has wrong format'
]
);
That should be it!

how to use laravel's validation rule in custom validation rule?

I have input $data =['identifier' = 'xxxxxxxxxx'];, and want to save the encrypt($data['identifier']) to the table info primary id column.
I've to validate before save it. Rule unique:info, id isn't suitable here, so I want to write a custom validation rule. And in the custom validation rule, I encrypt() the value first, then use the unique validation rule.
I know how to write a custom validation rule, but how to use the unique validation rule in my custom validation rule?
Rules "unique" and "exists" use the DatabasePresenceVerifier class. So, you don't need to really extend the unique rule, just access this presence verifier. For instance:
Validator::extend('encrypted_unique', function ($attribute, $value, $parameters, $validator) {
list ($table, $column, $ignore_id) = $parameters; // or hard-coded if fixed
$count = $validator->getPresenceVerifier()->getCount($table, $column, encrypt($value), $ignore_id);
return $count === 0;
});
Then you can use it as usual:
'identifier' => "encrypted_unique:table,column,$this_id"
Suppose you have A ModuleRequest that validates your inputs,you can write this method in this class
protected function validationData()
{
$all = parent::validationData();
$all['email'] = encrypt($all['email']);
return $all;
}
Laravel has Custom Validation Rules (https://laravel.com/docs/8.x/validation#using-rule-objects)
For example I have a table named clients who has two unique fields ecnrypt using Laravel's encryption services (https://laravel.com/docs/8.x/encryption) and because its encrypted, i can't aply the unique directive of validation method (https://laravel.com/docs/8.x/validation#rule-unique). The fields are code_client and email
That's the reason of implements a Custom Validation Rules.
this Service has two methods: passes and message. The method passes take two variables: $attributes (take de field to validate) and $value (take de value of field), and return true or false. Te method message retrieve message in case of failure.
In clients example i mentioned, folow the next steps:
php artisan make:rule ValidateFieldsClients
in class that composer creates ValidateFieldsClients, I have to declare a method for validate the fields in passes, I use this method for validate both fields (code_client and email).
next i complete de method message to retrieve the issue to user in views
additionally i declare a property $field to identify what´s the field it have the errors
The class ValidateFieldsClients example:
/***/class ValidateFieldsClients implements Rule{protected $field; /**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
$clients = client::all();
$this->field = $attribute;
foreach ($clients as $client ) {
if ($value == Crypt::decryptString($client->$attribute)) return false;
}
return true;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return strtoupper($this->field).' exists, check.';
}
}
Then to validate I use Form Request Validation (https://laravel.com/docs/8.x/validation#form-request-validation)
php artisan make:request ClientRequest
And in the validate method of the recently created class:
class ClientRequest extends FormRequest
{ /**
* 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 [
'code_client'=> ['required', new ValidateFieldsClients],
'email'=>['required', new ValidateFieldsClients],
];
}
Finally in controller:
public function store(ClientRequest $request)
{ $clientRequest = $request->validated();
foreach ($clientRequest as $key => $client) {
$encryptedClient[$key] = Crypt::encryptString($client);
}; client::create($encryptedClient+ [
'idorga' => 1,
'idcrea' => 1,
'idmodifica' => 1
]);
return redirect('clientes/create')->with('success', 'Registro creado correctamente');
//return redirect('cuadros')->with('success', 'Registro exitoso!');
}

Modify input before validation on Laravel 5.1

I'm trying to modify an user submitted input before validation success. I've followed this easy instructions, but when I test it on Laravel 5.1, It's not working. Am I doing something wrong?
This is my Request class on SSHAM\Http\Requests\UserCreateRequest.php
<?php
namespace SSHAM\Http\Requests;
use SSHAM\Http\Requests\Request;
class UserCreateRequest extends Request
{
// Some stuff not related with this problem
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
// Only for debug
$prova = $this->all();
echo "<pre>Inside Request - Before sanitize\n[" . $prova['public_key'] . "]</pre>\n";
// Call a function to sanitize user input
$this->sanitize();
// Only for debug
$prova = $this->all();
echo "<pre>Inside Request - After sanitize\n[" . $prova['public_key'] . "]</pre>\n";
return [
'username' => 'required|max:255|unique:users',
'public_key' => 'openssh_key:public',
];
}
/**
* Sanitizes user input. In special 'public_key' to remove carriage returns
*/
public function sanitize()
{
$input = $this->all();
// Removes carriage returns from 'public_key' input
$input['public_key'] = str_replace(["\n", "\t", "\r"], '', $input['public_key']);
$this->replace($input);
}
}
This is my custom validation rule on SSHAM\Providers\OpenSSHKeyValidatorServiceProvider.php
<?php
namespace SSHAM\Providers;
use Illuminate\Support\ServiceProvider;
class OpenSSHKeyValidatorServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
// Registering the validator extension with the validator factory
\Validator::extend('openssh_key', function ($attribute, $value, $parameters) {
// Some stuff not related with this problem
// Only for debug
echo "<pre>Inside Validator value\n[" . $value ."]</pre>\n";
dd();
return true;
});
}
// Some stuff not related with this problem
}
When I call for debugging I obtain this output:
Inside Request - Before sanitize
[blah
second line
third line]
Inside Request - After sanitize
[blah second line third line]
Inside Validator value
[blah
second line
third line]
Seems that sanitize() is working, but when value is treated on validation class it has not been sanitized.
This is a tricky one. I only figured out one way to achieve what you want.
The main point is, that it has no effect for the Validator if you change the Request Values in the rules() function.
You could do a workaround by adding a function to your UserCreateRequest:
protected function getValidatorInstance() {
$this->sanitize();
return parent::getValidatorInstance();
}
This overrides the parent's getValidatorInstance();
The parent's getValidatorInstance() method includes
return $factory->make(
$this->all(), $this->container->call([$this, 'rules']), $this->messages(), $this->attributes());
Which is reached before your code in the rules() function, so the old values (not affected by the changes in rules()) of $this->all() are used.
If you override that function in your own RequestClass you can manipulate the Request values before calling the actual parent's method.
UPDATE (L5.5)
If you are using the Controllers validate function you could do something like that:
$requestData = $request->all();
// modify somehow
$requestData['firstname'] = trim($requestData['firstname']);
$request->replace($requestData);
$values = $this->validate($request, $rules);
You can do this by modifying the request and setting the input value.
$request->request->set('key', 'value');
Or, if you prefer the request helper method.
request()->request->set('key', 'value');
If you are using a request MyClassRequest for keeping your validation then simply override all() method of Request class
public function all()
{
$attributes = parent::all();
//you can modify your inputs here before it is validated
$attribute['firstname'] = trim($attribute['firstname']);
$attribute['lastname'] = trim($attribute['lastname']);
return $attributes;
}
Hope this helps.
These answers no longer work for me in 5.5
you can use
protected function validationData()
{
$this->request->add([
'SomeField' => '..some code to modify it goes here'
]);
return $this->request->all();
}
the add method on request overwrites any existing input for that key.
You can see why this works in Illuminate\Foundation\Http\FormRequest, if you follow the trail
/**
* Get data to be validated from the request.
*
* #return array
*/
protected function validationData()
{
return $this->all();
}
You can use the prepareForValidation method
protected function prepareForValidation()
{
$this->merge(['field' => 'field value' ]) ;
}

Phalcon PHP custom validation rule raise an error

I'm using Phalcon framework, and I'm trying to make a custom validator:
<?php
use Phalcon\Validation\Validator,
Phalcon\Validation\ValidatorInterface,
Phalcon\Validation\Message;
class Currency extends Validator implements ValidatorInterface
{
/**
* Executes the validation
*
* #param Phalcon\Validation $validator
* #param string $attribute
* #return boolean
*/
public function validate($validator, $attribute)
{
$value = $validator->getValue($attribute);
if(! is_numeric($value))
{
$message = $this->getOption('message');
if(! $message){
$message = 'Not a valid currency.';
}
$validator->appendMessage(new Message($message, $attribute, 'Currency'));
return false;
}
return true;
}
}
I get this error when trying to use the validator above:
Unexpected value type: expected object implementing
Phalcon\Mvc\Model\ValidatorInterface, object of type Currency given
I put the validator class in /plugins/validators/Currency.php and auto-loaded it of course using DI.
Any clues?
this kind of validator cannot be used on model validation.
" Phalcon\Validation is an independent validation component that validates an arbitrary set of data. This component can be used to implement validation rules on data objects that do not belong to a model or collection. "
more info here: http://docs.phalconphp.com/en/latest/reference/validation.html#validators
for model validators you need to use another interface.
info here:
http://docs.phalconphp.com/en/latest/reference/models.html#validating-data-integrity

Categories