validators; } // }}} // setValidators() {{{ /** * Sets the validator functions. */ protected function setValidators($tests) { $parentClass = get_parent_class($this); $parentTests = []; if ($parentClass !== false && $parentClass !== AbstractValidator::class) { $parentTests = $parentClass::getInstance()->getValidators(); } $this->validators = array_merge($parentTests, $tests); } // }}} // addValidator() {{{ /** * Dynamically add a validator function * @param string $field The DomainObject Field to validate * @param callable $validator The Validator function to use * @param string $validatorIndex The internal index used to store the validator function. Use this to * remove or overwrite the validator */ public function addValidator(string $field, callable $validator, ?string $validatorIndex=null) { if (!isset($this->validators[$field])) $this->validators[$field] = []; $this->validators[$field][$validatorIndex] = $validator; } // }}} // removeValidator() {{{ /** * Dynamiocally remove a validator function */ public function removeValidator(string $field, $validatorIndex=null) { if (isset($validatorIndex)) { unset($this->validators[$field][$validatorIndex]); } else { unset($this->validators[$field]); } } // }}} // getInstance() {{{ /** * Returnst the instances of the validator, instantiates a new one if there isn't one already. * @return Validator */ public static function getInstance(): Validator { if (!isset(static::$instance)) { static::$instance = new static(); } assert( array_column( (new \ReflectionClass(static::$instance)) ->getProperties(\ReflectionProperty::IS_STATIC | \ReflectionProperty::IS_PROTECTED), 'class', 'name' )['instance'] === get_class(static::$instance), new \Exception('$instance has to be redeclared in '.get_class(static::$instance)) ); return static::$instance; } // }}} // validate() {{{ /** * Validates a DomainObject. * @param DomainObject $domainObject * @return ResultCollection|bool returns true if validations passed a ResultCollection otherwise */ public function validate(Validatable $domainObject) { $this->loadDefaultValidators($domainObject); $rc = new ResultCollection((new \ReflectionClass($domainObject))->getShortName()); $passed = true; // Validate properties foreach ($this->validators as $col => $validators) { if (!isset($domainObject->$col)) { $this->log()->notice('DomainObject '.get_class($domainObject)." has no field '$col'"); continue; } try { $valueObject = $domainObject->getValueObjectOf($col); foreach ($validators as $test) { if (true !== ($result = $test($valueObject))) { $rc->$col = $result; $passed = false; } } } catch (\OutOfRangeException $e) { self::log()->notice('Field not set', ['name' => $col]); } } return $passed ?: $rc; } // }}} // loadDefaultValidators() {{{ /** * load vaildators defined in ValueObjects. * Defined as Default and as such meaning always used. An example is the EAN13 ValueObject * which always validates checksum and length */ private function loadDefaultValidators(DomainObject $domainObject) { if (! $this->validatorsLoaded) { foreach ($domainObject->dataTypes() as $col => $dt) { if (is_subclass_of($dt, Value::class) && !empty($validators = ($dt)::defaultValidators())) { if (!isset($this->validators[$col])) $this->validators[$col] = []; $this->validators[$col] = array_merge($this->validators[$col], $validators); } } self::log()->debug('Registered Validators', $this->validators); $this->validatorsLoaded = true; } } // }}} } /* jEdit buffer local properties {{{ * :folding=explicit:collapseFolds=1: }}}*/