This commit is contained in:
Paolo A
2024-08-13 13:44:16 +00:00
parent 1bbb23088d
commit e796d76612
4001 changed files with 30101 additions and 40075 deletions

View File

@@ -20,6 +20,10 @@ trait FormatsMessages
*/
protected function getMessage($attribute, $rule)
{
$attributeWithPlaceholders = $attribute;
$attribute = $this->replacePlaceholderInString($attribute);
$inlineMessage = $this->getInlineMessage($attribute, $rule);
// First we will retrieve the custom message for the validation rule if one
@@ -46,7 +50,7 @@ trait FormatsMessages
// specific error message for the type of attribute being validated such
// as a number, file or string which all have different message types.
elseif (in_array($rule, $this->sizeRules)) {
return $this->getSizeMessage($attribute, $rule);
return $this->getSizeMessage($attributeWithPlaceholders, $rule);
}
// Finally, if no developer specified messages have been set, and no other
@@ -54,7 +58,7 @@ trait FormatsMessages
// messages out of the translator service for this validation rule.
$key = "validation.{$lowerRule}";
if ($key != ($value = $this->translator->get($key))) {
if ($key !== ($value = $this->translator->get($key))) {
return $value;
}
@@ -116,7 +120,7 @@ trait FormatsMessages
}
/**
* Get the custom error message from translator.
* Get the custom error message from the translator.
*
* @param string $key
* @return string
@@ -336,7 +340,11 @@ trait FormatsMessages
return $value ? 'true' : 'false';
}
return $value;
if (is_null($value)) {
return 'empty';
}
return (string) $value;
}
/**

View File

@@ -6,6 +6,42 @@ use Illuminate\Support\Arr;
trait ReplacesAttributes
{
/**
* Replace all place-holders for the accepted_if rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceAcceptedIf($message, $attribute, $rule, $parameters)
{
$parameters[1] = $this->getDisplayableValue($parameters[0], Arr::get($this->data, $parameters[0]));
$parameters[0] = $this->getDisplayableAttribute($parameters[0]);
return str_replace([':other', ':value'], $parameters, $message);
}
/**
* Replace all place-holders for the declined_if rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceDeclinedIf($message, $attribute, $rule, $parameters)
{
$parameters[1] = $this->getDisplayableValue($parameters[0], Arr::get($this->data, $parameters[0]));
$parameters[0] = $this->getDisplayableAttribute($parameters[0]);
return str_replace([':other', ':value'], $parameters, $message);
}
/**
* Replace all place-holders for the between rule.
*
@@ -104,6 +140,20 @@ trait ReplacesAttributes
return str_replace(':max', $parameters[0], $message);
}
/**
* Replace all place-holders for the multiple_of rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceMultipleOf($message, $attribute, $rule, $parameters)
{
return str_replace(':value', $parameters[0] ?? '', $message);
}
/**
* Replace all place-holders for the in rule.
*
@@ -150,6 +200,24 @@ trait ReplacesAttributes
return str_replace(':other', $this->getDisplayableAttribute($parameters[0]), $message);
}
/**
* Replace all place-holders for the required_array_keys rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceRequiredArrayKeys($message, $attribute, $rule, $parameters)
{
foreach ($parameters as &$parameter) {
$parameter = $this->getDisplayableValue($attribute, $parameter);
}
return str_replace(':values', implode(', ', $parameters), $message);
}
/**
* Replace all place-holders for the mimetypes rule.
*
@@ -360,6 +428,60 @@ trait ReplacesAttributes
return str_replace([':other', ':values'], [$other, implode(', ', $values)], $message);
}
/**
* Replace all place-holders for the prohibited_if rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceProhibitedIf($message, $attribute, $rule, $parameters)
{
$parameters[1] = $this->getDisplayableValue($parameters[0], Arr::get($this->data, $parameters[0]));
$parameters[0] = $this->getDisplayableAttribute($parameters[0]);
return str_replace([':other', ':value'], $parameters, $message);
}
/**
* Replace all place-holders for the prohibited_unless rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceProhibitedUnless($message, $attribute, $rule, $parameters)
{
$other = $this->getDisplayableAttribute($parameters[0]);
$values = [];
foreach (array_slice($parameters, 1) as $value) {
$values[] = $this->getDisplayableValue($parameters[0], $value);
}
return str_replace([':other', ':values'], [$other, implode(', ', $values)], $message);
}
/**
* Replace all place-holders for the prohibited_with rule.
*
* @param string $message
* @param string $attribute
* @param string $rule
* @param array $parameters
* @return string
*/
protected function replaceProhibits($message, $attribute, $rule, $parameters)
{
return str_replace(':other', implode(' / ', $this->getAttributeList($parameters)), $message);
}
/**
* Replace all place-holders for the same rule.
*

View File

@@ -14,7 +14,6 @@ use Egulias\EmailValidator\Validation\SpoofCheckValidation;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Exists;
@@ -42,6 +41,68 @@ trait ValidatesAttributes
return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true);
}
/**
* Validate that an attribute was "accepted" when another attribute has a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateAcceptedIf($attribute, $value, $parameters)
{
$acceptable = ['yes', 'on', '1', 1, true, 'true'];
$this->requireParameterCount(2, $parameters, 'accepted_if');
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true);
}
return true;
}
/**
* Validate that an attribute was "declined".
*
* This validation rule implies the attribute is "required".
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function validateDeclined($attribute, $value)
{
$acceptable = ['no', 'off', '0', 0, false, 'false'];
return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true);
}
/**
* Validate that an attribute was "declined" when another attribute has a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateDeclinedIf($attribute, $value, $parameters)
{
$acceptable = ['no', 'off', '0', 0, false, 'false'];
$this->requireParameterCount(2, $parameters, 'declined_if');
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value) && in_array($value, $acceptable, true);
}
return true;
}
/**
* Validate that an attribute is an active URL.
*
@@ -57,7 +118,7 @@ trait ValidatesAttributes
if ($url = parse_url($value, PHP_URL_HOST)) {
try {
return count(dns_get_record($url, DNS_A | DNS_AAAA)) > 0;
return count(dns_get_record($url.'.', DNS_A | DNS_AAAA)) > 0;
} catch (Exception $e) {
return false;
}
@@ -185,19 +246,9 @@ trait ValidatesAttributes
*/
protected function getDateTimestamp($value)
{
if ($value instanceof DateTimeInterface) {
return $value->getTimestamp();
}
$date = is_null($value) ? null : $this->getDateTime($value);
if ($this->isTestingRelativeDateTime($value)) {
$date = $this->getDateTime($value);
if (! is_null($date)) {
return $date->getTimestamp();
}
}
return strtotime($value);
return $date ? $date->getTimestamp() : null;
}
/**
@@ -214,7 +265,11 @@ trait ValidatesAttributes
$firstDate = $this->getDateTimeWithOptionalFormat($format, $first);
if (! $secondDate = $this->getDateTimeWithOptionalFormat($format, $second)) {
$secondDate = $this->getDateTimeWithOptionalFormat($format, $this->getValue($second));
if (is_null($second = $this->getValue($second))) {
return true;
}
$secondDate = $this->getDateTimeWithOptionalFormat($format, $second);
}
return ($firstDate && $secondDate) && ($this->compare($firstDate, $secondDate, $operator));
@@ -245,29 +300,12 @@ trait ValidatesAttributes
protected function getDateTime($value)
{
try {
if ($this->isTestingRelativeDateTime($value)) {
return Date::parse($value);
}
return date_create($value) ?: null;
return @Date::parse($value) ?: null;
} catch (Exception $e) {
//
}
}
/**
* Check if the given value should be adjusted to Carbon::getTestNow().
*
* @param mixed $value
* @return bool
*/
protected function isTestingRelativeDateTime($value)
{
return Carbon::hasTestNow() && is_string($value) && (
$value === 'now' || Carbon::hasRelativeKeywords($value)
);
}
/**
* Validate that an attribute contains only alphabetic characters.
*
@@ -333,6 +371,29 @@ trait ValidatesAttributes
return empty(array_diff_key($value, array_fill_keys($parameters, '')));
}
/**
* Validate that an array has all of the given keys.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @return bool
*/
public function validateRequiredArrayKeys($attribute, $value, $parameters)
{
if (! is_array($value)) {
return false;
}
foreach ($parameters as $param) {
if (! Arr::exists($value, $param)) {
return false;
}
}
return true;
}
/**
* Validate the size of an attribute is between a set of values.
*
@@ -376,6 +437,28 @@ trait ValidatesAttributes
return $this->validateSame($attribute, $value, [$attribute.'_confirmation']);
}
/**
* Validate that the password of the currently authenticated user matches the given value.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @return bool
*/
protected function validateCurrentPassword($attribute, $value, $parameters)
{
$auth = $this->container->make('auth');
$hasher = $this->container->make('hash');
$guard = $auth->guard(Arr::first($parameters));
if ($guard->guest()) {
return false;
}
return $hasher->check($value, $guard->user()->getAuthPassword());
}
/**
* Validate that an attribute is a valid date.
*
@@ -389,7 +472,11 @@ trait ValidatesAttributes
return true;
}
if ((! is_string($value) && ! is_numeric($value)) || strtotime($value) === false) {
try {
if ((! is_string($value) && ! is_numeric($value)) || strtotime($value) === false) {
return false;
}
} catch (Exception $e) {
return false;
}
@@ -414,11 +501,15 @@ trait ValidatesAttributes
return false;
}
$format = $parameters[0];
foreach ($parameters as $format) {
$date = DateTime::createFromFormat('!'.$format, $value);
$date = DateTime::createFromFormat('!'.$format, $value);
if ($date && $date->format($format) == $value) {
return true;
}
}
return $date && $date->format($format) == $value;
return false;
}
/**
@@ -584,7 +675,7 @@ trait ValidatesAttributes
return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data));
}
return ! in_array($value, array_values($data));
return ! in_array($value, array_values($data), in_array('strict', $parameters));
}
/**
@@ -645,15 +736,15 @@ trait ValidatesAttributes
->unique()
->map(function ($validation) {
if ($validation === 'rfc') {
return new RFCValidation();
return new RFCValidation;
} elseif ($validation === 'strict') {
return new NoRFCWarningsValidation();
return new NoRFCWarningsValidation;
} elseif ($validation === 'dns') {
return new DNSCheckValidation();
return new DNSCheckValidation;
} elseif ($validation === 'spoof') {
return new SpoofCheckValidation();
return new SpoofCheckValidation;
} elseif ($validation === 'filter') {
return new FilterEmailValidation();
return new FilterEmailValidation;
} elseif ($validation === 'filter_unicode') {
return FilterEmailValidation::unicode();
} elseif (is_string($validation) && class_exists($validation)) {
@@ -661,7 +752,7 @@ trait ValidatesAttributes
}
})
->values()
->all() ?: [new RFCValidation()];
->all() ?: [new RFCValidation];
return (new EmailValidator)->isValid($value, new MultipleValidationWithAnd($validations));
}
@@ -833,6 +924,11 @@ trait ValidatesAttributes
$table = $model->getTable();
$connection = $connection ?? $model->getConnectionName();
if (Str::contains($table, '.') && Str::startsWith($table, $connection)) {
$connection = null;
}
$idColumn = $model->getKeyName();
}
@@ -1091,7 +1187,7 @@ trait ValidatesAttributes
}
/**
* Validate that the values of an attribute is in another attribute.
* Validate that the values of an attribute are in another attribute.
*
* @param string $attribute
* @param mixed $value
@@ -1161,6 +1257,18 @@ trait ValidatesAttributes
return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
}
/**
* Validate that an attribute is a valid MAC address.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function validateMacAddress($attribute, $value)
{
return filter_var($value, FILTER_VALIDATE_MAC) !== false;
}
/**
* Validate the attribute is a valid JSON string.
*
@@ -1287,6 +1395,29 @@ trait ValidatesAttributes
return $this->getSize($attribute, $value) >= $parameters[0];
}
/**
* Validate the value of an attribute is a multiple of a given value.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @return bool
*/
public function validateMultipleOf($attribute, $value, $parameters)
{
$this->requireParameterCount(1, $parameters, 'multiple_of');
if (! $this->validateNumeric($attribute, $value) || ! $this->validateNumeric($attribute, $parameters[0])) {
return false;
}
if ((float) $parameters[0] === 0.0) {
return false;
}
return bcmod($value, $parameters[0], 16) === '0.0000000000000000';
}
/**
* "Indicate" validation should pass if value is null.
*
@@ -1325,7 +1456,7 @@ trait ValidatesAttributes
}
/**
* Validate that the current logged in user's password matches the given value.
* Validate that the password of the currently authenticated user matches the given value.
*
* @param string $attribute
* @param mixed $value
@@ -1334,16 +1465,7 @@ trait ValidatesAttributes
*/
protected function validatePassword($attribute, $value, $parameters)
{
$auth = $this->container->make('auth');
$hasher = $this->container->make('hash');
$guard = $auth->guard(Arr::first($parameters));
if ($guard->guest()) {
return false;
}
return $hasher->check($value, $guard->user()->getAuthPassword());
return $this->validateCurrentPassword($attribute, $value, $parameters);
}
/**
@@ -1430,15 +1552,97 @@ trait ValidatesAttributes
{
$this->requireParameterCount(2, $parameters, 'required_if');
[$values, $other] = $this->prepareValuesAndOther($parameters);
if (! Arr::has($this->data, $parameters[0])) {
return true;
}
if (in_array($other, $values)) {
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value);
}
return true;
}
/**
* Validate that an attribute does not exist.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateProhibited($attribute, $value)
{
return false;
}
/**
* Validate that an attribute does not exist when another attribute has a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateProhibitedIf($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'prohibited_if');
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (in_array($other, $values, is_bool($other) || is_null($other))) {
return ! $this->validateRequired($attribute, $value);
}
return true;
}
/**
* Validate that an attribute does not exist unless another attribute has a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateProhibitedUnless($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'prohibited_unless');
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (! in_array($other, $values, is_bool($other) || is_null($other))) {
return ! $this->validateRequired($attribute, $value);
}
return true;
}
/**
* Validate that other attributes do not exist when this attribute exists.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateProhibits($attribute, $value, $parameters)
{
return ! Arr::hasAny($this->data, $parameters);
}
/**
* Indicate that an attribute is excluded.
*
* @return bool
*/
public function validateExclude()
{
return false;
}
/**
* Indicate that an attribute should be excluded when another attribute has a given value.
*
@@ -1451,9 +1655,13 @@ trait ValidatesAttributes
{
$this->requireParameterCount(2, $parameters, 'exclude_if');
[$values, $other] = $this->prepareValuesAndOther($parameters);
if (! Arr::has($this->data, $parameters[0])) {
return true;
}
return ! in_array($other, $values);
[$values, $other] = $this->parseDependentRuleParameters($parameters);
return ! in_array($other, $values, is_bool($other) || is_null($other));
}
/**
@@ -1468,9 +1676,30 @@ trait ValidatesAttributes
{
$this->requireParameterCount(2, $parameters, 'exclude_unless');
[$values, $other] = $this->prepareValuesAndOther($parameters);
[$values, $other] = $this->parseDependentRuleParameters($parameters);
return in_array($other, $values);
return in_array($other, $values, is_bool($other) || is_null($other));
}
/**
* Validate that an attribute exists when another attribute does not have a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateRequiredUnless($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'required_unless');
[$values, $other] = $this->parseDependentRuleParameters($parameters);
if (! in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value);
}
return true;
}
/**
@@ -1498,19 +1727,34 @@ trait ValidatesAttributes
* @param array $parameters
* @return array
*/
protected function prepareValuesAndOther($parameters)
public function parseDependentRuleParameters($parameters)
{
$other = Arr::get($this->data, $parameters[0]);
$values = array_slice($parameters, 1);
if (is_bool($other)) {
if ($this->shouldConvertToBoolean($parameters[0]) || is_bool($other)) {
$values = $this->convertValuesToBoolean($values);
}
if (is_null($other)) {
$values = $this->convertValuesToNull($values);
}
return [$values, $other];
}
/**
* Check if parameter should be converted to boolean.
*
* @param string $parameter
* @return bool
*/
protected function shouldConvertToBoolean($parameter)
{
return in_array('boolean', Arr::get($this->rules, $parameter, []));
}
/**
* Convert the given values to boolean if they are string "true" / "false".
*
@@ -1531,24 +1775,16 @@ trait ValidatesAttributes
}
/**
* Validate that an attribute exists when another attribute does not have a given value.
* Convert the given values to null if they are string "null".
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
* @param array $values
* @return array
*/
public function validateRequiredUnless($attribute, $value, $parameters)
protected function convertValuesToNull($values)
{
$this->requireParameterCount(2, $parameters, 'required_unless');
[$values, $other] = $this->prepareValuesAndOther($parameters);
if (! in_array($other, $values)) {
return $this->validateRequired($attribute, $value);
}
return true;
return array_map(function ($value) {
return Str::lower($value) === 'null' ? null : $value;
}, $values);
}
/**
@@ -1569,7 +1805,7 @@ trait ValidatesAttributes
}
/**
* Validate that an attribute exists when all other attributes exists.
* Validate that an attribute exists when all other attributes exist.
*
* @param string $attribute
* @param mixed $value
@@ -1766,7 +2002,7 @@ trait ValidatesAttributes
* (c) Fabien Potencier <fabien@symfony.com> http://symfony.com
*/
$pattern = '~^
(aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|things|thismessage|tip|tn3270|tool|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s):// # protocol
(aaa|aaas|about|acap|acct|acd|acr|adiumxtra|adt|afp|afs|aim|amss|android|appdata|apt|ark|attachment|aw|barion|beshare|bitcoin|bitcoincash|blob|bolo|browserext|calculator|callto|cap|cast|casts|chrome|chrome-extension|cid|coap|coap\+tcp|coap\+ws|coaps|coaps\+tcp|coaps\+ws|com-eventbrite-attendee|content|conti|crid|cvs|dab|data|dav|diaspora|dict|did|dis|dlna-playcontainer|dlna-playsingle|dns|dntp|dpp|drm|drop|dtn|dvb|ed2k|elsi|example|facetime|fax|feed|feedready|file|filesystem|finger|first-run-pen-experience|fish|fm|ftp|fuchsia-pkg|geo|gg|git|gizmoproject|go|gopher|graph|gtalk|h323|ham|hcap|hcp|http|https|hxxp|hxxps|hydrazone|iax|icap|icon|im|imap|info|iotdisco|ipn|ipp|ipps|irc|irc6|ircs|iris|iris\.beep|iris\.lwz|iris\.xpc|iris\.xpcs|isostore|itms|jabber|jar|jms|keyparc|lastfm|ldap|ldaps|leaptofrogans|lorawan|lvlt|magnet|mailserver|mailto|maps|market|message|mid|mms|modem|mongodb|moz|ms-access|ms-browser-extension|ms-calculator|ms-drive-to|ms-enrollment|ms-excel|ms-eyecontrolspeech|ms-gamebarservices|ms-gamingoverlay|ms-getoffice|ms-help|ms-infopath|ms-inputapp|ms-lockscreencomponent-config|ms-media-stream-id|ms-mixedrealitycapture|ms-mobileplans|ms-officeapp|ms-people|ms-project|ms-powerpoint|ms-publisher|ms-restoretabcompanion|ms-screenclip|ms-screensketch|ms-search|ms-search-repair|ms-secondary-screen-controller|ms-secondary-screen-setup|ms-settings|ms-settings-airplanemode|ms-settings-bluetooth|ms-settings-camera|ms-settings-cellular|ms-settings-cloudstorage|ms-settings-connectabledevices|ms-settings-displays-topology|ms-settings-emailandaccounts|ms-settings-language|ms-settings-location|ms-settings-lock|ms-settings-nfctransactions|ms-settings-notifications|ms-settings-power|ms-settings-privacy|ms-settings-proximity|ms-settings-screenrotation|ms-settings-wifi|ms-settings-workplace|ms-spd|ms-sttoverlay|ms-transit-to|ms-useractivityset|ms-virtualtouchpad|ms-visio|ms-walk-to|ms-whiteboard|ms-whiteboard-cmd|ms-word|msnim|msrp|msrps|mss|mtqp|mumble|mupdate|mvn|news|nfs|ni|nih|nntp|notes|ocf|oid|onenote|onenote-cmd|opaquelocktoken|openpgp4fpr|pack|palm|paparazzi|payto|pkcs11|platform|pop|pres|prospero|proxy|pwid|psyc|pttp|qb|query|redis|rediss|reload|res|resource|rmi|rsync|rtmfp|rtmp|rtsp|rtsps|rtspu|s3|secondlife|service|session|sftp|sgn|shttp|sieve|simpleledger|sip|sips|skype|smb|sms|smtp|snews|snmp|soap\.beep|soap\.beeps|soldat|spiffe|spotify|ssh|steam|stun|stuns|submit|svn|tag|teamspeak|tel|teliaeid|telnet|tftp|tg|things|thismessage|tip|tn3270|tool|ts3server|turn|turns|tv|udp|unreal|urn|ut2004|v-event|vemmi|ventrilo|videotex|vnc|view-source|wais|webcal|wpid|ws|wss|wtai|wyciwyg|xcon|xcon-userid|xfire|xmlrpc\.beep|xmlrpc\.beeps|xmpp|xri|ymsgr|z39\.50|z39\.50r|z39\.50s):// # protocol
(((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+:)?((?:[\_\.\pL\pN-]|%[0-9A-Fa-f]{2})+)@)? # basic auth
(
([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name
@@ -1821,7 +2057,7 @@ trait ValidatesAttributes
return $value->getSize() / 1024;
}
return mb_strlen($value);
return mb_strlen($value ?? '');
}
/**
@@ -1873,7 +2109,7 @@ trait ValidatesAttributes
* @param array $parameters
* @return array
*/
protected function parseNamedParameters($parameters)
public function parseNamedParameters($parameters)
{
return array_reduce($parameters, function ($result, $item) {
[$key, $value] = array_pad(explode('=', $item, 2), 2, null);

View File

42
vendor/laravel/framework/src/Illuminate/Validation/Factory.php vendored Normal file → Executable file
View File

@@ -66,6 +66,13 @@ class Factory implements FactoryContract
*/
protected $fallbackMessages = [];
/**
* Indicates that unvalidated array keys should be excluded, even if the parent array was validated.
*
* @var bool
*/
protected $excludeUnvalidatedArrayKeys;
/**
* The Validator resolver instance.
*
@@ -115,6 +122,8 @@ class Factory implements FactoryContract
$validator->setContainer($this->container);
}
$validator->excludeUnvalidatedArrayKeys = $this->excludeUnvalidatedArrayKeys;
$this->addExtensions($validator);
return $validator;
@@ -239,6 +248,16 @@ class Factory implements FactoryContract
$this->replacers[$rule] = $replacer;
}
/**
* Indicate that unvalidated array keys should be excluded, even if the parent array was validated.
*
* @return void
*/
public function excludeUnvalidatedArrayKeys()
{
$this->excludeUnvalidatedArrayKeys = true;
}
/**
* Set the Validator instance resolver.
*
@@ -280,4 +299,27 @@ class Factory implements FactoryContract
{
$this->verifier = $presenceVerifier;
}
/**
* Get the container instance used by the validation factory.
*
* @return \Illuminate\Contracts\Container\Container
*/
public function getContainer()
{
return $this->container;
}
/**
* Set the container instance used by the validation factory.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return $this
*/
public function setContainer(Container $container)
{
$this->container = $container;
return $this;
}
}

View File

View File

@@ -15,6 +15,19 @@ class Rule
{
use Macroable;
/**
* Create a new conditional rule set.
*
* @param callable|bool $condition
* @param array|string $rules
* @param array|string $defaultRules
* @return \Illuminate\Validation\ConditionalRules
*/
public static function when($condition, $rules, $defaultRules = [])
{
return new ConditionalRules($condition, $rules, $defaultRules);
}
/**
* Get a dimensions constraint builder instance.
*

View File

@@ -65,9 +65,13 @@ trait DatabaseRule
if (is_subclass_of($table, Model::class)) {
$model = new $table;
return implode('.', array_filter(
[$model->getConnectionName(), $model->getTable()]
));
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;
@@ -77,7 +81,7 @@ trait DatabaseRule
* Set a "where" constraint on the query.
*
* @param \Closure|string $column
* @param array|string|null $value
* @param array|string|int|null $value
* @return $this
*/
public function where($column, $value = null)

View File

@@ -2,8 +2,12 @@
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Traits\Conditionable;
class Dimensions
{
use Conditionable;
/**
* The constraints for the dimensions rule.
*

View File

@@ -2,9 +2,24 @@
namespace Illuminate\Validation\Rules;
use Illuminate\Support\Traits\Conditionable;
class Exists
{
use DatabaseRule;
use Conditionable, DatabaseRule;
/**
* Ignore soft deleted models during the existence check.
*
* @param string $deletedAtColumn
* @return $this
*/
public function withoutTrashed($deletedAtColumn = 'deleted_at')
{
$this->whereNull($deletedAtColumn);
return $this;
}
/**
* Convert the rule to a validation string.

View File

@@ -2,6 +2,8 @@
namespace Illuminate\Validation\Rules;
use InvalidArgumentException;
class RequiredIf
{
/**
@@ -19,7 +21,11 @@ class RequiredIf
*/
public function __construct($condition)
{
$this->condition = $condition;
if (! is_string($condition)) {
$this->condition = $condition;
} else {
throw new InvalidArgumentException('The provided condition must be a callable or boolean.');
}
}
/**

View File

@@ -3,10 +3,11 @@
namespace Illuminate\Validation\Rules;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Traits\Conditionable;
class Unique
{
use DatabaseRule;
use Conditionable, DatabaseRule;
/**
* The ID that should be ignored.
@@ -56,6 +57,19 @@ class Unique
return $this;
}
/**
* Ignore soft deleted models during the unique check.
*
* @param string $deletedAtColumn
* @return $this
*/
public function withoutTrashed($deletedAtColumn = 'deleted_at')
{
$this->whereNull($deletedAtColumn);
return $this;
}
/**
* Convert the rule to a validation string.
*

View File

@@ -8,7 +8,7 @@ use Illuminate\Support\Str;
class ValidationData
{
/**
* Initialize and gather data for given attribute.
* Initialize and gather data for the given attribute.
*
* @param string $attribute
* @param array $masterData

View File

@@ -186,57 +186,57 @@ class ValidationRuleParser
/**
* Extract the rule name and parameters from a rule.
*
* @param array|string $rules
* @param array|string $rule
* @return array
*/
public static function parse($rules)
public static function parse($rule)
{
if ($rules instanceof RuleContract) {
return [$rules, []];
if ($rule instanceof RuleContract) {
return [$rule, []];
}
if (is_array($rules)) {
$rules = static::parseArrayRule($rules);
if (is_array($rule)) {
$rule = static::parseArrayRule($rule);
} else {
$rules = static::parseStringRule($rules);
$rule = static::parseStringRule($rule);
}
$rules[0] = static::normalizeRule($rules[0]);
$rule[0] = static::normalizeRule($rule[0]);
return $rules;
return $rule;
}
/**
* Parse an array based rule.
*
* @param array $rules
* @param array $rule
* @return array
*/
protected static function parseArrayRule(array $rules)
protected static function parseArrayRule(array $rule)
{
return [Str::studly(trim(Arr::get($rules, 0))), array_slice($rules, 1)];
return [Str::studly(trim(Arr::get($rule, 0, ''))), array_slice($rule, 1)];
}
/**
* Parse a string based rule.
*
* @param string $rules
* @param string $rule
* @return array
*/
protected static function parseStringRule($rules)
protected static function parseStringRule($rule)
{
$parameters = [];
// The format for specifying validation rules and parameters follows an
// easy {rule}:{parameters} formatting convention. For instance the
// rule "Max:3" states that the value may only be three letters.
if (strpos($rules, ':') !== false) {
[$rules, $parameter] = explode(':', $rules, 2);
if (strpos($rule, ':') !== false) {
[$rule, $parameter] = explode(':', $rule, 2);
$parameters = static::parseParameters($rules, $parameter);
$parameters = static::parseParameters($rule, $parameter);
}
return [Str::studly(trim($rules)), $parameters];
return [Str::studly(trim($rule)), $parameters];
}
/**
@@ -274,4 +274,35 @@ class ValidationRuleParser
return $rule;
}
}
/**
* Expand and conditional rules in the given array of rules.
*
* @param array $rules
* @param array $data
* @return array
*/
public static function filterConditionalRules($rules, array $data = [])
{
return collect($rules)->mapWithKeys(function ($attributeRules, $attribute) use ($data) {
if (! is_array($attributeRules) &&
! $attributeRules instanceof ConditionalRules) {
return [$attribute => $attributeRules];
}
if ($attributeRules instanceof ConditionalRules) {
return [$attribute => $attributeRules->passes($data)
? array_filter($attributeRules->rules())
: array_filter($attributeRules->defaultRules()), ];
}
return [$attribute => collect($attributeRules)->map(function ($rule) use ($data) {
if (! $rule instanceof ConditionalRules) {
return [$rule];
}
return $rule->passes($data) ? $rule->rules() : $rule->defaultRules();
})->filter()->flatten(1)->values()->all()];
})->all();
}
}

View File

@@ -3,6 +3,8 @@
namespace Illuminate\Validation;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Contracts\Validation\UncompromisedVerifier;
use Illuminate\Http\Client\Factory as HttpFactory;
use Illuminate\Support\ServiceProvider;
class ValidationServiceProvider extends ServiceProvider implements DeferrableProvider
@@ -15,7 +17,7 @@ class ValidationServiceProvider extends ServiceProvider implements DeferrablePro
public function register()
{
$this->registerPresenceVerifier();
$this->registerUncompromisedVerifier();
$this->registerValidationFactory();
}
@@ -52,6 +54,18 @@ class ValidationServiceProvider extends ServiceProvider implements DeferrablePro
});
}
/**
* Register the uncompromised password verifier.
*
* @return void
*/
protected function registerUncompromisedVerifier()
{
$this->app->singleton(UncompromisedVerifier::class, function ($app) {
return new NotPwnedVerifier($app[HttpFactory::class]);
});
}
/**
* Get the services provided by the provider.
*

192
vendor/laravel/framework/src/Illuminate/Validation/Validator.php vendored Normal file → Executable file
View File

@@ -5,14 +5,19 @@ namespace Illuminate\Validation;
use BadMethodCallException;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ImplicitRule;
use Illuminate\Contracts\Validation\Rule as RuleContract;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Fluent;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
use Illuminate\Support\ValidatedInput;
use InvalidArgumentException;
use RuntimeException;
use stdClass;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class Validator implements ValidatorContract
@@ -146,6 +151,20 @@ class Validator implements ValidatorContract
*/
public $customValues = [];
/**
* Indicates if the validator should stop on the first rule failure.
*
* @var bool
*/
protected $stopOnFirstFailure = false;
/**
* Indicates that unvalidated array keys should be excluded, even if the parent array was validated.
*
* @var bool
*/
public $excludeUnvalidatedArrayKeys = false;
/**
* All of the custom validator extensions.
*
@@ -163,7 +182,7 @@ class Validator implements ValidatorContract
/**
* The validation rules that may be applied to files.
*
* @var array
* @var string[]
*/
protected $fileRules = [
'Between',
@@ -180,10 +199,13 @@ class Validator implements ValidatorContract
/**
* The validation rules that imply the field is required.
*
* @var array
* @var string[]
*/
protected $implicitRules = [
'Accepted',
'AcceptedIf',
'Declined',
'DeclinedIf',
'Filled',
'Present',
'Required',
@@ -198,7 +220,7 @@ class Validator implements ValidatorContract
/**
* The validation rules which depend on other fields as parameters.
*
* @var array
* @var string[]
*/
protected $dependentRules = [
'After',
@@ -214,12 +236,18 @@ class Validator implements ValidatorContract
'Gte',
'Lt',
'Lte',
'AcceptedIf',
'DeclinedIf',
'RequiredIf',
'RequiredUnless',
'RequiredWith',
'RequiredWithAll',
'RequiredWithout',
'RequiredWithoutAll',
'Prohibited',
'ProhibitedIf',
'ProhibitedUnless',
'Prohibits',
'Same',
'Unique',
];
@@ -227,21 +255,21 @@ class Validator implements ValidatorContract
/**
* The validation rules that can exclude an attribute.
*
* @var array
* @var string[]
*/
protected $excludeRules = ['ExcludeIf', 'ExcludeUnless', 'ExcludeWithout'];
protected $excludeRules = ['Exclude', 'ExcludeIf', 'ExcludeUnless', 'ExcludeWithout'];
/**
* The size related validation rules.
*
* @var array
* @var string[]
*/
protected $sizeRules = ['Size', 'Between', 'Min', 'Max', 'Gt', 'Lt', 'Gte', 'Lte'];
/**
* The numeric related validation rules.
*
* @var array
* @var string[]
*/
protected $numericRules = ['Numeric', 'Integer'];
@@ -252,6 +280,13 @@ class Validator implements ValidatorContract
*/
protected $dotPlaceholder;
/**
* The exception to throw upon failure.
*
* @var string
*/
protected $exception = ValidationException::class;
/**
* Create a new Validator instance.
*
@@ -373,6 +408,10 @@ class Validator implements ValidatorContract
continue;
}
if ($this->stopOnFirstFailure && $this->messages->isNotEmpty()) {
break;
}
foreach ($rules as $rule) {
$this->validateAttribute($attribute, $rule);
@@ -447,9 +486,7 @@ class Validator implements ValidatorContract
*/
public function validate()
{
if ($this->fails()) {
throw new ValidationException($this);
}
throw_if($this->fails(), $this->exception, $this);
return $this->validated();
}
@@ -473,6 +510,19 @@ class Validator implements ValidatorContract
}
}
/**
* Get a validated input container for the validated input.
*
* @param array|null $keys
* @return \Illuminate\Support\ValidatedInput|array
*/
public function safe(array $keys = null)
{
return is_array($keys)
? (new ValidatedInput($this->validated()))->only($keys)
: new ValidatedInput($this->validated());
}
/**
* Get the attributes and values that were validated.
*
@@ -482,15 +532,19 @@ class Validator implements ValidatorContract
*/
public function validated()
{
if ($this->invalid()) {
throw new ValidationException($this);
}
throw_if($this->invalid(), $this->exception, $this);
$results = [];
$missingValue = Str::random(10);
$missingValue = new stdClass;
foreach ($this->getRules() as $key => $rules) {
if ($this->excludeUnvalidatedArrayKeys &&
in_array('array', $rules) &&
! empty(preg_grep('/^'.preg_quote($key, '/').'\.+/', array_keys($this->getRules())))) {
continue;
}
foreach (array_keys($this->getRules()) as $key) {
$value = data_get($this->getData(), $key, $missingValue);
if ($value !== $missingValue) {
@@ -514,16 +568,19 @@ class Validator implements ValidatorContract
[$rule, $parameters] = ValidationRuleParser::parse($rule);
if ($rule == '') {
if ($rule === '') {
return;
}
// First we will get the correct keys for the given attribute in case the field is nested in
// an array. Then we determine if the given rule accepts other field names as parameters.
// If so, we will replace any asterisks found in the parameters with the correct keys.
if (($keys = $this->getExplicitKeys($attribute)) &&
$this->dependsOnOtherFields($rule)) {
$parameters = $this->replaceAsterisksInParameters($parameters, $keys);
if ($this->dependsOnOtherFields($rule)) {
$parameters = $this->replaceDotInParameters($parameters);
if ($keys = $this->getExplicitKeys($attribute)) {
$parameters = $this->replaceAsterisksInParameters($parameters, $keys);
}
}
$value = $this->getValue($attribute);
@@ -606,6 +663,20 @@ class Validator implements ValidatorContract
return $attribute;
}
/**
* Replace each field parameter which has an escaped dot with the dot placeholder.
*
* @param array $parameters
* @param array $keys
* @return array
*/
protected function replaceDotInParameters(array $parameters)
{
return array_map(function ($field) {
return str_replace('\.', $this->dotPlaceholder, $field);
}, $parameters);
}
/**
* Replace each field parameter which has asterisks with the given keys.
*
@@ -732,6 +803,14 @@ class Validator implements ValidatorContract
$value = is_array($value) ? $this->replacePlaceholders($value) : $value;
if ($rule instanceof ValidatorAwareRule) {
$rule->setValidator($this);
}
if ($rule instanceof DataAwareRule) {
$rule->setData($this->data);
}
if (! $rule->passes($attribute, $value)) {
$this->failedRules[$attribute][get_class($rule)] = [];
@@ -788,6 +867,8 @@ class Validator implements ValidatorContract
$this->passes();
}
$attributeWithPlaceholders = $attribute;
$attribute = str_replace(
[$this->dotPlaceholder, '__asterisk__'],
['.', '*'],
@@ -799,7 +880,7 @@ class Validator implements ValidatorContract
}
$this->messages->add($attribute, $this->makeReplacements(
$this->getMessage($attribute, $rule), $attribute, $rule, $parameters
$this->getMessage($attributeWithPlaceholders, $rule), $attribute, $rule, $parameters
));
$this->failedRules[$attribute][$rule] = $parameters;
@@ -1041,7 +1122,7 @@ class Validator implements ValidatorContract
// of the explicit rules needed for the given data. For example the rule
// names.* would get expanded to names.0, names.1, etc. for this data.
$response = (new ValidationRuleParser($this->data))
->explode($rules);
->explode(ValidationRuleParser::filterConditionalRules($rules, $this->data));
$this->rules = array_merge_recursive(
$this->rules, $response->rules
@@ -1062,17 +1143,55 @@ class Validator implements ValidatorContract
*/
public function sometimes($attribute, $rules, callable $callback)
{
$payload = new Fluent($this->getData());
$payload = new Fluent($this->data);
if ($callback($payload)) {
foreach ((array) $attribute as $key) {
$this->addRules([$key => $rules]);
foreach ((array) $attribute as $key) {
$response = (new ValidationRuleParser($this->data))->explode([$key => $rules]);
$this->implicitAttributes = array_merge($response->implicitAttributes, $this->implicitAttributes);
foreach ($response->rules as $ruleKey => $ruleValue) {
if ($callback($payload, $this->dataForSometimesIteration($ruleKey, ! Str::endsWith($key, '.*')))) {
$this->addRules([$ruleKey => $ruleValue]);
}
}
}
return $this;
}
/**
* Get the data that should be injected into the iteration of a wildcard "sometimes" callback.
*
* @param string $attribute
* @return \Illuminate\Support\Fluent|array|mixed
*/
private function dataForSometimesIteration(string $attribute, $removeLastSegmentOfAttribute)
{
$lastSegmentOfAttribute = strrchr($attribute, '.');
$attribute = $lastSegmentOfAttribute && $removeLastSegmentOfAttribute
? Str::replaceLast($lastSegmentOfAttribute, '', $attribute)
: $attribute;
return is_array($data = data_get($this->data, $attribute))
? new Fluent($data)
: $data;
}
/**
* Instruct the validator to stop validating after the first rule failure.
*
* @param bool $stopOnFirstFailure
* @return $this
*/
public function stopOnFirstFailure($stopOnFirstFailure = true)
{
$this->stopOnFirstFailure = $stopOnFirstFailure;
return $this;
}
/**
* Register an array of custom validator extensions.
*
@@ -1229,7 +1348,7 @@ class Validator implements ValidatorContract
}
/**
* Set the callback that used to format an implicit attribute..
* Set the callback that used to format an implicit attribute.
*
* @param callable|null $formatter
* @return $this
@@ -1310,6 +1429,27 @@ class Validator implements ValidatorContract
$this->presenceVerifier = $presenceVerifier;
}
/**
* Set the exception to throw upon failed validation.
*
* @param string $exception
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setException($exception)
{
if (! is_a($exception, ValidationException::class, true)) {
throw new InvalidArgumentException(
sprintf('Exception [%s] is invalid. It must extend [%s].', $exception, ValidationException::class)
);
}
$this->exception = $exception;
return $this;
}
/**
* Get the Translator implementation.
*

21
vendor/laravel/framework/src/Illuminate/Validation/composer.json vendored Normal file → Executable file
View File

@@ -14,15 +14,17 @@
}
],
"require": {
"php": "^7.2.5|^8.0",
"php": "^7.3|^8.0",
"ext-json": "*",
"egulias/email-validator": "^2.1.10",
"illuminate/container": "^7.0",
"illuminate/contracts": "^7.0",
"illuminate/support": "^7.0",
"illuminate/translation": "^7.0",
"symfony/http-foundation": "^5.0",
"symfony/mime": "^5.0"
"illuminate/collections": "^8.0",
"illuminate/container": "^8.0",
"illuminate/contracts": "^8.0",
"illuminate/macroable": "^8.0",
"illuminate/support": "^8.0",
"illuminate/translation": "^8.0",
"symfony/http-foundation": "^5.4",
"symfony/mime": "^5.4"
},
"autoload": {
"psr-4": {
@@ -31,11 +33,12 @@
},
"extra": {
"branch-alias": {
"dev-master": "7.x-dev"
"dev-master": "8.x-dev"
}
},
"suggest": {
"illuminate/database": "Required to use the database presence verifier (^7.0)."
"ext-bcmath": "Required to use the multiple_of validation rule.",
"illuminate/database": "Required to use the database presence verifier (^8.0)."
},
"config": {
"sort-packages": true