How can I add condition in rules laravel? - laravel

My controller like this :
<?php
use App\Http\Requests\StoreReceiveOrderRequest;
class SellController extends Controller
{
public function receiveOrder(StoreReceiveOrderRequest $request)
{
dd($request->all());
...
}
}
Before executed statement in the receiveOrder method, it will check rules on the StoreReceiveOrderRequest
The StoreReceiveOrderRequest like this :
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreReceiveOrderRequest extends FormRequest
{
public function rules()
{
return [
'is_follow_up'=>'required',
'note'=>'max:300' // I want to make this to be required if is_follow_up = n
];
}
}
the result of dd($request->all());, there are 2 results, depending user input
If the is_follow_up = y, the result like this :
Array
(
[is_follow_up] => y
)
If the is_follow_up = n, the result like this :
Array
(
[is_follow_up] => n
[note] => test
)
If is_follow_up = n, I want to make the note is required
If is_follow_up = y, the note is not required
Seems it must to add condition on the rules
How can I do it?

There is a validation rule that does exactly this already. The Laravel docs for validation list all the available rules.
'note' => 'required_if:is_follow_up,n|...'
Laravel 5.3 - Docs - Validation - Rule - required if

Just change your validation to the following-
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreReceiveOrderRequest extends FormRequest
{
public function rules()
{
$rules = ['is_follow_up'=>'required',
];
if (Input::get('is_follow_up')=='n') {
$rules += [
'note'=>'max:300'
];
}
}
}

You can also write your conditions in Laravel Request File
public function rules()
{
$rules = [
'name' => ['required', 'string', 'max:255'],
'order' => ['nullable', 'integer'],
'type' => ['required', 'in:category,brand,vendor,image'],
'category_id' => ['required_if:type,category'],
'brand_id' => ['required_if:type,brand'],
'vendor_id' => ['required_if:type,vendor'],
'image_size' => ['required_if:type,image','in:small,medium,large'],
'images.*' => ['required_if:type,image'],
'image_links' => ['required_if:type,image,url'],
];
if (request()->get('image_size') == 'large') {
$rules += [
'images' => 'max:1',
];
} elseif (request()->get('image_size') == 'medium') {
$rules += [
'images' => 'min:2|max:2',
];
} elseif (request()->get('image_size') == 'small') {
$rules += [
'images' => 'min:3|max:3',
];
}
return $rules;
}

Read The Laravel docs for list of all the available validation rules.
'note' => 'required_if:is_follow_up,n|...'

Related

Cannot return null for non-nullable field - rebing/graphql

I have a problem with GraphQL(rebing-graphql)/Larvel app. App works fine when I query normal GraphQL query(single not nested), but when I query nested one, I face "debugMessage":"Cannot return null for non-nullable field \"Make Type.name\".
Normal query which works fine:
{model{id,name}}
Nested query that I want to execute:
{model{id,name,make_id{id,name}}
Where am I made mistake?
Thanks in advance.
Make Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
class Make extends Model
{
use HasFactory;
protected $fillable = [
'name',
'logo',
'website',
];
public function models()
{
return $this->hasMany(\App\Models\Model::class);
}
}
Model Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model as MModel;
class Model extends MModel
{
use HasFactory;
protected $fillable = [
'make_id',
'name',
'website',
];
public function make()
{
return $this->belongsTo(Make::class);
}
}
MakeQuery (Graphql part)
<?php
namespace App\GraphQL\Queries;
use App\Models\Make;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
class MakeQuery extends Query
{
protected $attributes = [
'name' => 'Make Type',
'description' => 'Fetch Make Query'
];
public function args(): array
{
return ["id" => ['type' => Type::int()]];
}
public function type(): type
{
return Type::listOf(GraphQL::type('make'));
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return Make::where("id",$args['id'])->get();
}
return Make::all();
}
}
MakeType
<?php
namespace App\GraphQL\Types;
use App\Models\Make;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
class MakeType extends GraphQLType
{
protected $attributes = [
'name' => 'Make Type',
'description' => 'Make API Type',
'model' => Make::class
];
public function fields(): array
{
return [
"id" => [
'type' => Type::nonNull(Type::int()),
'description' => 'Make ID'
],
"name" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
],
"logo" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
],
"website" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Make ID'
]
];
}
}
ModelQuery
<?php
namespace App\GraphQL\Queries;
use App\Models\Model;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;
class ModelQuery extends Query
{
protected $attributes = [
'name' => 'Model Type',
'description' => 'Fetch Model Query'
];
public function args(): array
{
return [
"id" => ['type' => Type::int()]
];
}
public function type(): type
{
return Type::listOf(GraphQL::type('model'));
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return Model::where("id", $args['id'])->get();
}
return Model::all();
}
}
ModelType
<?php
namespace App\GraphQL\Types;
use App\Models\Make;
use App\Models\Model;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Type as GraphQLType;
class ModelType extends GraphQLType
{
protected $attributes = [
'name' => 'Model Type',
'description' => 'Model API Type',
'model' => Model::class
];
public function fields(): array
{
return [
"id" => [
'type' => Type::nonNull(Type::int()),
'description' => 'Model ID'
],
"make_id" => [
'type' => GraphQL::type('make'),
'description' => 'Model_ID'
],
"name" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Model Name'
],
"website" => [
'type' => Type::nonNull(Type::string()),
'description' => 'Model website'
]
];
}
}
There are several things that you have to done to get your code works:
First: Be sure that your tables are full and have valid key relations.
Second: In ModelType change make_id to makeId.
Third: Reload composer autoload with composer dump-autoload.
Finally: In your Model Model it's better to define a column like below:
public function makeId()
{
return $this->belongsTo(Make::class, 'make_id', 'id');
}
I hope these steps would help you.

Laravel validate if same item is selected more than once

In my application I have add more functionality for selected multiple devices. I need to show an error message if the user has selected the same device two or more times.
Here is my code.
class ValidateDeviceRequest extends FormRequest
{
private $data = [];
public function __construct()
{
$this->data = request()->all();
}
public function rules()
{
$rules = [
'devices' => ['required', 'array'],
'devices.*.device_company_id' => [
'required',
'integer',
'exists:device_companies,id,company_id,' . session()->get('COMPANY_ID')
],
];
foreach($this->data['devices'] as $key => $array)
{
$rules["devices.{$key}.device_id"] = [
'required',
'integer',
"exists:devices,id,device_company_id," . #$array["device_company_id"]
];
}
# returning
return $rules;
}
}
If you're just checking duplicated values inside the array. You can use the validation rule distinct for this.
'devices.*.device_company_id' => [
'distinct',
// ...
]
If you wish to validate duplicates within a model you can use the rule unique:model
Thanks to #Tommie. Here is my final code.
class ValidateDeviceRequest extends FormRequest
{
private $data = [];
public function __construct()
{
$this->data = request()->all();
}
public function rules()
{
$rules = [
'devices' => ['required', 'array'],
'devices.*.device_company_id' => [
'required',
'integer',
'exists:device_companies,id,company_id,' . session()->get('COMPANY_ID')
],
'devices.*.device_company_id' => [
'required',
'distinct',
]
];
foreach($this->data['devices'] as $key => $array)
{
$rules["devices.{$key}.device_id"] = [
'required',
'distinct',
'integer',
"exists:devices,id,device_company_id," . #$array["device_company_id"]
];
}
# returning
return $rules;
}
}
I also found this Laravel array validation for unique attribute in array but not required to be unique in table

Test the exist validator in Yii2 without database with mockeryBuilder()

I want to test my AR model without connect to database in Yii 2 so I use mockBuilder() but I dont know how can I pass the mock object to the model exist validator, for example:
class Comment extends ActiveRecord
{
public function rules()
{
return [
[['id', 'user_id', 'post_id'], 'comment'],
['comment', 'string',
'max' => 200
],
['user_id', 'exist',
'targetClass' => User::className(),
'targetAttribute' => 'id'
],
['post_id', 'exist',
'targetClass' => Post::className(),
'targetAttribute' => 'id'
]
];
}
}
class CommentTest extends TestCase
{
public function testValidateCorrectData()
{
$user = $this->getMockBuilder(User::className())
->setMethods(['find'])
->getMock();
$user->method('find')->willReturn(new User([
'id' => 1
]));
$post = $this->getMockBuilder(Post::className())
->setMethods(['find'])
->getMock();
$post->method('find')->willReturn(new Post([
'id' => 1
]));
// How can I pass to $user and $post to exist validator in Comment model?
$comment = new Comment([
'user_id' => 1,
'post_id' => 1,
'comment' => 'test...'
]);
expect_that($comment->validate());
}
}
ok, It's not a best code just I'd like to introduce what I want to do.
Yii2 ExistValidator uses ActiveQuery::exists() for check existence and you should replace generated validator to mockobject where the method createQuery returns mockobject of ActiveQuery where ::exists() return something you want (true/false) e.g.
$activeQueryMock = $this->getMockBuilder(ActiveQuery::className())
->disableOriginalConstructor()
->setMethods(['exists'])
->getMock();
$activeQueryMock->expects($this->any())
->method('exists')
->willReturn($value); //Your value here true/false
$model = $this->getMockBuilder(Comment::className())
->setMethods(['getActiveValidators'])
->getMock();
$model->expects($this->any())
->method('getActiveValidators')
->willReturnCallback(function () use ($activeQueryMock) {
$validators = (new Comment())->activeValidators;
foreach ($validators as $key => $validator) {
if (($validator instanceof ExistValidator) && ($validator->attributes = ['user_id'])) {
$mock = $this->getMockBuilder(ExistValidator::className())
->setConstructorArgs(['config' => get_object_vars($validator)])
->setMethods(['createQuery'])
->getMock();
$mock->expects($this->any())
->method('createQuery')
->willReturn($activeQueryMock);
$validators[$key] = $mock;
break;
}
}
return $validators;
});
$model->validate();

How can I add condition in validator interface laravel?

I see from here : https://github.com/andersao/laravel-validator
For example the code like this :
use \Prettus\Validator\LaravelValidator;
class PostValidator extends LaravelValidator {
protected $rules = [
ValidatorInterface::RULE_CREATE => [
'title' => 'required',
'text' => 'min:3',
'author'=> 'required'
],
ValidatorInterface::RULE_UPDATE => [
'title' => 'required'
]
];
}
I want to add condition if user is member(if(Auth::id())) then the field author not required
So the validator to be like this :
ValidatorInterface::RULE_CREATE => [
'title' => 'required',
'text' => 'min:3'
],
The author required if the user is guest(no login)
Whether it can be done?
the Laravel documentation has a section on custom validators
Since you cannot execute instructions in a class properties, you can try to override the create method of your Repository instance, in order to modify the $rules parameter before the create actually takes place.
So in your Repository class, override the method create:
public function create(array $attributes)
{
$oldRule = $this->rules[ValidatorInterface::RULE_CREATE]['author'];
if(Auth::guest()){ // or use the preferred check
unset($this->rules[ValidatorInterface::RULE_CREATE]['author']);
}
$this->makeValidator();
$res = parent::create($attributes);
$this->rules[ValidatorInterface::RULE_CREATE]['author'] = $oldRule;
return $res;
}
EDIT
Another method could be specifying custom validation logic in your PostValidator as follows:
use \Prettus\Validator\LaravelValidator;
class PostValidator extends LaravelValidator {
const RULE_CREATE_FOR_MEMBER = 'RULE_CREATE_FOR_MEMBER';
protected $rules = [
ValidatorInterface::RULE_CREATE => [
'title' => 'required',
'text' => 'min:3',
'author'=> 'required'
],
self::RULE_CREATE_FOR_MEMBER => [
'title' => 'required',
'text' => 'min:3'
],
ValidatorInterface::RULE_UPDATE => [
'title' => 'required'
]
];
public function passes($action = null)
{
if($action == ValidatorInterface::RULE_CREATE && \Auth::id()) {
$action = self::RULE_CREATE_FOR_MEMBER;
}
return parent::passes($action);
}
}
But again, you need to override the standard behavior, it's up to you to decide which is the simplest solution for your needs.

Cakephp 3.x Custom Validation Rules Creation and Using

In cakephp3 Custom Validation Rules:
How to Use a global function validation method.
$validator->add('title', 'custom', [
'rule' => 'validate_title'
]);
Please any one done before? Pls Provide me the some example program.
http://book.cakephp.org/3.0/en/core-libraries/validation.html#custom-validation-rules
I tried the above but it doesn't work..?
here is an Example for validation using global function concept:
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
public function validationDefault(Validator $validator) {
$validator->add('title',[
'notEmptyCheck'=>[
'rule'=>'notEmptyCheck',
'provider'=>'table',
'message'=>'Please enter the title'
]
]);
return $validator;
}
public function notEmptyCheck($value,$context){
if(empty($context['data']['title'])) {
return false;
} else {
return true;
}
}
<?php
namespace App\Model\Table;
use App\Model\Entity\Member;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class MembersTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->table('members');
}
public function validationDefault(Validator $validator) {
$validator
->add("cedula", [
"custom" => [
"rule" => [$this, "customFunction"], //add the new rule 'customFunction' to cedula field
"message" => "Enter the value greater than 1000"
]
]
)
->notEmpty('cedula');
return $validator;
}
public function customFunction($value, $context) {
return $value > 1000;
}
}
Use $context variable to comare current value with other fields like $value >= $context['data']['another_field_name'];
?>
Use $context variable to comare current value with other fields like $value >= $context['data']['another_field_name'];
This actually work for me (Cakephp 3.x). It's a good way if your condition is simple:
<?php
namespace App\Form;
use Cake\Form\Form;
use Cake\Validation\Validator;
class addPostForm extends Form {
protected function _buildValidator(Validator $validator) {
return $validator->allowEmpty('my_input', function ($context) {
return (#context['data']['an_other_input'] != "");
});
}
public function setErrors($errors) {
$this->_errors = $errors;
}
}
Here the form input my_input is allow to be empty only if a second input an_other_input is completed.
You can get form data with the variable $context['data'].
This is what worked for me for CakePHP 3.0. The important parameter here is the 'provider', which is not very clear in the document examples.
$validator->add('title', 'custom', [
'rule' => 'validate_title',
'provider' => 'table',
'message' => 'some error message'
]);
Then define your function. The variable passed to the function is
$check='title'
:
public function validate_title($check)
{
...
}
here is an Example for validation.
In your Table.
public function validationDefault(Validator $validator)
{
$validator = new Validator();
$validator
->notEmpty('username', 'A username is required')
->add('username', [
'emailValid' => [
'rule' => ['email', true],
'message' => 'You must provide a valid email'
],
'emailUnique' => [
'message' => 'The email you provided is already taken. Please provide another one.',
'rule' => 'validateUnique',
'provider' => 'table'
]
]);
return $validator;
}

Resources