new: [crud:filter] Added support of IN searches using dropdown
parent
fdd876b1b2
commit
4d4642770f
|
@ -226,22 +226,41 @@ class CRUDComponent extends Component
|
||||||
} else {
|
} else {
|
||||||
$this->Controller->set('metaFieldsEnabled', false);
|
$this->Controller->set('metaFieldsEnabled', false);
|
||||||
}
|
}
|
||||||
$filters = !empty($this->Controller->filterFields) ? $this->Controller->filterFields : [];
|
$filtersConfigRaw= !empty($this->Controller->filterFields) ? $this->Controller->filterFields : [];
|
||||||
|
$filtersConfig = [];
|
||||||
|
foreach ($filtersConfigRaw as $fieldConfig) {
|
||||||
|
if (is_array($fieldConfig)) {
|
||||||
|
$filtersConfig[$fieldConfig['name']] = $fieldConfig;
|
||||||
|
} else {
|
||||||
|
$filtersConfig[$fieldConfig] = ['name' => $fieldConfig];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$filtersName = $this->getFilterFieldsName();
|
||||||
$typeMap = $this->Table->getSchema()->typeMap();
|
$typeMap = $this->Table->getSchema()->typeMap();
|
||||||
$associatedtypeMap = !empty($this->Controller->filterFields) ? $this->_getAssociatedTypeMap() : [];
|
$associatedtypeMap = !empty($filtersName) ? $this->_getAssociatedTypeMap() : [];
|
||||||
$typeMap = array_merge(
|
$typeMap = array_merge(
|
||||||
$this->Table->getSchema()->typeMap(),
|
$this->Table->getSchema()->typeMap(),
|
||||||
$associatedtypeMap
|
$associatedtypeMap
|
||||||
);
|
);
|
||||||
$typeMap = array_filter($typeMap, function ($field) use ($filters) {
|
$typeMap = array_filter($typeMap, function ($field) use ($filtersName) {
|
||||||
return in_array($field, $filters);
|
return in_array($field, $filtersName);
|
||||||
}, ARRAY_FILTER_USE_KEY);
|
}, ARRAY_FILTER_USE_KEY);
|
||||||
$this->Controller->set('typeMap', $typeMap);
|
$this->Controller->set('typeMap', $typeMap);
|
||||||
$this->Controller->set('filters', $filters);
|
$this->Controller->set('filters', $filtersName);
|
||||||
|
$this->Controller->set('filtersConfig', $filtersConfig);
|
||||||
$this->Controller->viewBuilder()->setLayout('ajax');
|
$this->Controller->viewBuilder()->setLayout('ajax');
|
||||||
$this->Controller->render('/genericTemplates/filters');
|
$this->Controller->render('/genericTemplates/filters');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFilterFieldsName(): array
|
||||||
|
{
|
||||||
|
$filters = !empty($this->Controller->filterFields) ? $this->Controller->filterFields : [];
|
||||||
|
$filters = array_map(function($item) {
|
||||||
|
return is_array($item) ? $item['name'] : $item;
|
||||||
|
}, $filters);
|
||||||
|
return $filters;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getResponsePayload Returns the adaquate response payload based on the request context
|
* getResponsePayload Returns the adaquate response payload based on the request context
|
||||||
*
|
*
|
||||||
|
@ -1613,7 +1632,7 @@ class CRUDComponent extends Component
|
||||||
protected function _getAssociatedTypeMap(): array
|
protected function _getAssociatedTypeMap(): array
|
||||||
{
|
{
|
||||||
$typeMap = [];
|
$typeMap = [];
|
||||||
foreach ($this->Controller->filterFields as $filter) {
|
foreach ($this->getFilterFieldsName() as $filter) {
|
||||||
$exploded = explode('.', $filter);
|
$exploded = explode('.', $filter);
|
||||||
if (count($exploded) > 1) {
|
if (count($exploded) > 1) {
|
||||||
$model = $exploded[0];
|
$model = $exploded[0];
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
$seed = 's-' . mt_rand();
|
$seed = 's-' . mt_rand();
|
||||||
$controlParams = [
|
$controlParams = [
|
||||||
'type' => 'select',
|
'type' => 'select',
|
||||||
'options' => $fieldData['options'],
|
'options' => $fieldData['options'] ?? [],
|
||||||
'empty' => $fieldData['empty'] ?? false,
|
'empty' => $fieldData['empty'] ?? false,
|
||||||
'value' => $fieldData['value'] ?? null,
|
'value' => $fieldData['value'] ?? null,
|
||||||
'multiple' => $fieldData['multiple'] ?? false,
|
'multiple' => $fieldData['multiple'] ?? false,
|
||||||
|
@ -20,8 +20,10 @@ if ($controlParams['options'] instanceof \Cake\ORM\Query) {
|
||||||
$controlParams['options'] = $controlParams['options']->all()->toList();
|
$controlParams['options'] = $controlParams['options']->all()->toList();
|
||||||
}
|
}
|
||||||
if (!empty($fieldData['select2'])) {
|
if (!empty($fieldData['select2'])) {
|
||||||
|
$fieldData['select2'] = $fieldData['select2'] === true ? [] : $fieldData['select2'];
|
||||||
$controlParams['class'] .= ' select2-input';
|
$controlParams['class'] .= ' select2-input';
|
||||||
}
|
}
|
||||||
|
$controlParams['class'] .= ' dropdown-custom-value' . "-$seed";
|
||||||
if (in_array('_custom', array_keys($controlParams['options']))) {
|
if (in_array('_custom', array_keys($controlParams['options']))) {
|
||||||
$customInputValue = $this->Form->getSourceValue($fieldData['field']);
|
$customInputValue = $this->Form->getSourceValue($fieldData['field']);
|
||||||
if (!in_array($customInputValue, $controlParams['options'])) {
|
if (!in_array($customInputValue, $controlParams['options'])) {
|
||||||
|
@ -34,7 +36,6 @@ if (in_array('_custom', array_keys($controlParams['options']))) {
|
||||||
} else {
|
} else {
|
||||||
$customInputValue = '';
|
$customInputValue = '';
|
||||||
}
|
}
|
||||||
$controlParams['class'] .= ' dropdown-custom-value' . "-$seed";
|
|
||||||
$adaptedField = $fieldData['field'] . '_custom';
|
$adaptedField = $fieldData['field'] . '_custom';
|
||||||
$controlParams['templates']['formGroup'] = sprintf(
|
$controlParams['templates']['formGroup'] = sprintf(
|
||||||
'<label class="col-sm-2 col-form-label form-label" {{attrs}}>{{label}}</label><div class="col-sm-10 multi-metafield-input-container"><div class="d-flex form-dropdown-with-freetext input-group">{{input}}{{error}}%s</div></div>',
|
'<label class="col-sm-2 col-form-label form-label" {{attrs}}>{{label}}</label><div class="col-sm-10 multi-metafield-input-container"><div class="d-flex form-dropdown-with-freetext input-group">{{input}}{{error}}%s</div></div>',
|
||||||
|
@ -57,9 +58,12 @@ echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $f
|
||||||
if ($container.length == 0) {
|
if ($container.length == 0) {
|
||||||
$container = $(document.body)
|
$container = $(document.body)
|
||||||
}
|
}
|
||||||
$select.select2({
|
const defaultSelect2Options = {
|
||||||
dropdownParent: $container,
|
dropdownParent: $container,
|
||||||
})
|
}
|
||||||
|
const passedSelect2Options = <?= json_encode($fieldData['select2']) ?>;
|
||||||
|
const select2Options = Object.assign({}, passedSelect2Options, defaultSelect2Options)
|
||||||
|
$select.select2(select2Options)
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -47,19 +47,28 @@ $filteringForm = $this->Bootstrap->table(
|
||||||
__('Value'),
|
__('Value'),
|
||||||
sprintf('<sup class="fa fa-info" title="%s"><sup>', __('Supports strict matches and LIKE matches with the `%` character. Example: `%.com`'))
|
sprintf('<sup class="fa fa-info" title="%s"><sup>', __('Supports strict matches and LIKE matches with the `%` character. Example: `%.com`'))
|
||||||
),
|
),
|
||||||
'formatter' => function ($field, $row) use ($typeMap, $formTypeMap) {
|
'formatter' => function ($field, $row) use ($typeMap, $formTypeMap, $filtersConfig) {
|
||||||
$fieldName = $row['fieldname'];
|
$fieldName = $row['fieldname'];
|
||||||
$formType = $formTypeMap[$typeMap[$fieldName]] ?? 'text';
|
$formType = $formTypeMap[$typeMap[$fieldName]] ?? 'text';
|
||||||
|
$fieldData = [
|
||||||
|
'field' => $fieldName,
|
||||||
|
'type' => $formType,
|
||||||
|
'label' => '',
|
||||||
|
'class' => 'fieldValue form-control-sm'
|
||||||
|
];
|
||||||
|
if (!empty($filtersConfig[$fieldName]['multiple'])) {
|
||||||
|
$fieldData['type'] = 'dropdown';
|
||||||
|
$fieldData['multiple'] = true;
|
||||||
|
$fieldData['select2'] = [
|
||||||
|
'tags' => true,
|
||||||
|
'tokenSeparators' => [',', ' '],
|
||||||
|
];
|
||||||
|
}
|
||||||
$this->Form->setTemplates([
|
$this->Form->setTemplates([
|
||||||
'formGroup' => '<div class="col-sm-10">{{input}}</div>',
|
'formGroup' => '<div class="col-sm-10">{{input}}</div>',
|
||||||
]);
|
]);
|
||||||
return $this->element('genericElements/Form/fieldScaffold', [
|
return $this->element('genericElements/Form/fieldScaffold', [
|
||||||
'fieldData' => [
|
'fieldData' => $fieldData,
|
||||||
'field' => $fieldName,
|
|
||||||
'type' => $formType,
|
|
||||||
'label' => '',
|
|
||||||
'class' => 'fieldValue form-control-sm'
|
|
||||||
],
|
|
||||||
'params' => []
|
'params' => []
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +178,36 @@ echo $this->Bootstrap->modal([
|
||||||
}
|
}
|
||||||
setFilteringValues($filteringTable, field, value, operator)
|
setFilteringValues($filteringTable, field, value, operator)
|
||||||
}
|
}
|
||||||
|
if (tags.length > 0) {
|
||||||
|
setFilteringTags($filteringTable, tags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFilteringValues($filteringTable, field, value, operator) {
|
||||||
|
$row = $filteringTable.find('td > span.fieldName').filter(function() {
|
||||||
|
return $(this).data('fieldname') == field
|
||||||
|
}).closest('tr')
|
||||||
|
$row.find('.fieldOperator').val(operator)
|
||||||
|
const $formElement = $row.find('.fieldValue');
|
||||||
|
if ($formElement.attr('type') === 'datetime-local') {
|
||||||
|
$formElement.val(moment(value).format('yyyy-MM-DDThh:mm:ss'))
|
||||||
|
} else if ($formElement.is('select') && Array.isArray(value)) {
|
||||||
|
let newOptions = [];
|
||||||
|
value.forEach(aValue => {
|
||||||
|
const existingOption = $formElement.find('option').filter(function() {
|
||||||
|
return $(this).val() === aValue
|
||||||
|
})
|
||||||
|
if (existingOption.length == 0) {
|
||||||
|
newOptions.push(new Option(aValue, aValue, true, true))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$formElement.append(newOptions).trigger('change');
|
||||||
|
} else {
|
||||||
|
$formElement.val(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFilteringTags($filteringTable, tags) {
|
||||||
$select = $filteringTable.closest('.modal-body').find('select.select2-input')
|
$select = $filteringTable.closest('.modal-body').find('select.select2-input')
|
||||||
let passedTags = []
|
let passedTags = []
|
||||||
tags.forEach(tagname => {
|
tags.forEach(tagname => {
|
||||||
|
@ -185,19 +224,6 @@ echo $this->Bootstrap->modal([
|
||||||
.trigger('change')
|
.trigger('change')
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFilteringValues($filteringTable, field, value, operator) {
|
|
||||||
$row = $filteringTable.find('td > span.fieldName').filter(function() {
|
|
||||||
return $(this).data('fieldname') == field
|
|
||||||
}).closest('tr')
|
|
||||||
$row.find('.fieldOperator').val(operator)
|
|
||||||
const $formElement = $row.find('.fieldValue');
|
|
||||||
if ($formElement.attr('type') === 'datetime-local') {
|
|
||||||
$formElement.val(moment(value).format('yyyy-MM-DDThh:mm:ss'))
|
|
||||||
} else {
|
|
||||||
$formElement.val(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDataFromRow($row) {
|
function getDataFromRow($row) {
|
||||||
const rowData = {};
|
const rowData = {};
|
||||||
rowData['name'] = $row.find('td > span.fieldName').data('fieldname')
|
rowData['name'] = $row.find('td > span.fieldName').data('fieldname')
|
||||||
|
|
Loading…
Reference in New Issue