Bez popisu

ValidModel.php 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. namespace MailPoetVendor\Sudzy;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoetVendor\Paris\Model;
  5. /**
  6. * @method static static|bool create($data=null)
  7. */
  8. abstract class ValidModel extends Model {
  9. protected $_validator = null; // Reference to Sudzy validator object
  10. protected $_validations = []; // Array of validations
  11. protected $_validationErrors = []; // Array of error messages
  12. protected $_validationOptions = [
  13. 'indexedErrors' => false, // If True getValidationErrors will return an array with the index
  14. // being the field name and the value the error. If multiple errors
  15. // are triggered for a field only the first will be kept.
  16. 'throw' => self::ON_SAVE, // One of self::ON_SET|ON_SAVE|NEVER.
  17. // + ON_SET throws immediately when field is set()
  18. // + ON_SAVE throws on save()
  19. // + NEVER means an exception is never thrown; check for ->getValidationErrors()
  20. ];
  21. const ON_SET = 'set';
  22. const ON_SAVE = 'save';
  23. const NEVER = null;
  24. public function __construct($validatorInstance = null) {
  25. $this->_validator = $validatorInstance;
  26. }
  27. public function setValidationOptions($options) {
  28. $this->_validationOptions = array_merge($this->_validationOptions, $options);
  29. }
  30. public function addValidation($field, $validation, $message) {
  31. if (!isset($this->_validations[$field])) {
  32. $this->_validations[$field] = [];
  33. }
  34. $this->_validations[$field][] = [
  35. 'validation' => $validation,
  36. 'message' => $message,
  37. ];
  38. }
  39. public function addValidations($field, $validators) {
  40. foreach ($validators as $validation => $message) {
  41. $this->addValidation($field, $validation, $message);
  42. }
  43. }
  44. // /**
  45. // * Checks, without throwing exceptions, model fields with validations
  46. // *
  47. // * @return bool If false, running $this->doValidationError() will respond appropriately
  48. // */
  49. // public function validate()
  50. // {
  51. // $fields = array_keys($this->_validations);
  52. // $success = true;
  53. // foreach ($fields as $f) {
  54. // $success = $success && $this->validateField($f, $this->$f);
  55. // }
  56. // return $success;
  57. // }
  58. /**
  59. * @return bool Will set a message if returning false
  60. **/
  61. public function validateField($field, $value) {
  62. $this->setupValidationEngine();
  63. if (!isset($this->_validations[$field])) {
  64. return true; // No validations, return true by default
  65. }
  66. $success = true;
  67. foreach ($this->_validations[$field] as $v) {
  68. $checks = explode(' ', $v['validation']);
  69. foreach ($checks as $check) {
  70. $params = explode('|', $check);
  71. $check = array_shift($params);
  72. if (!$this->_validator->executeOne($check, $value, $params)) {
  73. $this->addValidationError($v['message'], $field);
  74. $success = false;
  75. }
  76. }
  77. }
  78. return $success;
  79. }
  80. public function getValidationErrors() {
  81. return $this->_validationErrors;
  82. }
  83. public function resetValidationErrors() {
  84. $this->_validationErrors = [];
  85. }
  86. ///////////////////
  87. // Overloaded methods
  88. /**
  89. * Overload __set to call validateAndSet
  90. */
  91. public function __set($name, $value) {
  92. $this->validateAndSet($name, $value);
  93. }
  94. /**
  95. * Overload save; checks if errors exist before saving
  96. */
  97. public function save() {
  98. if ($this->isNew()) { //Fields populated by create() or hydrate() don't pass through set()
  99. foreach (array_keys($this->_validations) as $field) {
  100. $this->validateField($field, $this->$field);
  101. }
  102. }
  103. $errs = $this->getValidationErrors();
  104. if (!empty($errs)) {
  105. $this->doValidationError(self::ON_SAVE);
  106. }
  107. parent::save();
  108. }
  109. /**
  110. * Overload set; to call validateAndSet
  111. */
  112. public function set($key, $value = null) {
  113. if (is_array($key)) {
  114. // multiple values
  115. foreach ($key as $field => $value) {
  116. $this->validateAndSet($field, $value);
  117. }
  118. } else {
  119. $this->validateAndSet($key, $value);
  120. }
  121. // we should return $this to not break Idiorm's fluent interface:
  122. // $model->set('property', 'foo')->save();
  123. return $this;
  124. }
  125. ////////////////////
  126. // Protected methods
  127. protected function doValidationError($context) {
  128. if ($context == $this->_validationOptions['throw']) {
  129. throw new \MailPoetVendor\Sudzy\ValidationException($this->_validationErrors);
  130. }
  131. }
  132. protected function addValidationError($msg, $field = null) {
  133. if ($this->_validationOptions['indexedErrors'] && $field !== null) {
  134. // Only keep the first error found on a field
  135. if (!isset($this->_validationErrors[$field])) {
  136. $this->_validationErrors[$field] = $msg;
  137. }
  138. } else {
  139. $this->_validationErrors[] = $msg;
  140. }
  141. }
  142. /**
  143. * Overload set; to call validateAndSet
  144. */
  145. protected function validateAndSet($name, $value) {
  146. if (!$this->validateField($name, $value)) $this->doValidationError(self::ON_SET);
  147. parent::set($name, $value);
  148. }
  149. protected function setupValidationEngine() {
  150. if (null == $this->_validator) $this->_validator = new \MailPoetVendor\Sudzy\Engine(); // Is lazy setup worth it?
  151. }
  152. }