diff --git a/src/Controller/Component/ACLComponent.php b/src/Controller/Component/ACLComponent.php index cbd1cb8..7e8cd2f 100644 --- a/src/Controller/Component/ACLComponent.php +++ b/src/Controller/Component/ACLComponent.php @@ -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'], diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php index adc569b..9891b20 100644 --- a/src/Controller/Component/CRUDComponent.php +++ b/src/Controller/Component/CRUDComponent.php @@ -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); } diff --git a/src/Controller/Component/Navigation/sidemenu.php b/src/Controller/Component/Navigation/sidemenu.php index 84fcf6c..ec00e27 100644 --- a/src/Controller/Component/Navigation/sidemenu.php +++ b/src/Controller/Component/Navigation/sidemenu.php @@ -128,6 +128,11 @@ class Sidemenu { 'url' => '/permissionLimitations/index', 'icon' => 'jedi', ], + 'Enumerations' => [ + 'label' => __('Collections'), + 'url' => '/enumerationCollections/index', + 'icon' => 'list', + ], ] ], 'API' => [ diff --git a/src/Controller/EnumerationCollectionsController.php b/src/Controller/EnumerationCollectionsController.php new file mode 100644 index 0000000..bbf994f --- /dev/null +++ b/src/Controller/EnumerationCollectionsController.php @@ -0,0 +1,98 @@ +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'); + } +} diff --git a/src/Controller/EnumerationsController.php b/src/Controller/EnumerationsController.php new file mode 100644 index 0000000..c4aa956 --- /dev/null +++ b/src/Controller/EnumerationsController.php @@ -0,0 +1,40 @@ +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'); + } +} diff --git a/src/Model/Entity/Enumeration.php b/src/Model/Entity/Enumeration.php new file mode 100644 index 0000000..b6659a3 --- /dev/null +++ b/src/Model/Entity/Enumeration.php @@ -0,0 +1,11 @@ + [ + '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); + } + } + } +} diff --git a/src/Model/Table/EnumerationsTable.php b/src/Model/Table/EnumerationsTable.php new file mode 100644 index 0000000..a6a65bd --- /dev/null +++ b/src/Model/Table/EnumerationsTable.php @@ -0,0 +1,29 @@ +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; + } +} diff --git a/templates/EnumerationCollections/add.php b/templates/EnumerationCollections/add.php new file mode 100644 index 0000000..fc1be6f --- /dev/null +++ b/templates/EnumerationCollections/add.php @@ -0,0 +1,40 @@ +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') + ] + ] + ]); +?> + diff --git a/templates/EnumerationCollections/index.php b/templates/EnumerationCollections/index.php new file mode 100644 index 0000000..a4cefd1 --- /dev/null +++ b/templates/EnumerationCollections/index.php @@ -0,0 +1,96 @@ +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 ''; +?> diff --git a/templates/EnumerationCollections/view.php b/templates/EnumerationCollections/view.php new file mode 100644 index 0000000..7b46610 --- /dev/null +++ b/templates/EnumerationCollections/view.php @@ -0,0 +1,46 @@ +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') + ] + ] + ] +); diff --git a/templates/Enumerations/index.php b/templates/Enumerations/index.php new file mode 100644 index 0000000..e1b8e1b --- /dev/null +++ b/templates/Enumerations/index.php @@ -0,0 +1,43 @@ +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 ''; +?> diff --git a/templates/element/genericElements/Form/genericForm.php b/templates/element/genericElements/Form/genericForm.php index c0164a7..8a564de 100644 --- a/templates/element/genericElements/Form/genericForm.php +++ b/templates/element/genericElements/Form/genericForm.php @@ -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' => '
{{content}}
',