This commit is contained in:
2026-05-01 23:40:14 +08:00
commit b8f599a617
3867 changed files with 478663 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use InvalidArgumentException;
class AnyOf implements Rule, ValidatorAwareRule
{
/**
* The rules to match against.
*
* @var array
*/
protected array $rules = [];
/**
* The validator performing the validation.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* Sets the validation rules to match against.
*
* @param array $rules
*
* @throws \InvalidArgumentException
*/
public function __construct($rules)
{
if (! is_array($rules)) {
throw new InvalidArgumentException('The provided value must be an array of validation rules.');
}
$this->rules = $rules;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
foreach ($this->rules as $rule) {
$validator = Validator::make(
Arr::isAssoc(Arr::wrap($value)) ? $value : [$value],
Arr::isAssoc(Arr::wrap($rule)) ? $rule : [$rule],
$this->validator->customMessages,
$this->validator->customAttributes
);
if ($validator->passes()) {
return true;
}
}
return false;
}
/**
* Get the validation error messages.
*
* @return array
*/
public function message()
{
$message = $this->validator->getTranslator()->get('validation.any_of');
return $message === 'validation.any_of'
? ['The :attribute field is invalid.']
: $message;
}
/**
* Set the current validator.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Stringable;
use function Illuminate\Support\enum_value;
class ArrayRule implements Stringable
{
/**
* The accepted keys.
*
* @var array
*/
protected $keys;
/**
* Create a new array rule instance.
*
* @param \Illuminate\Contracts\Support\Arrayable|array|null $keys
*/
public function __construct($keys = null)
{
if ($keys instanceof Arrayable) {
$keys = $keys->toArray();
}
$this->keys = is_array($keys) ? $keys : func_get_args();
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (empty($this->keys)) {
return 'array';
}
$keys = array_map(
static fn ($key) => enum_value($key),
$this->keys,
);
return 'array:'.implode(',', $keys);
}
}
+86
View File
@@ -0,0 +1,86 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Facades\Gate;
class Can implements Rule, ValidatorAwareRule
{
/**
* The ability to check.
*
* @var string
*/
protected $ability;
/**
* The arguments to pass to the authorization check.
*
* @var array
*/
protected $arguments;
/**
* The current validator instance.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* Constructor.
*
* @param string $ability
* @param array $arguments
*/
public function __construct($ability, array $arguments = [])
{
$this->ability = $ability;
$this->arguments = $arguments;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$arguments = $this->arguments;
$model = array_shift($arguments);
return Gate::allows($this->ability, array_filter([$model, ...$arguments, $value]));
}
/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
$message = $this->validator->getTranslator()->get('validation.can');
return $message === 'validation.can'
? ['The :attribute field contains an unauthorized value.']
: $message;
}
/**
* Set the current validator.
*
* @param \Illuminate\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Stringable;
use function Illuminate\Support\enum_value;
class Contains implements Stringable
{
/**
* The values that should be contained in the attribute.
*
* @var array
*/
protected $values;
/**
* Create a new contains rule instance.
*
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|array|string $values
*/
public function __construct($values)
{
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->values = is_array($values) ? $values : func_get_args();
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$values = array_map(function ($value) {
$value = enum_value($value);
return '"'.str_replace('"', '""', (string) $value).'"';
}, $this->values);
return 'contains:'.implode(',', $values);
}
}
+238
View File
@@ -0,0 +1,238 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use function Illuminate\Support\enum_value;
trait DatabaseRule
{
/**
* The table to run the query against.
*
* @var string
*/
protected $table;
/**
* The column to check on.
*
* @var string
*/
protected $column;
/**
* The extra where clauses for the query.
*
* @var array
*/
protected $wheres = [];
/**
* The array of custom query callbacks.
*
* @var array
*/
protected $using = [];
/**
* Create a new rule instance.
*
* @param string $table
* @param string $column
*/
public function __construct($table, $column = 'NULL')
{
$this->column = $column;
$this->table = $this->resolveTableName($table);
}
/**
* Resolves the name of the table from the given string.
*
* @param string $table
* @return string
*/
public function resolveTableName($table)
{
if (! str_contains($table, '\\') || ! class_exists($table)) {
return $table;
}
if (is_subclass_of($table, Model::class)) {
$model = new $table;
if (str_contains($model->getTable(), '.')) {
return $table;
}
return implode('.', array_map(function (string $part) {
return trim($part, '.');
}, array_filter([$model->getConnectionName(), $model->getTable()])));
}
return $table;
}
/**
* Set a "where" constraint on the query.
*
* @param \Closure|string $column
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|\Closure|array|string|int|bool|null $value
* @return $this
*/
public function where($column, $value = null)
{
if ($value instanceof Arrayable || is_array($value)) {
return $this->whereIn($column, $value);
}
if ($column instanceof Closure) {
return $this->using($column);
}
if (is_null($value)) {
return $this->whereNull($column);
}
$value = enum_value($value);
$this->wheres[] = compact('column', 'value');
return $this;
}
/**
* Set a "where not" constraint on the query.
*
* @param string $column
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|array|string|int $value
* @return $this
*/
public function whereNot($column, $value)
{
if ($value instanceof Arrayable || is_array($value)) {
return $this->whereNotIn($column, $value);
}
$value = enum_value($value);
return $this->where($column, '!'.$value);
}
/**
* Set a "where null" constraint on the query.
*
* @param string $column
* @return $this
*/
public function whereNull($column)
{
return $this->where($column, 'NULL');
}
/**
* Set a "where not null" constraint on the query.
*
* @param string $column
* @return $this
*/
public function whereNotNull($column)
{
return $this->where($column, 'NOT_NULL');
}
/**
* Set a "where in" constraint on the query.
*
* @param string $column
* @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|array $values
* @return $this
*/
public function whereIn($column, $values)
{
return $this->where(function ($query) use ($column, $values) {
$query->whereIn($column, $values);
});
}
/**
* Set a "where not in" constraint on the query.
*
* @param string $column
* @param \Illuminate\Contracts\Support\Arrayable|\BackedEnum|array $values
* @return $this
*/
public function whereNotIn($column, $values)
{
return $this->where(function ($query) use ($column, $values) {
$query->whereNotIn($column, $values);
});
}
/**
* Ignore soft deleted models during the existence check.
*
* @param string $deletedAtColumn
* @return $this
*/
public function withoutTrashed($deletedAtColumn = 'deleted_at')
{
$this->whereNull($deletedAtColumn);
return $this;
}
/**
* Only include soft deleted models during the existence check.
*
* @param string $deletedAtColumn
* @return $this
*/
public function onlyTrashed($deletedAtColumn = 'deleted_at')
{
$this->whereNotNull($deletedAtColumn);
return $this;
}
/**
* Register a custom query callback.
*
* @param \Closure $callback
* @return $this
*/
public function using(Closure $callback)
{
$this->using[] = $callback;
return $this;
}
/**
* Get the custom query callbacks for the rule.
*
* @return array
*/
public function queryCallbacks()
{
return $this->using;
}
/**
* Format the where clauses.
*
* @return string
*/
protected function formatWheres()
{
return (new Collection($this->wheres))
->map(fn ($where) => $where['column'].','.'"'.str_replace('"', '""', $where['value']).'"')
->implode(',');
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
namespace Illuminate\Validation\Rules;
use DateTimeInterface;
use Illuminate\Support\Arr;
use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Macroable;
use Stringable;
class Date implements Stringable
{
use Conditionable, Macroable;
/**
* The format of the date.
*/
protected ?string $format = null;
/**
* The constraints for the date rule.
*/
protected array $constraints = [];
/**
* Ensure the date has the given format.
*/
public function format(string $format): static
{
$this->format = $format;
return $this;
}
/**
* Ensure the date is before today.
*/
public function beforeToday(): static
{
return $this->before('today');
}
/**
* Ensure the date is after today.
*/
public function afterToday(): static
{
return $this->after('today');
}
/**
* Ensure the date is before or equal to today.
*/
public function todayOrBefore(): static
{
return $this->beforeOrEqual('today');
}
/**
* Ensure the date is after or equal to today.
*/
public function todayOrAfter(): static
{
return $this->afterOrEqual('today');
}
/**
* Ensure the date is in the past.
*/
public function past(): static
{
return $this->before('now');
}
/**
* Ensure the date is in the future.
*/
public function future(): static
{
return $this->after('now');
}
/**
* Ensure the date is now or in the past.
*/
public function nowOrPast(): static
{
return $this->beforeOrEqual('now');
}
/**
* Ensure the date is now or in the future.
*/
public function nowOrFuture(): static
{
return $this->afterOrEqual('now');
}
/**
* Ensure the date is before the given date or date field.
*/
public function before(DateTimeInterface|string $date): static
{
return $this->addRule('before:'.$this->formatDate($date));
}
/**
* Ensure the date is after the given date or date field.
*/
public function after(DateTimeInterface|string $date): static
{
return $this->addRule('after:'.$this->formatDate($date));
}
/**
* Ensure the date is on or before the specified date or date field.
*/
public function beforeOrEqual(DateTimeInterface|string $date): static
{
return $this->addRule('before_or_equal:'.$this->formatDate($date));
}
/**
* Ensure the date is on or after the given date or date field.
*/
public function afterOrEqual(DateTimeInterface|string $date): static
{
return $this->addRule('after_or_equal:'.$this->formatDate($date));
}
/**
* Ensure the date is between two dates or date fields.
*/
public function between(DateTimeInterface|string $from, DateTimeInterface|string $to): static
{
return $this->after($from)->before($to);
}
/**
* Ensure the date is between or equal to two dates or date fields.
*/
public function betweenOrEqual(DateTimeInterface|string $from, DateTimeInterface|string $to): static
{
return $this->afterOrEqual($from)->beforeOrEqual($to);
}
/**
* Add custom rules to the validation rules array.
*/
protected function addRule(array|string $rules): static
{
$this->constraints = array_merge($this->constraints, Arr::wrap($rules));
return $this;
}
/**
* Format the date for the validation rule.
*/
protected function formatDate(DateTimeInterface|string $date): string
{
return $date instanceof DateTimeInterface
? $date->format($this->format ?? 'Y-m-d')
: $date;
}
/**
* Convert the rule to a validation string.
*/
public function __toString(): string
{
return implode('|', [
$this->format === null ? 'date' : 'date_format:'.$this->format,
...$this->constraints,
]);
}
}
+176
View File
@@ -0,0 +1,176 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
class Dimensions implements Stringable
{
use Conditionable;
/**
* The constraints for the dimensions rule.
*
* @var array
*/
protected $constraints = [];
/**
* Create a new dimensions rule instance.
*
* @param array $constraints
*/
public function __construct(array $constraints = [])
{
$this->constraints = $constraints;
}
/**
* Set the "width" constraint.
*
* @param int $value
* @return $this
*/
public function width($value)
{
$this->constraints['width'] = $value;
return $this;
}
/**
* Set the "height" constraint.
*
* @param int $value
* @return $this
*/
public function height($value)
{
$this->constraints['height'] = $value;
return $this;
}
/**
* Set the "min width" constraint.
*
* @param int $value
* @return $this
*/
public function minWidth($value)
{
$this->constraints['min_width'] = $value;
return $this;
}
/**
* Set the "min height" constraint.
*
* @param int $value
* @return $this
*/
public function minHeight($value)
{
$this->constraints['min_height'] = $value;
return $this;
}
/**
* Set the "max width" constraint.
*
* @param int $value
* @return $this
*/
public function maxWidth($value)
{
$this->constraints['max_width'] = $value;
return $this;
}
/**
* Set the "max height" constraint.
*
* @param int $value
* @return $this
*/
public function maxHeight($value)
{
$this->constraints['max_height'] = $value;
return $this;
}
/**
* Set the "ratio" constraint.
*
* @param float $value
* @return $this
*/
public function ratio($value)
{
$this->constraints['ratio'] = $value;
return $this;
}
/**
* Set the minimum aspect ratio.
*
* @param float $value
* @return $this
*/
public function minRatio($value)
{
$this->constraints['min_ratio'] = $value;
return $this;
}
/**
* Set the maximum aspect ratio.
*
* @param float $value
* @return $this
*/
public function maxRatio($value)
{
$this->constraints['max_ratio'] = $value;
return $this;
}
/**
* Set the aspect ratio range.
*
* @param float $min
* @param float $max
* @return $this
*/
public function ratioBetween($min, $max)
{
$this->constraints['min_ratio'] = $min;
$this->constraints['max_ratio'] = $max;
return $this;
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$result = '';
foreach ($this->constraints as $key => $value) {
$result .= "$key=$value,";
}
return 'dimensions:'.substr($result, 0, -1);
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Stringable;
use function Illuminate\Support\enum_value;
class DoesntContain implements Stringable
{
/**
* The values that should not be contained in the attribute.
*
* @var array
*/
protected $values;
/**
* Create a new doesntContain rule instance.
*
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|array|string $values
*/
public function __construct($values)
{
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->values = is_array($values) ? $values : func_get_args();
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$values = array_map(function ($value) {
$value = enum_value($value);
return '"'.str_replace('"', '""', (string) $value).'"';
}, $this->values);
return 'doesnt_contain:'.implode(',', $values);
}
}
+286
View File
@@ -0,0 +1,286 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Macroable;
use InvalidArgumentException;
class Email implements Rule, DataAwareRule, ValidatorAwareRule
{
use Conditionable, Macroable;
public bool $validateMxRecord = false;
public bool $preventSpoofing = false;
public bool $nativeValidation = false;
public bool $nativeValidationWithUnicodeAllowed = false;
public bool $rfcCompliant = false;
public bool $strictRfcCompliant = false;
/**
* The validator performing the validation.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* The data under validation.
*
* @var array
*/
protected $data;
/**
* An array of custom rules that will be merged into the validation rules.
*
* @var array
*/
protected $customRules = [];
/**
* The error message after validation, if any.
*
* @var array
*/
protected $messages = [];
/**
* The callback that will generate the "default" version of the email rule.
*
* @var string|array|callable|null
*/
public static $defaultCallback;
/**
* Set the default callback to be used for determining the email default rules.
*
* If no arguments are passed, the default email rule configuration will be returned.
*
* @param static|callable|null $callback
* @return static|void
*
* @phpstan-return ($callback is null ? static : ($callback is callable ? void : ($callback is static ? void : never)))
*
* @throws \InvalidArgumentException
*/
public static function defaults($callback = null)
{
if (is_null($callback)) {
return static::default();
}
if (! is_callable($callback) && ! $callback instanceof static) {
throw new InvalidArgumentException('The given callback should be callable or an instance of '.static::class);
}
static::$defaultCallback = $callback;
}
/**
* Get the default configuration of the email rule.
*
* @return static
*/
public static function default()
{
$email = is_callable(static::$defaultCallback)
? call_user_func(static::$defaultCallback)
: static::$defaultCallback;
return $email instanceof static ? $email : new static;
}
/**
* Ensure that the email is an RFC compliant email address.
*
* @param bool $strict
* @return $this
*/
public function rfcCompliant(bool $strict = false)
{
if ($strict) {
$this->strictRfcCompliant = true;
} else {
$this->rfcCompliant = true;
}
return $this;
}
/**
* Ensure that the email is a strictly enforced RFC compliant email address.
*
* @return $this
*/
public function strict()
{
return $this->rfcCompliant(true);
}
/**
* Ensure that the email address has a valid MX record.
*
* Requires the PHP intl extension.
*
* @return $this
*/
public function validateMxRecord()
{
$this->validateMxRecord = true;
return $this;
}
/**
* Ensure that the email address is not attempting to spoof another email address using invalid unicode characters.
*
* @return $this
*/
public function preventSpoofing()
{
$this->preventSpoofing = true;
return $this;
}
/**
* Ensure the email address is valid using PHP's native email validation functions.
*
* @param bool $allowUnicode
* @return $this
*/
public function withNativeValidation(bool $allowUnicode = false)
{
if ($allowUnicode) {
$this->nativeValidationWithUnicodeAllowed = true;
} else {
$this->nativeValidation = true;
}
return $this;
}
/**
* Specify additional validation rules that should be merged with the default rules during validation.
*
* @param string|array $rules
* @return $this
*/
public function rules($rules)
{
$this->customRules = array_merge($this->customRules, Arr::wrap($rules));
return $this;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$this->messages = [];
$validator = Validator::make(
$this->data,
[$attribute => $this->buildValidationRules()],
$this->validator->customMessages,
$this->validator->customAttributes
);
if ($validator->fails()) {
$this->messages = array_merge($this->messages, $validator->messages()->all());
return false;
}
return true;
}
/**
* Build the array of underlying validation rules based on the current state.
*
* @return array
*/
protected function buildValidationRules()
{
$rules = [];
if ($this->rfcCompliant) {
$rules[] = 'rfc';
}
if ($this->strictRfcCompliant) {
$rules[] = 'strict';
}
if ($this->validateMxRecord) {
$rules[] = 'dns';
}
if ($this->preventSpoofing) {
$rules[] = 'spoof';
}
if ($this->nativeValidation) {
$rules[] = 'filter';
}
if ($this->nativeValidationWithUnicodeAllowed) {
$rules[] = 'filter_unicode';
}
if ($rules) {
$rules = ['email:'.implode(',', $rules)];
} else {
$rules = ['email'];
}
return array_merge(array_filter($rules), $this->customRules);
}
/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
return $this->messages;
}
/**
* Set the current validator.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
/**
* Set the current data under validation.
*
* @param array $data
* @return $this
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
}
+170
View File
@@ -0,0 +1,170 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
use TypeError;
use function Illuminate\Support\enum_value;
class Enum implements Rule, ValidatorAwareRule, Stringable
{
use Conditionable;
/**
* The type of the enum.
*
* @var class-string<\UnitEnum>
*/
protected $type;
/**
* The current validator instance.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* The cases that should be considered valid.
*
* @var array
*/
protected $only = [];
/**
* The cases that should be considered invalid.
*
* @var array
*/
protected $except = [];
/**
* Create a new rule instance.
*
* @param class-string<\UnitEnum> $type
*/
public function __construct($type)
{
$this->type = $type;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
if ($value instanceof $this->type) {
return $this->isDesirable($value);
}
if (is_null($value) || ! enum_exists($this->type) || ! method_exists($this->type, 'tryFrom')) {
return false;
}
try {
$value = $this->type::tryFrom($value);
return ! is_null($value) && $this->isDesirable($value);
} catch (TypeError) {
return false;
}
}
/**
* Specify the cases that should be considered valid.
*
* @param \UnitEnum[]|\UnitEnum|\Illuminate\Contracts\Support\Arrayable<array-key, \UnitEnum> $values
* @return $this
*/
public function only($values)
{
$this->only = $values instanceof Arrayable ? $values->toArray() : Arr::wrap($values);
return $this;
}
/**
* Specify the cases that should be considered invalid.
*
* @param \UnitEnum[]|\UnitEnum|\Illuminate\Contracts\Support\Arrayable<array-key, \UnitEnum> $values
* @return $this
*/
public function except($values)
{
$this->except = $values instanceof Arrayable ? $values->toArray() : Arr::wrap($values);
return $this;
}
/**
* Determine if the given case is a valid case based on the only / except values.
*
* @param mixed $value
* @return bool
*/
protected function isDesirable($value)
{
return match (true) {
! empty($this->only) => in_array(needle: $value, haystack: $this->only, strict: true),
! empty($this->except) => ! in_array(needle: $value, haystack: $this->except, strict: true),
default => true,
};
}
/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
$message = $this->validator->getTranslator()->get('validation.enum');
return $message === 'validation.enum'
? ['The selected :attribute is invalid.']
: $message;
}
/**
* Set the current validator.
*
* @param \Illuminate\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$cases = ! empty($this->only)
? $this->only
: array_filter($this->type::cases(), fn ($case) => ! in_array($case, $this->except, true));
$values = array_map(function ($case) {
$value = enum_value($case);
return '"'.str_replace('"', '""', (string) $value).'"';
}, $cases);
return 'in:'.implode(',', $values);
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class ExcludeIf implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new exclude validation rule based on a condition.
*
* @param (\Closure(): bool)|bool $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? 'exclude' : '';
}
return $this->condition ? 'exclude' : '';
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class ExcludeUnless implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new exclude validation rule based on a condition.
*
* @param (\Closure(): bool)|bool $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? '' : 'exclude';
}
return $this->condition ? '' : 'exclude';
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
class Exists implements Stringable
{
use Conditionable, DatabaseRule;
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
return rtrim(sprintf('exists:%s,%s,%s',
$this->table,
$this->column,
$this->formatWheres()
), ',');
}
}
+403
View File
@@ -0,0 +1,403 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Macroable;
use InvalidArgumentException;
class File implements Rule, DataAwareRule, ValidatorAwareRule
{
use Conditionable, Macroable;
/**
* The MIME types that the given file should match. This array may also contain file extensions.
*
* @var array
*/
protected $allowedMimetypes = [];
/**
* The extensions that the given file should match.
*
* @var array
*/
protected $allowedExtensions = [];
/**
* The minimum size in kilobytes that the file can be.
*
* @var null|int
*/
protected $minimumFileSize = null;
/**
* The maximum size in kilobytes that the file can be.
*
* @var null|int
*/
protected $maximumFileSize = null;
/**
* The required file encoding.
*
* @var string|null
*/
protected $encoding = null;
/**
* An array of custom rules that will be merged into the validation rules.
*
* @var array
*/
protected $customRules = [];
/**
* The error message after validation, if any.
*
* @var array
*/
protected $messages = [];
/**
* The data under validation.
*
* @var array
*/
protected $data;
/**
* The validator performing the validation.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
/**
* The callback that will generate the "default" version of the file rule.
*
* @var string|array|callable|null
*/
public static $defaultCallback;
/**
* Set the default callback to be used for determining the file default rules.
*
* If no arguments are passed, the default file rule configuration will be returned.
*
* @param static|callable|null $callback
* @return static|void
*
* @throws \InvalidArgumentException
*/
public static function defaults($callback = null)
{
if (is_null($callback)) {
return static::default();
}
if (! is_callable($callback) && ! $callback instanceof static) {
throw new InvalidArgumentException('The given callback should be callable or an instance of '.static::class);
}
static::$defaultCallback = $callback;
}
/**
* Get the default configuration of the file rule.
*
* @return static
*/
public static function default()
{
$file = is_callable(static::$defaultCallback)
? call_user_func(static::$defaultCallback)
: static::$defaultCallback;
return $file instanceof Rule ? $file : new self();
}
/**
* Limit the uploaded file to only image types.
*
* @param bool $allowSvg
* @return ImageFile
*/
public static function image($allowSvg = false)
{
return new ImageFile($allowSvg);
}
/**
* Limit the uploaded file to the given MIME types or file extensions.
*
* @param string|array<int, string> $mimetypes
* @return static
*/
public static function types($mimetypes)
{
return tap(new static(), fn ($file) => $file->allowedMimetypes = (array) $mimetypes);
}
/**
* Limit the uploaded file to the given file extensions.
*
* @param string|array<int, string> $extensions
* @return $this
*/
public function extensions($extensions)
{
$this->allowedExtensions = (array) $extensions;
return $this;
}
/**
* Indicate that the uploaded file should be exactly a certain size in kilobytes.
*
* @param string|int $size
* @return $this
*/
public function size($size)
{
$this->minimumFileSize = $this->toKilobytes($size);
$this->maximumFileSize = $this->minimumFileSize;
return $this;
}
/**
* Indicate that the uploaded file should be between a minimum and maximum size in kilobytes.
*
* @param string|int $minSize
* @param string|int $maxSize
* @return $this
*/
public function between($minSize, $maxSize)
{
$this->minimumFileSize = $this->toKilobytes($minSize);
$this->maximumFileSize = $this->toKilobytes($maxSize);
return $this;
}
/**
* Indicate that the uploaded file should be no less than the given number of kilobytes.
*
* @param string|int $size
* @return $this
*/
public function min($size)
{
$this->minimumFileSize = $this->toKilobytes($size);
return $this;
}
/**
* Indicate that the uploaded file should be no more than the given number of kilobytes.
*
* @param string|int $size
* @return $this
*/
public function max($size)
{
$this->maximumFileSize = $this->toKilobytes($size);
return $this;
}
/**
* Indicate that the uploaded file should be in the given encoding.
*
* @param string $encoding
* @return $this
*/
public function encoding($encoding)
{
$this->encoding = $encoding;
return $this;
}
/**
* Convert a potentially human-friendly file size to kilobytes.
*
* @param string|int $size
* @return ($size is int ? int : int|float)
*
* @throws \InvalidArgumentException
*/
protected function toKilobytes($size)
{
if (! is_string($size)) {
return $size;
}
$size = strtolower(trim($size));
$value = (float) $size;
return round(match (true) {
Str::endsWith($size, 'kb') => $value * 1,
Str::endsWith($size, 'mb') => $value * 1_000,
Str::endsWith($size, 'gb') => $value * 1_000_000,
Str::endsWith($size, 'tb') => $value * 1_000_000_000,
default => throw new InvalidArgumentException('Invalid file size suffix.'),
});
}
/**
* Specify additional validation rules that should be merged with the default rules during validation.
*
* @param string|array $rules
* @return $this
*/
public function rules($rules)
{
$this->customRules = array_merge($this->customRules, Arr::wrap($rules));
return $this;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$this->messages = [];
$validator = Validator::make(
$this->data,
[$attribute => $this->buildValidationRules()],
$this->validator->customMessages,
$this->validator->customAttributes
);
if ($validator->fails()) {
return $this->fail($validator->messages()->all());
}
return true;
}
/**
* Build the array of underlying validation rules based on the current state.
*
* @return array
*/
protected function buildValidationRules()
{
$rules = ['file'];
$rules = array_merge($rules, $this->buildMimetypes());
if (! empty($this->allowedExtensions)) {
$rules[] = 'extensions:'.implode(',', array_map(strtolower(...), $this->allowedExtensions));
}
$rules[] = match (true) {
is_null($this->minimumFileSize) && is_null($this->maximumFileSize) => null,
is_null($this->maximumFileSize) => "min:{$this->minimumFileSize}",
is_null($this->minimumFileSize) => "max:{$this->maximumFileSize}",
$this->minimumFileSize !== $this->maximumFileSize => "between:{$this->minimumFileSize},{$this->maximumFileSize}",
default => "size:{$this->minimumFileSize}",
};
if ($this->encoding) {
$rules[] = 'encoding:'.$this->encoding;
}
return array_merge(array_filter($rules), $this->customRules);
}
/**
* Separate the given MIME types from extensions and return an array of correct rules to validate against.
*
* @return array
*/
protected function buildMimetypes()
{
if (count($this->allowedMimetypes) === 0) {
return [];
}
$rules = [];
$mimetypes = array_filter(
$this->allowedMimetypes,
fn ($type) => str_contains($type, '/')
);
$mimes = array_diff($this->allowedMimetypes, $mimetypes);
if ($mimetypes !== []) {
$rules[] = 'mimetypes:'.implode(',', $mimetypes);
}
if ($mimes !== []) {
$rules[] = 'mimes:'.implode(',', $mimes);
}
return $rules;
}
/**
* Adds the given failures, and return false.
*
* @param array|string $messages
* @return bool
*/
protected function fail($messages)
{
$this->messages = array_merge($this->messages, Arr::wrap($messages));
return false;
}
/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
return $this->messages;
}
/**
* Set the current validator.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
/**
* Set the current data under validation.
*
* @param array $data
* @return $this
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
namespace Illuminate\Validation\Rules;
class ImageFile extends File
{
/**
* Create a new image file rule instance.
*
* @param bool $allowSvg
*/
public function __construct($allowSvg = false)
{
if ($allowSvg) {
$this->rules('image:allow_svg');
} else {
$this->rules('image');
}
}
/**
* The dimension constraints for the uploaded file.
*
* @param \Illuminate\Validation\Rules\Dimensions $dimensions
* @return $this
*/
public function dimensions($dimensions)
{
$this->rules($dimensions);
return $this;
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Stringable;
use function Illuminate\Support\enum_value;
class In implements Stringable
{
/**
* The name of the rule.
*
* @var string
*/
protected $rule = 'in';
/**
* The accepted values.
*
* @var array
*/
protected $values;
/**
* Create a new in rule instance.
*
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|array|string $values
*/
public function __construct($values)
{
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->values = is_array($values) ? $values : func_get_args();
}
/**
* Convert the rule to a validation string.
*
* @return string
*
* @see \Illuminate\Validation\ValidationRuleParser::parseParameters
*/
public function __toString()
{
$values = array_map(function ($value) {
$value = enum_value($value);
return '"'.str_replace('"', '""', (string) $value).'"';
}, $this->values);
return $this->rule.':'.implode(',', $values);
}
}
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Contracts\Support\Arrayable;
use Stringable;
use function Illuminate\Support\enum_value;
class NotIn implements Stringable
{
/**
* The name of the rule.
*
* @var string
*/
protected $rule = 'not_in';
/**
* The accepted values.
*
* @var array
*/
protected $values;
/**
* Create a new "not in" rule instance.
*
* @param \Illuminate\Contracts\Support\Arrayable|\UnitEnum|array|string $values
*/
public function __construct($values)
{
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->values = is_array($values) ? $values : func_get_args();
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$values = array_map(function ($value) {
$value = enum_value($value);
return '"'.str_replace('"', '""', (string) $value).'"';
}, $this->values);
return $this->rule.':'.implode(',', $values);
}
}
+230
View File
@@ -0,0 +1,230 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Arr;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
class Numeric implements Stringable
{
use Conditionable;
/**
* The constraints for the number rule.
*/
protected array $constraints = ['numeric'];
/**
* The field under validation must have a size between the given min and max (inclusive).
*
* @param int|float $min
* @param int|float $max
* @return $this
*/
public function between(int|float $min, int|float $max): Numeric
{
return $this->addRule('between:'.$min.','.$max);
}
/**
* The field under validation must contain the specified number of decimal places.
*
* @param int $min
* @param int|null $max
* @return $this
*/
public function decimal(int $min, ?int $max = null): Numeric
{
$rule = 'decimal:'.$min;
if ($max !== null) {
$rule .= ','.$max;
}
return $this->addRule($rule);
}
/**
* The field under validation must have a different value than field.
*
* @param string $field
* @return $this
*/
public function different(string $field): Numeric
{
return $this->addRule('different:'.$field);
}
/**
* The integer under validation must have an exact number of digits.
*
* @param int $length
* @return $this
*/
public function digits(int $length): Numeric
{
return $this->integer()->addRule('digits:'.$length);
}
/**
* The integer under validation must between the given min and max number of digits.
*
* @param int $min
* @param int $max
* @return $this
*/
public function digitsBetween(int $min, int $max): Numeric
{
return $this->integer()->addRule('digits_between:'.$min.','.$max);
}
/**
* The field under validation must be greater than the given field or value.
*
* @param string $field
* @return $this
*/
public function greaterThan(string $field): Numeric
{
return $this->addRule('gt:'.$field);
}
/**
* The field under validation must be greater than or equal to the given field or value.
*
* @param string $field
* @return $this
*/
public function greaterThanOrEqualTo(string $field): Numeric
{
return $this->addRule('gte:'.$field);
}
/**
* The field under validation must be an integer.
*
* @return $this
*/
public function integer(bool $strict = false): Numeric
{
return $this->addRule($strict ? 'integer:strict' : 'integer');
}
/**
* The field under validation must be less than the given field.
*
* @param string $field
* @return $this
*/
public function lessThan(string $field): Numeric
{
return $this->addRule('lt:'.$field);
}
/**
* The field under validation must be less than or equal to the given field.
*
* @param string $field
* @return $this
*/
public function lessThanOrEqualTo(string $field): Numeric
{
return $this->addRule('lte:'.$field);
}
/**
* The field under validation must be less than or equal to a maximum value.
*
* @param int|float $value
* @return $this
*/
public function max(int|float $value): Numeric
{
return $this->addRule('max:'.$value);
}
/**
* The integer under validation must have a maximum number of digits.
*
* @param int $value
* @return $this
*/
public function maxDigits(int $value): Numeric
{
return $this->addRule('max_digits:'.$value);
}
/**
* The field under validation must have a minimum value.
*
* @param int|float $value
* @return $this
*/
public function min(int|float $value): Numeric
{
return $this->addRule('min:'.$value);
}
/**
* The integer under validation must have a minimum number of digits.
*
* @param int $value
* @return $this
*/
public function minDigits(int $value): Numeric
{
return $this->addRule('min_digits:'.$value);
}
/**
* The field under validation must be a multiple of the given value.
*
* @param int|float $value
* @return $this
*/
public function multipleOf(int|float $value): Numeric
{
return $this->addRule('multiple_of:'.$value);
}
/**
* The given field must match the field under validation.
*
* @param string $field
* @return $this
*/
public function same(string $field): Numeric
{
return $this->addRule('same:'.$field);
}
/**
* The field under validation must match the given value.
*
* @param int $value
* @return $this
*/
public function exactly(int $value): Numeric
{
return $this->integer()->addRule('size:'.$value);
}
/**
* Convert the rule to a validation string.
*/
public function __toString(): string
{
return implode('|', array_unique($this->constraints));
}
/**
* Add custom rules to the validation rules array.
*/
protected function addRule(array|string $rules): Numeric
{
$this->constraints = array_merge($this->constraints, Arr::wrap($rules));
return $this;
}
}
+450
View File
@@ -0,0 +1,450 @@
<?php
namespace Illuminate\Validation\Rules;
use ArrayIterator;
use Illuminate\Container\Container;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ImplicitRule;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\UncompromisedVerifier;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Traits\Conditionable;
use InvalidArgumentException;
use IteratorAggregate;
use Traversable;
class Password implements DataAwareRule, ImplicitRule, IteratorAggregate, Rule, ValidatorAwareRule
{
use Conditionable;
/**
* The validator performing the validation.
*
* @var \Illuminate\Contracts\Validation\Validator
*/
protected $validator;
/**
* The data under validation.
*
* @var array
*/
protected $data;
/**
* The minimum size of the password.
*
* @var int
*/
protected $min = 8;
/**
* The maximum size of the password.
*
* @var int
*/
protected $max;
/**
* If the password is required.
*
* @var bool
*/
protected $required = false;
/**
* If the password should only be validated when present.
*
* @var bool
*/
protected $sometimes = false;
/**
* If the password requires at least one uppercase and one lowercase letter.
*
* @var bool
*/
protected $mixedCase = false;
/**
* If the password requires at least one letter.
*
* @var bool
*/
protected $letters = false;
/**
* If the password requires at least one number.
*
* @var bool
*/
protected $numbers = false;
/**
* If the password requires at least one symbol.
*
* @var bool
*/
protected $symbols = false;
/**
* If the password should not have been compromised in data leaks.
*
* @var bool
*/
protected $uncompromised = false;
/**
* The number of times a password can appear in data leaks before being considered compromised.
*
* @var int
*/
protected $compromisedThreshold = 0;
/**
* Additional validation rules that should be merged into the default rules during validation.
*
* @var array
*/
protected $customRules = [];
/**
* The failure messages, if any.
*
* @var array
*/
protected $messages = [];
/**
* The callback that will generate the "default" version of the password rule.
*
* @var string|array|callable|null
*/
public static $defaultCallback;
/**
* Create a new rule instance.
*
* @param int $min
*/
public function __construct($min)
{
$this->min = max((int) $min, 1);
}
/**
* Set the default callback to be used for determining a password's default rules.
*
* If no arguments are passed, the default password rule configuration will be returned.
*
* @param static|callable|null $callback
* @return static|void
*
* @throws \InvalidArgumentException
*/
public static function defaults($callback = null)
{
if (is_null($callback)) {
return static::default();
}
if (! is_callable($callback) && ! $callback instanceof static) {
throw new InvalidArgumentException('The given callback should be callable or an instance of '.static::class);
}
static::$defaultCallback = $callback;
}
/**
* Get the default configuration of the password rule.
*
* @return static
*/
public static function default()
{
$password = is_callable(static::$defaultCallback)
? call_user_func(static::$defaultCallback)
: static::$defaultCallback;
return $password instanceof Rule ? $password : static::min(8);
}
/**
* Get the default configuration of the password rule and mark the field as required.
*
* @return static
*/
public static function required()
{
$password = static::default();
$password->required = true;
return $password;
}
/**
* Get the default configuration of the password rule and mark the field as sometimes being required.
*
* @return static
*/
public static function sometimes()
{
$password = static::default();
$password->sometimes = true;
return $password;
}
/**
* Set the performing validator.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return $this
*/
public function setValidator($validator)
{
$this->validator = $validator;
return $this;
}
/**
* Set the data under validation.
*
* @param array $data
* @return $this
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
/**
* Set the minimum size of the password.
*
* @param int $size
* @return $this
*/
public static function min($size)
{
return new static($size);
}
/**
* Set the maximum size of the password.
*
* @param int $size
* @return $this
*/
public function max($size)
{
$this->max = $size;
return $this;
}
/**
* Ensures the password has not been compromised in data leaks.
*
* @param int $threshold
* @return $this
*/
public function uncompromised($threshold = 0)
{
$this->uncompromised = true;
$this->compromisedThreshold = $threshold;
return $this;
}
/**
* Makes the password require at least one uppercase and one lowercase letter.
*
* @return $this
*/
public function mixedCase()
{
$this->mixedCase = true;
return $this;
}
/**
* Makes the password require at least one letter.
*
* @return $this
*/
public function letters()
{
$this->letters = true;
return $this;
}
/**
* Makes the password require at least one number.
*
* @return $this
*/
public function numbers()
{
$this->numbers = true;
return $this;
}
/**
* Makes the password require at least one symbol.
*
* @return $this
*/
public function symbols()
{
$this->symbols = true;
return $this;
}
/**
* Specify additional validation rules that should be merged with the default rules during validation.
*
* @param \Closure|string|array $rules
* @return $this
*/
public function rules($rules)
{
$this->customRules = Arr::wrap($rules);
return $this;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$this->messages = [];
if (! $this->required && ! $this->sometimes && ! Arr::has($this->data ?? [], $attribute)) {
return true;
}
if (blank($value) && ! $this->required && $this->validator?->hasRule($attribute, ['Nullable'])) {
return true;
}
$validator = Validator::make(
$this->data,
[$attribute => [...$this]],
$this->validator->customMessages,
$this->validator->customAttributes
)->after(function ($validator) use ($attribute, $value) {
if (! is_string($value)) {
return;
}
if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) {
$validator->addFailure($attribute, 'password.mixed');
}
if ($this->letters && ! preg_match('/\pL/u', $value)) {
$validator->addFailure($attribute, 'password.letters');
}
if ($this->symbols && ! preg_match('/\p{Z}|\p{S}|\p{P}/u', $value)) {
$validator->addFailure($attribute, 'password.symbols');
}
if ($this->numbers && ! preg_match('/\pN/u', $value)) {
$validator->addFailure($attribute, 'password.numbers');
}
});
if ($validator->fails()) {
return $this->fail($validator->messages()->all());
}
if ($this->uncompromised && ! Container::getInstance()->make(UncompromisedVerifier::class)->verify([
'value' => $value,
'threshold' => $this->compromisedThreshold,
])) {
$validator->addFailure($attribute, 'password.uncompromised');
return $this->fail($validator->messages()->all());
}
return true;
}
/**
* Get the validation error message.
*
* @return array
*/
public function message()
{
return $this->messages;
}
/**
* Adds the given failures, and return false.
*
* @param array|string $messages
* @return bool
*/
protected function fail($messages)
{
$this->messages = array_merge($this->messages, Arr::wrap($messages));
return false;
}
/**
* Get information about the current state of the password validation rules.
*
* @return array
*/
public function appliedRules()
{
return [
'min' => $this->min,
'max' => $this->max,
'mixedCase' => $this->mixedCase,
'letters' => $this->letters,
'numbers' => $this->numbers,
'symbols' => $this->symbols,
'uncompromised' => $this->uncompromised,
'compromisedThreshold' => $this->compromisedThreshold,
'customRules' => $this->customRules,
];
}
/**
* Get an iterator for the password validation rules.
*
* @return \ArrayIterator<TKey, TValue>
*/
public function getIterator(): Traversable
{
return new ArrayIterator([
...($this->required ? ['required'] : []),
...($this->sometimes ? ['sometimes'] : []),
'string',
'min:'.$this->min,
...($this->max ? ['max:'.$this->max] : []),
...$this->customRules,
]);
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class ProhibitedIf implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new prohibited validation rule based on a condition.
*
* @param (\Closure(): bool)|bool $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? 'prohibited' : '';
}
return $this->condition ? 'prohibited' : '';
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class ProhibitedUnless implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new prohibited validation rule based on a condition.
*
* @param (\Closure(): bool)|bool $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? '' : 'prohibited';
}
return $this->condition ? '' : 'prohibited';
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class RequiredIf implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new required validation rule based on a condition.
*
* @param (\Closure(): bool)|bool|null $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if (is_null($condition)) {
$condition = false;
}
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? 'required' : '';
}
return $this->condition ? 'required' : '';
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace Illuminate\Validation\Rules;
use Closure;
use InvalidArgumentException;
use Stringable;
class RequiredUnless implements Stringable
{
/**
* The condition that validates the attribute.
*
* @var (\Closure(): bool)|bool
*/
public $condition;
/**
* Create a new required validation rule based on a condition.
*
* @param (\Closure(): bool)|bool|null $condition
*
* @throws \InvalidArgumentException
*/
public function __construct($condition)
{
if (is_null($condition)) {
$condition = false;
}
if ($condition instanceof Closure || is_bool($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
if (is_callable($this->condition)) {
return call_user_func($this->condition) ? '' : 'required';
}
return $this->condition ? '' : 'required';
}
}
+187
View File
@@ -0,0 +1,187 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Arr;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
class StringRule implements Stringable
{
use Conditionable;
/**
* The constraints for the string rule.
*/
protected array $constraints = ['string'];
/**
* The field under validation must be entirely alphabetic characters.
*
* @param bool $ascii
* @return $this
*/
public function alpha(bool $ascii = false): static
{
return $this->addRule($ascii ? 'alpha:ascii' : 'alpha');
}
/**
* The field under validation must be entirely alpha-numeric characters, dashes, and underscores.
*
* @param bool $ascii
* @return $this
*/
public function alphaDash(bool $ascii = false): static
{
return $this->addRule($ascii ? 'alpha_dash:ascii' : 'alpha_dash');
}
/**
* The field under validation must be entirely alpha-numeric characters.
*
* @param bool $ascii
* @return $this
*/
public function alphaNumeric(bool $ascii = false): static
{
return $this->addRule($ascii ? 'alpha_num:ascii' : 'alpha_num');
}
/**
* The field under validation must be entirely ASCII characters.
*
* @return $this
*/
public function ascii(): static
{
return $this->addRule('ascii');
}
/**
* The field under validation must have a length between the given min and max (inclusive).
*
* @param int $min
* @param int $max
* @return $this
*/
public function between(int $min, int $max): static
{
return $this->addRule('between:'.$min.','.$max);
}
/**
* The field under validation must not end with any of the given values.
*
* @param string ...$values
* @return $this
*/
public function doesntEndWith(string ...$values): static
{
return $this->addRule('doesnt_end_with:'.implode(',', $values));
}
/**
* The field under validation must not start with any of the given values.
*
* @param string ...$values
* @return $this
*/
public function doesntStartWith(string ...$values): static
{
return $this->addRule('doesnt_start_with:'.implode(',', $values));
}
/**
* The field under validation must end with one of the given values.
*
* @param string ...$values
* @return $this
*/
public function endsWith(string ...$values): static
{
return $this->addRule('ends_with:'.implode(',', $values));
}
/**
* The field under validation must have an exact length.
*
* @param int $value
* @return $this
*/
public function exactly(int $value): static
{
return $this->addRule('size:'.$value);
}
/**
* The field under validation must be entirely lowercase.
*
* @return $this
*/
public function lowercase(): static
{
return $this->addRule('lowercase');
}
/**
* The field under validation must not exceed the given length.
*
* @param int $value
* @return $this
*/
public function max(int $value): static
{
return $this->addRule('max:'.$value);
}
/**
* The field under validation must have a minimum length.
*
* @param int $value
* @return $this
*/
public function min(int $value): static
{
return $this->addRule('min:'.$value);
}
/**
* The field under validation must start with one of the given values.
*
* @param string ...$values
* @return $this
*/
public function startsWith(string ...$values): static
{
return $this->addRule('starts_with:'.implode(',', $values));
}
/**
* The field under validation must be entirely uppercase.
*
* @return $this
*/
public function uppercase(): static
{
return $this->addRule('uppercase');
}
/**
* Convert the rule to a validation string.
*/
public function __toString(): string
{
return implode('|', array_unique($this->constraints));
}
/**
* Add custom rules to the validation rules array.
*/
protected function addRule(array|string $rules): static
{
$this->constraints = array_merge($this->constraints, Arr::wrap($rules));
return $this;
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace Illuminate\Validation\Rules;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Traits\Conditionable;
use Stringable;
class Unique implements Stringable
{
use Conditionable, DatabaseRule;
/**
* The ID that should be ignored.
*
* @var mixed
*/
protected $ignore;
/**
* The name of the ID column.
*
* @var string
*/
protected $idColumn = 'id';
/**
* Ignore the given ID during the unique check.
*
* @param mixed $id
* @param string|null $idColumn
* @return $this
*/
public function ignore($id, $idColumn = null)
{
if ($id instanceof Model) {
return $this->ignoreModel($id, $idColumn);
}
$this->ignore = $id;
$this->idColumn = $idColumn ?? 'id';
return $this;
}
/**
* Ignore the given model during the unique check.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string|null $idColumn
* @return $this
*/
public function ignoreModel($model, $idColumn = null)
{
$this->idColumn = $idColumn ?? $model->getKeyName();
$this->ignore = $model->{$this->idColumn};
return $this;
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
$this->table,
$this->column,
$this->ignore ? '"'.addslashes($this->ignore).'"' : 'NULL',
$this->idColumn,
$this->formatWheres()
), ',');
}
}