From f6494257dea46467a0eb2fc04e0cb6c80be80467 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Wed, 18 Apr 2018 17:33:47 +0200 Subject: [PATCH] Add class name form field See #2509 --- .../field/ClassNameFormField.class.php | 204 ++++++++++++++++++ .../builder/field/TextFormField.class.php | 11 +- wcfsetup/install/lang/de.xml | 9 + wcfsetup/install/lang/en.xml | 9 + 4 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/form/builder/field/ClassNameFormField.class.php diff --git a/wcfsetup/install/files/lib/system/form/builder/field/ClassNameFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/ClassNameFormField.class.php new file mode 100644 index 0000000000..8e83415b7c --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/field/ClassNameFormField.class.php @@ -0,0 +1,204 @@ + + * @package WoltLabSuite\Core\System\Form\Builder\Field + * @since 3.2 + */ +class ClassNameFormField extends TextFormField { + /** + * `true` if the entered class must exist + * @var bool + */ + protected $__classExists = true; + + /** + * name of the interface the entered class must implement + * @var string + */ + protected $__implementedInterface = ''; + + /** + * `true` if the entered class must be instantiable + * @var bool + */ + protected $__isInstantiable = true; + + /** + * name of the class the entered class must extend + * @var string + */ + protected $__parentClass = ''; + + /** + * Sets whether entered class must exist and returns this field. + * + * @param bool $classExists determines if entered class must exist + * @return static this field + */ + public function classExists(bool $classExists = true): ClassNameFormField { + $this->__classExists = $classExists; + + return $this; + } + + /** + * Returns `true` if the entered class must exist. By default, `true` is + * returned. + * + * @return bool + */ + public function getClassExists(): bool { + return $this->__classExists; + } + + /** + * Returns class the entered class must extend or an empty string if the + * entered class does not have to extend any specific class. By default, + * an empty string is returned. + * + * @return string + */ + public function getImplementedInterface(): string { + return $this->__implementedInterface; + } + + /** + * Returns `true` if the entered class must be instantiable. By default, + * `true` is returned. + * + * @return bool + */ + public function getIsInstantiable(): bool { + return $this->__isInstantiable; + } + + /** + * Returns name of the interface the entered class must implement or an + * empty string if the entered class does not have to implement any specific + * interface. By default, an empty string is returned. + * + * @return string + */ + public function getParentClass(): string { + return $this->__parentClass; + } + + /** + * Returns the name of the interface the entered class must implement. + * + * @param string $interface name of the interface the entered class must implement + * @return static this field + * + * @throws \InvalidArgumentException if the entered interface does not exists + */ + public function implementedInterface(string $interface): ClassNameFormField { + if (!interface_exists($interface)) { + throw new \InvalidArgumentException("Interface '{$interface}' does not exist."); + } + + $this->__implementedInterface = $interface; + + return $this; + } + + /** + * Sets whether entered class must be instantiable and returns this field. + * + * @param bool $isInstantiable determines if entered class must be instantiable + * @return static this field + */ + public function isInstantiable(bool $isInstantiable = true): ClassNameFormField { + $this->__isInstantiable = $isInstantiable; + + return $this; + } + + /** + * Returns the name of the class the entered class must extend. + * + * @param string $parentClass name of the class the entered class must extend + * @return static this field + * + * @throws \InvalidArgumentException if the entered class does not exists + */ + public function parentClass(string $parentClass): ClassNameFormField { + if (!class_exists($parentClass)) { + throw new \InvalidArgumentException("Class '{$parentClass}' does not exist."); + } + + $this->__parentClass = $parentClass; + + return $this; + } + + /** + * @inheritDoc + */ + protected function validateText(string $text, Language $language = null) { + parent::validateText($text, $language); + + if (empty($this->getValidationErrors())) { + if (substr($text, 0, 1) === '\\') { + $this->addValidationError( + new FormFieldValidationError( + 'leadingBackslash', + 'wcf.form.field.className.error.leadingBackslash', + ['language' => $language] + ) + ); + } + else if ($this->getClassExists() && !class_exists($text)) { + $this->addValidationError( + new FormFieldValidationError( + 'nonExistent', + 'wcf.form.field.className.error.nonExistent', + ['language' => $language] + ) + ); + } + else if ($this->getImplementedInterface() !== '' && !is_subclass_of($text, $this->getImplementedInterface())) { + $this->addValidationError( + new FormFieldValidationError( + 'interface', + 'wcf.form.field.className.error.interface', + [ + 'language' => $language, + 'interface' => $this->getImplementedInterface() + ] + ) + ); + } + else if ($this->getParentClass() !== '' && !is_subclass_of($text, $this->getParentClass())) { + $this->addValidationError( + new FormFieldValidationError( + 'parentClass', + 'wcf.form.field.className.error.parentClass', + [ + 'language' => $language, + 'parentClass' => $this->getParentClass() + ] + ) + ); + } + else if ($this->getIsInstantiable()) { + $reflection = new \ReflectionClass($text); + if (!$reflection->isInstantiable()) { + $this->addValidationError( + new FormFieldValidationError( + 'isInstantiable', + 'wcf.form.field.className.error.isInstantiable', + ['language' => $language] + ) + ); + } + } + } + } +} diff --git a/wcfsetup/install/files/lib/system/form/builder/field/TextFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/TextFormField.class.php index 26e1c27167..59dd53731e 100644 --- a/wcfsetup/install/files/lib/system/form/builder/field/TextFormField.class.php +++ b/wcfsetup/install/files/lib/system/form/builder/field/TextFormField.class.php @@ -39,7 +39,7 @@ class TextFormField extends AbstractFormField implements II18nFormField, IMaximu } else { foreach ($value as $languageID => $languageValue) { - $this->validateText($languageValue, $languageID); + $this->validateText($languageValue, LanguageFactory::getInstance()->getLanguage($languageID)); } } } @@ -59,14 +59,9 @@ class TextFormField extends AbstractFormField implements II18nFormField, IMaximu * Checks the length of the given text with the given language. * * @param string $text validated text - * @param null|int $languageID language id of validated text or `null` for monolingual text + * @param null|Language $language language of validated text or `null` for monolingual text */ - protected function validateText(string $text, int $languageID = null) { - $language = null; - if ($languageID !== null) { - $language = LanguageFactory::getInstance()->getLanguage($languageID); - } - + protected function validateText(string $text, Language $language = null) { $this->validateMinimumLength($text, $language); $this->validateMaximumLength($text, $language); } diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index da417fe42f..7f5d3b6595 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -3015,6 +3015,15 @@ E-Mail-Adresse: {@$emailAddress} {* this line ends with a space *} + + {$interface}.]]> + + + + {$parentClass}.]]> + + + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 1fdfaf6c86..e15978ce83 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -2961,6 +2961,15 @@ Email: {@$emailAddress} {* this line ends with a space *} + + {$interface}.]]> + + + + {$parentClass}.]]> + + + -- 2.20.1