1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-12 09:44:38 +02:00

Minor code updates in FieldtypeOptions and supporting classes

This commit is contained in:
Ryan Cramer
2022-09-30 12:04:03 -04:00
parent cce5073969
commit c1e1cecf93
4 changed files with 71 additions and 39 deletions

View File

@@ -3,7 +3,7 @@
/** /**
* ProcessWire Select Options Fieldtype * ProcessWire Select Options Fieldtype
* *
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer * ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
* @property SelectableOptionManager $manager * @property SelectableOptionManager $manager
@@ -66,6 +66,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
* *
*/ */
public function getBlankValue(Page $page, Field $field) { public function getBlankValue(Page $page, Field $field) {
/** @var SelectableOptionArray $a */
$a = $this->wire(new SelectableOptionArray()); $a = $this->wire(new SelectableOptionArray());
$a->setPage($page); $a->setPage($page);
$a->setField($field); $a->setField($field);
@@ -99,8 +100,9 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
$inputfieldClass = $field->get('inputfieldClass'); $inputfieldClass = $field->get('inputfieldClass');
if(!$inputfieldClass) $inputfieldClass = 'InputfieldSelect'; if(!$inputfieldClass) $inputfieldClass = 'InputfieldSelect';
$inputfield = $this->wire('modules')->get($inputfieldClass); /** @var InputfieldSelect $inputfield */
if(!$inputfield) $inputfield = $this->wire('modules')->get('InputfieldSelect'); $inputfield = $this->wire()->modules->get($inputfieldClass);
if(!$inputfield) $inputfield = $this->wire()->modules->get('InputfieldSelect');
foreach($this->manager->getOptions($field) as $option) { foreach($this->manager->getOptions($field) as $option) {
$inputfield->addOption((int) $option->id, $option->getTitle()); $inputfield->addOption((int) $option->id, $option->getTitle());
@@ -112,7 +114,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
if(empty($value) || !wireCount($value)) { if(empty($value) || !wireCount($value)) {
$page->set($field->name, $field->get('initValue')); $page->set($field->name, $field->get('initValue'));
} }
} else if($this->wire('process') != 'ProcessField' && !wireCount($value)) { } else if($this->wire()->process != 'ProcessField' && !wireCount($value)) {
$this->warning( $this->warning(
$field->getLabel() . " ($field->name): " . $field->getLabel() . " ($field->name): " .
$this->_('Configured pre-selection not populated since value is not always required. Please correct this field configuration.') $this->_('Configured pre-selection not populated since value is not always required. Please correct this field configuration.')
@@ -133,7 +135,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
*/ */
public function ___getCompatibleFieldtypes(Field $field) { public function ___getCompatibleFieldtypes(Field $field) {
$fieldtypes = $this->wire(new Fieldtypes()); $fieldtypes = $this->wire(new Fieldtypes());
foreach($this->wire('fieldtypes') as $fieldtype) { foreach($this->wire()->fieldtypes as $fieldtype) {
if($fieldtype instanceof FieldtypeOptions) $fieldtypes->add($fieldtype); if($fieldtype instanceof FieldtypeOptions) $fieldtypes->add($fieldtype);
} }
return $fieldtypes; return $fieldtypes;
@@ -259,9 +261,13 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
} }
return $sleepValue; return $sleepValue;
} }
if(!$value instanceof SelectableOptionArray) throw new WireException("sleepValue requires SelectableOptionArray");
if(!$value instanceof SelectableOptionArray) {
throw new WireException("sleepValue requires SelectableOptionArray");
}
foreach($value as $option) { foreach($value as $option) {
/** @var SelectableOption $option */
$sleepValue[] = (int) $option->id; $sleepValue[] = (int) $option->id;
} }
return $sleepValue; return $sleepValue;
@@ -361,6 +367,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
$subfield = 'data'; $subfield = 'data';
if(count($options) < 2) { if(count($options) < 2) {
/** @var SelectableOption $option */
$option = $options->first(); $option = $options->first();
$value = $option ? $option->id : ''; $value = $option ? $option->id : '';
} else { } else {
@@ -373,7 +380,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
if($operator == '!=') { if($operator == '!=') {
// force a != for one value to prevent matching, even if more than one value // force a != for one value to prevent matching, even if more than one value
$database = $this->wire('database'); $database = $this->wire()->database;
$t = $database->escapeTable($query->field->getTable()); $t = $database->escapeTable($query->field->getTable());
$s = $database->escapeCol($subfield); $s = $database->escapeCol($subfield);
@@ -402,14 +409,15 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
* @param string $table * @param string $table
* @param string $subfield * @param string $subfield
* @param bool $desc * @param bool $desc
* @return bool|string * @return bool
* @since 3.0.167 * @since 3.0.167
* *
*/ */
public function getMatchQuerySort(Field $field, $query, $table, $subfield, $desc) { public function getMatchQuerySort(Field $field, $query, $table, $subfield, $desc) {
// FieldtypeOptions uses an separate table for option values/labels // FieldtypeOptions uses an separate table for option values/labels
$subfield = $this->wire()->sanitizer->fieldName($subfield);
if(empty($subfield)) return false; if(empty($subfield)) return false;
$table2 = "_sort_options_$field->name" . ($subfield ? "_$subfield" : ''); $table2 = "_sort_options_{$field->name}_$subfield";
$bindKey = $query->bindValueGetKey($field->id, \PDO::PARAM_INT); $bindKey = $query->bindValueGetKey($field->id, \PDO::PARAM_INT);
$query->leftjoin("fieldtype_options AS $table2 ON $table2.fields_id=$bindKey AND $table.data=$table2.option_id"); $query->leftjoin("fieldtype_options AS $table2 ON $table2.fields_id=$bindKey AND $table.data=$table2.option_id");
$query->orderby("$table2.$subfield " . ($desc ? 'DESC' : ''), true); $query->orderby("$table2.$subfield " . ($desc ? 'DESC' : ''), true);
@@ -494,7 +502,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
$data['export_options'] = array('default' => $data['_options']); $data['export_options'] = array('default' => $data['_options']);
unset($data['_options']); unset($data['_options']);
} }
if($this->manager->useLanguages()) foreach($this->wire('languages') as $language) { if($this->manager->useLanguages()) foreach($this->wire()->languages as $language) {
if($language->isDefault()) continue; if($language->isDefault()) continue;
$key = "_options__$language"; $key = "_options__$language";
if(isset($data[$key])) { if(isset($data[$key])) {
@@ -529,7 +537,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
* *
*/ */
public function ___cloneField(Field $field) { public function ___cloneField(Field $field) {
$this->wire('fields')->addHookAfter('cloned', $this, 'hookCloned'); $this->wire()->fields->addHookAfter('cloned', $this, 'hookCloned');
return parent::___cloneField($field); return parent::___cloneField($field);
} }
@@ -584,6 +592,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
public function ___getConfigInputfields(Field $field) { public function ___getConfigInputfields(Field $field) {
$inputfields = parent::___getConfigInputfields($field); $inputfields = parent::___getConfigInputfields($field);
include_once(dirname(__FILE__) . '/SelectableOptionConfig.php'); include_once(dirname(__FILE__) . '/SelectableOptionConfig.php');
/** @var SelectableOptionConfig $cfg */
$cfg = $this->wire(new SelectableOptionConfig($field, $inputfields)); $cfg = $this->wire(new SelectableOptionConfig($field, $inputfields));
$inputfields = $cfg->getConfigInputfields(); $inputfields = $cfg->getConfigInputfields();
return $inputfields; return $inputfields;
@@ -599,7 +608,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
protected function _getField($field) { protected function _getField($field) {
if(!$field instanceof Field) { if(!$field instanceof Field) {
$_field = $field; $_field = $field;
$field = $this->wire('fields')->get($field); $field = $this->wire()->fields->get($field);
if(!$field) throw new WireException("Unknown field: $_field"); if(!$field) throw new WireException("Unknown field: $_field");
} }
if(!$field->type instanceof FieldtypeOptions) { if(!$field->type instanceof FieldtypeOptions) {
@@ -634,7 +643,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
* *
*/ */
public function getOptions($field) { public function getOptions($field) {
return $this->manager->getOptions($field = $this->_getField($field)); return $this->manager->getOptions($this->_getField($field));
} }
/** /**
@@ -647,7 +656,7 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
* *
*/ */
public function setOptions($field, SelectableOptionArray $options) { public function setOptions($field, SelectableOptionArray $options) {
return $this->manager->setOptions($field = $this->_getField($field), $options, true); return $this->manager->setOptions($this->_getField($field), $options, true);
} }
/** /**

View File

@@ -3,7 +3,7 @@
/** /**
* ProcessWire Selectable Option class, for FieldtypeOptions * ProcessWire Selectable Option class, for FieldtypeOptions
* *
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer * ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
* @property int $id * @property int $id
@@ -31,6 +31,7 @@ class SelectableOption extends WireData { // implements LanguagesValueInterface
protected $of = false; protected $of = false;
public function __construct() { public function __construct() {
parent::__construct();
foreach(self::$defaults as $property => $value) { foreach(self::$defaults as $property => $value) {
$this->set($property, $value); $this->set($property, $value);
} }

View File

@@ -3,8 +3,12 @@
/** /**
* ProcessWire Selectable Option Array, for FieldtypeOptions * ProcessWire Selectable Option Array, for FieldtypeOptions
* *
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer * ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* https://processwire.com * https://processwire.com
*
* @property string $title
* @property string $value
* @property int $id
* *
*/ */
@@ -51,7 +55,7 @@ class SelectableOptionArray extends WireArray {
* *
*/ */
public function getPage() { public function getPage() {
return $this->page ? $this->page : $this->wire('pages')->newNullPage(); return $this->page ? $this->page : $this->wire()->pages->newNullPage();
} }
/** /**
@@ -85,7 +89,10 @@ class SelectableOptionArray extends WireArray {
$_of = $this->of; $_of = $this->of;
if(is_null($of)) return $_of; if(is_null($of)) return $_of;
$this->of = $of ? true : false; $this->of = $of ? true : false;
foreach($this as $option) $option->of($this->of); foreach($this as $option) {
/** @var SelectableOption $option */
$option->of($this->of);
}
return $_of; // whatever previous value was return $_of; // whatever previous value was
} }
@@ -143,8 +150,9 @@ class SelectableOptionArray extends WireArray {
public function setProperty($property, $value) { public function setProperty($property, $value) {
if(SelectableOption::isProperty($property)) { if(SelectableOption::isProperty($property)) {
if($this->count()) { if($this->count()) {
/** @var SelectableOption|null $option */
$option = $this->first(); $option = $this->first();
return $option->set($property, $value); if($option) return $option->set($property, $value);
} }
} }
// note: there is no parent method for this one // note: there is no parent method for this one
@@ -159,8 +167,11 @@ class SelectableOptionArray extends WireArray {
public function __set($key, $value) { public function __set($key, $value) {
// we must have both this and set() per behavior of WireArray::__set() // we must have both this and set() per behavior of WireArray::__set()
// which throws exceptions if attempting to set a property // which throws exceptions if attempting to set a property
if(SelectableOption::isProperty($key)) return $this->setProperty($key, $value); if(SelectableOption::isProperty($key)) {
return parent::__set($key, $value); $this->setProperty($key, $value);
} else {
parent::__set($key, $value);
}
} }
public function isValidItem($item) { public function isValidItem($item) {
@@ -172,6 +183,7 @@ class SelectableOptionArray extends WireArray {
} }
public function getItemKey($item) { public function getItemKey($item) {
/** @var SelectableOption $item */
return $item->id ? $item->id : null; return $item->id ? $item->id : null;
} }
@@ -189,6 +201,7 @@ class SelectableOptionArray extends WireArray {
*/ */
public function isIdentical(WireArray $items, $strict = true) { public function isIdentical(WireArray $items, $strict = true) {
$isIdentical = parent::isIdentical($items, false); // force non-strict $isIdentical = parent::isIdentical($items, false); // force non-strict
/** @var SelectableOptionArray $items */
if($isIdentical && $strict) { if($isIdentical && $strict) {
if($this->of() != $items->of()) $isIdentical = false; if($this->of() != $items->of()) $isIdentical = false;
if($isIdentical && ((string) $this->getPage()) !== ((string) $items->getPage())) $isIdentical = false; if($isIdentical && ((string) $this->getPage()) !== ((string) $items->getPage())) $isIdentical = false;
@@ -208,6 +221,7 @@ class SelectableOptionArray extends WireArray {
protected function getOptionByProperty($property, $value) { protected function getOptionByProperty($property, $value) {
$match = false; $match = false;
foreach($this as $option) { foreach($this as $option) {
/** @var SelectableOption $option */
$v = $option->getProperty($property); $v = $option->getProperty($property);
if($v !== $value) continue; if($v !== $value) continue;
$match = $option; $match = $option;

View File

@@ -6,7 +6,7 @@
* Handles management of the fieldtype_options table and related field_[name] table * Handles management of the fieldtype_options table and related field_[name] table
* to assist FieldtypeOptions module. * to assist FieldtypeOptions module.
* *
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer * ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* https://processwire.com * https://processwire.com
* *
*/ */
@@ -46,7 +46,7 @@ class SelectableOptionManager extends Wire {
protected $removedOptionIDs = array(); protected $removedOptionIDs = array();
public function wired() { public function wired() {
if($this->wire('modules')->isInstalled('LanguageSupportFields')) { if($this->wire()->modules->isInstalled('LanguageSupportFields')) {
$this->useLanguages = true; $this->useLanguages = true;
$this->addHookAfter('Languages::updated', $this, 'updateLanguages'); $this->addHookAfter('Languages::updated', $this, 'updateLanguages');
} }
@@ -81,11 +81,13 @@ class SelectableOptionManager extends Wire {
* *
* @param Field $field * @param Field $field
* @param array $ids * @param array $ids
* @return SelectableOptionArray * @return SelectableOptionArray|SelectableOption[]
* *
*/ */
public function getOptionsByID(Field $field, array $ids) { public function getOptionsByID(Field $field, array $ids) {
return $this->getOptions($field, array('id' => $ids)); /** @var SelectableOptionArray|SelectableOption[] $value */
$value = $this->getOptions($field, array('id' => $ids));
return $value;
} }
/** /**
@@ -96,12 +98,13 @@ class SelectableOptionManager extends Wire {
* *
* @param Field $field * @param Field $field
* @param array $filters Any of array(property => array) where property is 'id', 'title' or 'value'. * @param array $filters Any of array(property => array) where property is 'id', 'title' or 'value'.
* @return SelectableOptionArray * @return SelectableOptionArray|SelectableOption[]
* @throws WireException * @throws WireException
* *
*/ */
public function getOptions(Field $field, array $filters = array()) { public function getOptions(Field $field, array $filters = array()) {
$database = $this->wire()->database;
$hasFilters = count($filters) > 0; $hasFilters = count($filters) > 0;
if(isset($this->optionsCache[$field->id]) && !$hasFilters) { if(isset($this->optionsCache[$field->id]) && !$hasFilters) {
@@ -141,7 +144,7 @@ class SelectableOptionManager extends Wire {
if(!count($filters[$property])) continue; if(!count($filters[$property])) continue;
$s = "`$property` IN("; $s = "`$property` IN(";
foreach($filters[$property] as $val) { foreach($filters[$property] as $val) {
$s .= $this->wire('database')->quote($val) . ','; $s .= $database->quote($val) . ',';
$sorted[$val] = ''; // placeholder $sorted[$val] = ''; // placeholder
} }
$s = rtrim($s, ',') . ')'; $s = rtrim($s, ',') . ')';
@@ -159,7 +162,7 @@ class SelectableOptionManager extends Wire {
if($sortKey === true) $sql .= 'ORDER BY sort ASC'; if($sortKey === true) $sql .= 'ORDER BY sort ASC';
$query = $this->wire('database')->prepare($sql); $query = $database->prepare($sql);
$query->bindValue(':fields_id', $field->id); $query->bindValue(':fields_id', $field->id);
$query->execute(); $query->execute();
@@ -183,6 +186,7 @@ class SelectableOptionManager extends Wire {
$query->closeCursor(); $query->closeCursor();
/** @var SelectableOptionArray $options */
$options = $this->wire(new SelectableOptionArray()); $options = $this->wire(new SelectableOptionArray());
$options->setField($field); $options->setField($field);
foreach($sorted as $option) { foreach($sorted as $option) {
@@ -200,7 +204,8 @@ class SelectableOptionManager extends Wire {
* Perform a partial match on title of options * Perform a partial match on title of options
* *
* @param Field $field * @param Field $field
* @param string $property Either 'title' or 'value'. May also be blank (to imply 'either') if operator is '=' or '!=' * @param string $property Either 'title' or 'value'. May also be blank (to imply 'either') if operator is '=' or
* '!='
* @param string $operator * @param string $operator
* @param string $value Value to find * @param string $value Value to find
* @return SelectableOptionArray * @return SelectableOptionArray
@@ -253,7 +258,7 @@ class SelectableOptionManager extends Wire {
if(isset($a['title'])) $option->set('title', $a['title']); if(isset($a['title'])) $option->set('title', $a['title']);
if(isset($a['value'])) $option->set('value', $a['value']); if(isset($a['value'])) $option->set('value', $a['value']);
if(isset($a['sort'])) $option->set('sort', (int) $a['sort']); if(isset($a['sort'])) $option->set('sort', (int) $a['sort']);
if($this->useLanguages) foreach($this->wire('languages') as $language) { if($this->useLanguages) foreach($this->wire()->languages as $language) {
if($language->isDefault()) continue; if($language->isDefault()) continue;
if(isset($a["title$language"])) $option->set("title$language", $a["title$language"]); if(isset($a["title$language"])) $option->set("title$language", $a["title$language"]);
if(isset($a["value$language"])) $option->set("value$language", $a["value$language"]); if(isset($a["value$language"])) $option->set("value$language", $a["value$language"]);
@@ -360,7 +365,7 @@ class SelectableOptionManager extends Wire {
if($language && $this->useLanguages()) { if($language && $this->useLanguages()) {
if(is_string($language) || is_int($language)) { if(is_string($language) || is_int($language)) {
$language = $this->wire('languages')->get($language); $language = $this->wire()->languages->get($language);
if(!$language->id) throw new WireException("Unknown language: $language"); if(!$language->id) throw new WireException("Unknown language: $language");
} }
if(is_object($language) && $language->isDefault()) $language = ''; if(is_object($language) && $language->isDefault()) $language = '';
@@ -371,6 +376,7 @@ class SelectableOptionManager extends Wire {
$out = ''; $out = '';
foreach($options as $option) { foreach($options as $option) {
/** @var SelectableOption $option */
$title = trim((string) $option->get("title$language")); $title = trim((string) $option->get("title$language"));
$value = trim((string) $option->get("value$language")); $value = trim((string) $option->get("value$language"));
$titleLength = strlen($title); $titleLength = strlen($title);
@@ -427,8 +433,9 @@ class SelectableOptionManager extends Wire {
if(!$this->useLanguages) throw new WireException("Language support not active"); if(!$this->useLanguages) throw new WireException("Language support not active");
$arrays = array(); $arrays = array();
$default = array(); $default = array();
$languages = $this->wire()->languages;
foreach($values as $languageID => $value) { foreach($values as $languageID => $value) {
$language = $this->wire('languages')->get($languageID); $language = $languages->get($languageID);
if(!$language || !$language->id) { if(!$language || !$language->id) {
$this->error("Unknown language: $language"); $this->error("Unknown language: $language");
continue; continue;
@@ -443,6 +450,7 @@ class SelectableOptionManager extends Wire {
$options = $this->optionsArrayToObjects($default); $options = $this->optionsArrayToObjects($default);
$options->setField($field); $options->setField($field);
foreach($options as $option) { foreach($options as $option) {
/** @var SelectableOption $option */
foreach($arrays as $languageID => $a) { foreach($arrays as $languageID => $a) {
$key = "id$option->id"; $key = "id$option->id";
if(!isset($a[$key])) continue; if(!isset($a[$key])) continue;
@@ -484,6 +492,7 @@ class SelectableOptionManager extends Wire {
$sort = 0; $sort = 0;
foreach($options as $option) { foreach($options as $option) {
/** @var SelectableOption $option */
$option->set('sort', $sort); $option->set('sort', $sort);
@@ -563,11 +572,11 @@ class SelectableOptionManager extends Wire {
unset($this->optionsCache[$field->id]); unset($this->optionsCache[$field->id]);
$database = $this->wire('database'); $database = $this->wire()->database;
$sql = "UPDATE " . self::optionsTable . " SET sort=:sort, title=:title, `value`=:value "; $sql = "UPDATE " . self::optionsTable . " SET sort=:sort, title=:title, `value`=:value ";
$bindCols = array(); $bindCols = array();
if($this->useLanguages) foreach($this->wire('languages') as $language) { if($this->useLanguages) foreach($this->wire()->languages as $language) {
if($language->isDefault()) continue; if($language->isDefault()) continue;
foreach(array('title', 'value') as $name) { foreach(array('title', 'value') as $name) {
$name .= (int) $language->id; $name .= (int) $language->id;
@@ -637,11 +646,11 @@ class SelectableOptionManager extends Wire {
public function deleteOptionsByID(Field $field, array $ids) { public function deleteOptionsByID(Field $field, array $ids) {
unset($this->optionsCache[$field->id]); unset($this->optionsCache[$field->id]);
$database = $this->wire('database'); $database = $this->wire()->database;
$table = $database->escapeTable($field->getTable()); $table = $database->escapeTable($field->getTable());
$cleanIDs = array(); $cleanIDs = array();
foreach($ids as $key => $id) { foreach($ids as $id) {
$cleanIDs[] = (int) $id; $cleanIDs[] = (int) $id;
} }
@@ -699,8 +708,7 @@ class SelectableOptionManager extends Wire {
*/ */
public function addOptions(Field $field, $options) { public function addOptions(Field $field, $options) {
/** @var WireDatabasePDO $database */ $database = $this->wire()->database;
$database = $this->wire('database');
// options that have pre-assigned IDs // options that have pre-assigned IDs
$optionsByID = array(); $optionsByID = array();