MessageBag.php 8.4 KB

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