custom Laravel Validation Rule example - validation

I'm having difficulty figuring out how to write a custom validation rule in Laravel 5.1. I've read the documentation, but it seems incomplete. Looking it over, I just don't see where I'm supposed to put my actual validation logic, such as if (stristr($string, 'test')) { ... and so on.
For another thing, it doesn't show in what method/array the error message defintions should go:
"foo" => "Your input was invalid!",
"accepted" => "The :attribute must be accepted.",
// The rest of the validation error messages...
My actual use case is somewhat strange, so for this question, let's use the example of validating a secure password. A secure password must be at least 8 characters long, containing a lowercase and uppercase letter, a number and a special character.
Actually, that's a pretty tall order for an example, so how about just checking for a number? Or running any string function on the value?
How would one create such a validation rule?

As described in the document you've linked, you need to put your validation logic inside the boot function of a ServiceProvider, (e.g. AppServiceProvider) by using the static extend method.
Here is a short example (associated with the example in the docs).
<?php
namespace App\Providers;
use Validator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('yourFunctionNameHere', function($attribute, $value, $parameters, $validator) {
return $value == 'yourTestValueHere'; //change the body as you need it
});
}
}
The input of the user is assigned to $value

Related

How to use custom keys in laravel routes without scoping?

When using custom keys Laravel forces us with scoping, for example, I have a route to getting a country and a post
api/countries/{country:slug}/posts/{post:slug}
but I can't get that using slug key because it doesn't have a relation with country, and in this case, I want to handle scope myself and I don't need implicitly scope binding, but I get an error (Call to undefined method App\Country::posts() ).
so because of that I cant using this Laravel feature. is there a way to turn the implicitly scope binding off?
If the posts are not related to the countries, it may not make sense to nest them in the URI?
But, nonetheless, to answer your question, you need to do one of two things:
Instead of setting {country:slug}, just use {country} and then override getKeyRouteName() function on your Country and Post models.
Alternatively, especially if you want to use the ID elsewhere, use explicit model binding.
To use a slug without custom keys in the routes file
class Post
{
[...]
public function getRouteKeyName()
{
return 'slug';
}
}
To use explicit route model binding
Add the following to the boot() method of your RouteServiceProvider:
public function boot()
{
parent::boot();
Route::bind('post', function ($value) {
return App\Post::where('slug', $value)->firstOrFail();
});
}

How can i get value from config file and set in $attribute variable in laravel model file?

I want to assign a default value in Laravel model but the value should come from the config file.
I am writing below code but its giving me error
protected $attributes = [
'is_generation' => true,
'price' => config('test.MY_PRICE'),
];
it's showing me an error like Constant expression contains invalid operations
How can I get value from config file and set in $attribute variable in Laravel model file?
You can use the saving model event by adding this code to your Eloquent Model:
protected static function boot()
{
// sets default values on saving
static::saving(function ($model) {
$model->price = $model->price ?? config('test.MY_PRICE');
});
parent::boot();
}
With this code in place, if the field price is null, it will have assigned a value from the config key just a moment before saving the Model in the database.
BTW you can change the check like if it's an empty string or less then a number and so on, this is only an example.
Class member variables are called "properties". You may also see them
referred to using other terms such as "attributes" or "fields", but
for the purposes of this reference we will use "properties". They are
defined by using one of the keywords public, protected, or private,
followed by a normal variable declaration. This declaration may
include an initialization, but this initialization must be a constant
value--that is, it must be able to be evaluated at compile time and
must not depend on run-time information in order to be evaluated.
The only way you can make this work is :-
<?php
namespace App;
class Amazon
{
protected $serviceURL;
public function __construct()
{
$this->serviceURL = config('api.amazon.service_url');
}
}
You can use attribute mutator as explained here: https://laravel.com/docs/5.8/eloquent-mutators#defining-a-mutator
Class Example{
public function setPriceAttribute(){
return $this->attributes['price'] = config('test.MY_PRICE');
}
}

Want to create custom validation rules with parameter in Laravel

I want to add a custom validation rules with parameter and in the Laravel documentation https://laravel.com/docs/5.8/validation#custom-validation-rules there is no validation parameters option. I want a validation rule like required_if.
You can pass it in the constructor
new CustomRule($parameter);
class CustomRule implements Rule
{
public function __construct($parameter)
{
$this->parameter = $parameter;
}
...
You can use sometimes method on validator instance. Use a required rules and add your condition in the function as below:
$v->sometimes('reason', 'required|max:500', function ($input) {
return $input->games >= 100;
});
The example above will check if games are more than or equal to 100, then user will required to have a reason, otherwise it will trigger an error.
The example is from Laravel documentation that you can find here here

Automatic generation of rules in laravel from migration

When I describe in database migration some field, that it must be at maximum 256 characters long I have to describe this in model too, so that when user enters 257 characters database does not generate exception.
May be there is a better way to do it?
The best practice for this would be to use request validation in your controller when you submit your form. I can give you an example of this
Firstly make a request using artisan
php artisan make:request MyRequest
This will make a file called MyRequest.php in App/Http/Requests
Add your validation rules to the rules() function
public function rules()
{
return [
'text_field_name' => 'required|string|max:256'
];
}
You can find all the validation options here
https://laravel.com/docs/5.4/validation#available-validation-rules
You then just need to apply the request to the function that accepts your POST data. The Data will be validated before the function is run, ensuring that you will not get database exceptions from string length
In your controller
public function myPostController(\App\Http\Requests\MyRequest $request)
{
//Do something
}

Override URL validation rule to tolerate whitespaces at ends of URL

I would like to override the standard URL validation rule to make it more tolerant of a whitespace character before or after the URL. Basically use the trim() function on the url before passing it to the standard URL validation handler.
I know I need to override that rule but I'm not exactly where and how I need to do it.
(Plus, the CakePHP API and book documentation are currently offline. Upgrades, I know...)
You can add custom validation rules in your Model classes, your Behavior classes, or in the AppModel class:
http://book.cakephp.org/view/150/Custom-Validation-Rules#Adding-your-own-Validation-Methods-152
Since you want to override an existing method, just give it the same name and signature as the original. Something like this might do the trick:
function url($check, $strict = false) {
return Validation::url(trim($check), $strict);
}
Why would you wanna do that?
Simply make sure all posted data is always trimmed.
Thats cleaner and more secure, anyway.
I have a component doing that in beforeFilter:
/** DATA PREPARATION **/
if (!empty($controller->data) && !Configure::read('DataPreparation.notrim')) {
$controller->data = $this->trimDeep($controller->data);
}
The trimDeep method:
/**
* #static
*/
function trimDeep($value) {
$value = is_array($value) ? array_map(array(&$this, 'trimDeep'), $value) : trim($value);
return $value;
}

Resources