123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- <?php
-
- namespace Illuminate\Validation\Concerns;
-
- use Closure;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Str;
- use Symfony\Component\HttpFoundation\File\UploadedFile;
-
- trait FormatsMessages
- {
- use ReplacesAttributes;
-
- /**
- * Get the validation message for an attribute and rule.
- *
- * @param string $attribute
- * @param string $rule
- * @return string
- */
- protected function getMessage($attribute, $rule)
- {
- $inlineMessage = $this->getInlineMessage($attribute, $rule);
-
- // First we will retrieve the custom message for the validation rule if one
- // exists. If a custom validation message is being used we'll return the
- // custom message, otherwise we'll keep searching for a valid message.
- if (! is_null($inlineMessage)) {
- return $inlineMessage;
- }
-
- $lowerRule = Str::snake($rule);
-
- $customMessage = $this->getCustomMessageFromTranslator(
- $customKey = "validation.custom.{$attribute}.{$lowerRule}"
- );
-
- // First we check for a custom defined validation message for the attribute
- // and rule. This allows the developer to specify specific messages for
- // only some attributes and rules that need to get specially formed.
- if ($customMessage !== $customKey) {
- return $customMessage;
- }
-
- // If the rule being validated is a "size" rule, we will need to gather the
- // 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);
- }
-
- // Finally, if no developer specified messages have been set, and no other
- // special messages apply for this rule, we will just pull the default
- // messages out of the translator service for this validation rule.
- $key = "validation.{$lowerRule}";
-
- if ($key != ($value = $this->translator->trans($key))) {
- return $value;
- }
-
- return $this->getFromLocalArray(
- $attribute, $lowerRule, $this->fallbackMessages
- ) ?: $key;
- }
-
- /**
- * Get the proper inline error message for standard and size rules.
- *
- * @param string $attribute
- * @param string $rule
- * @return string|null
- */
- protected function getInlineMessage($attribute, $rule)
- {
- $inlineEntry = $this->getFromLocalArray($attribute, Str::snake($rule));
-
- return is_array($inlineEntry) && in_array($rule, $this->sizeRules)
- ? $inlineEntry[$this->getAttributeType($attribute)]
- : $inlineEntry;
- }
-
- /**
- * Get the inline message for a rule if it exists.
- *
- * @param string $attribute
- * @param string $lowerRule
- * @param array|null $source
- * @return string|null
- */
- protected function getFromLocalArray($attribute, $lowerRule, $source = null)
- {
- $source = $source ?: $this->customMessages;
-
- $keys = ["{$attribute}.{$lowerRule}", $lowerRule];
-
- // First we will check for a custom message for an attribute specific rule
- // message for the fields, then we will check for a general custom line
- // that is not attribute specific. If we find either we'll return it.
- foreach ($keys as $key) {
- foreach (array_keys($source) as $sourceKey) {
- if (Str::is($sourceKey, $key)) {
- return $source[$sourceKey];
- }
- }
- }
- }
-
- /**
- * Get the custom error message from translator.
- *
- * @param string $key
- * @return string
- */
- protected function getCustomMessageFromTranslator($key)
- {
- if (($message = $this->translator->trans($key)) !== $key) {
- return $message;
- }
-
- // If an exact match was not found for the key, we will collapse all of these
- // messages and loop through them and try to find a wildcard match for the
- // given key. Otherwise, we will simply return the key's value back out.
- $shortKey = preg_replace(
- '/^validation\.custom\./', '', $key
- );
-
- return $this->getWildcardCustomMessages(Arr::dot(
- (array) $this->translator->trans('validation.custom')
- ), $shortKey, $key);
- }
-
- /**
- * Check the given messages for a wildcard key.
- *
- * @param array $messages
- * @param string $search
- * @param string $default
- * @return string
- */
- protected function getWildcardCustomMessages($messages, $search, $default)
- {
- foreach ($messages as $key => $message) {
- if ($search === $key || (Str::contains($key, ['*']) && Str::is($key, $search))) {
- return $message;
- }
- }
-
- return $default;
- }
-
- /**
- * Get the proper error message for an attribute and size rule.
- *
- * @param string $attribute
- * @param string $rule
- * @return string
- */
- protected function getSizeMessage($attribute, $rule)
- {
- $lowerRule = Str::snake($rule);
-
- // There are three different types of size validations. The attribute may be
- // either a number, file, or string so we will check a few things to know
- // which type of value it is and return the correct line for that type.
- $type = $this->getAttributeType($attribute);
-
- $key = "validation.{$lowerRule}.{$type}";
-
- return $this->translator->trans($key);
- }
-
- /**
- * Get the data type of the given attribute.
- *
- * @param string $attribute
- * @return string
- */
- protected function getAttributeType($attribute)
- {
- // We assume that the attributes present in the file array are files so that
- // means that if the attribute does not have a numeric rule and the files
- // list doesn't have it we'll just consider it a string by elimination.
- if ($this->hasRule($attribute, $this->numericRules)) {
- return 'numeric';
- } elseif ($this->hasRule($attribute, ['Array'])) {
- return 'array';
- } elseif ($this->getValue($attribute) instanceof UploadedFile) {
- return 'file';
- }
-
- return 'string';
- }
-
- /**
- * Replace all error message place-holders with actual values.
- *
- * @param string $message
- * @param string $attribute
- * @param string $rule
- * @param array $parameters
- * @return string
- */
- public function makeReplacements($message, $attribute, $rule, $parameters)
- {
- $message = $this->replaceAttributePlaceholder(
- $message, $this->getDisplayableAttribute($attribute)
- );
-
- $message = $this->replaceInputPlaceholder($message, $attribute);
-
- if (isset($this->replacers[Str::snake($rule)])) {
- return $this->callReplacer($message, $attribute, Str::snake($rule), $parameters, $this);
- } elseif (method_exists($this, $replacer = "replace{$rule}")) {
- return $this->$replacer($message, $attribute, $rule, $parameters);
- }
-
- return $message;
- }
-
- /**
- * Get the displayable name of the attribute.
- *
- * @param string $attribute
- * @return string
- */
- public function getDisplayableAttribute($attribute)
- {
- $primaryAttribute = $this->getPrimaryAttribute($attribute);
-
- $expectedAttributes = $attribute != $primaryAttribute
- ? [$attribute, $primaryAttribute] : [$attribute];
-
- foreach ($expectedAttributes as $name) {
- // The developer may dynamically specify the array of custom attributes on this
- // validator instance. If the attribute exists in this array it is used over
- // the other ways of pulling the attribute name for this given attributes.
- if (isset($this->customAttributes[$name])) {
- return $this->customAttributes[$name];
- }
-
- // We allow for a developer to specify language lines for any attribute in this
- // application, which allows flexibility for displaying a unique displayable
- // version of the attribute name instead of the name used in an HTTP POST.
- if ($line = $this->getAttributeFromTranslations($name)) {
- return $line;
- }
- }
-
- // When no language line has been specified for the attribute and it is also
- // an implicit attribute we will display the raw attribute's name and not
- // modify it with any of these replacements before we display the name.
- if (isset($this->implicitAttributes[$primaryAttribute])) {
- return $attribute;
- }
-
- return str_replace('_', ' ', Str::snake($attribute));
- }
-
- /**
- * Get the given attribute from the attribute translations.
- *
- * @param string $name
- * @return string
- */
- protected function getAttributeFromTranslations($name)
- {
- return Arr::get($this->translator->trans('validation.attributes'), $name);
- }
-
- /**
- * Replace the :attribute placeholder in the given message.
- *
- * @param string $message
- * @param string $value
- * @return string
- */
- protected function replaceAttributePlaceholder($message, $value)
- {
- return str_replace(
- [':attribute', ':ATTRIBUTE', ':Attribute'],
- [$value, Str::upper($value), Str::ucfirst($value)],
- $message
- );
- }
-
- /**
- * Replace the :input placeholder in the given message.
- *
- * @param string $message
- * @param string $attribute
- * @return string
- */
- protected function replaceInputPlaceholder($message, $attribute)
- {
- $actualValue = $this->getValue($attribute);
-
- if (is_scalar($actualValue) || is_null($actualValue)) {
- $message = str_replace(':input', $actualValue, $message);
- }
-
- return $message;
- }
-
- /**
- * Get the displayable name of the value.
- *
- * @param string $attribute
- * @param mixed $value
- * @return string
- */
- public function getDisplayableValue($attribute, $value)
- {
- if (isset($this->customValues[$attribute][$value])) {
- return $this->customValues[$attribute][$value];
- }
-
- $key = "validation.values.{$attribute}.{$value}";
-
- if (($line = $this->translator->trans($key)) !== $key) {
- return $line;
- }
-
- return $value;
- }
-
- /**
- * Transform an array of attributes to their displayable form.
- *
- * @param array $values
- * @return array
- */
- protected function getAttributeList(array $values)
- {
- $attributes = [];
-
- // For each attribute in the list we will simply get its displayable form as
- // this is convenient when replacing lists of parameters like some of the
- // replacement functions do when formatting out the validation message.
- foreach ($values as $key => $value) {
- $attributes[$key] = $this->getDisplayableAttribute($value);
- }
-
- return $attributes;
- }
-
- /**
- * Call a custom validator message replacer.
- *
- * @param string $message
- * @param string $attribute
- * @param string $rule
- * @param array $parameters
- * @param \Illuminate\Validation\Validator $validator
- * @return string|null
- */
- protected function callReplacer($message, $attribute, $rule, $parameters, $validator)
- {
- $callback = $this->replacers[$rule];
-
- if ($callback instanceof Closure) {
- return call_user_func_array($callback, func_get_args());
- } elseif (is_string($callback)) {
- return $this->callClassBasedReplacer($callback, $message, $attribute, $rule, $parameters, $validator);
- }
- }
-
- /**
- * Call a class based validator message replacer.
- *
- * @param string $callback
- * @param string $message
- * @param string $attribute
- * @param string $rule
- * @param array $parameters
- * @param \Illuminate\Validation\Validator $validator
- * @return string
- */
- protected function callClassBasedReplacer($callback, $message, $attribute, $rule, $parameters, $validator)
- {
- list($class, $method) = Str::parseCallback($callback, 'replace');
-
- return call_user_func_array([$this->container->make($class), $method], array_slice(func_get_args(), 1));
- }
- }
|