validator.php 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. <?php namespace Laravel; use Closure;
  2. class Validator {
  3. /**
  4. * The array being validated.
  5. *
  6. * @var array
  7. */
  8. public $attributes;
  9. /**
  10. * The post-validation error messages.
  11. *
  12. * @var Messages
  13. */
  14. public $errors;
  15. /**
  16. * The validation rules.
  17. *
  18. * @var array
  19. */
  20. protected $rules = array();
  21. /**
  22. * The validation messages.
  23. *
  24. * @var array
  25. */
  26. protected $messages = array();
  27. /**
  28. * The database connection that should be used by the validator.
  29. *
  30. * @var Database\Connection
  31. */
  32. protected $db;
  33. /**
  34. * The bundle for which the validation is being run.
  35. *
  36. * @var string
  37. */
  38. protected $bundle = DEFAULT_BUNDLE;
  39. /**
  40. * The language that should be used when retrieving error messages.
  41. *
  42. * @var string
  43. */
  44. protected $language;
  45. /**
  46. * The size related validation rules.
  47. *
  48. * @var array
  49. */
  50. protected $size_rules = array('size', 'between', 'min', 'max');
  51. /**
  52. * The numeric related validation rules.
  53. *
  54. * @var array
  55. */
  56. protected $numeric_rules = array('numeric', 'integer');
  57. /**
  58. * The registered custom validators.
  59. *
  60. * @var array
  61. */
  62. protected static $validators = array();
  63. /**
  64. * Create a new validator instance.
  65. *
  66. * @param array $attributes
  67. * @param array $rules
  68. * @param array $messages
  69. * @return void
  70. */
  71. public function __construct($attributes, $rules, $messages = array())
  72. {
  73. foreach ($rules as $key => &$rule)
  74. {
  75. $rule = (is_string($rule)) ? explode('|', $rule) : $rule;
  76. }
  77. $this->rules = $rules;
  78. $this->messages = $messages;
  79. $this->attributes = $attributes;
  80. }
  81. /**
  82. * Create a new validator instance.
  83. *
  84. * @param array $attributes
  85. * @param array $rules
  86. * @param array $messages
  87. * @return Validator
  88. */
  89. public static function make($attributes, $rules, $messages = array())
  90. {
  91. return new static($attributes, $rules, $messages);
  92. }
  93. /**
  94. * Register a custom validator.
  95. *
  96. * @param string $name
  97. * @param Closure $validator
  98. * @return void
  99. */
  100. public static function register($name, $validator)
  101. {
  102. static::$validators[$name] = $validator;
  103. }
  104. /**
  105. * Validate the target array using the specified validation rules.
  106. *
  107. * @return bool
  108. */
  109. public function passes()
  110. {
  111. return $this->valid();
  112. }
  113. /**
  114. * Validate the target array using the specified validation rules.
  115. *
  116. * @return bool
  117. */
  118. public function fails()
  119. {
  120. return $this->invalid();
  121. }
  122. /**
  123. * Validate the target array using the specified validation rules.
  124. *
  125. * @return bool
  126. */
  127. public function invalid()
  128. {
  129. return ! $this->valid();
  130. }
  131. /**
  132. * Validate the target array using the specified validation rules.
  133. *
  134. * @return bool
  135. */
  136. public function valid()
  137. {
  138. $this->errors = new Messages;
  139. foreach ($this->rules as $attribute => $rules)
  140. {
  141. foreach ($rules as $rule) $this->check($attribute, $rule);
  142. }
  143. return count($this->errors->messages) == 0;
  144. }
  145. /**
  146. * Evaluate an attribute against a validation rule.
  147. *
  148. * @param string $attribute
  149. * @param string $rule
  150. * @return void
  151. */
  152. protected function check($attribute, $rule)
  153. {
  154. list($rule, $parameters) = $this->parse($rule);
  155. $value = array_get($this->attributes, $attribute);
  156. // Before running the validator, we need to verify that the attribute and rule
  157. // combination is actually validatable. Only the "accepted" rule implies that
  158. // the attribute is "required", so if the attribute does not exist, the other
  159. // rules will not be run for the attribute.
  160. $validatable = $this->validatable($rule, $attribute, $value);
  161. if ($validatable and ! $this->{'validate_'.$rule}($attribute, $value, $parameters, $this))
  162. {
  163. $this->error($attribute, $rule, $parameters);
  164. }
  165. }
  166. /**
  167. * Determine if an attribute is validatable.
  168. *
  169. * To be considered validatable, the attribute must either exist, or the rule
  170. * being checked must implicitly validate "required", such as the "required"
  171. * rule or the "accepted" rule.
  172. *
  173. * @param string $rule
  174. * @param string $attribute
  175. * @param mixed $value
  176. * @return bool
  177. */
  178. protected function validatable($rule, $attribute, $value)
  179. {
  180. return $this->validate_required($attribute, $value) or $this->implicit($rule);
  181. }
  182. /**
  183. * Determine if a given rule implies that the attribute is required.
  184. *
  185. * @param string $rule
  186. * @return bool
  187. */
  188. protected function implicit($rule)
  189. {
  190. return $rule == 'required' or $rule == 'accepted' or $rule == 'required_with';
  191. }
  192. /**
  193. * Add an error message to the validator's collection of messages.
  194. *
  195. * @param string $attribute
  196. * @param string $rule
  197. * @param array $parameters
  198. * @return void
  199. */
  200. protected function error($attribute, $rule, $parameters)
  201. {
  202. $message = $this->replace($this->message($attribute, $rule), $attribute, $rule, $parameters);
  203. $this->errors->add($attribute, $message);
  204. }
  205. /**
  206. * Validate that a required attribute exists in the attributes array.
  207. *
  208. * @param string $attribute
  209. * @param mixed $value
  210. * @return bool
  211. */
  212. protected function validate_required($attribute, $value)
  213. {
  214. if (is_null($value))
  215. {
  216. return false;
  217. }
  218. elseif (is_string($value) and trim($value) === '')
  219. {
  220. return false;
  221. }
  222. elseif ( ! is_null(Input::file($attribute)) and is_array($value) and $value['tmp_name'] == '')
  223. {
  224. return false;
  225. }
  226. return true;
  227. }
  228. /**
  229. * Validate that an attribute exists in the attributes array, if another
  230. * attribute exists in the attributes array.
  231. *
  232. * @param string $attribute
  233. * @param mixed $value
  234. * @param array $parameters
  235. * @return bool
  236. */
  237. protected function validate_required_with($attribute, $value, $parameters)
  238. {
  239. $other = $parameters[0];
  240. if ($this->validate_required($other, $this->attributes[$other]))
  241. {
  242. return $this->validate_required($attribute, $value);
  243. }
  244. return true;
  245. }
  246. /**
  247. * Validate that an attribute has a matching confirmation attribute.
  248. *
  249. * @param string $attribute
  250. * @param mixed $value
  251. * @return bool
  252. */
  253. protected function validate_confirmed($attribute, $value)
  254. {
  255. return $this->validate_same($attribute, $value, array($attribute.'_confirmation'));
  256. }
  257. /**
  258. * Validate that an attribute was "accepted".
  259. *
  260. * This validation rule implies the attribute is "required".
  261. *
  262. * @param string $attribute
  263. * @param mixed $value
  264. * @return bool
  265. */
  266. protected function validate_accepted($attribute, $value)
  267. {
  268. return $this->validate_required($attribute, $value) and ($value == 'yes' or $value == '1');
  269. }
  270. /**
  271. * Validate that an attribute is the same as another attribute.
  272. *
  273. * @param string $attribute
  274. * @param mixed $value
  275. * @param array $parameters
  276. * @return bool
  277. */
  278. protected function validate_same($attribute, $value, $parameters)
  279. {
  280. $other = $parameters[0];
  281. return isset($this->attributes[$other]) and $value == $this->attributes[$other];
  282. }
  283. /**
  284. * Validate that an attribute is different from another attribute.
  285. *
  286. * @param string $attribute
  287. * @param mixed $value
  288. * @param array $parameters
  289. * @return bool
  290. */
  291. protected function validate_different($attribute, $value, $parameters)
  292. {
  293. $other = $parameters[0];
  294. return isset($this->attributes[$other]) and $value != $this->attributes[$other];
  295. }
  296. /**
  297. * Validate that an attribute is numeric.
  298. *
  299. * @param string $attribute
  300. * @param mixed $value
  301. * @return bool
  302. */
  303. protected function validate_numeric($attribute, $value)
  304. {
  305. return is_numeric($value);
  306. }
  307. /**
  308. * Validate that an attribute is an integer.
  309. *
  310. * @param string $attribute
  311. * @param mixed $value
  312. * @return bool
  313. */
  314. protected function validate_integer($attribute, $value)
  315. {
  316. return filter_var($value, FILTER_VALIDATE_INT) !== false;
  317. }
  318. /**
  319. * Validate the size of an attribute.
  320. *
  321. * @param string $attribute
  322. * @param mixed $value
  323. * @param array $parameters
  324. * @return bool
  325. */
  326. protected function validate_size($attribute, $value, $parameters)
  327. {
  328. return $this->size($attribute, $value) == $parameters[0];
  329. }
  330. /**
  331. * Validate the size of an attribute is between a set of values.
  332. *
  333. * @param string $attribute
  334. * @param mixed $value
  335. * @param array $parameters
  336. * @return bool
  337. */
  338. protected function validate_between($attribute, $value, $parameters)
  339. {
  340. $size = $this->size($attribute, $value);
  341. return $size >= $parameters[0] and $size <= $parameters[1];
  342. }
  343. /**
  344. * Validate the size of an attribute is greater than a minimum value.
  345. *
  346. * @param string $attribute
  347. * @param mixed $value
  348. * @param array $parameters
  349. * @return bool
  350. */
  351. protected function validate_min($attribute, $value, $parameters)
  352. {
  353. return $this->size($attribute, $value) >= $parameters[0];
  354. }
  355. /**
  356. * Validate the size of an attribute is less than a maximum value.
  357. *
  358. * @param string $attribute
  359. * @param mixed $value
  360. * @param array $parameters
  361. * @return bool
  362. */
  363. protected function validate_max($attribute, $value, $parameters)
  364. {
  365. return $this->size($attribute, $value) <= $parameters[0];
  366. }
  367. /**
  368. * Get the size of an attribute.
  369. *
  370. * @param string $attribute
  371. * @param mixed $value
  372. * @return mixed
  373. */
  374. protected function size($attribute, $value)
  375. {
  376. // This method will determine if the attribute is a number, string, or file and
  377. // return the proper size accordingly. If it is a number, the number itself is
  378. // the size; if it is a file, the kilobytes is the size; if it is a
  379. // string, the length is the size.
  380. if (is_numeric($value) and $this->has_rule($attribute, $this->numeric_rules))
  381. {
  382. return $this->attributes[$attribute];
  383. }
  384. elseif (array_key_exists($attribute, Input::file()))
  385. {
  386. return $value['size'] / 1024;
  387. }
  388. else
  389. {
  390. return Str::length(trim($value));
  391. }
  392. }
  393. /**
  394. * Validate an attribute is contained within a list of values.
  395. *
  396. * @param string $attribute
  397. * @param mixed $value
  398. * @param array $parameters
  399. * @return bool
  400. */
  401. protected function validate_in($attribute, $value, $parameters)
  402. {
  403. return in_array($value, $parameters);
  404. }
  405. /**
  406. * Validate an attribute is not contained within a list of values.
  407. *
  408. * @param string $attribute
  409. * @param mixed $value
  410. * @param array $parameters
  411. * @return bool
  412. */
  413. protected function validate_not_in($attribute, $value, $parameters)
  414. {
  415. return ! in_array($value, $parameters);
  416. }
  417. /**
  418. * Validate the uniqueness of an attribute value on a given database table.
  419. *
  420. * If a database column is not specified, the attribute will be used.
  421. *
  422. * @param string $attribute
  423. * @param mixed $value
  424. * @param array $parameters
  425. * @return bool
  426. */
  427. protected function validate_unique($attribute, $value, $parameters)
  428. {
  429. // We allow the table column to be specified just in case the column does
  430. // not have the same name as the attribute. It must be within the second
  431. // parameter position, right after the database table name.
  432. if (isset($parameters[1]))
  433. {
  434. $attribute = $parameters[1];
  435. }
  436. $query = $this->db()->table($parameters[0])->where($attribute, '=', $value);
  437. // We also allow an ID to be specified that will not be included in the
  438. // uniqueness check. This makes updating columns easier since it is
  439. // fine for the given ID to exist in the table.
  440. if (isset($parameters[2]))
  441. {
  442. $id = (isset($parameters[3])) ? $parameters[3] : 'id';
  443. $query->where($id, '<>', $parameters[2]);
  444. }
  445. return $query->count() == 0;
  446. }
  447. /**
  448. * Validate the existence of an attribute value in a database table.
  449. *
  450. * @param string $attribute
  451. * @param mixed $value
  452. * @param array $parameters
  453. * @return bool
  454. */
  455. protected function validate_exists($attribute, $value, $parameters)
  456. {
  457. if (isset($parameters[1])) $attribute = $parameters[1];
  458. // Grab the number of elements we are looking for. If the given value is
  459. // in array, we'll count all of the values in the array, otherwise we
  460. // can just make sure the count is greater or equal to one.
  461. $count = (is_array($value)) ? count($value) : 1;
  462. $query = $this->db()->table($parameters[0]);
  463. // If the given value is an array, we will check for the existence of
  464. // all the values in the database, otherwise we'll check for the
  465. // presence of the single given value in the database.
  466. if (is_array($value))
  467. {
  468. $query = $query->where_in($attribute, $value);
  469. }
  470. else
  471. {
  472. $query = $query->where($attribute, '=', $value);
  473. }
  474. return $query->count() >= $count;
  475. }
  476. /**
  477. * Validate that an attribute is a valid IP.
  478. *
  479. * @param string $attribute
  480. * @param mixed $value
  481. * @return bool
  482. */
  483. protected function validate_ip($attribute, $value)
  484. {
  485. return filter_var($value, FILTER_VALIDATE_IP) !== false;
  486. }
  487. /**
  488. * Validate that an attribute is a valid e-mail address.
  489. *
  490. * @param string $attribute
  491. * @param mixed $value
  492. * @return bool
  493. */
  494. protected function validate_email($attribute, $value)
  495. {
  496. return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
  497. }
  498. /**
  499. * Validate that an attribute is a valid URL.
  500. *
  501. * @param string $attribute
  502. * @param mixed $value
  503. * @return bool
  504. */
  505. protected function validate_url($attribute, $value)
  506. {
  507. return filter_var($value, FILTER_VALIDATE_URL) !== false;
  508. }
  509. /**
  510. * Validate that an attribute is an active URL.
  511. *
  512. * @param string $attribute
  513. * @param mixed $value
  514. * @return bool
  515. */
  516. protected function validate_active_url($attribute, $value)
  517. {
  518. $url = str_replace(array('http://', 'https://', 'ftp://'), '', Str::lower($value));
  519. return (trim($url) !== '') ? checkdnsrr($url) : false;
  520. }
  521. /**
  522. * Validate the MIME type of a file is an image MIME type.
  523. *
  524. * @param string $attribute
  525. * @param mixed $value
  526. * @return bool
  527. */
  528. protected function validate_image($attribute, $value)
  529. {
  530. return $this->validate_mimes($attribute, $value, array('jpg', 'png', 'gif', 'bmp'));
  531. }
  532. /**
  533. * Validate that an attribute contains only alphabetic characters.
  534. *
  535. * @param string $attribute
  536. * @param mixed $value
  537. * @return bool
  538. */
  539. protected function validate_alpha($attribute, $value)
  540. {
  541. return preg_match('/^([a-z])+$/i', $value);
  542. }
  543. /**
  544. * Validate that an attribute contains only alpha-numeric characters.
  545. *
  546. * @param string $attribute
  547. * @param mixed $value
  548. * @return bool
  549. */
  550. protected function validate_alpha_num($attribute, $value)
  551. {
  552. return preg_match('/^([a-z0-9])+$/i', $value);
  553. }
  554. /**
  555. * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores.
  556. *
  557. * @param string $attribute
  558. * @param mixed $value
  559. * @return bool
  560. */
  561. protected function validate_alpha_dash($attribute, $value)
  562. {
  563. return preg_match('/^([-a-z0-9_-])+$/i', $value);
  564. }
  565. /**
  566. * Validate that an attribute passes a regular expression check.
  567. *
  568. * @param string $attribute
  569. * @param mixed $value
  570. * @param array $parameters
  571. * @return bool
  572. */
  573. protected function validate_match($attribute, $value, $parameters)
  574. {
  575. return preg_match($parameters[0], $value);
  576. }
  577. /**
  578. * Validate the MIME type of a file upload attribute is in a set of MIME types.
  579. *
  580. * @param string $attribute
  581. * @param array $value
  582. * @param array $parameters
  583. * @return bool
  584. */
  585. protected function validate_mimes($attribute, $value, $parameters)
  586. {
  587. if ( ! is_array($value) or array_get($value, 'tmp_name', '') == '') return true;
  588. foreach ($parameters as $extension)
  589. {
  590. if (File::is($extension, $value['tmp_name']))
  591. {
  592. return true;
  593. }
  594. }
  595. return false;
  596. }
  597. /**
  598. * Validate that an attribute is an array
  599. *
  600. * @param string $attribute
  601. * @param mixed $value
  602. * @return bool
  603. */
  604. protected function validate_array($attribute, $value)
  605. {
  606. return is_array($value);
  607. }
  608. /**
  609. * Validate that an attribute of type array has a specific count
  610. *
  611. * @param string $attribute
  612. * @param mixed $value
  613. * @param array $parameters
  614. * @return bool
  615. */
  616. protected function validate_count($attribute, $value, $parameters)
  617. {
  618. return (is_array($value) && count($value) == $parameters[0]);
  619. }
  620. /**
  621. * Validate that an attribute of type array has a minimum of elements.
  622. *
  623. * @param string $attribute
  624. * @param mixed $value
  625. * @param array $parameters
  626. * @return bool
  627. */
  628. protected function validate_countmin($attribute, $value, $parameters)
  629. {
  630. return (is_array($value) && count($value) >= $parameters[0]);
  631. }
  632. /**
  633. * Validate that an attribute of type array has a maximum of elements.
  634. *
  635. * @param string $attribute
  636. * @param mixed $value
  637. * @param array $parameters
  638. * @return bool
  639. */
  640. protected function validate_countmax($attribute, $value, $parameters)
  641. {
  642. return (is_array($value) && count($value) <= $parameters[0]);
  643. }
  644. /**
  645. * Validate that an attribute of type array has elements between max and min.
  646. *
  647. * @param string $attribute
  648. * @param mixed $value
  649. * @param array $parameters
  650. * @return bool
  651. */
  652. protected function validate_countbetween($attribute, $value, $parameters)
  653. {
  654. return (is_array($value) && count($value) >= $parameters[0] && count($value) <= $parameters[1] );
  655. }
  656. /**
  657. * Validate the date is before a given date.
  658. *
  659. * @param string $attribute
  660. * @param mixed $value
  661. * @param array $parameters
  662. * @return bool
  663. */
  664. protected function validate_before($attribute, $value, $parameters)
  665. {
  666. return (strtotime($value) < strtotime($parameters[0]));
  667. }
  668. /**
  669. * Validate the date is after a given date.
  670. *
  671. * @param string $attribute
  672. * @param mixed $value
  673. * @param array $parameters
  674. * @return bool
  675. */
  676. protected function validate_after($attribute, $value, $parameters)
  677. {
  678. return (strtotime($value) > strtotime($parameters[0]));
  679. }
  680. /**
  681. * Get the proper error message for an attribute and rule.
  682. *
  683. * @param string $attribute
  684. * @param string $rule
  685. * @return string
  686. */
  687. protected function message($attribute, $rule)
  688. {
  689. $bundle = Bundle::prefix($this->bundle);
  690. // First we'll check for developer specified, attribute specific messages.
  691. // These messages take first priority. They allow the fine-grained tuning
  692. // of error messages for each rule.
  693. $custom = $attribute.'_'.$rule;
  694. if (array_key_exists($custom, $this->messages))
  695. {
  696. return $this->messages[$custom];
  697. }
  698. elseif (Lang::has($custom = "{$bundle}validation.custom.{$custom}", $this->language))
  699. {
  700. return Lang::line($custom)->get($this->language);
  701. }
  702. // Next we'll check for developer specified, rule specific error messages.
  703. // These allow the developer to override the error message for an entire
  704. // rule, regardless of the attribute being validated by that rule.
  705. elseif (array_key_exists($rule, $this->messages))
  706. {
  707. return $this->messages[$rule];
  708. }
  709. // If the rule being validated is a "size" rule, we will need to gather
  710. // the specific size message for the type of attribute being validated,
  711. // either a number, file, or string.
  712. elseif (in_array($rule, $this->size_rules))
  713. {
  714. return $this->size_message($bundle, $attribute, $rule);
  715. }
  716. // If no developer specified messages have been set, and no other special
  717. // messages apply to the rule, we will just pull the default validation
  718. // message from the validation language file.
  719. else
  720. {
  721. $line = "{$bundle}validation.{$rule}";
  722. return Lang::line($line)->get($this->language);
  723. }
  724. }
  725. /**
  726. * Get the proper error message for an attribute and size rule.
  727. *
  728. * @param string $bundle
  729. * @param string $attribute
  730. * @param string $rule
  731. * @return string
  732. */
  733. protected function size_message($bundle, $attribute, $rule)
  734. {
  735. // There are three different types of size validations. The attribute
  736. // may be either a number, file, or a string, so we'll check a few
  737. // things to figure out which one it is.
  738. if ($this->has_rule($attribute, $this->numeric_rules))
  739. {
  740. $line = 'numeric';
  741. }
  742. // We assume that attributes present in the $_FILES array are files,
  743. // which makes sense. If the attribute doesn't have numeric rules
  744. // and isn't a file, it's a string.
  745. elseif (array_key_exists($attribute, Input::file()))
  746. {
  747. $line = 'file';
  748. }
  749. else
  750. {
  751. $line = 'string';
  752. }
  753. return Lang::line("{$bundle}validation.{$rule}.{$line}")->get($this->language);
  754. }
  755. /**
  756. * Replace all error message place-holders with actual values.
  757. *
  758. * @param string $message
  759. * @param string $attribute
  760. * @param string $rule
  761. * @param array $parameters
  762. * @return string
  763. */
  764. protected function replace($message, $attribute, $rule, $parameters)
  765. {
  766. $message = str_replace(':attribute', $this->attribute($attribute), $message);
  767. if (method_exists($this, $replacer = 'replace_'.$rule))
  768. {
  769. $message = $this->$replacer($message, $attribute, $rule, $parameters);
  770. }
  771. return $message;
  772. }
  773. /**
  774. * Replace all place-holders for the required_with rule.
  775. *
  776. * @param string $message
  777. * @param string $attribute
  778. * @param string $rule
  779. * @param array $parameters
  780. * @return string
  781. */
  782. protected function replace_required_with($message, $attribute, $rule, $parameters)
  783. {
  784. return str_replace(':field', $this->attribute($parameters[0]), $message);
  785. }
  786. /**
  787. * Replace all place-holders for the between rule.
  788. *
  789. * @param string $message
  790. * @param string $attribute
  791. * @param string $rule
  792. * @param array $parameters
  793. * @return string
  794. */
  795. protected function replace_between($message, $attribute, $rule, $parameters)
  796. {
  797. return str_replace(array(':min', ':max'), $parameters, $message);
  798. }
  799. /**
  800. * Replace all place-holders for the size rule.
  801. *
  802. * @param string $message
  803. * @param string $attribute
  804. * @param string $rule
  805. * @param array $parameters
  806. * @return string
  807. */
  808. protected function replace_size($message, $attribute, $rule, $parameters)
  809. {
  810. return str_replace(':size', $parameters[0], $message);
  811. }
  812. /**
  813. * Replace all place-holders for the min rule.
  814. *
  815. * @param string $message
  816. * @param string $attribute
  817. * @param string $rule
  818. * @param array $parameters
  819. * @return string
  820. */
  821. protected function replace_min($message, $attribute, $rule, $parameters)
  822. {
  823. return str_replace(':min', $parameters[0], $message);
  824. }
  825. /**
  826. * Replace all place-holders for the max rule.
  827. *
  828. * @param string $message
  829. * @param string $attribute
  830. * @param string $rule
  831. * @param array $parameters
  832. * @return string
  833. */
  834. protected function replace_max($message, $attribute, $rule, $parameters)
  835. {
  836. return str_replace(':max', $parameters[0], $message);
  837. }
  838. /**
  839. * Replace all place-holders for the in rule.
  840. *
  841. * @param string $message
  842. * @param string $attribute
  843. * @param string $rule
  844. * @param array $parameters
  845. * @return string
  846. */
  847. protected function replace_in($message, $attribute, $rule, $parameters)
  848. {
  849. return str_replace(':values', implode(', ', $parameters), $message);
  850. }
  851. /**
  852. * Replace all place-holders for the not_in rule.
  853. *
  854. * @param string $message
  855. * @param string $attribute
  856. * @param string $rule
  857. * @param array $parameters
  858. * @return string
  859. */
  860. protected function replace_not_in($message, $attribute, $rule, $parameters)
  861. {
  862. return str_replace(':values', implode(', ', $parameters), $message);
  863. }
  864. /**
  865. * Replace all place-holders for the mimes rule.
  866. *
  867. * @param string $message
  868. * @param string $attribute
  869. * @param string $rule
  870. * @param array $parameters
  871. * @return string
  872. */
  873. protected function replace_mimes($message, $attribute, $rule, $parameters)
  874. {
  875. return str_replace(':values', implode(', ', $parameters), $message);
  876. }
  877. /**
  878. * Replace all place-holders for the same rule.
  879. *
  880. * @param string $message
  881. * @param string $attribute
  882. * @param string $rule
  883. * @param array $parameters
  884. * @return string
  885. */
  886. protected function replace_same($message, $attribute, $rule, $parameters)
  887. {
  888. return str_replace(':other', $parameters[0], $message);
  889. }
  890. /**
  891. * Replace all place-holders for the different rule.
  892. *
  893. * @param string $message
  894. * @param string $attribute
  895. * @param string $rule
  896. * @param array $parameters
  897. * @return string
  898. */
  899. protected function replace_different($message, $attribute, $rule, $parameters)
  900. {
  901. return str_replace(':other', $parameters[0], $message);
  902. }
  903. /**
  904. * Replace all place-holders for the before rule.
  905. *
  906. * @param string $message
  907. * @param string $attribute
  908. * @param string $rule
  909. * @param array $parameters
  910. * @return string
  911. */
  912. protected function replace_before($message, $attribute, $rule, $parameters)
  913. {
  914. return str_replace(':date', $parameters[0], $message);
  915. }
  916. /**
  917. * Replace all place-holders for the after rule.
  918. *
  919. * @param string $message
  920. * @param string $attribute
  921. * @param string $rule
  922. * @param array $parameters
  923. * @return string
  924. */
  925. protected function replace_after($message, $attribute, $rule, $parameters)
  926. {
  927. return str_replace(':date', $parameters[0], $message);
  928. }
  929. /**
  930. * Replace all place-holders for the count rule.
  931. *
  932. * @param string $message
  933. * @param string $attribute
  934. * @param string $rule
  935. * @param array $parameters
  936. * @return string
  937. */
  938. protected function replace_count($message, $attribute, $rule, $parameters)
  939. {
  940. return str_replace(':count', $parameters[0], $message);
  941. }
  942. /**
  943. * Replace all place-holders for the countmin rule.
  944. *
  945. * @param string $message
  946. * @param string $attribute
  947. * @param string $rule
  948. * @param array $parameters
  949. * @return string
  950. */
  951. protected function replace_countmin($message, $attribute, $rule, $parameters)
  952. {
  953. return str_replace(':min', $parameters[0], $message);
  954. }
  955. /**
  956. * Replace all place-holders for the countmax rule.
  957. *
  958. * @param string $message
  959. * @param string $attribute
  960. * @param string $rule
  961. * @param array $parameters
  962. * @return string
  963. */
  964. protected function replace_countmax($message, $attribute, $rule, $parameters)
  965. {
  966. return str_replace(':max', $parameters[0], $message);
  967. }
  968. /**
  969. * Replace all place-holders for the between rule.
  970. *
  971. * @param string $message
  972. * @param string $attribute
  973. * @param string $rule
  974. * @param array $parameters
  975. * @return string
  976. */
  977. protected function replace_countbetween($message, $attribute, $rule, $parameters)
  978. {
  979. return str_replace(array(':min', ':max'), $parameters, $message);
  980. }
  981. /**
  982. * Get the displayable name for a given attribute.
  983. *
  984. * @param string $attribute
  985. * @return string
  986. */
  987. protected function attribute($attribute)
  988. {
  989. $bundle = Bundle::prefix($this->bundle);
  990. // More reader friendly versions of the attribute names may be stored
  991. // in the validation language file, allowing a more readable version
  992. // of the attribute name in the message.
  993. $line = "{$bundle}validation.attributes.{$attribute}";
  994. if (Lang::has($line, $this->language))
  995. {
  996. return Lang::line($line)->get($this->language);
  997. }
  998. // If no language line has been specified for the attribute, all of
  999. // the underscores are removed from the attribute name and that
  1000. // will be used as the attribute name.
  1001. else
  1002. {
  1003. return str_replace('_', ' ', $attribute);
  1004. }
  1005. }
  1006. /**
  1007. * Determine if an attribute has a rule assigned to it.
  1008. *
  1009. * @param string $attribute
  1010. * @param array $rules
  1011. * @return bool
  1012. */
  1013. protected function has_rule($attribute, $rules)
  1014. {
  1015. foreach ($this->rules[$attribute] as $rule)
  1016. {
  1017. list($rule, $parameters) = $this->parse($rule);
  1018. if (in_array($rule, $rules)) return true;
  1019. }
  1020. return false;
  1021. }
  1022. /**
  1023. * Extract the rule name and parameters from a rule.
  1024. *
  1025. * @param string $rule
  1026. * @return array
  1027. */
  1028. protected function parse($rule)
  1029. {
  1030. $parameters = array();
  1031. // The format for specifying validation rules and parameters follows a
  1032. // {rule}:{parameters} formatting convention. For instance, the rule
  1033. // "max:3" specifies that the value may only be 3 characters long.
  1034. if (($colon = strpos($rule, ':')) !== false)
  1035. {
  1036. $parameters = str_getcsv(substr($rule, $colon + 1));
  1037. }
  1038. return array(is_numeric($colon) ? substr($rule, 0, $colon) : $rule, $parameters);
  1039. }
  1040. /**
  1041. * Set the bundle that the validator is running for.
  1042. *
  1043. * The bundle determines which bundle the language lines will be loaded from.
  1044. *
  1045. * @param string $bundle
  1046. * @return Validator
  1047. */
  1048. public function bundle($bundle)
  1049. {
  1050. $this->bundle = $bundle;
  1051. return $this;
  1052. }
  1053. /**
  1054. * Set the language that should be used when retrieving error messages.
  1055. *
  1056. * @param string $language
  1057. * @return Validator
  1058. */
  1059. public function speaks($language)
  1060. {
  1061. $this->language = $language;
  1062. return $this;
  1063. }
  1064. /**
  1065. * Set the database connection that should be used by the validator.
  1066. *
  1067. * @param Database\Connection $connection
  1068. * @return Validator
  1069. */
  1070. public function connection(Database\Connection $connection)
  1071. {
  1072. $this->db = $connection;
  1073. return $this;
  1074. }
  1075. /**
  1076. * Get the database connection for the Validator.
  1077. *
  1078. * @return Database\Connection
  1079. */
  1080. protected function db()
  1081. {
  1082. if ( ! is_null($this->db)) return $this->db;
  1083. return $this->db = Database::connection();
  1084. }
  1085. /**
  1086. * Dynamically handle calls to custom registered validators.
  1087. */
  1088. public function __call($method, $parameters)
  1089. {
  1090. // First we will slice the "validate_" prefix off of the validator since
  1091. // custom validators aren't registered with such a prefix, then we can
  1092. // just call the method with the given parameters.
  1093. if (isset(static::$validators[$method = substr($method, 9)]))
  1094. {
  1095. return call_user_func_array(static::$validators[$method], $parameters);
  1096. }
  1097. throw new \Exception("Method [$method] does not exist.");
  1098. }
  1099. }