<?php
declare(strict_types=1);
namespace wcf\acp\form;
+use wcf\data\user\UserList;
use wcf\form\AbstractForm;
use wcf\system\exception\UserInputException;
use wcf\system\form\builder\container\FormContainer;
->description('wcf.global.description')
->addClass('someSection')
->appendChildren([
+ SingleSelectionFormField::create('dboTest')
+ ->label('Users')
+ ->options(new UserList()),
ShowOrderFormField::create()
->options([
2 => 'Object with id 2',
5 => 'Object with id 5',
4 => 'Object with id 4'
- ])
- ->value(2),
+ ]),
TextFormField::create('name')
->label('wcf.global.name'),
TitleFormField::create()
<?php
declare(strict_types=1);
namespace wcf\system\form\builder\field;
+use wcf\data\DatabaseObjectList;
/**
* Represents a form field that consists of a predefined set of possible values.
* and the this field is nullable, then the save value of that key is `null`
* instead of the given empty value.
*
- * @param array|callable $options selectable options or callable returning the options
+ * If a `callable` is passed, it is expected that it either returns an array
+ * or a `DatabaseObjectList` object.
+ *
+ * If a `DatabaseObjectList` object is passed and `$options->objectIDs === null`,
+ * `$options->readObjects()` is called so that the `readObjects()` does not have
+ * to be called by the API user.
+ *
+ * @param array|callable|DatabaseObjectList $options selectable options or callable returning the options
* @return static this field
*
* @throws \InvalidArgumentException if given options are no array or callable or otherwise invalid
<?php
declare(strict_types=1);
namespace wcf\system\form\builder\field;
+use wcf\data\DatabaseObjectList;
+use wcf\data\ITitledObject;
use wcf\system\form\builder\field\validation\FormFieldValidationError;
use wcf\system\WCF;
+use wcf\util\ClassUtil;
/**
* Provides default implementations of `ISelectionFormField` methods.
* @throws \UnexpectedValueException if callable does not return an array
*/
public function options($options): ISelectionFormField {
- if (!is_array($options) && !is_callable($options)) {
+ if (!is_array($options) && !is_callable($options) && !($options instanceof DatabaseObjectList)) {
throw new \InvalidArgumentException("Given options are neither an array nor a callable, " . gettype($options) . " given.");
}
if (is_callable($options)) {
$options = $options();
- if (!is_array($options)) {
- throw new \UnexpectedValueException("The options callable is expected to return an array, " . gettype($options) . " returned.");
+ if (!is_array($options) && !($options instanceof DatabaseObjectList)) {
+ throw new \UnexpectedValueException("The options callable is expected to return an array or database object list, " . gettype($options) . " returned.");
}
+
+ return $this->options($options);
+ }
+ else if ($options instanceof DatabaseObjectList) {
+ // automatically read objects
+ if ($options->objectIDs === null) {
+ $options->readObjects();
+ }
+
+ $dboOptions = [];
+ foreach ($options as $object) {
+ if (!ClassUtil::isDecoratedInstanceOf($object, ITitledObject::class)) {
+ throw new \InvalidArgumentException("The database objects in the passed list must implement '" . ITitledObject::class . "'.");
+ }
+ if (!$object::getDatabaseTableIndexIsIdentity()) {
+ throw new \InvalidArgumentException("The database objects in the passed list must must have an index that identifies the objects.");
+ }
+
+ $dboOptions[$object->getObjectID()] = $object->getTitle();
+ }
+
+ $options = $dboOptions;
}
// validate options and read possible values
<?php
declare(strict_types=1);
namespace wcf\util;
+use wcf\data\DatabaseObjectDecorator;
use wcf\system\exception\SystemException;
/**
return is_subclass_of($className, $targetClass);
}
+ /**
+ * Returns `true` if the given class extends or implements the target class
+ * or interface or if the given class is database object decorator and the
+ * decorated class extends or implements the target class.
+ *
+ * This method also supports decorated decorators.
+ *
+ * @param string $className checked class
+ * @param string $targetClass target class or interface
+ * @return bool
+ */
+ public static function isDecoratedInstanceOf($className, $targetClass) {
+ if (is_subclass_of($className, $targetClass)) {
+ return true;
+ }
+
+ $parentClass = new \ReflectionClass($className);
+ do {
+ $className = $parentClass->name;
+
+ if (!is_subclass_of($className, DatabaseObjectDecorator::class)) {
+ return false;
+ }
+
+ if (is_subclass_of($className::getBaseClass(), $targetClass)) {
+ return true;
+ }
+ }
+ while (($parentClass = $parentClass->getParentClass()));
+
+ return false;
+ }
+
/**
* Forbid creation of ClassUtil objects.
*/