validator.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  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 invalid()
  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 valid()
  119. {
  120. $this->errors = new Messages;
  121. foreach ($this->rules as $attribute => $rules)
  122. {
  123. foreach ($rules as $rule) $this->check($attribute, $rule);
  124. }
  125. return count($this->errors->messages) == 0;
  126. }
  127. /**
  128. * Evaluate an attribute against a validation rule.
  129. *
  130. * @param string $attribute
  131. * @param string $rule
  132. * @return void
  133. */
  134. protected function check($attribute, $rule)
  135. {
  136. list($rule, $parameters) = $this->parse($rule);
  137. $value = array_get($this->attributes, $attribute);
  138. // Before running the validator, we need to verify that the attribute and rule
  139. // combination is actually validatable. Only the "accepted" rule implies that
  140. // the attribute is "required", so if the attribute does not exist, the other
  141. // rules will not be run for the attribute.
  142. $validatable = $this->validatable($rule, $attribute, $value);
  143. if ($validatable and ! $this->{'validate_'.$rule}($attribute, $value, $parameters, $this))
  144. {
  145. $this->error($attribute, $rule, $parameters);
  146. }
  147. }
  148. /**
  149. * Determine if an attribute is validatable.
  150. *
  151. * To be considered validatable, the attribute must either exist, or the rule
  152. * being checked must implicitly validate "required", such as the "required"
  153. * rule or the "accepted" rule.
  154. *
  155. * @param string $rule
  156. * @param string $attribute
  157. * @param mixed $value
  158. * @return bool
  159. */
  160. protected function validatable($rule, $attribute, $value)
  161. {
  162. return $this->validate_required($attribute, $value) or $this->implicit($rule);
  163. }
  164. /**
  165. * Determine if a given rule implies that the attribute is required.
  166. *
  167. * @param string $rule
  168. * @return bool
  169. */
  170. protected function implicit($rule)
  171. {
  172. return $rule == 'required' or $rule == 'accepted';
  173. }
  174. /**
  175. * Add an error message to the validator's collection of messages.
  176. *
  177. * @param string $attribute
  178. * @param string $rule
  179. * @param array $parameters
  180. * @return void
  181. */
  182. protected function error($attribute, $rule, $parameters)
  183. {
  184. $message = $this->replace($this->message($attribute, $rule), $attribute, $rule, $parameters);
  185. $this->errors->add($attribute, $message);
  186. }
  187. /**
  188. * Validate that a required attribute exists in the attributes array.
  189. *
  190. * @param string $attribute
  191. * @param mixed $value
  192. * @return bool
  193. */
  194. protected function validate_required($attribute, $value)
  195. {
  196. if (is_null($value))
  197. {
  198. return false;
  199. }
  200. elseif (is_string($value) and trim($value) === '')
  201. {
  202. return false;
  203. }
  204. elseif ( ! is_null(Input::file($attribute)) and $value['tmp_name'] == '')
  205. {
  206. return false;
  207. }
  208. return true;
  209. }
  210. /**
  211. * Validate that an attribute has a matching confirmation attribute.
  212. *
  213. * @param string $attribute
  214. * @param mixed $value
  215. * @return bool
  216. */
  217. protected function validate_confirmed($attribute, $value)
  218. {
  219. return $this->validate_same($attribute, $value, array($attribute.'_confirmation'));
  220. }
  221. /**
  222. * Validate that an attribute was "accepted".
  223. *
  224. * This validation rule implies the attribute is "required".
  225. *
  226. * @param string $attribute
  227. * @param mixed $value
  228. * @return bool
  229. */
  230. protected function validate_accepted($attribute, $value)
  231. {
  232. return $this->validate_required($attribute, $value) and ($value == 'yes' or $value == '1');
  233. }
  234. /**
  235. * Validate that an attribute is the same as another attribute.
  236. *
  237. * @param string $attribute
  238. * @param mixed $value
  239. * @param array $parameters
  240. * @return bool
  241. */
  242. protected function validate_same($attribute, $value, $parameters)
  243. {
  244. $other = $parameters[0];
  245. return isset($this->attributes[$other]) and $value == $this->attributes[$other];
  246. }
  247. /**
  248. * Validate that an attribute is different from another attribute.
  249. *
  250. * @param string $attribute
  251. * @param mixed $value
  252. * @param array $parameters
  253. * @return bool
  254. */
  255. protected function validate_different($attribute, $value, $parameters)
  256. {
  257. $other = $parameters[0];
  258. return isset($this->attributes[$other]) and $value != $this->attributes[$other];
  259. }
  260. /**
  261. * Validate that an attribute is numeric.
  262. *
  263. * @param string $attribute
  264. * @param mixed $value
  265. * @return bool
  266. */
  267. protected function validate_numeric($attribute, $value)
  268. {
  269. return is_numeric($value);
  270. }
  271. /**
  272. * Validate that an attribute is an integer.
  273. *
  274. * @param string $attribute
  275. * @param mixed $value
  276. * @return bool
  277. */
  278. protected function validate_integer($attribute, $value)
  279. {
  280. return filter_var($value, FILTER_VALIDATE_INT) !== false;
  281. }
  282. /**
  283. * Validate the size of an attribute.
  284. *
  285. * @param string $attribute
  286. * @param mixed $value
  287. * @param array $parameters
  288. * @return bool
  289. */
  290. protected function validate_size($attribute, $value, $parameters)
  291. {
  292. return $this->size($attribute, $value) == $parameters[0];
  293. }
  294. /**
  295. * Validate the size of an attribute is between a set of values.
  296. *
  297. * @param string $attribute
  298. * @param mixed $value
  299. * @param array $parameters
  300. * @return bool
  301. */
  302. protected function validate_between($attribute, $value, $parameters)
  303. {
  304. $size = $this->size($attribute, $value);
  305. return $size >= $parameters[0] and $size <= $parameters[1];
  306. }
  307. /**
  308. * Validate the size of an attribute is greater than a minimum value.
  309. *
  310. * @param string $attribute
  311. * @param mixed $value
  312. * @param array $parameters
  313. * @return bool
  314. */
  315. protected function validate_min($attribute, $value, $parameters)
  316. {
  317. return $this->size($attribute, $value) >= $parameters[0];
  318. }
  319. /**
  320. * Validate the size of an attribute is less than a maximum value.
  321. *
  322. * @param string $attribute
  323. * @param mixed $value
  324. * @param array $parameters
  325. * @return bool
  326. */
  327. protected function validate_max($attribute, $value, $parameters)
  328. {
  329. return $this->size($attribute, $value) <= $parameters[0];
  330. }
  331. /**
  332. * Get the size of an attribute.
  333. *
  334. * @param string $attribute
  335. * @param mixed $value
  336. * @return mixed
  337. */
  338. protected function size($attribute, $value)
  339. {
  340. // This method will determine if the attribute is a number, string, or file and
  341. // return the proper size accordingly. If it is a number, then number itself is
  342. // the size; if it is a file, the size is kilobytes in the size; if it is a
  343. // string, the length is the size.
  344. if (is_numeric($value) and $this->has_rule($attribute, $this->numeric_rules))
  345. {
  346. return $this->attributes[$attribute];
  347. }
  348. elseif (array_key_exists($attribute, Input::file()))
  349. {
  350. return $value['size'] / 1024;
  351. }
  352. else
  353. {
  354. return Str::length(trim($value));
  355. }
  356. }
  357. /**
  358. * Validate an attribute is contained within a list of values.
  359. *
  360. * @param string $attribute
  361. * @param mixed $value
  362. * @param array $parameters
  363. * @return bool
  364. */
  365. protected function validate_in($attribute, $value, $parameters)
  366. {
  367. return in_array($value, $parameters);
  368. }
  369. /**
  370. * Validate an attribute is not contained within a list of values.
  371. *
  372. * @param string $attribute
  373. * @param mixed $value
  374. * @param array $parameters
  375. * @return bool
  376. */
  377. protected function validate_not_in($attribute, $value, $parameters)
  378. {
  379. return ! in_array($value, $parameters);
  380. }
  381. /**
  382. * Validate the uniqueness of an attribute value on a given database table.
  383. *
  384. * If a database column is not specified, the attribute will be used.
  385. *
  386. * @param string $attribute
  387. * @param mixed $value
  388. * @param array $parameters
  389. * @return bool
  390. */
  391. protected function validate_unique($attribute, $value, $parameters)
  392. {
  393. // We allow the table column to be specified just in case the column does
  394. // not have the same name as the attribute. It must be within the second
  395. // parameter position, right after the database table name.
  396. if (isset($parameters[1])) $attribute = $parameters[1];
  397. $query = $this->db()->table($parameters[0])->where($attribute, '=', $value);
  398. // We also allow an ID to be specified that will not be included in the
  399. // uniqueness check. This makes updating columns easier since it is
  400. // fine for the given ID to exist in the table.
  401. if (isset($parameters[2]))
  402. {
  403. $id = (isset($parameters[3])) ? $parameters[3] : 'id';
  404. $query->where($id, '<>', $parameters[2]);
  405. }
  406. return $query->count() == 0;
  407. }
  408. /**
  409. * Validate the existence of an attribute value in a database table.
  410. *
  411. * @param string $attribute
  412. * @param mixed $value
  413. * @param array $parameters
  414. * @return bool
  415. */
  416. protected function validate_exists($attribute, $value, $parameters)
  417. {
  418. if (isset($parameters[1])) $attribute = $parameters[1];
  419. // Grab the number of elements we are looking for. If the given value is
  420. // in array, we'll count all of the values in the array, otherwise we
  421. // can just make sure the count is greater or equal to one.
  422. $count = (is_array($value)) ? count($value) : 1;
  423. $query = $this->db()->table($parameters[0]);
  424. // If the given value is an array, we will check for the existence of
  425. // all the values in the database, otherwise we'll check for the
  426. // presence of the single given value in the database.
  427. if (is_array($value))
  428. {
  429. $query = $query->where_in($attribute, $value);
  430. }
  431. else
  432. {
  433. $query = $query->where($attribute, '=', $value);
  434. }
  435. return $query->count() >= $count;
  436. }
  437. /**
  438. * Validate that an attribute is a valid IP.
  439. *
  440. * @param string $attribute
  441. * @param mixed $value
  442. * @return bool
  443. */
  444. protected function validate_ip($attribute, $value)
  445. {
  446. return filter_var($value, FILTER_VALIDATE_IP) !== false;
  447. }
  448. /**
  449. * Validate that an attribute is a valid e-mail address.
  450. *
  451. * @param string $attribute
  452. * @param mixed $value
  453. * @return bool
  454. */
  455. protected function validate_email($attribute, $value)
  456. {
  457. return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
  458. }
  459. /**
  460. * Validate that an attribute is a valid URL.
  461. *
  462. * @param string $attribute
  463. * @param mixed $value
  464. * @return bool
  465. */
  466. protected function validate_url($attribute, $value)
  467. {
  468. return filter_var($value, FILTER_VALIDATE_URL) !== false;
  469. }
  470. /**
  471. * Validate that an attribute is an active URL.
  472. *
  473. * @param string $attribute
  474. * @param mixed $value
  475. * @return bool
  476. */
  477. protected function validate_active_url($attribute, $value)
  478. {
  479. $url = str_replace(array('http://', 'https://', 'ftp://'), '', Str::lower($value));
  480. return checkdnsrr($url);
  481. }
  482. /**
  483. * Validate the MIME type of a file is an image MIME type.
  484. *
  485. * @param string $attribute
  486. * @param mixed $value
  487. * @return bool
  488. */
  489. protected function validate_image($attribute, $value)
  490. {
  491. return $this->validate_mimes($attribute, $value, array('jpg', 'png', 'gif', 'bmp'));
  492. }
  493. /**
  494. * Validate that an attribute contains only alphabetic characters.
  495. *
  496. * @param string $attribute
  497. * @param mixed $value
  498. * @return bool
  499. */
  500. protected function validate_alpha($attribute, $value)
  501. {
  502. return preg_match('/^([a-z])+$/i', $value);
  503. }
  504. /**
  505. * Validate that an attribute contains only alpha-numeric characters.
  506. *
  507. * @param string $attribute
  508. * @param mixed $value
  509. * @return bool
  510. */
  511. protected function validate_alpha_num($attribute, $value)
  512. {
  513. return preg_match('/^([a-z0-9])+$/i', $value);
  514. }
  515. /**
  516. * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores.
  517. *
  518. * @param string $attribute
  519. * @param mixed $value
  520. * @return bool
  521. */
  522. protected function validate_alpha_dash($attribute, $value)
  523. {
  524. return preg_match('/^([-a-z0-9_-])+$/i', $value);
  525. }
  526. /**
  527. * Validate the MIME type of a file upload attribute is in a set of MIME types.
  528. *
  529. * @param string $attribute
  530. * @param array $value
  531. * @param array $parameters
  532. * @return bool
  533. */
  534. protected function validate_mimes($attribute, $value, $parameters)
  535. {
  536. if ( ! is_array($value) or array_get($value, 'tmp_name', '') == '') return true;
  537. foreach ($parameters as $extension)
  538. {
  539. if (File::is($extension, $value['tmp_name']))
  540. {
  541. return true;
  542. }
  543. }
  544. return false;
  545. }
  546. /**
  547. * Get the proper error message for an attribute and rule.
  548. *
  549. * @param string $attribute
  550. * @param string $rule
  551. * @return string
  552. */
  553. protected function message($attribute, $rule)
  554. {
  555. $bundle = Bundle::prefix($this->bundle);
  556. // First we'll check for developer specified, attribute specific messages.
  557. // These messages take first priority. They allow the fine-grained tuning
  558. // of error messages for each rule.
  559. $custom = $attribute.'_'.$rule;
  560. if (array_key_exists($custom, $this->messages))
  561. {
  562. return $this->messages[$custom];
  563. }
  564. elseif (Lang::has($custom = "validation.custom.{$custom}", $this->language))
  565. {
  566. return Lang::line($custom)->get($this->language);
  567. }
  568. // Next we'll check for developer specified, rule specific error messages.
  569. // These allow the developer to override the error message for an entire
  570. // rule, regardless of the attribute being validated by that rule.
  571. elseif (array_key_exists($rule, $this->messages))
  572. {
  573. return $this->messages[$rule];
  574. }
  575. // If the rule being validated is a "size" rule, we will need to gather
  576. // the specific size message for the type of attribute being validated,
  577. // either a number, file, or string.
  578. elseif (in_array($rule, $this->size_rules))
  579. {
  580. return $this->size_message($bundle, $attribute, $rule);
  581. }
  582. // If no developer specified messages have been set, and no other special
  583. // messages apply to the rule, we will just pull the default validation
  584. // message from the validation language file.
  585. else
  586. {
  587. $line = "{$bundle}validation.{$rule}";
  588. return Lang::line($line)->get($this->language);
  589. }
  590. }
  591. /**
  592. * Get the proper error message for an attribute and size rule.
  593. *
  594. * @param string $bundle
  595. * @param string $attribute
  596. * @param string $rule
  597. * @return string
  598. */
  599. protected function size_message($bundle, $attribute, $rule)
  600. {
  601. // There are three different types of size validations. The attribute
  602. // may be either a number, file, or a string. If the attribute has a
  603. // numeric rule attached to it, we can assume it is a number. If the
  604. // attribute is in the file array, it is a file, otherwise we can
  605. // assume the attribute is simply a string.
  606. if ($this->has_rule($attribute, $this->numeric_rules))
  607. {
  608. $line = 'numeric';
  609. }
  610. elseif (array_key_exists($attribute, Input::file()))
  611. {
  612. $line = 'file';
  613. }
  614. else
  615. {
  616. $line = 'string';
  617. }
  618. return Lang::line("{$bundle}validation.{$rule}.{$line}")->get($this->language);
  619. }
  620. /**
  621. * Replace all error message place-holders with actual values.
  622. *
  623. * @param string $message
  624. * @param string $attribute
  625. * @param string $rule
  626. * @param array $parameters
  627. * @return string
  628. */
  629. protected function replace($message, $attribute, $rule, $parameters)
  630. {
  631. $message = str_replace(':attribute', $this->attribute($attribute), $message);
  632. if (method_exists($this, $replacer = 'replace_'.$rule))
  633. {
  634. $message = $this->$replacer($message, $attribute, $rule, $parameters);
  635. }
  636. return $message;
  637. }
  638. /**
  639. * Replace all place-holders for the between rule.
  640. *
  641. * @param string $message
  642. * @param string $attribute
  643. * @param string $rule
  644. * @param array $parameters
  645. * @return string
  646. */
  647. protected function replace_between($message, $attribute, $rule, $parameters)
  648. {
  649. return str_replace(array(':min', ':max'), $parameters, $message);
  650. }
  651. /**
  652. * Replace all place-holders for the size rule.
  653. *
  654. * @param string $message
  655. * @param string $attribute
  656. * @param string $rule
  657. * @param array $parameters
  658. * @return string
  659. */
  660. protected function replace_size($message, $attribute, $rule, $parameters)
  661. {
  662. return str_replace(':size', $parameters[0], $message);
  663. }
  664. /**
  665. * Replace all place-holders for the min rule.
  666. *
  667. * @param string $message
  668. * @param string $attribute
  669. * @param string $rule
  670. * @param array $parameters
  671. * @return string
  672. */
  673. protected function replace_min($message, $attribute, $rule, $parameters)
  674. {
  675. return str_replace(':min', $parameters[0], $message);
  676. }
  677. /**
  678. * Replace all place-holders for the max rule.
  679. *
  680. * @param string $message
  681. * @param string $attribute
  682. * @param string $rule
  683. * @param array $parameters
  684. * @return string
  685. */
  686. protected function replace_max($message, $attribute, $rule, $parameters)
  687. {
  688. return str_replace(':max', $parameters[0], $message);
  689. }
  690. /**
  691. * Replace all place-holders for the in rule.
  692. *
  693. * @param string $message
  694. * @param string $attribute
  695. * @param string $rule
  696. * @param array $parameters
  697. * @return string
  698. */
  699. protected function replace_in($message, $attribute, $rule, $parameters)
  700. {
  701. return str_replace(':values', implode(', ', $parameters), $message);
  702. }
  703. /**
  704. * Replace all place-holders for the not_in rule.
  705. *
  706. * @param string $message
  707. * @param string $attribute
  708. * @param string $rule
  709. * @param array $parameters
  710. * @return string
  711. */
  712. protected function replace_not_in($message, $attribute, $rule, $parameters)
  713. {
  714. return str_replace(':values', implode(', ', $parameters), $message);
  715. }
  716. /**
  717. * Replace all place-holders for the not_in rule.
  718. *
  719. * @param string $message
  720. * @param string $attribute
  721. * @param string $rule
  722. * @param array $parameters
  723. * @return string
  724. */
  725. protected function replace_mimes($message, $attribute, $rule, $parameters)
  726. {
  727. return str_replace(':values', implode(', ', $parameters), $message);
  728. }
  729. /**
  730. * Replace all place-holders for the same rule.
  731. *
  732. * @param string $message
  733. * @param string $attribute
  734. * @param string $rule
  735. * @param array $parameters
  736. * @return string
  737. */
  738. protected function replace_same($message, $attribute, $rule, $parameters)
  739. {
  740. return str_replace(':other', $parameters[0], $message);
  741. }
  742. /**
  743. * Replace all place-holders for the different rule.
  744. *
  745. * @param string $message
  746. * @param string $attribute
  747. * @param string $rule
  748. * @param array $parameters
  749. * @return string
  750. */
  751. protected function replace_different($message, $attribute, $rule, $parameters)
  752. {
  753. return str_replace(':other', $parameters[0], $message);
  754. }
  755. /**
  756. * Get the displayable name for a given attribute.
  757. *
  758. * @param string $attribute
  759. * @return string
  760. */
  761. protected function attribute($attribute)
  762. {
  763. $bundle = Bundle::prefix($this->bundle);
  764. // More reader friendly versions of the attribute names may be stored
  765. // in the validation language file, allowing a more readable version
  766. // of the attribute name to be used in the message.
  767. //
  768. // If no language line has been specified for the attribute, all of
  769. // the underscores will be removed from the attribute name and that
  770. // will be used as the attribtue name.
  771. $line = "{$bundle}validation.attributes.{$attribute}";
  772. $display = Lang::line($line)->get($this->language);
  773. return (is_null($display)) ? str_replace('_', ' ', $attribute) : $display;
  774. }
  775. /**
  776. * Determine if an attribute has a rule assigned to it.
  777. *
  778. * @param string $attribute
  779. * @param array $rules
  780. * @return bool
  781. */
  782. protected function has_rule($attribute, $rules)
  783. {
  784. foreach ($this->rules[$attribute] as $rule)
  785. {
  786. list($rule, $parameters) = $this->parse($rule);
  787. if (in_array($rule, $rules)) return true;
  788. }
  789. return false;
  790. }
  791. /**
  792. * Extract the rule name and parameters from a rule.
  793. *
  794. * @param string $rule
  795. * @return array
  796. */
  797. protected function parse($rule)
  798. {
  799. $parameters = array();
  800. // The format for specifying validation rules and parameters follows a
  801. // {rule}:{parameters} formatting convention. For instance, the rule
  802. // "max:3" specifies that the value may only be 3 characters long.
  803. if (($colon = strpos($rule, ':')) !== false)
  804. {
  805. $parameters = explode(',', substr($rule, $colon + 1));
  806. }
  807. return array(is_numeric($colon) ? substr($rule, 0, $colon) : $rule, $parameters);
  808. }
  809. /**
  810. * Set the bundle that the validator is running for.
  811. *
  812. * The bundle determines which bundle the language lines will be loaded from.
  813. *
  814. * @param string $bundle
  815. * @return Validator
  816. */
  817. public function bundle($bundle)
  818. {
  819. $this->bundle = $bundle;
  820. return $this;
  821. }
  822. /**
  823. * Set the language that should be used when retrieving error messages.
  824. *
  825. * @param string $language
  826. * @return Validator
  827. */
  828. public function speaks($language)
  829. {
  830. $this->language = $language;
  831. return $this;
  832. }
  833. /**
  834. * Set the database connection that should be used by the validator.
  835. *
  836. * @param Database\Connection $connection
  837. * @return Validator
  838. */
  839. public function connection(Database\Connection $connection)
  840. {
  841. $this->db = $connection;
  842. return $this;
  843. }
  844. /**
  845. * Get the database connection for the Validator.
  846. *
  847. * @return Database\Connection
  848. */
  849. protected function db()
  850. {
  851. if ( ! is_null($this->db)) return $this->db;
  852. return $this->db = Database::connection();
  853. }
  854. /**
  855. * Dynamically handle calls to custom registered validators.
  856. */
  857. public function __call($method, $parameters)
  858. {
  859. // First we will slice the "validate_" prefix off of the validator since
  860. // custom validators aren't registered with such a prefix, then we can
  861. // just call the method with the given parameters.
  862. if (isset(static::$validators[$method = substr($method, 9)]))
  863. {
  864. return call_user_func_array(static::$validators[$method], $parameters);
  865. }
  866. throw new \Exception("Call to undefined method [$method] on Validator instance.");
  867. }
  868. }