1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-17 12:10:45 +02:00

Improvements to searchability of FieldtypeOptions fields, now enabling it to match either value or title.

This commit is contained in:
Ryan Cramer
2019-01-11 08:52:12 -05:00
parent 36c0f401e7
commit 703fa29c85
2 changed files with 45 additions and 20 deletions

View File

@@ -100,11 +100,11 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
$inputfield->addOption((int) $option->id, $option->getTitle());
}
if($field->initValue) {
if($field->get('initValue')) {
$value = $page->getUnformatted($field->name);
if($field->required && !$field->requiredIf) {
if(empty($value) || !wireCount($value)) {
$page->set($field->name, $field->initValue);
$page->set($field->name, $field->get('initValue'));
}
} else if($this->wire('process') != 'ProcessField' && !wireCount($value)) {
$this->warning(
@@ -230,10 +230,10 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
$sleepValue = array();
if(empty($value) || !count($value)) {
// value is empty
if($field->required && $field->initValue) {
if($field->required && $field->get('initValue')) {
// value is required, and an initial value is supplied
// so populate the initial value
$initValue = $field->initValue;
$initValue = $field->get('initValue');
if(!is_array($initValue)) $initValue = array($initValue);
foreach($initValue as $v) {
$sleepValue[] = (int) $v;
@@ -306,19 +306,34 @@ class FieldtypeOptions extends FieldtypeMulti implements Module {
if($subfield == 'data' && (ctype_digit("$value") || empty($value))) {
// this is fine (presumed to be an option_id)
} else {
// some other subfield
// some other subfield, which needs to be mapped to either value or title
$options = array();
if(!$subfield || !SelectableOption::isProperty($subfield)) {
// if empty subfield or not a subfield we recognize, just assume title
$subfield = 'title';
if($subfield === 'data' && ($operator === '=' || $operator === '!=')) {
// subfield not specified: matching some string value, is it a value or a title? (allow for either)
$options = $this->manager->getOptions($query->field, array(
'value' => $value,
'title' => $value,
'or' => true
));
}
$options = $this->manager->findOptionsByProperty($query->field, $subfield, $operator, $value);
if(!count($options)) {
if(!$subfield || !SelectableOption::isProperty($subfield)) {
// if empty subfield or not a subfield we recognize, just assume title
$subfield = 'title';
}
$options = $this->manager->findOptionsByProperty($query->field, $subfield, $operator, $value);
}
$option = $options->first();
if($operator != '=' && $operator != '!=') {
// for fulltext operations...
// since we are now just matching IDs of already found options
$operator = '=';
}
$subfield = 'data';
$value = $option ? $option->id : null;
}

View File

@@ -97,41 +97,51 @@ class SelectableOptionManager extends Wire {
'id' => array(),
'title' => array(),
'value' => array(),
'or' => false, // change conditions from AND to OR?
);
$sortKey = true;
$sorted = array();
$filters = array_merge($defaults, $filters);
$wheres = array();
// make sure that all filters are arrays
foreach($defaults as $key => $unused) {
if(!is_array($filters[$key])) $filters[$key] = array($filters[$key]);
}
$sql = 'SELECT * FROM ' . self::optionsTable . ' WHERE fields_id=:fields_id ';
if(count($filters['id'])) {
$sql .= 'AND option_id IN(';
$s = 'option_id IN(';
foreach($filters['id'] as $id) {
$id = (int) $id;
$sql .= "$id,";
$s .= "$id,";
$sorted[$id] = ''; // placeholder
}
$sql = rtrim($sql, ',') . ')';
$s = rtrim($s, ',') . ')';
$sortKey = 'filters-id';
$wheres[] = $s;
}
foreach(array('title', 'value') as $property) {
if(!count($filters[$property])) continue;
$sql .= "AND `$property` IN(";
$s = "`$property` IN(";
foreach($filters[$property] as $val) {
$sql .= $this->wire('database')->quote($val) . ',';
$s .= $this->wire('database')->quote($val) . ',';
$sorted[$val] = ''; // placeholder
}
$sql = rtrim($sql, ',') . ')';
$s = rtrim($s, ',') . ')';
$sortKey = "filters-$property";
$wheres[] = $s;
}
$sql = 'SELECT * FROM ' . self::optionsTable . ' WHERE fields_id=:fields_id ';
if(count($wheres) > 1) {
$andOr = $filters['or'] ? ' OR ' : ' AND ';
$sql .= 'AND (' . implode($andOr, $wheres) . ') ';
} else if(count($wheres) === 1) {
$sql .= 'AND ' . reset($wheres);
}
if($sortKey === true) $sql .= 'ORDER BY sort ASC';
$query = $this->wire('database')->prepare($sql);
@@ -173,7 +183,7 @@ class SelectableOptionManager extends Wire {
* Perform a partial match on title of options
*
* @param Field $field
* @param string $property Either 'title' or 'value'
* @param string $property Either 'title' or 'value'. May also be blank (to imply 'either') if operator is '=' or '!='
* @param string $operator
* @param string $value Value to find
* @return SelectableOptionArray