new: [enumerations] added enumerations system
- for string entry fields, simply add lists of values to convert the text entry for values - helps with maintaining accurate lists - currently the fields that are valid targets are organisations.nationality, organisations.sector, organisations.typepull/163/head
parent
011f7f452c
commit
52e8a5c6a6
|
@ -75,6 +75,17 @@ class ACLComponent extends Component
|
|||
'delete' => ['*'],
|
||||
'index' => ['*']
|
||||
],
|
||||
'Enumerations' => [
|
||||
'delete' => ['perm_admin'],
|
||||
'index' => ['*']
|
||||
],
|
||||
'EnumerationCollections' => [
|
||||
'view' => ['*'],
|
||||
'add' => ['perm_admin'],
|
||||
'edit' => ['perm_admin'],
|
||||
'delete' => ['perm_admin'],
|
||||
'index' => ['*']
|
||||
],
|
||||
'Inbox' => [
|
||||
'createEntry' => ['OR' => ['perm_admin', 'perm_sync']],
|
||||
'delete' => ['perm_admin'],
|
||||
|
|
|
@ -399,6 +399,14 @@ class CRUDComponent extends Component
|
|||
if (!empty($params['fields'])) {
|
||||
$this->Controller->set('fields', $params['fields']);
|
||||
}
|
||||
$EnumerationCollections = TableRegistry::getTableLocator()->get('EnumerationCollections');
|
||||
$modelAlias = $this->Table->getAlias();
|
||||
if (in_array($this->Table->getAlias(), $EnumerationCollections->getValidModelList())) {
|
||||
$enumerations = $EnumerationCollections->getFieldValues($modelAlias);
|
||||
if (!empty($enumerations)) {
|
||||
$this->Controller->set('enumerations', $enumerations);
|
||||
}
|
||||
}
|
||||
$this->Controller->entity = $data;
|
||||
$this->Controller->set('entity', $data);
|
||||
}
|
||||
|
|
|
@ -128,6 +128,11 @@ class Sidemenu {
|
|||
'url' => '/permissionLimitations/index',
|
||||
'icon' => 'jedi',
|
||||
],
|
||||
'Enumerations' => [
|
||||
'label' => __('Collections'),
|
||||
'url' => '/enumerationCollections/index',
|
||||
'icon' => 'list',
|
||||
],
|
||||
]
|
||||
],
|
||||
'API' => [
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
use Cake\Http\Exception\NotFoundException;
|
||||
use Cake\Http\Exception\MethodNotAllowedException;
|
||||
use Cake\Http\Exception\ForbiddenException;
|
||||
|
||||
class EnumerationCollectionsController extends AppController
|
||||
{
|
||||
public $filterFields = ['name', 'target_model', 'target_field'];
|
||||
public $quickFilterFields = ['name', 'target_model', 'target_field'];
|
||||
public $containFields = [];
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => $this->filterFields,
|
||||
'quickFilters' => $this->quickFilterFields,
|
||||
'contain' => ['Enumerations'],
|
||||
'afterFind' => function($data) {
|
||||
$data->value_count = isset($data->enumerations) ? count($data->enumerations) : 0;
|
||||
$data->values = Hash::extract($data, 'enumerations.{n}.value');
|
||||
unset($data->enumerations);
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$this->CRUD->add([
|
||||
'afterSave' => function($data) {
|
||||
$this->EnumerationCollections->captureValues($data);
|
||||
}
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set(compact('enumerations'));
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$this->CRUD->view($id);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$this->CRUD->edit($id, [
|
||||
'afterSave' => function($data) {
|
||||
$this->EnumerationCollections->purgeValues($data);
|
||||
$this->EnumerationCollections->captureValues($data);
|
||||
},
|
||||
'contain' => ['Enumerations'],
|
||||
'afterFind' => function($data) {
|
||||
$values = [];
|
||||
foreach ($data['enumerations'] as $enumeration) {
|
||||
$values[] = $enumeration['value'];
|
||||
}
|
||||
$data->values = implode(PHP_EOL, $values);
|
||||
return $data;
|
||||
}
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
$this->render('add');
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$this->CRUD->delete($id);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\Utility\Hash;
|
||||
use Cake\Utility\Text;
|
||||
use \Cake\Database\Expression\QueryExpression;
|
||||
use Cake\Http\Exception\NotFoundException;
|
||||
use Cake\Http\Exception\MethodNotAllowedException;
|
||||
use Cake\Http\Exception\ForbiddenException;
|
||||
|
||||
class EnumerationsController extends AppController
|
||||
{
|
||||
public $filterFields = ['value'];
|
||||
public $quickFilterFields = ['value'];
|
||||
public $containFields = [];
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->CRUD->index([
|
||||
'filters' => $this->filterFields,
|
||||
'quickFilters' => $this->quickFilterFields
|
||||
]);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
public function delete($id)
|
||||
{
|
||||
$this->CRUD->delete($id);
|
||||
$responsePayload = $this->CRUD->getResponsePayload();
|
||||
if (!empty($responsePayload)) {
|
||||
return $responsePayload;
|
||||
}
|
||||
$this->set('metaGroup', 'Enumerations');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Entity;
|
||||
|
||||
use App\Model\Entity\AppModel;
|
||||
use Cake\ORM\Entity;
|
||||
|
||||
class Enumeration extends AppModel
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Entity;
|
||||
|
||||
use App\Model\Entity\AppModel;
|
||||
use Cake\ORM\Entity;
|
||||
|
||||
class EnumerationCollection extends AppModel
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;;
|
||||
use Cake\Datasource\EntityInterface;
|
||||
use Cake\Event\Event;
|
||||
use Cake\Event\EventInterface;
|
||||
use Cake\Utility\Text;
|
||||
use ArrayObject;
|
||||
|
||||
class EnumerationCollectionsTable extends AppTable
|
||||
{
|
||||
private $fieldMapping = [
|
||||
'Organisations' => [
|
||||
'country',
|
||||
'sector',
|
||||
'type'
|
||||
]
|
||||
];
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->addBehavior('UUID');
|
||||
$this->addBehavior('AuditLog');
|
||||
$this->addBehavior('Timestamp');
|
||||
$this->hasMany(
|
||||
'Enumerations',
|
||||
[
|
||||
'dependent' => true
|
||||
]
|
||||
);
|
||||
$this->setDisplayField('name');
|
||||
}
|
||||
|
||||
public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options)
|
||||
{
|
||||
if (empty($data['uuid'])) {
|
||||
$data['uuid'] = Text::uuid();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
$validator
|
||||
->notEmptyString('name')
|
||||
->requirePresence(['name'], 'create')
|
||||
->notEmptyString('uuid')
|
||||
->requirePresence(['uuid'], 'create')
|
||||
->notEmptyString('target_model')
|
||||
->requirePresence(['target_model'], 'create')
|
||||
->notEmptyString('target_field')
|
||||
->requirePresence(['target_field'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
|
||||
public function getValidFieldList(?string $model = null): array
|
||||
{
|
||||
if (!empty($model)) {
|
||||
if (empty($this->fieldMapping[$model])) {
|
||||
return [];
|
||||
} else {
|
||||
return $this->fieldMapping[$model];
|
||||
}
|
||||
} else {
|
||||
return $this->fieldMapping;
|
||||
}
|
||||
}
|
||||
|
||||
public function getValidModelList(?string $model = null): array
|
||||
{
|
||||
|
||||
return array_keys($this->fieldMapping);
|
||||
}
|
||||
|
||||
public function getFieldValues($model): array
|
||||
{
|
||||
$collections = $this->find('all')->where(['target_model' => $model, 'enabled' => 1, 'deleted' => 0])->contain(['Enumerations'])->disableHydration()->all()->toArray();
|
||||
$options = [];
|
||||
foreach ($collections as $collection) {
|
||||
if (empty($collection['target_field'])) {
|
||||
$options[$collection['target_field']] = [];
|
||||
}
|
||||
foreach ($collection['enumerations'] as $enumeration) {
|
||||
$options[$collection['target_field']][$enumeration['value']] = $enumeration['value'];
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function purgeValues(\App\Model\Entity\EnumerationCollection $entity): void
|
||||
{
|
||||
$this->Enumerations->deleteAll([
|
||||
'enumeration_collection_id' => $entity->id
|
||||
]);
|
||||
}
|
||||
|
||||
public function captureValues(\App\Model\Entity\EnumerationCollection $entity): void
|
||||
{
|
||||
if (!empty($entity->values)) {
|
||||
$values = $entity->values;
|
||||
$collection_id = $entity->id;
|
||||
if (!is_array($values)) {
|
||||
$values = explode("\n", $values);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$enumeration = $this->Enumerations->newEntity([
|
||||
'value' => trim($value),
|
||||
'enumeration_collection_id' => $entity->id
|
||||
]);
|
||||
$this->Enumerations->save($enumeration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
class EnumerationsTable extends AppTable
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->belongsTo(
|
||||
'EnumerationCollection'
|
||||
);
|
||||
$this->setDisplayField('value');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
$validator
|
||||
->notEmptyString('value')
|
||||
->requirePresence(['value'], 'create')
|
||||
->notEmptyString('enumeration_collection_id')
|
||||
->requirePresence(['enumeration_collection_id'], 'create');
|
||||
return $validator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => __('Roles define global rules for a set of users, including first and foremost access controls to certain functionalities.'),
|
||||
'model' => 'EnumerationCollections',
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'name',
|
||||
'label' => __('Name')
|
||||
],
|
||||
[
|
||||
'field' => 'enabled',
|
||||
'label' => __('Enabled'),
|
||||
'type' => 'checkbox',
|
||||
],
|
||||
[
|
||||
'field' => 'target_model',
|
||||
'label' => __('Model'),
|
||||
],
|
||||
[
|
||||
'field' => 'target_field',
|
||||
'label' => __('Field'),
|
||||
],
|
||||
[
|
||||
'field' => 'description',
|
||||
'label' => __('Description'),
|
||||
],
|
||||
[
|
||||
'field' => 'values',
|
||||
'label' => __('Values'),
|
||||
'type' => 'textarea'
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->getParam('action')
|
||||
]
|
||||
]
|
||||
]);
|
||||
?>
|
||||
</div>
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
$topbarChildren = [];
|
||||
if (!empty($loggedUser->role->perm_admin)) {
|
||||
$topbarChildren[] = [
|
||||
'type' => 'simple',
|
||||
'children' => [
|
||||
'data' => [
|
||||
'type' => 'simple',
|
||||
'text' => __('Add Enumeration Collection'),
|
||||
'class' => 'btn btn-primary',
|
||||
'popover_url' => '/enumerationCollections/add'
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
$topbarChildren[] = [
|
||||
'type' => 'search',
|
||||
'button' => __('Search'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value'
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'children' => $topbarChildren,
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'sort' => 'name',
|
||||
'data_path' => 'name',
|
||||
],
|
||||
[
|
||||
'name' => __('Enabled'),
|
||||
'sort' => 'enabled',
|
||||
'data_path' => 'enabled',
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'sort' => 'uuid',
|
||||
'data_path' => 'uuid',
|
||||
],
|
||||
[
|
||||
'name' => __('Model'),
|
||||
'sort' => 'target_model',
|
||||
'data_path' => 'target_model',
|
||||
],
|
||||
[
|
||||
'name' => __('Field'),
|
||||
'sort' => 'target_field',
|
||||
'data_path' => 'target_field',
|
||||
],
|
||||
[
|
||||
'name' => __('Values'),
|
||||
'sort' => 'value_count',
|
||||
'data_path' => 'value_count',
|
||||
],
|
||||
[
|
||||
'name' => __('Description'),
|
||||
'data_path' => 'description',
|
||||
],
|
||||
],
|
||||
'title' => __('Enumeration Collections Index'),
|
||||
'description' => __('A list collections that can be used to convert string input fields into selections wherever it makes sense.'),
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/enumerationCollections/view',
|
||||
'url_params_data_paths' => ['id'],
|
||||
'icon' => 'eye'
|
||||
],
|
||||
[
|
||||
'open_modal' => '/enumerationCollections/edit/[onclick_params_data_path]',
|
||||
'modal_params_data_path' => 'id',
|
||||
'icon' => 'edit',
|
||||
'requirement' => !empty($loggedUser['role']['perm_admin'])
|
||||
],
|
||||
[
|
||||
'open_modal' => '/enumerationCollections/delete/[onclick_params_data_path]',
|
||||
'modal_params_data_path' => 'id',
|
||||
'icon' => 'trash',
|
||||
'requirement' => !empty($loggedUser['role']['perm_admin'])
|
||||
],
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
echo $this->element(
|
||||
'/genericElements/SingleViews/single_view',
|
||||
[
|
||||
'data' => $entity,
|
||||
'fields' => [
|
||||
[
|
||||
'key' => __('ID'),
|
||||
'path' => 'id'
|
||||
],
|
||||
[
|
||||
'key' => __('Name'),
|
||||
'path' => 'name'
|
||||
],
|
||||
[
|
||||
'key' => __('Enabled'),
|
||||
'path' => 'enabled',
|
||||
'type' => 'boolean'
|
||||
],
|
||||
[
|
||||
'key' => __('UUID'),
|
||||
'path' => 'uuid'
|
||||
],
|
||||
[
|
||||
'key' => __('Model'),
|
||||
'path' => 'target_model'
|
||||
],
|
||||
[
|
||||
'key' => __('Field'),
|
||||
'path' => 'target_field'
|
||||
],
|
||||
[
|
||||
'key' => __('Description'),
|
||||
'path' => 'description'
|
||||
],
|
||||
|
||||
],
|
||||
'children' => [
|
||||
[
|
||||
'url' => '/Enumerations/index?EnumerationCollection.id={{0}}',
|
||||
'url_params' => ['id'],
|
||||
'title' => __('Values')
|
||||
]
|
||||
]
|
||||
]
|
||||
);
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Search'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'value'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => '#',
|
||||
'sort' => 'id',
|
||||
'data_path' => 'id',
|
||||
],
|
||||
[
|
||||
'name' => __('Value'),
|
||||
'sort' => 'value',
|
||||
'data_path' => 'value',
|
||||
]
|
||||
],
|
||||
'title' => __('Enumerations Index'),
|
||||
'description' => null,
|
||||
'pull' => 'right',
|
||||
'actions' => [
|
||||
[
|
||||
'open_modal' => '/enumerations/delete/[onclick_params_data_path]',
|
||||
'modal_params_data_path' => 'id',
|
||||
'icon' => 'trash',
|
||||
'requirement' => !empty($loggedUser['role']['perm_admin'])
|
||||
],
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
?>
|
|
@ -26,6 +26,14 @@
|
|||
}
|
||||
$formRandomValue = Cake\Utility\Security::randomString(8);
|
||||
$initSelect2 = false;
|
||||
|
||||
if (!empty($enumerations)) {
|
||||
foreach ($data['fields'] as $k => $field) {
|
||||
if (isset($enumerations[$field['field']])) {
|
||||
$data['fields'][$k]['options'] = $enumerations[$field['field']];
|
||||
}
|
||||
}
|
||||
}
|
||||
$formCreate = $this->Form->create($entity, ['id' => 'form-' . $formRandomValue]);
|
||||
$default_template = [
|
||||
'inputContainer' => '<div class="row mb-3">{{content}}</div>',
|
||||
|
|
Loading…
Reference in New Issue