WhereQuery.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <?php
  2. /*
  3. * File: Query.php
  4. * Category: -
  5. * Author: M. Goldenbaum
  6. * Created: 21.07.18 18:54
  7. * Updated: -
  8. *
  9. * Description:
  10. * -
  11. */
  12. namespace Webklex\PHPIMAP\Query;
  13. use Closure;
  14. use Illuminate\Support\Str;
  15. use Webklex\PHPIMAP\Exceptions\InvalidWhereQueryCriteriaException;
  16. use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
  17. use Webklex\PHPIMAP\Exceptions\MessageSearchValidationException;
  18. /**
  19. * Class WhereQuery
  20. *
  21. * @package Webklex\PHPIMAP\Query
  22. *
  23. * @method WhereQuery all()
  24. * @method WhereQuery answered()
  25. * @method WhereQuery deleted()
  26. * @method WhereQuery new()
  27. * @method WhereQuery old()
  28. * @method WhereQuery recent()
  29. * @method WhereQuery seen()
  30. * @method WhereQuery unanswered()
  31. * @method WhereQuery undeleted()
  32. * @method WhereQuery unflagged()
  33. * @method WhereQuery unseen()
  34. * @method WhereQuery not()
  35. * @method WhereQuery unkeyword($value)
  36. * @method WhereQuery to($value)
  37. * @method WhereQuery text($value)
  38. * @method WhereQuery subject($value)
  39. * @method WhereQuery since($date)
  40. * @method WhereQuery on($date)
  41. * @method WhereQuery keyword($value)
  42. * @method WhereQuery from($value)
  43. * @method WhereQuery flagged()
  44. * @method WhereQuery cc($value)
  45. * @method WhereQuery body($value)
  46. * @method WhereQuery before($date)
  47. * @method WhereQuery bcc($value)
  48. * @method WhereQuery inReplyTo($value)
  49. * @method WhereQuery messageId($value)
  50. *
  51. * @mixin Query
  52. */
  53. class WhereQuery extends Query {
  54. /**
  55. * @var array $available_criteria
  56. */
  57. protected $available_criteria = [
  58. 'OR', 'AND',
  59. 'ALL', 'ANSWERED', 'BCC', 'BEFORE', 'BODY', 'CC', 'DELETED', 'FLAGGED', 'FROM', 'KEYWORD',
  60. 'NEW', 'NOT', 'OLD', 'ON', 'RECENT', 'SEEN', 'SINCE', 'SUBJECT', 'TEXT', 'TO',
  61. 'UNANSWERED', 'UNDELETED', 'UNFLAGGED', 'UNKEYWORD', 'UNSEEN', 'UID'
  62. ];
  63. /**
  64. * Magic method in order to allow alias usage of all "where" methods in an optional connection with "NOT"
  65. * @param string $name
  66. * @param array|null $arguments
  67. *
  68. * @return mixed
  69. * @throws InvalidWhereQueryCriteriaException
  70. * @throws MethodNotFoundException
  71. */
  72. public function __call($name, $arguments) {
  73. $that = $this;
  74. $name = Str::camel($name);
  75. if (strtolower(substr($name, 0, 3)) === 'not') {
  76. $that = $that->whereNot();
  77. $name = substr($name, 3);
  78. }
  79. if (strpos(strtolower($name), "where") === false) {
  80. $method = 'where' . ucfirst($name);
  81. } else {
  82. $method = lcfirst($name);
  83. }
  84. if (method_exists($this, $method) === true) {
  85. return call_user_func_array([$that, $method], $arguments);
  86. }
  87. throw new MethodNotFoundException("Method " . self::class . '::' . $method . '() is not supported');
  88. }
  89. /**
  90. * Validate a given criteria
  91. * @param $criteria
  92. *
  93. * @return string
  94. * @throws InvalidWhereQueryCriteriaException
  95. */
  96. protected function validate_criteria($criteria) {
  97. $criteria = strtoupper($criteria);
  98. if (substr($criteria, 0, 7) === "CUSTOM ") {
  99. return substr($criteria, 7);
  100. }
  101. if (in_array($criteria, $this->available_criteria) === false) {
  102. throw new InvalidWhereQueryCriteriaException();
  103. }
  104. return $criteria;
  105. }
  106. /**
  107. * Register search parameters
  108. * @param mixed $criteria
  109. * @param null $value
  110. *
  111. * @return $this
  112. * @throws InvalidWhereQueryCriteriaException
  113. *
  114. * Examples:
  115. * $query->from("someone@email.tld")->seen();
  116. * $query->whereFrom("someone@email.tld")->whereSeen();
  117. * $query->where([["FROM" => "someone@email.tld"], ["SEEN"]]);
  118. * $query->where(["FROM" => "someone@email.tld"])->where(["SEEN"]);
  119. * $query->where(["FROM" => "someone@email.tld", "SEEN"]);
  120. * $query->where("FROM", "someone@email.tld")->where("SEEN");
  121. */
  122. public function where($criteria, $value = null): WhereQuery {
  123. if (is_array($criteria)) {
  124. foreach ($criteria as $key => $value) {
  125. if (is_numeric($key)) {
  126. $this->where($value);
  127. }else{
  128. $this->where($key, $value);
  129. }
  130. }
  131. } else {
  132. $this->push_search_criteria($criteria, $value);
  133. }
  134. return $this;
  135. }
  136. /**
  137. * Push a given search criteria and value pair to the search query
  138. * @param $criteria string
  139. * @param $value mixed
  140. *
  141. * @throws InvalidWhereQueryCriteriaException
  142. */
  143. protected function push_search_criteria(string $criteria, $value){
  144. $criteria = $this->validate_criteria($criteria);
  145. $value = $this->parse_value($value);
  146. if ($value === null || $value === '') {
  147. $this->query->push([$criteria]);
  148. } else {
  149. $this->query->push([$criteria, $value]);
  150. }
  151. }
  152. /**
  153. * @param Closure $closure
  154. *
  155. * @return $this
  156. */
  157. public function orWhere(Closure $closure = null) {
  158. $this->query->push(['OR']);
  159. if ($closure !== null) $closure($this);
  160. return $this;
  161. }
  162. /**
  163. * @param Closure $closure
  164. *
  165. * @return $this
  166. */
  167. public function andWhere(Closure $closure = null) {
  168. $this->query->push(['AND']);
  169. if ($closure !== null) $closure($this);
  170. return $this;
  171. }
  172. /**
  173. * @return WhereQuery
  174. * @throws InvalidWhereQueryCriteriaException
  175. */
  176. public function whereAll() {
  177. return $this->where('ALL');
  178. }
  179. /**
  180. * @return WhereQuery
  181. * @throws InvalidWhereQueryCriteriaException
  182. */
  183. public function whereAnswered() {
  184. return $this->where('ANSWERED');
  185. }
  186. /**
  187. * @param string $value
  188. *
  189. * @return WhereQuery
  190. * @throws InvalidWhereQueryCriteriaException
  191. */
  192. public function whereBcc($value) {
  193. return $this->where('BCC', $value);
  194. }
  195. /**
  196. * @param mixed $value
  197. * @return WhereQuery
  198. * @throws InvalidWhereQueryCriteriaException
  199. * @throws MessageSearchValidationException
  200. */
  201. public function whereBefore($value) {
  202. $date = $this->parse_date($value);
  203. return $this->where('BEFORE', $date);
  204. }
  205. /**
  206. * @param string $value
  207. *
  208. * @return WhereQuery
  209. * @throws InvalidWhereQueryCriteriaException
  210. */
  211. public function whereBody($value) {
  212. return $this->where('BODY', $value);
  213. }
  214. /**
  215. * @param string $value
  216. *
  217. * @return WhereQuery
  218. * @throws InvalidWhereQueryCriteriaException
  219. */
  220. public function whereCc($value) {
  221. return $this->where('CC', $value);
  222. }
  223. /**
  224. * @return WhereQuery
  225. * @throws InvalidWhereQueryCriteriaException
  226. */
  227. public function whereDeleted() {
  228. return $this->where('DELETED');
  229. }
  230. /**
  231. * @param string $value
  232. *
  233. * @return WhereQuery
  234. * @throws InvalidWhereQueryCriteriaException
  235. */
  236. public function whereFlagged($value) {
  237. return $this->where('FLAGGED', $value);
  238. }
  239. /**
  240. * @param string $value
  241. *
  242. * @return WhereQuery
  243. * @throws InvalidWhereQueryCriteriaException
  244. */
  245. public function whereFrom($value) {
  246. return $this->where('FROM', $value);
  247. }
  248. /**
  249. * @param string $value
  250. *
  251. * @return WhereQuery
  252. * @throws InvalidWhereQueryCriteriaException
  253. */
  254. public function whereKeyword($value) {
  255. return $this->where('KEYWORD', $value);
  256. }
  257. /**
  258. * @return WhereQuery
  259. * @throws InvalidWhereQueryCriteriaException
  260. */
  261. public function whereNew() {
  262. return $this->where('NEW');
  263. }
  264. /**
  265. * @return WhereQuery
  266. * @throws InvalidWhereQueryCriteriaException
  267. */
  268. public function whereNot() {
  269. return $this->where('NOT');
  270. }
  271. /**
  272. * @return WhereQuery
  273. * @throws InvalidWhereQueryCriteriaException
  274. */
  275. public function whereOld() {
  276. return $this->where('OLD');
  277. }
  278. /**
  279. * @param mixed $value
  280. *
  281. * @return WhereQuery
  282. * @throws MessageSearchValidationException
  283. * @throws InvalidWhereQueryCriteriaException
  284. */
  285. public function whereOn($value) {
  286. $date = $this->parse_date($value);
  287. return $this->where('ON', $date);
  288. }
  289. /**
  290. * @return WhereQuery
  291. * @throws InvalidWhereQueryCriteriaException
  292. */
  293. public function whereRecent() {
  294. return $this->where('RECENT');
  295. }
  296. /**
  297. * @return WhereQuery
  298. * @throws InvalidWhereQueryCriteriaException
  299. */
  300. public function whereSeen() {
  301. return $this->where('SEEN');
  302. }
  303. /**
  304. * @param mixed $value
  305. *
  306. * @return WhereQuery
  307. * @throws MessageSearchValidationException
  308. * @throws InvalidWhereQueryCriteriaException
  309. */
  310. public function whereSince($value) {
  311. $date = $this->parse_date($value);
  312. return $this->where('SINCE', $date);
  313. }
  314. /**
  315. * @param string $value
  316. *
  317. * @return WhereQuery
  318. * @throws InvalidWhereQueryCriteriaException
  319. */
  320. public function whereSubject($value) {
  321. return $this->where('SUBJECT', $value);
  322. }
  323. /**
  324. * @param string $value
  325. *
  326. * @return WhereQuery
  327. * @throws InvalidWhereQueryCriteriaException
  328. */
  329. public function whereText($value) {
  330. return $this->where('TEXT', $value);
  331. }
  332. /**
  333. * @param string $value
  334. *
  335. * @return WhereQuery
  336. * @throws InvalidWhereQueryCriteriaException
  337. */
  338. public function whereTo($value) {
  339. return $this->where('TO', $value);
  340. }
  341. /**
  342. * @param string $value
  343. *
  344. * @return WhereQuery
  345. * @throws InvalidWhereQueryCriteriaException
  346. */
  347. public function whereUnkeyword($value) {
  348. return $this->where('UNKEYWORD', $value);
  349. }
  350. /**
  351. * @return WhereQuery
  352. * @throws InvalidWhereQueryCriteriaException
  353. */
  354. public function whereUnanswered() {
  355. return $this->where('UNANSWERED');
  356. }
  357. /**
  358. * @return WhereQuery
  359. * @throws InvalidWhereQueryCriteriaException
  360. */
  361. public function whereUndeleted() {
  362. return $this->where('UNDELETED');
  363. }
  364. /**
  365. * @return WhereQuery
  366. * @throws InvalidWhereQueryCriteriaException
  367. */
  368. public function whereUnflagged() {
  369. return $this->where('UNFLAGGED');
  370. }
  371. /**
  372. * @return WhereQuery
  373. * @throws InvalidWhereQueryCriteriaException
  374. */
  375. public function whereUnseen() {
  376. return $this->where('UNSEEN');
  377. }
  378. /**
  379. * @return WhereQuery
  380. * @throws InvalidWhereQueryCriteriaException
  381. */
  382. public function whereNoXSpam() {
  383. return $this->where("CUSTOM X-Spam-Flag NO");
  384. }
  385. /**
  386. * @return WhereQuery
  387. * @throws InvalidWhereQueryCriteriaException
  388. */
  389. public function whereIsXSpam() {
  390. return $this->where("CUSTOM X-Spam-Flag YES");
  391. }
  392. /**
  393. * Search for a specific header value
  394. * @param $header
  395. * @param $value
  396. *
  397. * @return WhereQuery
  398. * @throws InvalidWhereQueryCriteriaException
  399. */
  400. public function whereHeader($header, $value) {
  401. return $this->where("CUSTOM HEADER $header $value");
  402. }
  403. /**
  404. * Search for a specific message id
  405. * @param $messageId
  406. *
  407. * @return WhereQuery
  408. * @throws InvalidWhereQueryCriteriaException
  409. */
  410. public function whereMessageId($messageId) {
  411. return $this->whereHeader("Message-ID", $messageId);
  412. }
  413. /**
  414. * Search for a specific message id
  415. * @param $messageId
  416. *
  417. * @return WhereQuery
  418. * @throws InvalidWhereQueryCriteriaException
  419. */
  420. public function whereInReplyTo($messageId) {
  421. return $this->whereHeader("In-Reply-To", $messageId);
  422. }
  423. /**
  424. * @param $country_code
  425. *
  426. * @return WhereQuery
  427. * @throws InvalidWhereQueryCriteriaException
  428. */
  429. public function whereLanguage($country_code) {
  430. return $this->where("Content-Language $country_code");
  431. }
  432. /**
  433. * Get message be it UID.
  434. *
  435. * @param int|string $uid
  436. *
  437. * @return WhereQuery
  438. * @throws InvalidWhereQueryCriteriaException
  439. */
  440. public function whereUid($uid)
  441. {
  442. return $this->where('UID', $uid);
  443. }
  444. /**
  445. * Get messages by their UIDs.
  446. *
  447. * @param array<int, int> $uids
  448. *
  449. * @return WhereQuery
  450. * @throws InvalidWhereQueryCriteriaException
  451. */
  452. public function whereUidIn($uids)
  453. {
  454. $uids = implode(',', $uids);
  455. return $this->where('UID', $uids);
  456. }
  457. /**
  458. * Apply the callback if the given "value" is truthy.
  459. * copied from @url https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Traits/Conditionable.php
  460. *
  461. * @param mixed $value
  462. * @param callable $callback
  463. * @param callable|null $default
  464. * @return $this|mixed
  465. */
  466. public function when($value, $callback, $default = null) {
  467. if ($value) {
  468. return $callback($this, $value) ?: $this;
  469. } elseif ($default) {
  470. return $default($this, $value) ?: $this;
  471. }
  472. return $this;
  473. }
  474. /**
  475. * Apply the callback if the given "value" is falsy.
  476. * copied from @url https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Traits/Conditionable.php
  477. *
  478. * @param mixed $value
  479. * @param callable $callback
  480. * @param callable|null $default
  481. * @return $this|mixed
  482. */
  483. public function unless($value, $callback, $default = null) {
  484. if (! $value) {
  485. return $callback($this, $value) ?: $this;
  486. } elseif ($default) {
  487. return $default($this, $value) ?: $this;
  488. }
  489. return $this;
  490. }
  491. }