I wrote an API (Rest, JSON) and would like to validate incoming requests.
The API expects an field "Plan".
Within this field, the client have two choices: "o2_Plan" or "telekom_Plan".
One of them are required. So my validation looks like:
'Plan.o2_Plan' => 'required_without:Plan.telekom_Plan|array',
'Plan.telekom_Plan' => 'required_without:Plan.o2_Plan',
This is working fine. But there are another conditional rules within the plans:
'Plan.o2_Plan.tariff_variation_code' => 'required_without:Plan.o2_Plan.article_id|string',
'Plan.o2_Plan.article_id' => 'sometimes|required_without:Plan.o2_Plan.tariff_variation_code|string',
That means, you have to enter a tariff_variation_code OR an article_id or both of them.
But if the client only transfer the telekom_Plan (which must possible), the validation failed, with this errors:
{
"errors": {
"Plan.o2_Plan.tariff_variation_code": [
"The tariff_variation_code field is required when article_id is not present."
],
"Plan.o2_Plan.article_id": [
"The article_id field is required when tariff_variation_code is not present."
]
}
}
How can I achive, that the validation inside the o2_Plan only works, if the o2_Plan is present.
Thanks in advance.
best regards
Martin
I have the following solution:
Changed
'Plan.o2_Plan' => 'required_without:Plan.telekom_Plan|array',
to
'Plan.o2_Plan' => ['required_without:Plan.telekom_Plan', 'array', new o2Plan(request('Plan.o2_Plan'))],
My o2Plan rule class looks like:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class o2Plan implements Rule
{
protected $request;
protected $message_text = '';
/**
* Create a new rule instance.
*
* #param array $request
*/
public function __construct($request)
{
$this->request = $request;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if ((!isset($this->request['tariff_variation_code']) || empty($this->request['tariff_variation_code']))
&&
(!isset($this->request['article_id']) || empty($this->request['article_id']))
) {
$this->message_text = 'tariff_variation_code or article should not be empty';
return false;
}
return true;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return $this->message_text;
}
}
And it is working fine :-)
I'm working with Laravel 5.5 and I'm trying to do some complex field validations and I don't seem to be able to find a solution for this.
I have three fields:
field_a (Boolean)
field_b (String)
field_c (String)
I need to validate that if field_a is true then field_b OR field_c are not empty.
I've tried to do something like:
'field_b' => 'required_with:field_a|required_if:field_c,',
'field_c' => 'required_with:field_a|required_if:field_b,',
But this way makes both fields required if field_a has been passed to the request.
Thank you in advance for your help.
I haven't been able to use Laravel's built-in validation system to do this kind of validation so I have created my own custom rule. I leave it here just in case somebody finds it useful.
class IfXOR implements Rule {
private $required;
private $fields;
/**
* Create a new rule instance.
*
* #param bool $required
* #param mixed $fields
* #return void
*/
public function __construct($required, $fields) {
$this->required = $required;
$this->fields = $fields;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value) {
if(!$this->required) return true;
if(!is_array($this->fields)) return $value || !empty($this->fields);
return $value || !empty(array_filter(function($f) { return !empty($f); }, $this->fields));
}
/**
* Get the validation error message.
*
* #return string
*/
public function message() {
return 'The validation error message.';
}
}
Is it possible to use my custom validation rule in a validation request file?
i want to use my custom rule called EmployeeMail
here is the code of the request file
class CoachRequest 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()
{
$rules = [];
if ($this->isMethod('post') ) {
$rules = [
'name' => 'required|string',
'email' => 'required|email|employeemail', <<<--- this
'till' => 'required|date_format:H:i|after:from',
];
}
//TODO fix this
//TODO add custom messages for every field
return $rules;
}
}
it gives me an error when i try to use it like this
Method [validateEmployeemail] does not exist.
code of custom rule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class EmployeeMail implements Rule
{
/**
* 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)
{
// If mail is that of an employee and not a student pass it
return preg_match("/#test.nl$/", $value) === 1;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'Email is geen werknemers mail';
}
}
can i only use this custom rule like this?
$items = $request->validate([
'name' => [new FiveCharacters],
]);
Rutvij Kothari answered the question in the comments.
It seems you are validating string with a regular expression, the same logic can be achieved by regex buit-in validation method. Check it out. laravel.com/docs/5.5/validation#rule-regex No need to create your own validation rule. – Rutvij Kothari
If you want to use your validation pass it into an array. like this. 'email' => ['required', 'email', new employeemail]
How can I have a unique validation rule on 2 fields?
a. The application should not allow two people to have the same identical first name and last name.
It is allowed that the users fills in only a first name or only a last name. Because the user may have only one of them.
b. But if the user enters only a first name (Glen), no other person in the table should have the same (first name = 'Glen' and last name = null). another 'Glen Smith' ok.
I tried the following rule. It works great when both fields (first and last name) are not null:
'firstName' => 'unique:people,firstName,NULL,id,lastName,' . $request->lastName
This rule fails on b. when only one field is present.
Any hint?
The built in unique validator wouldn't really support what you're trying to do. It's purpose is to ensure that a single valid is unique in the database, rather than a composite of two values. However, you can create a custom validator:
Validator::extend('uniqueFirstAndLastName', function ($attribute, $value, $parameters, $validator) {
$count = DB::table('people')->where('firstName', $value)
->where('lastName', $parameters[0])
->count();
return $count === 0;
});
You could then access this new rule with:
'firstName' => "uniqueFirstAndLastName:{$request->lastName}"
You'll probably find you might need to tweak your database query a little bit as it's untested.
I think you are looking for something like that:
'unique:table_name,column1,null,null,column2,'.$request->column2.',column3,check3'
This is an extensive answer to this question and how to create Laravel custom validator generally, you can simply copy and paste, and try to understand later:
Step 1: Create a provider app/Providers/CustomValidatorProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator as ValidatorFacade;
/**
* Provider for custom validators. Handles registration for custom validators.
*
*/
class CustomValidatorProvider extends ServiceProvider {
/**
* An array of fully qualified class names of the custom validators to be
* registered.
*
* #var array
*/
protected $validators = [
\App\Validators\MultipleUniqueValidator::class,
];
/**
* Bootstrap the application services.
*
* #return void
* #throws \Exception
*/
public function boot() {
//register custom validators
foreach ($this->validators as $class) {
$customValidator = new $class();
ValidatorFacade::extend($customValidator->getName(), function() use ($customValidator) {
//set custom error messages on the validator
func_get_args()[3]->setCustomMessages($customValidator->getCustomErrorMessages());
return call_user_func_array([$customValidator, "validate"], func_get_args());
});
ValidatorFacade::replacer($customValidator->getName(), function() use ($customValidator) {
return call_user_func_array([$customValidator, "replacer"], func_get_args());
});
}
}
/**
* Register the application services.
*
* #return void
*/
public function register() {
//
}
}
Step 2: Update your app.php in your config folder config/app.php to include your created provider in the provider array
App\Providers\CustomValidatorProvider::class,
Step 3: Create your custom validator, in my case, I am creating multiple unique fields validator app/Validators/MultipleUniqueValidator.php
<?php
namespace App\Validators;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Validation\Validator;
/**
* Multiple field uniqueness in laravel
*/
class MultipleUniqueValidator{
/**
* Name of the validator.
*
* #var string
*/
protected $name = "multiple_unique";
/**
* Return the name of the validator. This is the name that is used to specify
* that this validator be used.
*
* #return string name of the validator
*/
public function getName(): string {
return $this->name;
}
/**
*
* #param string $message
* #param string $attribute
* #param string $rule
* #param array $parameters
* #return string
*/
public function replacer(string $message, string $attribute, string $rule, array $parameters): string {
unset($parameters[0]);
$replacement = implode(", ", $parameters);
$replacement = str_replace("_", " ", $replacement);
$replacement = Str::replaceLast(", ", " & ", $replacement);
$replacement = Str::title($replacement);
return str_replace(":fields", "$replacement", $message);
}
/**
*
* #param string $attribute
* #param mixed $value
* #param array $parameters
* #param Validator $validator
* #return bool
* #throws \Exception
*/
public function validate(string $attribute, $value, array $parameters, Validator $validator): bool {
$model = new $parameters[0];
if (!$model instanceof Model) {
throw new \Exception($parameters[0] . " is not an Eloquent model");
}
unset($parameters[0]);
$this->fields = $parameters;
$query = $model->query();
$request = app("request");
foreach($parameters as $parameter){
$query->where($parameter, $request->get($parameter));
}
return $query->count() == 0;
}
/**
* Custom error messages
*
* #return array
*/
public function getCustomErrorMessages(): array {
return [
$this->getName() => ":fields fields should be unique"
];
}
}
Now you can do this in your request
'ANY_FIELD_CAN_CARRY_IT' => 'required|numeric|multiple_unique:'.YOUR_MODEL_HERE::class.',FIELD_1,FIELD_2,FIELD_3...',
Laravel now allows you to add where clauses into the unique rule.
In your case you could do something like this:
'firstName' => [
Rule::unique('people', 'firstName')->where(function ($query) use ($lastName) {
return $query->where('lastName', $lastName);
})
],
in my case this works just fine (in controller):
$request->validate([
'firstName' => 'required|min:3|max:255|unique:people,firstName,NULL,id,lastname,' . $request->input('lastname'),
], [
'unique' => 'Some message for "unique" error',
]);
You can do it if the Validator class isn't required for you:
if(Model::query()->where([
'column_1' => 'data_1',
'column_2' => 'data_2'
])->exists())
{
// some code..
}
I am right now getting myself more and more familiar with Zend Framework 2 and in the meantime I was getting myself updated with the validation part in Zend Framework 2. I have seen few examples how to validate the data from the database using Zend Db adapter, for example the code from the Zend Framework 2 official website:
//Check that the username is not present in the database
$validator = new Zend\Validator\Db\NoRecordExists(
array(
'table' => 'users',
'field' => 'username'
)
);
if ($validator->isValid($username)) {
// username appears to be valid
} else {
// username is invalid; print the reason
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}
Now my question is how can do the validation part?
For example, I need to validate a name before inserting into database to check that the same name does not exist in the database, I have updated Zend Framework 2 example Album module to use Doctrine 2 to communicate with the database and right now I want to add the validation part to my code.
Let us say that before adding the album name to the database I want to validate that the same album name does not exist in the database.
Any information regarding this would be really helpful!
if you use the DoctrineModule, there is already a validator for your case.
I had the same problem and solved it this way:
Create a custom validator class, name it something like NoEntityExists (or whatever you want).
Extend Zend\Validator\AbstractValidator
Provide a getter and setter for Doctrine\ORM\EntityManager
Provide some extra getters and setters for options (entityname, ...)
Create an isValid($value) method that checks if a record exists and returns a boolean
To use it, create a new instance of it, assign the EntityManager and use it just like any other validator.
To get an idea of how to implement the validator class, check the validators that already exist (preferably a simple one like Callback or GreaterThan).
Hope I could help you.
// Edit: Sorry, I'm late ;-)
So here is a quite advanced example of how you can implement such a validator.
Note that I added a translate() method in order to catch language strings with PoEdit (a translation helper tool that fetches such strings from the source codes and puts them into a list for you). If you're not using gettext(), you can problably skip that.
Also, this was one of my first classes with ZF2, I wouldn't put this into the Application module again. Maybe, create a new module that fits better, for instance MyDoctrineValidator or so.
This validator gives you a lot of flexibility as you have to set the query before using it. Of course, you can pre-define a query and set the entity, search column etc. in the options. Have fun!
<?php
namespace Application\Validator\Doctrine;
use Zend\Validator\AbstractValidator;
use Doctrine\ORM\EntityManager;
class NoEntityExists extends AbstractValidator
{
const ENTITY_FOUND = 'entityFound';
protected $messageTemplates = array();
/**
* #var EntityManager
*/
protected $entityManager;
/**
* #param string
*/
protected $query;
/**
* Determines if empty values (null, empty string) will <b>NOT</b> be included in the check.
* Defaults to true
* #var bool
*/
protected $ignoreEmpty = true;
/**
* Dummy to catch messages with PoEdit...
* #param string $msg
* #return string
*/
public function translate($msg)
{
return $msg;
}
/**
* #return the $ignoreEmpty
*/
public function getIgnoreEmpty()
{
return $this->ignoreEmpty;
}
/**
* #param boolean $ignoreEmpty
*/
public function setIgnoreEmpty($ignoreEmpty)
{
$this->ignoreEmpty = $ignoreEmpty;
return $this;
}
/**
*
* #param unknown_type $entityManager
* #param unknown_type $query
*/
public function __construct($entityManager = null, $query = null, $options = null)
{
if(null !== $entityManager)
$this->setEntityManager($entityManager);
if(null !== $query)
$this->setQuery($query);
// Init messages
$this->messageTemplates[self::ENTITY_FOUND] = $this->translate('There is already an entity with this value.');
return parent::__construct($options);
}
/**
*
* #param EntityManager $entityManager
* #return \Application\Validator\Doctrine\NoEntityExists
*/
public function setEntityManager(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
return $this;
}
/**
* #return the $query
*/
public function getQuery()
{
return $this->query;
}
/**
* #param field_type $query
*/
public function setQuery($query)
{
$this->query = $query;
return $this;
}
/**
* #return \Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->entityManager;
}
/**
* (non-PHPdoc)
* #see \Zend\Validator\ValidatorInterface::isValid()
* #throws Exception\RuntimeException() in case EntityManager or query is missing
*/
public function isValid($value)
{
// Fetch entityManager
$em = $this->getEntityManager();
if(null === $em)
throw new Exception\RuntimeException(__METHOD__ . ' There is no entityManager set.');
// Fetch query
$query = $this->getQuery();
if(null === $query)
throw new Exception\RuntimeException(__METHOD__ . ' There is no query set.');
// Ignore empty values?
if((null === $value || '' === $value) && $this->getIgnoreEmpty())
return true;
$queryObj = $em->createQuery($query)->setMaxResults(1);
$entitiesFound = !! count($queryObj->execute(array(':value' => $value)));
// Set Error message
if($entitiesFound)
$this->error(self::ENTITY_FOUND);
// Valid if no records are found -> result count is 0
return ! $entitiesFound;
}
}