Add class name form field
authorMatthias Schmidt <gravatronics@live.com>
Wed, 18 Apr 2018 15:33:47 +0000 (17:33 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Wed, 18 Apr 2018 15:33:47 +0000 (17:33 +0200)
See #2509

wcfsetup/install/files/lib/system/form/builder/field/ClassNameFormField.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/TextFormField.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

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 (file)
index 0000000..8e83415
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+namespace wcf\system\form\builder\field;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+
+/**
+ * Implementation of a form field to enter the name of a PHP class.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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]
+                                               )
+                                       );
+                               }
+                       }
+               }
+       }
+}
index 26e1c27167b12c2410fbc6d1c7b9ab837579b197..59dd53731eccf466174683c971382e80b96c0a38 100644 (file)
@@ -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);
        }
index da417fe42fdbc0b03599ed28cf0cf2bf8b125fdb..7f5d3b65958e1b19fc2035a9d27a7fe5453b8282 100644 (file)
@@ -3015,6 +3015,15 @@ E-Mail-Adresse: {@$emailAddress} {* this line ends with a space *}
                <!-- /deprecated since 2.1 -->
        </category>
        
+       <category name="wcf.form">
+               <item name="wcf.form.field.className.error.interface"><![CDATA[Die angegebene Klasse{if $language|isset} ({$language}){/if} implementiert nicht das Interface <code>{$interface}</code>.]]></item>
+               <item name="wcf.form.field.className.error.isInstantiable"><![CDATA[Die angegebene Klasse{if $language|isset} ({$language}){/if} ist nicht instanziierbar.]]></item>
+               <item name="wcf.form.field.className.error.leadingBackslash"><![CDATA[Die angegebene Klasse{if $language|isset} ({$language}){/if} darf keinen führenden Backslash besitzen.]]></item>
+               <item name="wcf.form.field.className.error.nonExistent"><![CDATA[Die angegebene Klasse{if $language|isset} ({$language}){/if} existiert nicht.]]></item>
+               <item name="wcf.form.field.className.error.parentClass"><![CDATA[Die angegebene Klasse{if $language|isset} ({$language}){/if} erbt nicht von <code>{$parentClass}</code>.]]></item>
+               <item name="wcf.form.field.itemList.error.separator"><![CDATA[Die folgenden Elemente dürfen kein {if $separator === ','}Komma{else}Leerzeichen{/if} enthalten: {implode from=$invalidItems item=item}“{$item}”{/implode}.]]></item>
+       </category>
+       
        <category name="wcf.imageViewer">
                <item name="wcf.imageViewer.button.enlarge"><![CDATA[Vollbild-Modus]]></item>
                <item name="wcf.imageViewer.button.full"><![CDATA[Originalversion aufrufen]]></item>
index 1fdfaf6c8611ff26476aced026f12e977d117d0e..e15978ce831b994af7738c3e4b8d3ffc6ffdb773 100644 (file)
@@ -2961,6 +2961,15 @@ Email: {@$emailAddress} {* this line ends with a space *}
                <!-- /deprecated since 2.1 -->
        </category>
        
+       <category name="wcf.form">
+               <item name="wcf.form.field.className.error.interface"><![CDATA[The entered class{if $language|isset} ({$language}){/if} does not implement the interface <code>{$interface}</code>.]]></item>
+               <item name="wcf.form.field.className.error.isInstantiable"><![CDATA[The entered class{if $language|isset} ({$language}){/if} is not instantiable.]]></item>
+               <item name="wcf.form.field.className.error.leadingBackslash"><![CDATA[The entered class name{if $language|isset} ({$language}){/if} must not have a leading backslash.]]></item>
+               <item name="wcf.form.field.className.error.nonExistent"><![CDATA[The entered class{if $language|isset} ({$language}){/if} does not exist.]]></item>
+               <item name="wcf.form.field.className.error.parentClass"><![CDATA[The entered class{if $language|isset} ({$language}){/if} does not extend <code>{$parentClass}</code>.]]></item>
+               <item name="wcf.form.field.itemList.error.separator"><![CDATA[The following items may contain no {if $separator === ','}comma{else}space{/if}: {implode from=$invalidItems item=item}“{$item}”{/implode}.]]></item>
+       </category>
+       
        <category name="wcf.imageViewer">
                <item name="wcf.imageViewer.button.enlarge"><![CDATA[Full Screen Mode]]></item>
                <item name="wcf.imageViewer.button.full"><![CDATA[View Source Image]]></item>