MessageBag.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Support;
  12. use Countable;
  13. use Hyperf\Collection\Arr;
  14. use Hyperf\Contract\Arrayable;
  15. use Hyperf\Contract\Jsonable;
  16. use Hyperf\Contract\MessageBag as MessageBagContract;
  17. use Hyperf\Contract\MessageProvider;
  18. use Hyperf\Stringable\Str;
  19. use JsonSerializable;
  20. use function Hyperf\Collection\collect;
  21. class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, MessageBagContract, MessageProvider
  22. {
  23. /**
  24. * All the registered messages.
  25. */
  26. protected array $messages = [];
  27. /**
  28. * Default format for message output.
  29. */
  30. protected string $format = ':message';
  31. /**
  32. * Create a new message bag instance.
  33. */
  34. public function __construct(array $messages = [])
  35. {
  36. foreach ($messages as $key => $value) {
  37. $value = $value instanceof Arrayable ? $value->toArray() : (array) $value;
  38. $this->messages[$key] = array_unique($value);
  39. }
  40. }
  41. /**
  42. * Convert the message bag to its string representation.
  43. */
  44. public function __toString(): string
  45. {
  46. return $this->toJson();
  47. }
  48. /**
  49. * Get the keys present in the message bag.
  50. */
  51. public function keys(): array
  52. {
  53. return array_keys($this->messages);
  54. }
  55. /**
  56. * Add a message to the message bag.
  57. */
  58. public function add(string $key, string $message): MessageBagContract
  59. {
  60. if ($this->isUnique($key, $message)) {
  61. $this->messages[$key][] = $message;
  62. }
  63. return $this;
  64. }
  65. /**
  66. * Merge a new array of messages into the message bag.
  67. *
  68. * @param array|MessageProvider $messages
  69. * @return $this
  70. */
  71. public function merge($messages)
  72. {
  73. if ($messages instanceof MessageProvider) {
  74. $messages = $messages->getMessageBag()->getMessages();
  75. }
  76. $this->messages = array_merge_recursive($this->messages, $messages);
  77. return $this;
  78. }
  79. /**
  80. * Determine if messages exist for all the given keys.
  81. *
  82. * @param null|array|string $key
  83. */
  84. public function has($key): bool
  85. {
  86. if ($this->isEmpty()) {
  87. return false;
  88. }
  89. if (is_null($key)) {
  90. return $this->any();
  91. }
  92. $keys = is_array($key) ? $key : func_get_args();
  93. foreach ($keys as $key) {
  94. if ($this->first($key) === '') {
  95. return false;
  96. }
  97. }
  98. return true;
  99. }
  100. /**
  101. * Determine if messages exist for any of the given keys.
  102. *
  103. * @param array|string $keys
  104. */
  105. public function hasAny($keys = []): bool
  106. {
  107. if ($this->isEmpty()) {
  108. return false;
  109. }
  110. $keys = is_array($keys) ? $keys : func_get_args();
  111. foreach ($keys as $key) {
  112. if ($this->has($key)) {
  113. return true;
  114. }
  115. }
  116. return false;
  117. }
  118. /**
  119. * Get the first message from the message bag for a given key.
  120. *
  121. * @param string $key
  122. * @param string $format
  123. */
  124. public function first($key = null, $format = null): string
  125. {
  126. $messages = is_null($key) ? $this->all($format) : $this->get($key, $format);
  127. $firstMessage = Arr::first($messages, null, '');
  128. return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage;
  129. }
  130. /**
  131. * Get all the messages from the message bag for a given key.
  132. */
  133. public function get(string $key, ?string $format = null): array
  134. {
  135. // If the message exists in the message bag, we will transform it and return
  136. // the message. Otherwise, we will check if the key is implicit & collect
  137. // all the messages that match the given key and output it as an array.
  138. if (array_key_exists($key, $this->messages)) {
  139. return $this->transform(
  140. $this->messages[$key],
  141. $this->checkFormat($format),
  142. $key
  143. );
  144. }
  145. if (Str::contains($key, '*')) {
  146. return $this->getMessagesForWildcardKey($key, $format);
  147. }
  148. return [];
  149. }
  150. /**
  151. * Get all the messages for every key in the message bag.
  152. */
  153. public function all(?string $format = null): array
  154. {
  155. $format = $this->checkFormat($format);
  156. $all = [];
  157. foreach ($this->messages as $key => $messages) {
  158. $all = array_merge($all, $this->transform($messages, $format, $key));
  159. }
  160. return $all;
  161. }
  162. /**
  163. * Get all the unique messages for every key in the message bag.
  164. */
  165. public function unique(?string $format = null): array
  166. {
  167. return array_unique($this->all($format));
  168. }
  169. /**
  170. * Get the raw messages in the message bag.
  171. */
  172. public function messages(): array
  173. {
  174. return $this->messages;
  175. }
  176. /**
  177. * Get the raw messages in the message bag.
  178. */
  179. public function getMessages(): array
  180. {
  181. return $this->messages();
  182. }
  183. /**
  184. * Get the messages for the instance.
  185. */
  186. public function getMessageBag(): MessageBagContract
  187. {
  188. return $this;
  189. }
  190. /**
  191. * Get the default message format.
  192. */
  193. public function getFormat(): string
  194. {
  195. return $this->format;
  196. }
  197. /**
  198. * Set the default message format.
  199. */
  200. public function setFormat(string $format = ':message'): self
  201. {
  202. $this->format = $format;
  203. return $this;
  204. }
  205. /**
  206. * Determine if the message bag has any messages.
  207. */
  208. public function isEmpty(): bool
  209. {
  210. return ! $this->any();
  211. }
  212. /**
  213. * Determine if the message bag has any messages.
  214. */
  215. public function isNotEmpty(): bool
  216. {
  217. return $this->any();
  218. }
  219. /**
  220. * Determine if the message bag has any messages.
  221. */
  222. public function any(): bool
  223. {
  224. return $this->count() > 0;
  225. }
  226. /**
  227. * Get the number of messages in the message bag.
  228. */
  229. public function count(): int
  230. {
  231. return count($this->messages, COUNT_RECURSIVE) - count($this->messages);
  232. }
  233. /**
  234. * Get the instance as an array.
  235. */
  236. public function toArray(): array
  237. {
  238. return $this->getMessages();
  239. }
  240. /**
  241. * Convert the object into something JSON serializable.
  242. */
  243. public function jsonSerialize(): mixed
  244. {
  245. return $this->toArray();
  246. }
  247. /**
  248. * Convert the object to its JSON representation.
  249. */
  250. public function toJson(int $options = 0): string
  251. {
  252. return json_encode($this->jsonSerialize(), $options);
  253. }
  254. /**
  255. * Determine if a key and message combination already exists.
  256. */
  257. protected function isUnique(string $key, string $message): bool
  258. {
  259. $messages = $this->messages;
  260. return ! isset($messages[$key]) || ! in_array($message, $messages[$key]);
  261. }
  262. /**
  263. * Get the messages for a wildcard key.
  264. */
  265. protected function getMessagesForWildcardKey(string $key, ?string $format): array
  266. {
  267. return collect($this->messages)
  268. ->filter(function ($messages, $messageKey) use ($key) {
  269. return Str::is($key, $messageKey);
  270. })
  271. ->map(function ($messages, $messageKey) use ($format) {
  272. return $this->transform(
  273. $messages,
  274. $this->checkFormat($format),
  275. $messageKey
  276. );
  277. })->all();
  278. }
  279. /**
  280. * Format an array of messages.
  281. */
  282. protected function transform(array $messages, string $format, string $messageKey): array
  283. {
  284. return collect($messages)
  285. ->map(function ($message) use ($format, $messageKey) {
  286. // We will simply spin through the given messages and transform each one
  287. // replacing the :message placeholder with the real message allowing
  288. // the messages to be easily formatted to each developer's desires.
  289. return str_replace([':message', ':key'], [$message, $messageKey], $format);
  290. })->all();
  291. }
  292. /**
  293. * Get the appropriate format based on the given format.
  294. */
  295. protected function checkFormat(?string $format): string
  296. {
  297. return $format ?: $this->format;
  298. }
  299. }