From 2ffa55cf6543159b5052027a95099414019379bb Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 5 Nov 2024 18:01:12 +0200 Subject: [PATCH] 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 92b35e72b..95288d700 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 f416f1e66..000000000 --- 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 dc30198bb..441ae7d28 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 000000000..0aa16367d --- /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 4e112d6e4..95820190d 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 000000000..fa7adc356 --- /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 3bc6ff24d..9bda744ab 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 25d0a78c6..e320eb39f 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 4ad59395c..a2e2a4bbd 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 eea417c3a..91234d80a 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