From e9f06a6a304d3dd857727f54e4b579a170e1ea6c Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Thu, 24 Oct 2024 19:30:33 +0300 Subject: [PATCH 01/10] Add support for attribute collection fieldsets --- .../Model/Table/EnrollmentAttributesTable.php | 7 +- .../AttributeCollectors/attribute.inc | 107 +++++++ .../AttributeCollectors/dispatch.inc | 78 +----- .../multifield_attribute.inc | 89 ++++++ .../Controller/StandardEnrollerController.php | 9 +- app/src/Lib/Util/CountryCodeUtilities.php | 263 ++++++++++++++++++ 6 files changed, 474 insertions(+), 79 deletions(-) create mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc create mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc create mode 100644 app/src/Lib/Util/CountryCodeUtilities.php diff --git a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php index cee5f79a..707a3406 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php @@ -155,7 +155,12 @@ public function initialize(array $config): void { 'urlTypes' => [ 'type' => 'type', 'attribute' => 'Urls.type' - ] + ], + // Required for attribute collection + 'cosettings' => [ + 'type' => 'auxiliary', + 'model' => 'CoSettings' + ], ]); $this->setLayout([ 'index' => 'iframe', diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc new file mode 100644 index 00000000..d8dec4a3 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc @@ -0,0 +1,107 @@ +default_value) => $attr->default_value, + isset($attr->default_value_env_name) + && getenv($attr->default_value_env_name) !== false => getenv($attr->default_value_env_name), + isset($attr->default_value_datetime) => $attr->default_value_datetime, + default => '' +}; + +// If we are re-rendering the Petition override the default value with whatever +// was previously saved +if(!empty($vv_petition_attributes)) { + $curEntity = $vv_petition_attributes->firstMatch(['enrollment_attribute_id' => $attr->id]); + + if(!empty($curEntity->value)) { + $options['default'] = $curEntity->value; + } +} + +// Construct the field arguments +$formArguments = [ + // We prefix the attribute ID with a string because Cake seems to sometimes have + // problems with field names that are purely integers (even if cast to strings) + 'fieldName' => 'field-' . $attr->id, + 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes + 'fieldType' => $supportedAttributes['fieldType'], + 'fieldDescription' => $attr->description, + 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name +]; + + +/* + * Get the values for the attributes ending with _id + * Supported for attributes: group_id, cou_id, affiliation_type_id + */ +if(str_ends_with($attr->attribute, '_id')) { + $suffix = substr($attr->attribute, 0, -3); + $suffix = Inflector::pluralize(Inflector::camelize($suffix)) ; + $defaultValuesPopulated = 'defaultValue' . $suffix; + if ($this->get($defaultValuesPopulated) !== null) { + $formArguments['fieldType'] = 'select'; + $formArguments['fieldSelectOptions'] = $this->get($defaultValuesPopulated); + } +} + +// READ-ONLY +if (isset($attr->modifiable) && !$attr->modifiable) { + $options['readonly'] = true; +} + +// REQUIRED +if (isset($attr->required) && $attr->required) { + $options['required'] = true; +} + +// Set the final fieldOptions +$formArguments['fieldOptions'] = $options; + +// HIDDEN Field +// We print directly, we do not delegate to the element for further processing +if ($attr->hidden) { + // In case this is a hidden field, we need to get only the value + print $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]); +} else { + // Print the element + print $this->element('form/listItem', [ + 'arguments' => $formArguments + ]); +} \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc index a90b4322..92b35e72 100644 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc @@ -57,80 +57,10 @@ foreach($vv_enrollment_attributes_sorted as $attr) { // Get the static configuration of my attribute $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); - // Field Options array - $options = []; - - - // Do we have a default value configured? - // Either a value or an Environmental Variable, - // Each default value is mutually exclusive to the rest. We do not have to worry about a conflict. - $options['default'] = match(true) { - isset($attr->default_value) => $attr->default_value, - isset($attr->default_value_env_name) - && getenv($attr->default_value_env_name) !== false => getenv($attr->default_value_env_name), - isset($attr->default_value_datetime) => $attr->default_value_datetime, - default => '' - }; - - // If we are rerendering the Petition override the default value with whatever - // was previously saved - if(!empty($vv_petition_attributes)) { - $curEntity = $vv_petition_attributes->firstMatch(['enrollment_attribute_id' => $attr->id]); - - if(!empty($curEntity->value)) { - $options['default'] = $curEntity->value; - } - } - - // Construct the field arguments - $formArguments = [ - // We prefix the attribute ID with a string because Cake seems to sometimes have - // problems with field names that are purely integers (even if cast to strings) - 'fieldName' => 'field-' . $attr->id, - 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes - 'fieldType' => $supportedAttributes['fieldType'], - 'fieldDescription' => $attr->description, - 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name - ]; - - - /* - * Get the values for the attributes ending with _id - * Supported for attributes: group_id, cou_id, affiliation_type_id - */ - if(str_ends_with($attr->attribute, '_id')) { - $suffix = substr($attr->attribute, 0, -3); - $suffix = Inflector::pluralize(Inflector::camelize($suffix)) ; - $defaultValuesPopulated = 'defaultValue' . $suffix; - if ($this->get($defaultValuesPopulated) !== null) { - $formArguments['fieldType'] = 'select'; - $formArguments['fieldSelectOptions'] = $this->get($defaultValuesPopulated); - } - } - - // READ-ONLY - if (isset($attr->modifiable) && !$attr->modifiable) { - $options['readonly'] = true; - } - - // REQUIRED - if (isset($attr->required) && $attr->required) { - $options['required'] = true; - } - - // Set the final fieldOptions - $formArguments['fieldOptions'] = $options; - - // HIDDEN Field - // We print directly, we do not delegate to the element for further processing - if ($attr->hidden) { - // In case this is a hidden field, we need to get only the value - print $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]); - continue; + if(empty($attr->attribute_required_fields)) { + include( $vv_template_path . DS . 'attribute.inc'); + } else { + include( $vv_template_path . DS . 'multifield_attribute.inc'); } - // Print the element - print $this->element('form/listItem', [ - 'arguments' => $formArguments - ]); } \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc new file mode 100644 index 00000000..e9bd8019 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc @@ -0,0 +1,89 @@ +attribute . 'Types'; +// Check if this mvea model supports types, if it does then render the attribute type +// dropdown list +$fieldLabel = 'Not found'; +if ($this->get($mveaAutoPopulatedVariable) !== null) { + $fieldLabel = $this->get($mveaAutoPopulatedVariable)[$attr->attribute_type] . ' ' . ucfirst($attr->attribute); +} + +$required_fields_variable_name = "required_fields_$attr->attribute"; +$permitted_fields_variable_name = "permitted_fields_$attr->attribute"; +$permitted_fields_list = []; +$required_fields_list = []; +if (!empty($cosettings[0][$required_fields_variable_name])) { + $required_fields_list = explode(',', $cosettings[0][$required_fields_variable_name]); +} + +if (!empty($cosettings[0][$permitted_fields_variable_name])) { + $permitted_fields_list = explode(',', $cosettings[0][$permitted_fields_variable_name]); +} +?> + +
  • +
    + + + +
    + +attribute_required_fields) as $field) : ?> + + "field-$field-$attr->id", + 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes + 'fieldType' => $supportedAttributes['fieldType'], + 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name + ]; +?> + +
    + + element('form/requiredSpan') : ''?> +
    + Field->formField(...$formArguments) ?> +
    +
    + + +
    +
    +
  • diff --git a/app/src/Controller/StandardEnrollerController.php b/app/src/Controller/StandardEnrollerController.php index 601141bb..25d0a78c 100644 --- a/app/src/Controller/StandardEnrollerController.php +++ b/app/src/Controller/StandardEnrollerController.php @@ -55,10 +55,11 @@ public function beforeRender(\Cake\Event\EventInterface $event) { // Make the Petition available to the view $this->set( 'vv_petition', - $Petition->findById($this->petition->id) - ->contain($Petition->getIndexContains()) - ->firstOrFail() - ); + $this->petition?->id ? + $Petition->findById($this->petition->id) + ->contain($Petition->getIndexContains()) + ->firstOrFail() : null + ); return parent::beforeRender($event); } diff --git a/app/src/Lib/Util/CountryCodeUtilities.php b/app/src/Lib/Util/CountryCodeUtilities.php new file mode 100644 index 00000000..aea299ad --- /dev/null +++ b/app/src/Lib/Util/CountryCodeUtilities.php @@ -0,0 +1,263 @@ + 'UK (+44)', + 1 => 'USA (+1)', + 213 => 'Algeria (+213)', + 376 => 'Andorra (+376)', + 244 => 'Angola (+244)', + 1264 => 'Anguilla (+1264)', + 1268 => 'Antigua & Barbuda (+1268)', + 54 => 'Argentina (+54)', + 374 => 'Armenia (+374)', + 297 => 'Aruba (+297)', + 61 => 'Australia (+61)', + 43 => 'Austria (+43)', + 994 => 'Azerbaijan (+994)', + 1242 => 'Bahamas (+1242)', + 973 => 'Bahrain (+973)', + 880 => 'Bangladesh (+880)', + 1246 => 'Barbados (+1246)', + 375 => 'Belarus (+375)', + 32 => 'Belgium (+32)', + 501 => 'Belize (+501)', + 229 => 'Benin (+229)', + 1441 => 'Bermuda (+1441)', + 975 => 'Bhutan (+975)', + 591 => 'Bolivia (+591)', + 387 => 'Bosnia Herzegovina (+387)', + 267 => 'Botswana (+267)', + 55 => 'Brazil (+55)', + 673 => 'Brunei (+673)', + 359 => 'Bulgaria (+359)', + 226 => 'Burkina Faso (+226)', + 257 => 'Burundi (+257)', + 855 => 'Cambodia (+855)', + 237 => 'Cameroon (+237)', + 1 => 'Canada (+1)', + 238 => 'Cape Verde Islands (+238)', + 1345 => 'Cayman Islands (+1345)', + 236 => 'Central African Republic (+236)', + 56 => 'Chile (+56)', + 86 => 'China (+86)', + 57 => 'Colombia (+57)', + 269 => 'Comoros (+269)', + 242 => 'Congo (+242)', + 682 => 'Cook Islands (+682)', + 506 => 'Costa Rica (+506)', + 385 => 'Croatia (+385)', + 53 => 'Cuba (+53)', + 90392 => 'Cyprus North (+90392)', + 357 => 'Cyprus South (+357)', + 42 => 'Czech Republic (+42)', + 45 => 'Denmark (+45)', + 253 => 'Djibouti (+253)', + 1809 => 'Dominica (+1809)', + 1809 => 'Dominican Republic (+1809)', + 593 => 'Ecuador (+593)', + 20 => 'Egypt (+20)', + 503 => 'El Salvador (+503)', + 240 => 'Equatorial Guinea (+240)', + 291 => 'Eritrea (+291)', + 372 => 'Estonia (+372)', + 251 => 'Ethiopia (+251)', + 500 => 'Falkland Islands (+500)', + 298 => 'Faroe Islands (+298)', + 679 => 'Fiji (+679)', + 358 => 'Finland (+358)', + 33 => 'France (+33)', + 594 => 'French Guiana (+594)', + 689 => 'French Polynesia (+689)', + 241 => 'Gabon (+241)', + 220 => 'Gambia (+220)', + 7880 => 'Georgia (+7880)', + 49 => 'Germany (+49)', + 233 => 'Ghana (+233)', + 350 => 'Gibraltar (+350)', + 30 => 'Greece (+30)', + 299 => 'Greenland (+299)', + 1473 => 'Grenada (+1473)', + 590 => 'Guadeloupe (+590)', + 671 => 'Guam (+671)', + 502 => 'Guatemala (+502)', + 224 => 'Guinea (+224)', + 245 => 'Guinea - Bissau (+245)', + 592 => 'Guyana (+592)', + 509 => 'Haiti (+509)', + 504 => 'Honduras (+504)', + 852 => 'Hong Kong (+852)', + 36 => 'Hungary (+36)', + 354 => 'Iceland (+354)', + 91 => 'India (+91)', + 62 => 'Indonesia (+62)', + 98 => 'Iran (+98)', + 964 => 'Iraq (+964)', + 353 => 'Ireland (+353)', + 972 => 'Israel (+972)', + 39 => 'Italy (+39)', + 1876 => 'Jamaica (+1876)', + 81 => 'Japan (+81)', + 962 => 'Jordan (+962)', + 7 => 'Kazakhstan (+7)', + 254 => 'Kenya (+254)', + 686 => 'Kiribati (+686)', + 850 => 'Korea North (+850)', + 82 => 'Korea South (+82)', + 965 => 'Kuwait (+965)', + 996 => 'Kyrgyzstan (+996)', + 856 => 'Laos (+856)', + 371 => 'Latvia (+371)', + 961 => 'Lebanon (+961)', + 266 => 'Lesotho (+266)', + 231 => 'Liberia (+231)', + 218 => 'Libya (+218)', + 417 => 'Liechtenstein (+417)', + 370 => 'Lithuania (+370)', + 352 => 'Luxembourg (+352)', + 853 => 'Macao (+853)', + 389 => 'Macedonia (+389)', + 261 => 'Madagascar (+261)', + 265 => 'Malawi (+265)', + 60 => 'Malaysia (+60)', + 960 => 'Maldives (+960)', + 223 => 'Mali (+223)', + 356 => 'Malta (+356)', + 692 => 'Marshall Islands (+692)', + 596 => 'Martinique (+596)', + 222 => 'Mauritania (+222)', + 269 => 'Mayotte (+269)', + 52 => 'Mexico (+52)', + 691 => 'Micronesia (+691)', + 373 => 'Moldova (+373)', + 377 => 'Monaco (+377)', + 976 => 'Mongolia (+976)', + 1664 => 'Montserrat (+1664)', + 212 => 'Morocco (+212)', + 258 => 'Mozambique (+258)', + 95 => 'Myanmar (+95)', + 264 => 'Namibia (+264)', + 674 => 'Nauru (+674)', + 977 => 'Nepal (+977)', + 31 => 'Netherlands (+31)', + 687 => 'New Caledonia (+687)', + 64 => 'New Zealand (+64)', + 505 => 'Nicaragua (+505)', + 227 => 'Niger (+227)', + 234 => 'Nigeria (+234)', + 683 => 'Niue (+683)', + 672 => 'Norfolk Islands (+672)', + 670 => 'Northern Marianas (+670)', + 47 => 'Norway (+47)', + 968 => 'Oman (+968)', + 680 => 'Palau (+680)', + 507 => 'Panama (+507)', + 675 => 'Papua New Guinea (+675)', + 595 => 'Paraguay (+595)', + 51 => 'Peru (+51)', + 63 => 'Philippines (+63)', + 48 => 'Poland (+48)', + 351 => 'Portugal (+351)', + 1787 => 'Puerto Rico (+1787)', + 974 => 'Qatar (+974)', + 262 => 'Reunion (+262)', + 40 => 'Romania (+40)', + 7 => 'Russia (+7)', + 250 => 'Rwanda (+250)', + 378 => 'San Marino (+378)', + 239 => 'Sao Tome & Principe (+239)', + 966 => 'Saudi Arabia (+966)', + 221 => 'Senegal (+221)', + 381 => 'Serbia (+381)', + 248 => 'Seychelles (+248)', + 232 => 'Sierra Leone (+232)', + 65 => 'Singapore (+65)', + 421 => 'Slovak Republic (+421)', + 386 => 'Slovenia (+386)', + 677 => 'Solomon Islands (+677)', + 252 => 'Somalia (+252)', + 27 => 'South Africa (+27)', + 34 => 'Spain (+34)', + 94 => 'Sri Lanka (+94)', + 290 => 'St. Helena (+290)', + 1869 => 'St. Kitts (+1869)', + 1758 => 'St. Lucia (+1758)', + 249 => 'Sudan (+249)', + 597 => 'Suriname (+597)', + 268 => 'Swaziland (+268)', + 46 => 'Sweden (+46)', + 41 => 'Switzerland (+41)', + 963 => 'Syria (+963)', + 886 => 'Taiwan (+886)', + 7 => 'Tajikstan (+7)', + 66 => 'Thailand (+66)', + 228 => 'Togo (+228)', + 676 => 'Tonga (+676)', + 1868 => 'Trinidad & Tobago (+1868)', + 216 => 'Tunisia (+216)', + 90 => 'Turkey (+90)', + 7 => 'Turkmenistan (+7)', + 993 => 'Turkmenistan (+993)', + 1649 => 'Turks & Caicos Islands (+1649)', + 688 => 'Tuvalu (+688)', + 256 => 'Uganda (+256)', + 380 => 'Ukraine (+380)', + 971 => 'United Arab Emirates (+971)', + 598 => 'Uruguay (+598)', + 7 => 'Uzbekistan (+7)', + 678 => 'Vanuatu (+678)', + 379 => 'Vatican City (+379)', + 58 => 'Venezuela (+58)', + 84 => 'Vietnam (+84)', + 84 => 'Virgin Islands - British (+1284)', + 84 => 'Virgin Islands - US (+1340)', + 681 => 'Wallis & Futuna (+681)', + 969 => 'Yemen (North)(+969)', + 967 => 'Yemen (South)(+967)', + 260 => 'Zambia (+260)', + 263 => 'Zimbabwe (+263)', + ]; + + return $ccodes[$code] ?? $ccodes; + } +} \ No newline at end of file From 8cea579332f95f16a291449e1e380a2ac81018f4 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Sat, 2 Nov 2024 20:34:35 +0200 Subject: [PATCH 02/10] Attribute Collection view FieldGroups --- .../Model/Table/EnrollmentAttributesTable.php | 4 + .../AttributeCollectors/fieldset-field.inc | 54 +++++++++++++ .../AttributeCollectors/fieldset-group.inc | 54 +++++++++++++ .../multifield_attribute.inc | 80 ++++++++++++------- app/resources/locales/en_US/enumeration.po | 17 +++- app/src/Lib/Enum/GroupedAddressFieldsEnum.php | 38 +++++++++ 6 files changed, 212 insertions(+), 35 deletions(-) create mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc create mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc create mode 100644 app/src/Lib/Enum/GroupedAddressFieldsEnum.php diff --git a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php index 707a3406..42a30fbf 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php @@ -85,6 +85,10 @@ public function initialize(array $config): void { 'type' => 'enum', 'class' => 'RequiredAddressFieldsEnum' ], + 'addressGroupedFields' => [ + 'type' => 'enum', + 'class' => 'GroupedAddressFieldsEnum' + ], 'addressTypes' => [ 'type' => 'type', 'attribute' => 'Addresses.type' diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc new file mode 100644 index 00000000..4e112d6e --- /dev/null +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc @@ -0,0 +1,54 @@ + "field-$field-$attr->id", + 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes + 'fieldType' => $supportedAttributes['fieldType'], + 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name +]; +?> + +
    + + element('form/requiredSpan') : ''?> +
    + Field->formField(...$formArguments) ?> +
    +
    \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc new file mode 100644 index 00000000..3bc6ff24 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc @@ -0,0 +1,54 @@ + + + $fields): ?> +
    + filter(fn($value) => str_replace(' ', '_', Inflector::underscore($value)) !== $field); + include($vv_template_path . DS . 'fieldset-field.inc'); + } + ?> +
    + + + + + diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc index e9bd8019..f416f1e6 100644 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc @@ -27,7 +27,6 @@ declare(strict_types = 1); -use App\Lib\Enum\StatusEnum; use \Cake\Utility\Inflector; // This field is called attribute_type and not attribute_type_id because we want this @@ -38,20 +37,53 @@ $mveaAutoPopulatedVariable = $attr->attribute . 'Types'; // dropdown list $fieldLabel = 'Not found'; if ($this->get($mveaAutoPopulatedVariable) !== null) { - $fieldLabel = $this->get($mveaAutoPopulatedVariable)[$attr->attribute_type] . ' ' . ucfirst($attr->attribute); + $fieldLabel = $this->get($mveaAutoPopulatedVariable)[$attr->attribute_type] + . ' ' + . Inflector::humanize(Inflector::underscore($attr->attribute)); } -$required_fields_variable_name = "required_fields_$attr->attribute"; -$permitted_fields_variable_name = "permitted_fields_$attr->attribute"; +$required_fields_variable_name = 'required_fields_' . Inflector::underscore($attr->attribute); +$permitted_fields_variable_name = 'permitted_fields_' . Inflector::underscore($attr->attribute); $permitted_fields_list = []; $required_fields_list = []; -if (!empty($cosettings[0][$required_fields_variable_name])) { - $required_fields_list = explode(',', $cosettings[0][$required_fields_variable_name]); -} if (!empty($cosettings[0][$permitted_fields_variable_name])) { $permitted_fields_list = explode(',', $cosettings[0][$permitted_fields_variable_name]); } + +// Required fields +// - first look at the enrollment flow level +// - if not set look at the co level +$required_fields = match(true) { + // Enrollment Flow + !empty($attr?->attribute_required_fields) => $attr?->attribute_required_fields, + // Co Level + !empty($cosettings[0][$required_fields_variable_name]) => $cosettings[0][$required_fields_variable_name], + // XXX Do i need CMP level here? + default => '' +}; +// List of the required fields +$required_fields_list = explode(',', $required_fields); + +// Address has not permitted fields configuration at CO level. And according to our design, +// the permitted fields are found in CoSettings. As a result, if we do not have any we need to get +// For all the attributes that have no +// permitted configuration at the CO level we will get all the fields that we support +$requiredDropDownListVar = $attr->attribute . 'RequiredFields'; +if(empty($permitted_fields_list) && !empty($$requiredDropDownListVar)) { + usort($$requiredDropDownListVar, static fn($a, $b) => count(explode(',', $a)) <=> count(explode(',', $b))); + $permitted_fields = end($$requiredDropDownListVar); + $permitted_fields_list = collection(explode(',', $permitted_fields))->map(fn($value) => trim($value)); +} + +// Grouped fields +$groupedFieldsVar = $attr->attribute . 'GroupedFields'; +$groupedFieldsArray = []; +if(!empty($$groupedFieldsVar)) { + $groupedFieldsArray = collection(array_keys($$groupedFieldsVar))->map(static fn($fields) => explode(',', $fields))->toArray(); +} +// Now that we have the permitted fields array and the grouped fields array, we need to put the permitted fields to groups + ?>
  • @@ -60,30 +92,16 @@ if (!empty($cosettings[0][$permitted_fields_variable_name])) {
    - -attribute_required_fields) as $field) : ?> - - "field-$field-$attr->id", - 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes - 'fieldType' => $supportedAttributes['fieldType'], - 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name - ]; -?> - -
    - - element('form/requiredSpan') : ''?> -
    - Field->formField(...$formArguments) ?> -
    -
    - - +
  • diff --git a/app/resources/locales/en_US/enumeration.po b/app/resources/locales/en_US/enumeration.po index 9cd7394f..363e85a8 100644 --- a/app/resources/locales/en_US/enumeration.po +++ b/app/resources/locales/en_US/enumeration.po @@ -529,11 +529,20 @@ msgstr "Postal Code" msgid "RequiredAddressFieldsEnum.street" msgstr "Street" -msgid "RequiredAddressFieldsEnum.street,locality,state,postal_code" -msgstr "Street, City, State, Postal Code" +msgid "RequiredAddressFieldsEnum.street,room,locality,state,postal_code" +msgstr "Street, Room, Locality, City, State, Postal Code" -msgid "RequiredAddressFieldsEnum.street,locality,state,postal_code,country" -msgstr "Street, City, State, Postal Code, Country" +msgid "RequiredAddressFieldsEnum.street,room,locality,state,postal_code,country" +msgstr "Street, Room, Locality, City, State, Postal Code, Country" + +msgid "GroupedAddressFieldsEnum.street,room" +msgstr "Street, Room" + +msgid "GroupedAddressFieldsEnum.city,locality" +msgstr "City, Locality" + +msgid "GroupedAddressFieldsEnum.state,postal_code,country" +msgstr "State, Postal Code, Country" msgid "RequiredNameFieldsEnum.given" msgstr "Given" diff --git a/app/src/Lib/Enum/GroupedAddressFieldsEnum.php b/app/src/Lib/Enum/GroupedAddressFieldsEnum.php new file mode 100644 index 00000000..7a2bd3ff --- /dev/null +++ b/app/src/Lib/Enum/GroupedAddressFieldsEnum.php @@ -0,0 +1,38 @@ + Date: Sat, 2 Nov 2024 20:44:48 +0200 Subject: [PATCH 03/10] fix fieldst hover css --- app/webroot/css/co-base.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/webroot/css/co-base.css b/app/webroot/css/co-base.css index 624bd665..a0ae64e9 100644 --- a/app/webroot/css/co-base.css +++ b/app/webroot/css/co-base.css @@ -1391,7 +1391,8 @@ ul.form-list li .field { margin: 0; padding: 0.75em; } -ul.form-list li .field:hover { +ul.form-list li .field:hover, +ul.form-list li fieldset:hover { background-color: var(--cmg-color-bg-001); } ul.form-list li.fields-submit { From c59e6844a76bf0de92eb35cec37b4edeb4144783 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 5 Nov 2024 18:01:12 +0200 Subject: [PATCH 04/10] Refactored required and permitted calculations.Moved attribute collections parts to elements. --- .../AttributeCollectors/dispatch.inc | 14 +-- .../multifield_attribute.inc | 107 ----------------- .../templates/EnrollmentAttributes/fields.inc | 4 +- .../CoreEnroller/templates/element/field.php | 110 ++++++++++++++++++ .../mveas/fieldset-field.php} | 23 +++- .../element/mveas/fieldset-group.php | 86 ++++++++++++++ .../mveas/mvea-fieldset.php} | 46 ++++---- .../Controller/StandardEnrollerController.php | 5 +- .../Lib/Enum/RequiredAddressFieldsEnum.php | 4 +- app/src/View/Helper/PetitionHelper.php | 15 +++ 10 files changed, 269 insertions(+), 145 deletions(-) delete mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc create mode 100644 app/plugins/CoreEnroller/templates/element/field.php rename app/plugins/CoreEnroller/templates/{AttributeCollectors/fieldset-field.inc => element/mveas/fieldset-field.php} (72%) create mode 100644 app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php rename app/plugins/CoreEnroller/templates/{AttributeCollectors/fieldset-group.inc => element/mveas/mvea-fieldset.php} (54%) diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc index 92b35e72..95288d70 100644 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc +++ b/app/plugins/CoreEnroller/templates/AttributeCollectors/dispatch.inc @@ -28,7 +28,6 @@ declare(strict_types = 1); use App\Lib\Enum\StatusEnum; -use \Cake\Utility\Inflector; // This view is intended to work with dispatch if($vv_action !== 'dispatch') { @@ -54,13 +53,12 @@ foreach($vv_enrollment_attributes_sorted as $attr) { continue; } - // Get the static configuration of my attribute - $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); - - if(empty($attr->attribute_required_fields)) { - include( $vv_template_path . DS . 'attribute.inc'); - } else { - include( $vv_template_path . DS . 'multifield_attribute.inc'); + // Fieldset with legend for MVEAs + if(\in_array($attr->attribute, ['name', 'address', 'telephoneNumber'], true)) { + print $this->element('CoreEnroller.mveas/mvea-fieldset', compact('attr')); + continue; } + // Default + print $this->element('CoreEnroller.field', compact('attr')); } \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc deleted file mode 100644 index f416f1e6..00000000 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/multifield_attribute.inc +++ /dev/null @@ -1,107 +0,0 @@ -attribute . 'Types'; -// Check if this mvea model supports types, if it does then render the attribute type -// dropdown list -$fieldLabel = 'Not found'; -if ($this->get($mveaAutoPopulatedVariable) !== null) { - $fieldLabel = $this->get($mveaAutoPopulatedVariable)[$attr->attribute_type] - . ' ' - . Inflector::humanize(Inflector::underscore($attr->attribute)); -} - -$required_fields_variable_name = 'required_fields_' . Inflector::underscore($attr->attribute); -$permitted_fields_variable_name = 'permitted_fields_' . Inflector::underscore($attr->attribute); -$permitted_fields_list = []; -$required_fields_list = []; - -if (!empty($cosettings[0][$permitted_fields_variable_name])) { - $permitted_fields_list = explode(',', $cosettings[0][$permitted_fields_variable_name]); -} - -// Required fields -// - first look at the enrollment flow level -// - if not set look at the co level -$required_fields = match(true) { - // Enrollment Flow - !empty($attr?->attribute_required_fields) => $attr?->attribute_required_fields, - // Co Level - !empty($cosettings[0][$required_fields_variable_name]) => $cosettings[0][$required_fields_variable_name], - // XXX Do i need CMP level here? - default => '' -}; -// List of the required fields -$required_fields_list = explode(',', $required_fields); - -// Address has not permitted fields configuration at CO level. And according to our design, -// the permitted fields are found in CoSettings. As a result, if we do not have any we need to get -// For all the attributes that have no -// permitted configuration at the CO level we will get all the fields that we support -$requiredDropDownListVar = $attr->attribute . 'RequiredFields'; -if(empty($permitted_fields_list) && !empty($$requiredDropDownListVar)) { - usort($$requiredDropDownListVar, static fn($a, $b) => count(explode(',', $a)) <=> count(explode(',', $b))); - $permitted_fields = end($$requiredDropDownListVar); - $permitted_fields_list = collection(explode(',', $permitted_fields))->map(fn($value) => trim($value)); -} - -// Grouped fields -$groupedFieldsVar = $attr->attribute . 'GroupedFields'; -$groupedFieldsArray = []; -if(!empty($$groupedFieldsVar)) { - $groupedFieldsArray = collection(array_keys($$groupedFieldsVar))->map(static fn($fields) => explode(',', $fields))->toArray(); -} -// Now that we have the permitted fields array and the grouped fields array, we need to put the permitted fields to groups - -?> - -
  • -
    - - - -
    - -
    -
    -
  • diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc index dc30198b..441ae7d2 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc @@ -172,8 +172,10 @@ if (\in_array($attribute_type, ['adHocAttribute'], true)) { * Attribute Language field * * Supported for attributes: name, address + * todo: probably should go away. The attribute required fields could become hidden and store what we have in CoSettings + * at the time we saved the required fields. */ -if(\in_array($attribute_type, ['name', 'address', 'pronoun'], true)) { +if(\in_array($attribute_type, ['address', 'pronoun'], true)) { $requiredFieldsPopulated = $attribute_type . 'RequiredFields'; // Pronouns have no required fields at the moment, as a result we will not render any. if ($this->get($requiredFieldsPopulated) !== null) { diff --git a/app/plugins/CoreEnroller/templates/element/field.php b/app/plugins/CoreEnroller/templates/element/field.php new file mode 100644 index 00000000..0aa16367 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/field.php @@ -0,0 +1,110 @@ +Petition->getSupportedEnrollmentAttribute($attr->attribute); + +// Do we have a default value configured? +// Either a value or an Environmental Variable, +// Each default value is mutually exclusive to the rest. We do not have to worry about a conflict. +$options['default'] = match(true) { + isset($attr->default_value) => $attr->default_value, + isset($attr->default_value_env_name) + && getenv($attr->default_value_env_name) !== false => getenv($attr->default_value_env_name), + isset($attr->default_value_datetime) => $attr->default_value_datetime, + default => '' +}; + +// If we are re-rendering the Petition override the default value with whatever +// was previously saved +if(!empty($vv_petition_attributes)) { + $curEntity = $vv_petition_attributes->firstMatch(['enrollment_attribute_id' => $attr->id]); + + if(!empty($curEntity->value)) { + $options['default'] = $curEntity->value; + } +} + +// Construct the field arguments +$formArguments = [ + // We prefix the attribute ID with a string because Cake seems to sometimes have + // problems with field names that are purely integers (even if cast to strings) + 'fieldName' => 'field-' . $attr->id, + 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes + 'fieldType' => $supportedAttributes['fieldType'], + 'fieldDescription' => $attr->description, + 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name +]; + + +/* + * Get the values for the attributes ending with _id + * Supported for attributes: group_id, cou_id, affiliation_type_id + */ +if(str_ends_with($attr->attribute, '_id')) { + $suffix = substr($attr->attribute, 0, -3); + $suffix = Inflector::pluralize(Inflector::camelize($suffix)) ; + $defaultValuesPopulated = 'defaultValue' . $suffix; + if ($this->get($defaultValuesPopulated) !== null) { + $formArguments['fieldType'] = 'select'; + $formArguments['fieldSelectOptions'] = $this->get($defaultValuesPopulated); + } +} + +// READ-ONLY +if (isset($attr->modifiable) && !$attr->modifiable) { + $options['readonly'] = true; +} + +// REQUIRED +if (isset($attr->required) && $attr->required) { + $options['required'] = true; +} + +// Set the final fieldOptions +$formArguments['fieldOptions'] = $options; + +// HIDDEN Field +// We print directly, we do not delegate to the element for further processing +if ($attr->hidden) { + // In case this is a hidden field, we need to get only the value + print $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]); +} else { + // Print the element + print $this->element('form/listItem', [ + 'arguments' => $formArguments + ]); +} \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php similarity index 72% rename from app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc rename to app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 4e112d6e..95820190 100644 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-field.inc +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -1,6 +1,6 @@ Petition->getSupportedEnrollmentAttribute($attr->attribute); + +if(isset($supportedAttributes['mveaModel'])) { + $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); + $tableValidator = $this->Petition->getTableValidator($supportedAttributes['mveaModel']); + $isRequiredFromValidationRule = !$tableValidator->field($field)->isEmptyAllowed(); +} // Construct the field arguments $formArguments = [ @@ -47,8 +57,11 @@
    - element('form/requiredSpan') : ''?> + element('form/requiredSpan') : ''?> + element('form/requiredSpan') : ''?>
    Field->formField(...$formArguments) ?>
    -
    \ No newline at end of file + + + diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php new file mode 100644 index 00000000..fa7adc35 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php @@ -0,0 +1,86 @@ +attribute . 'GroupedFields'; +$groupedFieldsArray = []; +if(!empty($$groupedFieldsVar)) { + $groupedFieldsArray = collection(array_keys($$groupedFieldsVar))->map(static fn($fields) => explode(',', $fields))->toArray(); +} + +$permitted_fields_list = []; +$permitted_fields_variable_name = 'permitted_fields_' . Inflector::underscore($attr->attribute); +if (!empty($cosettings[0][$permitted_fields_variable_name])) { + $permitted_fields_list = explode(',', $cosettings[0][$permitted_fields_variable_name]); +} +// Address has no permitted fields configuration at CO level. And according to our design, +// the permitted fields are found in CoSettings. +// For all the attributes that have no permitted configuration at the CO level, +// we will get all the fields that we support +// We will construct the list of permitted fields from the list of required fields. +// The permitted fields will be the set that contains all the required fields. +$requiredDropDownListVar = $attr->attribute . 'RequiredFields'; +if(empty($permitted_fields_list) && !empty($$requiredDropDownListVar)) { + usort($$requiredDropDownListVar, static fn($a, $b) => count(explode(',', $a)) <=> count(explode(',', $b))); + $permitted_fields = end($$requiredDropDownListVar); + $permitted_fields_list = collection(explode(',', $permitted_fields))->map(fn($value) => trim($value)); +} + +?> + + $fields): ?> +
    + map(static fn($value) => str_replace(' ', '_', Inflector::underscore($value))); + foreach($fields as $field) { + if($permitted_fields_list->contains($field)) { + // Print the element + print $this->element('CoreEnroller.mveas/fieldset-field', compact('field', 'attr')); + } + // Remove the field we render from the permitted list. + $permitted_fields_list = $permitted_fields_list->filter(fn($value) => $value !== $field); + } + ?> +
    + + +element('CoreEnroller.mveas/fieldset-field', compact('field', 'attr')); +} +?> + + diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc b/app/plugins/CoreEnroller/templates/element/mveas/mvea-fieldset.php similarity index 54% rename from app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc rename to app/plugins/CoreEnroller/templates/element/mveas/mvea-fieldset.php index 3bc6ff24..9bda744a 100644 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/fieldset-group.inc +++ b/app/plugins/CoreEnroller/templates/element/mveas/mvea-fieldset.php @@ -1,6 +1,6 @@ - - $fields): ?> -
    - filter(fn($value) => str_replace(' ', '_', Inflector::underscore($value)) !== $field); - include($vv_template_path . DS . 'fieldset-field.inc'); - } - ?> -
    - - -attribute . 'Types'; +// Check if this mvea model supports types, if it does then render the attribute type +// dropdown list +$fieldLabel = 'Not found'; +if ($this->get($mveaAutoPopulatedVariable) !== null) { + $fieldLabel = $this->get($mveaAutoPopulatedVariable)[$attr->attribute_type] + . ' ' + . Inflector::humanize(Inflector::underscore($attr->attribute)); } -?> +?> +
  • +
    + + + +
    + element('CoreEnroller.mveas/fieldset-group', compact( 'attr')) ?> +
    +
    +
  • diff --git a/app/src/Controller/StandardEnrollerController.php b/app/src/Controller/StandardEnrollerController.php index 25d0a78c..e320eb39 100644 --- a/app/src/Controller/StandardEnrollerController.php +++ b/app/src/Controller/StandardEnrollerController.php @@ -57,7 +57,10 @@ public function beforeRender(\Cake\Event\EventInterface $event) { 'vv_petition', $this->petition?->id ? $Petition->findById($this->petition->id) - ->contain($Petition->getIndexContains()) + // We need to include the Enrollment Flow of the Petition. + // The least, we can get if the co id which cannot be calculated + // for unauthenticated use cases. + ->contain(['EnrollmentFlows']) ->firstOrFail() : null ); diff --git a/app/src/Lib/Enum/RequiredAddressFieldsEnum.php b/app/src/Lib/Enum/RequiredAddressFieldsEnum.php index 4ad59395..a2e2a4bb 100644 --- a/app/src/Lib/Enum/RequiredAddressFieldsEnum.php +++ b/app/src/Lib/Enum/RequiredAddressFieldsEnum.php @@ -34,6 +34,6 @@ class RequiredAddressFieldsEnum extends StandardEnum { const Country = "country"; const Postal = "postal_code"; const Street = "street"; - const StreetCityStatePostal = "street,locality,state,postal_code"; - const StreetCityStatePostalCountry = "street,locality,state,postal_code,country"; + const StreetCityStatePostal = "street,room,locality,state,postal_code"; + const StreetCityStatePostalCountry = "street,room,locality,state,postal_code,country"; } \ No newline at end of file diff --git a/app/src/View/Helper/PetitionHelper.php b/app/src/View/Helper/PetitionHelper.php index eea417c3..91234d80 100644 --- a/app/src/View/Helper/PetitionHelper.php +++ b/app/src/View/Helper/PetitionHelper.php @@ -34,6 +34,7 @@ use Cake\ORM\Table; use Cake\ORM\TableRegistry; use Cake\Utility\Inflector; +use Cake\Validation\Validator; use Cake\View\Helper; use CoreEnroller\Model\Table\EnrollmentAttributesTable; @@ -81,4 +82,18 @@ public function populateAutoViewVars(): void $this->getView()->set($vvar, $value); } } + + /** + * Get the table validation rules + * + * @param string $tableName + * + * @return Validator + * @since COmanage Registry v5.0.0 + */ + public function getTableValidator(string $tableName): \Cake\Validation\Validator + { + $ModelTable = TableRegistry::getTableLocator()->get($tableName); + return $ModelTable->getValidator();// For MVEAs we retrieve the validation rules from CoSettings. Telephone numbers are different + } } \ No newline at end of file From e7aae1fe0d71f35644d867d5eceb918fa1a1fc93 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 5 Nov 2024 19:39:19 +0200 Subject: [PATCH 05/10] Add FieldHelper support for textarea. Refactored fieldset-group. --- .../AttributeCollectors/attribute.inc | 107 ------------------ .../element/mveas/fieldset-field.php | 6 +- .../element/mveas/fieldset-group.php | 28 ++--- app/src/Model/Table/AddressesTable.php | 13 +++ app/src/View/Helper/FieldHelper.php | 1 + app/src/View/Helper/PetitionHelper.php | 7 +- 6 files changed, 32 insertions(+), 130 deletions(-) delete mode 100644 app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc diff --git a/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc b/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc deleted file mode 100644 index d8dec4a3..00000000 --- a/app/plugins/CoreEnroller/templates/AttributeCollectors/attribute.inc +++ /dev/null @@ -1,107 +0,0 @@ -default_value) => $attr->default_value, - isset($attr->default_value_env_name) - && getenv($attr->default_value_env_name) !== false => getenv($attr->default_value_env_name), - isset($attr->default_value_datetime) => $attr->default_value_datetime, - default => '' -}; - -// If we are re-rendering the Petition override the default value with whatever -// was previously saved -if(!empty($vv_petition_attributes)) { - $curEntity = $vv_petition_attributes->firstMatch(['enrollment_attribute_id' => $attr->id]); - - if(!empty($curEntity->value)) { - $options['default'] = $curEntity->value; - } -} - -// Construct the field arguments -$formArguments = [ - // We prefix the attribute ID with a string because Cake seems to sometimes have - // problems with field names that are purely integers (even if cast to strings) - 'fieldName' => 'field-' . $attr->id, - 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes - 'fieldType' => $supportedAttributes['fieldType'], - 'fieldDescription' => $attr->description, - 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name -]; - - -/* - * Get the values for the attributes ending with _id - * Supported for attributes: group_id, cou_id, affiliation_type_id - */ -if(str_ends_with($attr->attribute, '_id')) { - $suffix = substr($attr->attribute, 0, -3); - $suffix = Inflector::pluralize(Inflector::camelize($suffix)) ; - $defaultValuesPopulated = 'defaultValue' . $suffix; - if ($this->get($defaultValuesPopulated) !== null) { - $formArguments['fieldType'] = 'select'; - $formArguments['fieldSelectOptions'] = $this->get($defaultValuesPopulated); - } -} - -// READ-ONLY -if (isset($attr->modifiable) && !$attr->modifiable) { - $options['readonly'] = true; -} - -// REQUIRED -if (isset($attr->required) && $attr->required) { - $options['required'] = true; -} - -// Set the final fieldOptions -$formArguments['fieldOptions'] = $options; - -// HIDDEN Field -// We print directly, we do not delegate to the element for further processing -if ($attr->hidden) { - // In case this is a hidden field, we need to get only the value - print $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]); -} else { - // Print the element - print $this->element('form/listItem', [ - 'arguments' => $formArguments - ]); -} \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 95820190..754f861a 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -40,8 +40,8 @@ if(isset($supportedAttributes['mveaModel'])) { $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); - $tableValidator = $this->Petition->getTableValidator($supportedAttributes['mveaModel']); - $isRequiredFromValidationRule = !$tableValidator->field($field)->isEmptyAllowed(); + $modelTable = $this->Petition->getTable($supportedAttributes['mveaModel']); + $isRequiredFromValidationRule = !$modelTable->getValidator()->field($field)->isEmptyAllowed(); } // Construct the field arguments @@ -50,7 +50,7 @@ // problems with field names that are purely integers (even if cast to strings) 'fieldName' => "field-$field-$attr->id", 'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes - 'fieldType' => $supportedAttributes['fieldType'], + 'fieldType' => $modelTable->getSchema()->getColumn($field)['type'], 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name ]; ?> diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php index fa7adc35..8ac21952 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php @@ -44,32 +44,28 @@ if (!empty($cosettings[0][$permitted_fields_variable_name])) { $permitted_fields_list = explode(',', $cosettings[0][$permitted_fields_variable_name]); } -// Address has no permitted fields configuration at CO level. And according to our design, -// the permitted fields are found in CoSettings. -// For all the attributes that have no permitted configuration at the CO level, -// we will get all the fields that we support -// We will construct the list of permitted fields from the list of required fields. -// The permitted fields will be the set that contains all the required fields. -$requiredDropDownListVar = $attr->attribute . 'RequiredFields'; -if(empty($permitted_fields_list) && !empty($$requiredDropDownListVar)) { - usort($$requiredDropDownListVar, static fn($a, $b) => count(explode(',', $a)) <=> count(explode(',', $b))); - $permitted_fields = end($$requiredDropDownListVar); - $permitted_fields_list = collection(explode(',', $permitted_fields))->map(fn($value) => trim($value)); +// Address has no permitted fields configuration at CO level. We will get them from +// the model configuration +$supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); +$modelTable = $this->Petition->getTable($supportedAttributes['mveaModel']); +if(empty($permitted_fields_list) && !empty($modelTable?->getPermittedFields())) { + $permitted_fields_list = $modelTable->getPermittedFields(); } +$permitted_fields_list_flipped = array_flip($permitted_fields_list); + ?> $fields): ?>
    map(static fn($value) => str_replace(' ', '_', Inflector::underscore($value))); foreach($fields as $field) { - if($permitted_fields_list->contains($field)) { + if(isset($permitted_fields_list_flipped[$field])) { // Print the element print $this->element('CoreEnroller.mveas/fieldset-field', compact('field', 'attr')); } - // Remove the field we render from the permitted list. - $permitted_fields_list = $permitted_fields_list->filter(fn($value) => $value !== $field); + // Remove the field we rendered from the permitted list. + unset($permitted_fields_list_flipped[$field]); } ?>
    @@ -78,7 +74,7 @@ element('CoreEnroller.mveas/fieldset-field', compact('field', 'attr')); } ?> diff --git a/app/src/Model/Table/AddressesTable.php b/app/src/Model/Table/AddressesTable.php index fa0f81f1..3a0d8018 100644 --- a/app/src/Model/Table/AddressesTable.php +++ b/app/src/Model/Table/AddressesTable.php @@ -59,6 +59,9 @@ class AddressesTable extends Table { 'postal' ] ]; + + // Default permitted Fields. Used for the Attribute Collection + private $permittedFields = ['locality', 'state', 'postal_code', 'country', 'street', 'room']; /** * Perform Cake Model initialization. @@ -262,4 +265,14 @@ public function validationDefault(Validator $validator): Validator { return $validator; } + + /** + * Get the hardcoded list of the Default Permitted Fields + * + * @since COmanage Registry v5.0.0 + * @return array List of permitted fields + */ + public function getPermittedFields(): array { + return $this->permittedFields; + } } \ No newline at end of file diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 03749912..3f4b5cf1 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -409,6 +409,7 @@ public function formField(string $fieldName, 'class' => 'form-check-input', ]), 'select' => $this->Form->select($fieldName, $fieldSelectOptions, $fieldArgs), + 'text' => $this->Form->textarea($fieldName, $fieldArgs), 'date' => $this->dateField(fieldName: $fieldName, dateType: DateTypeEnum::DateOnly, fieldArgs: $fieldArgs), 'datetime', 'timestamp' => $this->dateField(fieldName: $fieldName, fieldArgs: $fieldArgs), diff --git a/app/src/View/Helper/PetitionHelper.php b/app/src/View/Helper/PetitionHelper.php index 91234d80..2de9a636 100644 --- a/app/src/View/Helper/PetitionHelper.php +++ b/app/src/View/Helper/PetitionHelper.php @@ -88,12 +88,11 @@ public function populateAutoViewVars(): void * * @param string $tableName * - * @return Validator + * @return Table * @since COmanage Registry v5.0.0 */ - public function getTableValidator(string $tableName): \Cake\Validation\Validator + public function getTable(string $tableName): Table { - $ModelTable = TableRegistry::getTableLocator()->get($tableName); - return $ModelTable->getValidator();// For MVEAs we retrieve the validation rules from CoSettings. Telephone numbers are different + return TableRegistry::getTableLocator()->get($tableName); } } \ No newline at end of file From 879b10219070020fe15e58bd99c56ddd788faab0 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 5 Nov 2024 19:48:15 +0200 Subject: [PATCH 06/10] fix enumerations and locales --- app/resources/locales/en_US/enumeration.po | 7 ++----- app/src/Lib/Enum/GroupedAddressFieldsEnum.php | 2 +- app/src/Lib/Enum/RequiredAddressFieldsEnum.php | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/resources/locales/en_US/enumeration.po b/app/resources/locales/en_US/enumeration.po index 363e85a8..c6f01644 100644 --- a/app/resources/locales/en_US/enumeration.po +++ b/app/resources/locales/en_US/enumeration.po @@ -529,11 +529,8 @@ msgstr "Postal Code" msgid "RequiredAddressFieldsEnum.street" msgstr "Street" -msgid "RequiredAddressFieldsEnum.street,room,locality,state,postal_code" -msgstr "Street, Room, Locality, City, State, Postal Code" - -msgid "RequiredAddressFieldsEnum.street,room,locality,state,postal_code,country" -msgstr "Street, Room, Locality, City, State, Postal Code, Country" +msgid "RequiredAddressFieldsEnum.street,locality,state,postal_code" +msgstr "Street, City, State, Postal Code" msgid "GroupedAddressFieldsEnum.street,room" msgstr "Street, Room" diff --git a/app/src/Lib/Enum/GroupedAddressFieldsEnum.php b/app/src/Lib/Enum/GroupedAddressFieldsEnum.php index 7a2bd3ff..c44c7c27 100644 --- a/app/src/Lib/Enum/GroupedAddressFieldsEnum.php +++ b/app/src/Lib/Enum/GroupedAddressFieldsEnum.php @@ -33,6 +33,6 @@ class GroupedAddressFieldsEnum extends StandardEnum { // The order needs to be from local to country. Since this is the // ordering that will be used for rendering const StreetRoom = 'street,room'; - const CityLocality = 'city,locality'; + const Locality = 'locality'; const StatePostalCountry = 'state,postal_code,country'; } \ No newline at end of file diff --git a/app/src/Lib/Enum/RequiredAddressFieldsEnum.php b/app/src/Lib/Enum/RequiredAddressFieldsEnum.php index a2e2a4bb..4ad59395 100644 --- a/app/src/Lib/Enum/RequiredAddressFieldsEnum.php +++ b/app/src/Lib/Enum/RequiredAddressFieldsEnum.php @@ -34,6 +34,6 @@ class RequiredAddressFieldsEnum extends StandardEnum { const Country = "country"; const Postal = "postal_code"; const Street = "street"; - const StreetCityStatePostal = "street,room,locality,state,postal_code"; - const StreetCityStatePostalCountry = "street,room,locality,state,postal_code,country"; + const StreetCityStatePostal = "street,locality,state,postal_code"; + const StreetCityStatePostalCountry = "street,locality,state,postal_code,country"; } \ No newline at end of file From 5c179cc9e944d3b5c193fc1bbbf93dfb42e5248c Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 6 Nov 2024 11:32:48 +0200 Subject: [PATCH 07/10] improvements --- .../Table/BasicAttributeCollectorsTable.php | 1 + .../CoreEnroller/templates/element/field.php | 19 ++++++++----------- .../element/mveas/fieldset-field.php | 1 - .../element/mveas/fieldset-group.php | 1 - app/src/View/Helper/FieldHelper.php | 4 ++++ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php b/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php index 5ed3d6aa..1ec67cea 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php @@ -45,6 +45,7 @@ class BasicAttributeCollectorsTable extends Table { use \App\Lib\Traits\PrimaryLinkTrait; use \App\Lib\Traits\TableMetaTrait; use \App\Lib\Traits\ValidationTrait; + use \App\Lib\Traits\LayoutTrait; /** * Perform Cake Model initialization. diff --git a/app/plugins/CoreEnroller/templates/element/field.php b/app/plugins/CoreEnroller/templates/element/field.php index 0aa16367..44ee1ce8 100644 --- a/app/plugins/CoreEnroller/templates/element/field.php +++ b/app/plugins/CoreEnroller/templates/element/field.php @@ -48,7 +48,7 @@ default => '' }; -// If we are re-rendering the Petition override the default value with whatever +// If we are re-rendering the Petition, override the default value with whatever // was previously saved if(!empty($vv_petition_attributes)) { $curEntity = $vv_petition_attributes->firstMatch(['enrollment_attribute_id' => $attr->id]); @@ -97,14 +97,11 @@ // Set the final fieldOptions $formArguments['fieldOptions'] = $options; -// HIDDEN Field -// We print directly, we do not delegate to the element for further processing -if ($attr->hidden) { +print match(true) { + // HIDDEN Field + // We print directly, we do not delegate to the element for further processing // In case this is a hidden field, we need to get only the value - print $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]); -} else { - // Print the element - print $this->element('form/listItem', [ - 'arguments' => $formArguments - ]); -} \ No newline at end of file + $attr->hidden =>$this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]), + // Default use case + default => $this->element('form/listItem', ['arguments' => $formArguments]) +}; diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 754f861a..95ef0999 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -57,7 +57,6 @@
    - element('form/requiredSpan') : ''?> element('form/requiredSpan') : ''?>
    Field->formField(...$formArguments) ?> diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php index 8ac21952..380e77e8 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-group.php @@ -53,7 +53,6 @@ } $permitted_fields_list_flipped = array_flip($permitted_fields_list); - ?> $fields): ?> diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 3f4b5cf1..8fcf3ad6 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -212,6 +212,10 @@ public function calculateLiClasses(): string $classes .= 'fields-people-autocomplete '; } + // Each field should have a class like `fields-` + $field = $vv_field_arguments['fieldNameAlias'] ?? $fieldName ?? 'unknown'; + $classes .= " fields-$field"; + return $classes; } From f93cd07bad44a70fb2bd4ba90a01e4915bb873d2 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 6 Nov 2024 16:53:38 +0200 Subject: [PATCH 08/10] Remove duplicate element --- .../CoreEnroller/templates/element/mveas/fieldset-field.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 95ef0999..7ceef849 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -58,9 +58,7 @@
    element('form/requiredSpan') : ''?> -
    - Field->formField(...$formArguments) ?> -
    + Field->formField(...$formArguments) ?>
    From 684bc46b8f619a6470c8073393f0f0b3a9934a3d Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 6 Nov 2024 17:01:07 +0200 Subject: [PATCH 09/10] Improve classes in element --- .../CoreEnroller/templates/element/mveas/fieldset-field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 7ceef849..58c89298 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -55,7 +55,7 @@ ]; ?> -
    +
    "> element('form/requiredSpan') : ''?> Field->formField(...$formArguments) ?> From 7b0eb0c89da4bd5f766d0f2f8a83bfffcae79324 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Wed, 13 Nov 2024 18:24:37 +0200 Subject: [PATCH 10/10] cleanup --- .../Model/Table/EnrollmentAttributesTable.php | 2 -- .../CoreEnroller/src/config/plugin.json | 1 - .../templates/EnrollmentAttributes/fields.inc | 25 +------------------ .../CoreEnroller/templates/element/field.php | 13 +++++++++- 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php index 42a30fbf..3ca48ba2 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/EnrollmentAttributesTable.php @@ -413,8 +413,6 @@ public function validationDefault(Validator $validator): Validator { ]); $validator->allowEmptyString('attribute_mvea_parent'); - $this->registerStringValidation($validator, $schema, 'attribute_required_fields', false); - $this->registerStringValidation($validator, $schema, 'attribute_tag', false); $validator->add('status', [ diff --git a/app/plugins/CoreEnroller/src/config/plugin.json b/app/plugins/CoreEnroller/src/config/plugin.json index 158bf233..679d2cf6 100644 --- a/app/plugins/CoreEnroller/src/config/plugin.json +++ b/app/plugins/CoreEnroller/src/config/plugin.json @@ -72,7 +72,6 @@ "attribute_type": { "type": "integer", "foreignkey": { "table": "types", "column": "id" } }, "attribute_language": { "type": "string", "size": 16 }, "attribute_mvea_parent": { "type": "string", "size": 32 }, - "attribute_required_fields": { "type": "string", "size": 160 }, "attribute_tag": { "type": "string", "size": 128 }, "status": {}, "label": { "type": "string", "size": 80 }, diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc index 441ae7d2..9b17608f 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc @@ -168,32 +168,9 @@ if (\in_array($attribute_type, ['adHocAttribute'], true)) { } /* - * Attribute Required field * Attribute Language field - * - * Supported for attributes: name, address - * todo: probably should go away. The attribute required fields could become hidden and store what we have in CoSettings - * at the time we saved the required fields. */ -if(\in_array($attribute_type, ['address', 'pronoun'], true)) { - $requiredFieldsPopulated = $attribute_type . 'RequiredFields'; - // Pronouns have no required fields at the moment, as a result we will not render any. - if ($this->get($requiredFieldsPopulated) !== null) { - $label = __d('core_enroller', 'field.EnrollmentAttributes.' . $attribute_type . '_required_fields'); - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldLabel' => $label, - 'fieldName' => 'attribute_required_fields', - 'fieldOptions' => [ - 'empty' => true - ], - 'fieldType' => 'select', - 'fieldSelectOptions' => $this->get($requiredFieldsPopulated) - ] - ]); - } - - +if(\in_array($attribute_type, ['name', 'address', 'pronoun'], true)) { print $this->element('form/listItem', [ 'arguments' => [ 'fieldName' => 'attribute_language', diff --git a/app/plugins/CoreEnroller/templates/element/field.php b/app/plugins/CoreEnroller/templates/element/field.php index 44ee1ce8..68e4be12 100644 --- a/app/plugins/CoreEnroller/templates/element/field.php +++ b/app/plugins/CoreEnroller/templates/element/field.php @@ -94,6 +94,17 @@ $options['required'] = true; } +$hidden = true; +// XXX We need to render a field that is required and expects a value from the environment but +// the env value is empty. +if ( + isset($attr->default_value_env_name, $attr->required) + && empty($options['default']) + && $attr->required +) { + $hidden = false; +} + // Set the final fieldOptions $formArguments['fieldOptions'] = $options; @@ -101,7 +112,7 @@ // HIDDEN Field // We print directly, we do not delegate to the element for further processing // In case this is a hidden field, we need to get only the value - $attr->hidden =>$this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]), + $attr->hidden && $hidden =>$this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]), // Default use case default => $this->element('form/listItem', ['arguments' => $formArguments]) };