diff --git a/app/plugins/CoreEnroller/src/Controller/AttributeCollectorsController.php b/app/plugins/CoreEnroller/src/Controller/AttributeCollectorsController.php index 27faa274..7e1631bd 100644 --- a/app/plugins/CoreEnroller/src/Controller/AttributeCollectorsController.php +++ b/app/plugins/CoreEnroller/src/Controller/AttributeCollectorsController.php @@ -30,9 +30,9 @@ namespace CoreEnroller\Controller; use App\Controller\StandardEnrollerController; -use App\Lib\Enum\PetitionStatusEnum; use Cake\Event\EventInterface; use Cake\Http\Response; +use Cake\ORM\TableRegistry; class AttributeCollectorsController extends StandardEnrollerController { public $paginate = [ @@ -121,16 +121,4 @@ public function dispatch(string $id) { $this->render('/Standard/dispatch'); } - - /** - * Display information about this Step. - * - * @since COmanage Registry v5.0.0 - * @param string $id Attribute Collector ID - */ - - public function display(string $id) { - debug("display something for this petition"); - debug($this->getPetition()); - } } diff --git a/app/plugins/CoreEnroller/src/Controller/BasicAttributeCollectorsController.php b/app/plugins/CoreEnroller/src/Controller/BasicAttributeCollectorsController.php index bf3f701f..01890e70 100644 --- a/app/plugins/CoreEnroller/src/Controller/BasicAttributeCollectorsController.php +++ b/app/plugins/CoreEnroller/src/Controller/BasicAttributeCollectorsController.php @@ -87,21 +87,4 @@ public function dispatch(string $id) { $this->render('/Standard/dispatch'); } - - /** - * Display information about this Step. - * - * @since COmanage Registry v5.1.0 - * @param string $id Attribute Collector ID - */ - - public function display(string $id) { - $petition = $this->getPetition(); - - $this->set('vv_petition_basic_attribute_set', $this->BasicAttributeCollectors - ->PetitionBasicAttributeSets - ->find() - ->where(['PetitionBasicAttributeSets.petition_id' => $petition->id]) - ->firstOrFail()); - } } diff --git a/app/plugins/CoreEnroller/src/Controller/EmailVerifiersController.php b/app/plugins/CoreEnroller/src/Controller/EmailVerifiersController.php index c79f21e4..35595ccd 100644 --- a/app/plugins/CoreEnroller/src/Controller/EmailVerifiersController.php +++ b/app/plugins/CoreEnroller/src/Controller/EmailVerifiersController.php @@ -216,25 +216,4 @@ public function dispatch(string $id) { $this->render('/Standard/dispatch'); } - - /** - * Display information about this Step. - * - * @since COmanage Registry v5.1.0 - * @param string $id Email Verifiers ID - */ - - public function display(string $id) { - $petition = $this->getPetition(); - - $PetitionVerifications = TableRegistry::getTableLocator()->get('CoreEnroller.PetitionVerifications'); - - // Because Petition Verifications are not tracked on a per-step basis, we just pull all - // associated with the Petition - - $this->set('vv_pv', $PetitionVerifications->find() - ->where(['PetitionVerifications.petition_id' => $petition->id]) - ->contain(['Verifications']) - ->all()); - } } \ No newline at end of file diff --git a/app/plugins/CoreEnroller/src/Controller/IdentifierCollectorsController.php b/app/plugins/CoreEnroller/src/Controller/IdentifierCollectorsController.php index 9b0fe090..be0e63cf 100644 --- a/app/plugins/CoreEnroller/src/Controller/IdentifierCollectorsController.php +++ b/app/plugins/CoreEnroller/src/Controller/IdentifierCollectorsController.php @@ -96,21 +96,6 @@ public function dispatch(string $id) { } } - /** - * Display information about this Step. - * - * @since COmanage Registry v5.1.0 - * @param string $id Invitation Accepters ID - */ - - public function display(string $id) { - $petition = $this->getPetition(); - - $PetitionIdentifiers = TableRegistry::getTableLocator()->get('CoreEnroller.PetitionIdentifiers'); - - $this->set('vv_pi', $PetitionIdentifiers->find()->where(['petition_id' => $petition->id])->first()); - } - /** * Indicate whether this Controller will handle some or all authnz. * diff --git a/app/plugins/CoreEnroller/src/Controller/InvitationAcceptersController.php b/app/plugins/CoreEnroller/src/Controller/InvitationAcceptersController.php index d6b91802..90d05ba7 100644 --- a/app/plugins/CoreEnroller/src/Controller/InvitationAcceptersController.php +++ b/app/plugins/CoreEnroller/src/Controller/InvitationAcceptersController.php @@ -133,19 +133,4 @@ public function dispatch(string $id) { $this->render('/Standard/dispatch'); } - - /** - * Display information about this Step. - * - * @since COmanage Registry v5.1.0 - * @param string $id Invitation Accepters ID - */ - - public function display(string $id) { - $petition = $this->getPetition(); - - $PetitionAcceptances = TableRegistry::getTableLocator()->get('CoreEnroller.PetitionAcceptances'); - - $this->set('vv_pa', $PetitionAcceptances->find()->where(['petition_id' => $petition->id])->first()); - } } diff --git a/app/plugins/CoreEnroller/src/Model/Table/AttributeCollectorsTable.php b/app/plugins/CoreEnroller/src/Model/Table/AttributeCollectorsTable.php index 18e3c22e..03ecee81 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/AttributeCollectorsTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/AttributeCollectorsTable.php @@ -29,6 +29,7 @@ namespace CoreEnroller\Model\Table; +use App\Model\Entity\Petition; use Cake\Datasource\ConnectionManager; use Cake\ORM\Query; use Cake\ORM\RulesChecker; @@ -117,21 +118,32 @@ public function initialize(array $config): void { /** * Perform steps necessary to finalize the Petition. - * - * @since COmanage Registry v5.0.0 - * @param int $id Attribute Collector ID - * @param int $petitionId Petition ID + * + * @param int $id Attribute Collector ID + * @param Petition $petition * @return bool true on success + * @since COmanage Registry v5.1.0 */ - public function finalize(int $id, int $petitionId) { -// XXX convert Petition Attributes to operational Attributes -// keep in mind this can be called multiple times if the plugin is -// instantiated more than once in the Enrollment Flow ($id will be different) -// any errors should be logged or otherwise managed, returning false -// or throwing an error will NOT prevent the petition from finalizing + public function finalize(int $id, \App\Model\Entity\Petition $petition) { + $cfg = $this->get($id); + + if(empty($petition->enrollee_person_id)) { + throw new \InvalidArgumentException(__d('error', 'Petitions.enrollee.notfound', [$petition->id])); + } + + $People = TableRegistry::getTableLocator()->get('People'); + + $person = $People->get($petition->enrollee_person_id); -debug("in AttributeCollector finalize"); + $attributes = $this->EnrollmentAttributes + ->PetitionAttributes + ->find() + ->where(['petition_id' => $petition->id]) + ->firstOrFail(); + + // XXX Should i save the primary name? + // XXX Should i save the email? return true; } @@ -166,15 +178,33 @@ public function upsert(int $id, int $petitionId, array $attributes) { foreach($attributes as $enrollmentAttributeLabel => $value) { // Remove field- prefix from the form field name - $enrollmentAttributeId = (int)substr($enrollmentAttributeLabel, 6); + $fieldToParts = explode('-', $enrollmentAttributeLabel); + // MVAs have multiple columns. For example a name has: + // given, surname, prefix, ... + $columnName = null; + if (count($fieldToParts) > 2) { + // There is a type ID in the middle + $columnName = $fieldToParts[1]; + } + // The enrollment Attribute ID is the last part + $enrollmentAttributeId = (int)array_pop($fieldToParts); + + // The people picker will send a complex string and not just the id. We need to extract it ourselves. + $re = '/^.*\(ID: (\d+)\)$/m'; + preg_match_all($re, $value, $matches, PREG_SET_ORDER, 0); + if(!empty($matches)) { + $value = $matches[0][1]; + } $newAttribute = [ 'petition_id' => $petitionId, 'enrollment_attribute_id' => $enrollmentAttributeId, - 'value' => $value + 'value' => $value, + // This is the column name for the attributes that consist of multiple fields, like the name or the address + 'column_name' => $columnName, ]; - if(array_key_exists($enrollmentAttributeId, $currentAttributes)) { + if(\array_key_exists($enrollmentAttributeId, $currentAttributes)) { // This is an update of an existing attribute $newAttribute['id'] = $currentAttributes[$enrollmentAttributeId]; diff --git a/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php b/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php index cd0ac076..5fa74858 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/BasicAttributeCollectorsTable.php @@ -147,7 +147,7 @@ public function finalize(int $id, \App\Model\Entity\Petition $petition) { // At this point there is a Person record allocated and stored in the Petition, // but it doesn't have any attributes on it, including a Primary Name. // We assume we're the only attribute collector, so we'll force a Primary Name - // based on the Basic Attribtues, and create a skeletal role. + // based on the Basic Attributes, and create a skeletal role. if(empty($petition->enrollee_person_id)) { throw new \InvalidArgumentException(__d('error', 'Petitions.enrollee.notfound', [$petition->id])); diff --git a/app/plugins/CoreEnroller/src/Model/Table/PetitionAttributesTable.php b/app/plugins/CoreEnroller/src/Model/Table/PetitionAttributesTable.php index 161d873e..d26329d5 100644 --- a/app/plugins/CoreEnroller/src/Model/Table/PetitionAttributesTable.php +++ b/app/plugins/CoreEnroller/src/Model/Table/PetitionAttributesTable.php @@ -103,6 +103,7 @@ public function validationDefault(Validator $validator): Validator { $validator->notEmptyString('enrollment_attribute_id'); $this->registerStringValidation($validator, $schema, 'value', false); + $this->registerStringValidation($validator, $schema, 'column', false); return $validator; } diff --git a/app/plugins/CoreEnroller/src/config/plugin.json b/app/plugins/CoreEnroller/src/config/plugin.json index dbb666b8..bb58ddb5 100644 --- a/app/plugins/CoreEnroller/src/config/plugin.json +++ b/app/plugins/CoreEnroller/src/config/plugin.json @@ -111,7 +111,8 @@ "id": {}, "petition_id": {}, "enrollment_attribute_id": { "type": "integer", "foreignkey": { "table": "enrollment_attributes", "column": "id" } }, - "value": { "type": "string", "size": 160 } + "value": { "type": "string", "size": 160 }, + "column_name": { "notnull": false, "type": "string", "size": 64 } }, "indexes": { "petition_attributes_i1": { "columns": [ "petition_id" ] }, diff --git a/app/plugins/CoreEnroller/templates/BasicAttributeCollectors/display.php b/app/plugins/CoreEnroller/templates/BasicAttributeCollectors/display.php deleted file mode 100644 index 4247e740..00000000 --- a/app/plugins/CoreEnroller/templates/BasicAttributeCollectors/display.php +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/app/plugins/CoreEnroller/templates/EmailVerifiers/display.php b/app/plugins/CoreEnroller/templates/EmailVerifiers/display.php deleted file mode 100644 index a3aded80..00000000 --- a/app/plugins/CoreEnroller/templates/EmailVerifiers/display.php +++ /dev/null @@ -1,24 +0,0 @@ -\n"; - - foreach($vv_pv as $pv) { - print "
  • " . $pv->mail . ": "; - - if(!empty($pv->verification) && $pv->verification->isVerified()) { - print __d('result', 'Verifications.status', [ - VerificationMethodEnum::getLocalization($pv->verification->method), - $this->Time->nice($pv->verification->verification_time, $vv_tz) - ]); - } else { - print __d('field', 'unverified'); - } - - print "
  • "; - } - - print "\n"; -} \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc index 26fcceba..2a4a83c3 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/columns.inc @@ -49,6 +49,10 @@ $indexColumns = [ 'required' => [ 'type' => 'boolean', 'class' => 'YesBooleanEnum' + ], + 'hidden' => [ + 'type' => 'boolean', + 'class' => 'YesBooleanEnum' ] ]; diff --git a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc index 0ea015f2..09a3a971 100644 --- a/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc +++ b/app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc @@ -32,8 +32,7 @@ use \Cake\Utility\Inflector; $attribute_type = null; if($vv_action == 'add') { $attribute_type = $this->request->getQuery('attribute_type'); -} else if($vv_action == 'edit' && !empty($vv_obj) -) { +} else if($vv_action == 'edit' && !empty($vv_obj)) { $attribute_type = $vv_obj->attribute; } diff --git a/app/plugins/CoreEnroller/templates/IdentifierCollectors/display.php b/app/plugins/CoreEnroller/templates/IdentifierCollectors/display.php deleted file mode 100644 index 30359a60..00000000 --- a/app/plugins/CoreEnroller/templates/IdentifierCollectors/display.php +++ /dev/null @@ -1,4 +0,0 @@ -identifier)) { - print __d('core_enroller', 'result.IdentifierCollector.collected', [$vv_pi->identifier]); -} diff --git a/app/plugins/CoreEnroller/templates/element/field.php b/app/plugins/CoreEnroller/templates/element/field.php index b5cd48d5..80a3b8cd 100644 --- a/app/plugins/CoreEnroller/templates/element/field.php +++ b/app/plugins/CoreEnroller/templates/element/field.php @@ -119,5 +119,5 @@ 'formArguments' => $formArguments ]), // Default use case - default => $this->element('form/listItem', ['arguments' => $formArguments]) + default => $this->Field->getElementsForDisabledInput('form/listItem', $formArguments) }; diff --git a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php index 58c89298..e8e7e53e 100644 --- a/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php +++ b/app/plugins/CoreEnroller/templates/element/mveas/fieldset-field.php @@ -38,12 +38,41 @@ $isRequiredFromValidationRule = false; $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); +// Field Options array +$options = []; + if(isset($supportedAttributes['mveaModel'])) { $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); $modelTable = $this->Petition->getTable($supportedAttributes['mveaModel']); $isRequiredFromValidationRule = !$modelTable->getValidator()->field($field)->isEmptyAllowed(); } +// 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, + // XXX The $attr->default_value_env_name for the name attribute is tricky. Since the name has many values. + // Check the EnvSource plugin + 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, + 'column_name' => $field + ]); + + 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 @@ -53,6 +82,9 @@ 'fieldType' => $modelTable->getSchema()->getColumn($field)['type'], 'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name ]; + +// Set the final fieldOptions +$formArguments['fieldOptions'] = $options; ?>
    "> diff --git a/app/plugins/CoreEnroller/templates/element/petition/attributeCollectorsStep.php b/app/plugins/CoreEnroller/templates/element/petition/attributeCollectorsStep.php new file mode 100644 index 00000000..0293a519 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/petition/attributeCollectorsStep.php @@ -0,0 +1,92 @@ +petition_attributes, '{n}.enrollment_attribute_id'); +$vv_enrollment_atttributes_ids = array_unique($vv_enrollment_atttributes_ids); + +$enrollmentAttributesTable = $this->Petition->getTable('EnrollmentAttributes'); +$vv_enrollment_attributes = $enrollmentAttributesTable->find() + ->where(fn(QueryExpression $exp, Query $q) => $exp->in('id', $vv_enrollment_atttributes_ids)) + ->order(['ordr' => 'ASC']) + ->toArray(); + +?> + + diff --git a/app/plugins/CoreEnroller/templates/element/petition/basicAttributeCollectorsStep.php b/app/plugins/CoreEnroller/templates/element/petition/basicAttributeCollectorsStep.php new file mode 100644 index 00000000..e56d9dfd --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/petition/basicAttributeCollectorsStep.php @@ -0,0 +1,69 @@ +id === null) { + return __d('error', 'notfound', 'Petition Attributes'); + } + + $tableObj = $this->Petition->getTable('PetitionBasicAttributeSets'); + $vv_petition_basic_attribute_set = $tableObj->find() + ->where(['PetitionBasicAttributeSets.petition_id' => $vv_obj->id]) + ->firstOrFail(); +?> + diff --git a/app/plugins/CoreEnroller/templates/element/petition/emailVerifiersStep.php b/app/plugins/CoreEnroller/templates/element/petition/emailVerifiersStep.php new file mode 100644 index 00000000..8e1aec59 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/petition/emailVerifiersStep.php @@ -0,0 +1,32 @@ +Petition->getTable('CoreEnroller.PetitionVerifications'); + +// Because Petition Verifications are not tracked on a per-step basis, we just pull all +// associated with the Petition + +$vv_pv = $PetitionVerifications->find() + ->where(['PetitionVerifications.petition_id' => $vv_obj->id]) + ->contain(['Verifications']) + ->all(); + +?> + + + + \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/element/petition/identifierCollectorsStep.php b/app/plugins/CoreEnroller/templates/element/petition/identifierCollectorsStep.php new file mode 100644 index 00000000..f486c6e1 --- /dev/null +++ b/app/plugins/CoreEnroller/templates/element/petition/identifierCollectorsStep.php @@ -0,0 +1,8 @@ +Petition->getTable('CoreEnroller.PetitionIdentifiers'); + +$vv_pi = $PetitionIdentifiers->find()->where(['petition_id' => $vv_obj->id])->first(); + +if(!empty($vv_pi->identifier)) { + print __d('core_enroller', 'result.IdentifierCollector.collected', [$vv_pi->identifier]); +} \ No newline at end of file diff --git a/app/plugins/CoreEnroller/templates/InvitationAccepters/display.php b/app/plugins/CoreEnroller/templates/element/petition/invitationAcceptersStep.php similarity index 65% rename from app/plugins/CoreEnroller/templates/InvitationAccepters/display.php rename to app/plugins/CoreEnroller/templates/element/petition/invitationAcceptersStep.php index d1d91110..08ca2582 100644 --- a/app/plugins/CoreEnroller/templates/InvitationAccepters/display.php +++ b/app/plugins/CoreEnroller/templates/element/petition/invitationAcceptersStep.php @@ -1,4 +1,8 @@ Petition->getTable('CoreEnroller.PetitionAcceptances'); + +$vv_pa = $PetitionAcceptances->find()->where(['petition_id' => $vv_obj->id])->first(); + if(!empty($vv_pa)) { if($vv_pa['accepted']) { print __d('core_enroller', 'result.InvitationAccepters.accepted', [$vv_pa['modified']]); diff --git a/app/src/Controller/MVEAController.php b/app/src/Controller/MVEAController.php index 52fb641c..4a7ec650 100644 --- a/app/src/Controller/MVEAController.php +++ b/app/src/Controller/MVEAController.php @@ -100,7 +100,7 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { $personName = $Names->primaryName($externalIdentity->person_id); $this->set('vv_person_name', $personName); $this->set('vv_supertitle', $personName->full_name); - $this->set('vv_person_id', $externalIdentity->person_id); + $this->set('vv_mvea_person_id', $externalIdentity->person_id); break; case 'person_role_id': $PersonRoles = $this->getTableLocator()->get('PersonRoles'); @@ -113,13 +113,13 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { $personName = $Names->primaryName($roleEntity->person_id); $this->set('vv_person_name', $personName); $this->set('vv_supertitle', $personName->full_name); - $this->set('vv_person_id', $roleEntity->person_id); + $this->set('vv_mvea_person_id', $roleEntity->person_id); break; case 'person_id': $personName = $Names->primaryName((int)$primaryLink->value); $this->set('vv_person_name', $personName); $this->set('vv_supertitle', $personName->full_name); - $this->set('vv_person_id', $primaryLink->value); + $this->set('vv_mvea_person_id', $primaryLink->value); break; default; break; diff --git a/app/src/Model/Table/PetitionsTable.php b/app/src/Model/Table/PetitionsTable.php index fd760387..065ab20e 100644 --- a/app/src/Model/Table/PetitionsTable.php +++ b/app/src/Model/Table/PetitionsTable.php @@ -90,6 +90,9 @@ public function initialize(array $config): void { $this->hasMany('PetitionStepResults') ->setDependent(true) ->setCascadeCallbacks(true); + $this->hasMany('CoreEnroller.PetitionAttributes') + ->setDependent(true) + ->setCascadeCallbacks(true); $this->hasOne('Verifications') ->setDependent(true) @@ -116,7 +119,8 @@ public function initialize(array $config): void { 'EnrolleePeople' => ['PrimaryName' => ['foreignKey' => 'person_id']], 'PetitionerPeople' => ['PrimaryName' => ['foreignKey' => 'person_id']], 'PetitionHistoryRecords', - 'PetitionStepResults' + 'PetitionStepResults', + 'PetitionAttributes', ]); $this->setAutoViewVars([ diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 4a221150..34ca57ce 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -304,7 +304,7 @@ public function dateField(string $fieldName, isset($fieldArgs['default']) && is_string($fieldArgs['default']) => FrozenTime::parse($fieldArgs['default']), // Petition View/ Value saved a FronzenTime isset($fieldArgs['default']) - && is_a($fieldArgs['default'], 'Cake\I18n\FrozenTime') => $fieldArgs['default'], + && is_a($fieldArgs['default'], 'Cake\I18n\FrozenTime') => $fieldArgs['default'], // Table record/ Retrieve it from the Entity object default => $this->getEntity()?->$fieldName, }; diff --git a/app/src/View/Helper/PetitionHelper.php b/app/src/View/Helper/PetitionHelper.php index 0f1ddec5..be426a30 100644 --- a/app/src/View/Helper/PetitionHelper.php +++ b/app/src/View/Helper/PetitionHelper.php @@ -35,6 +35,7 @@ use Cake\Utility\Inflector; use Cake\View\Helper; use CoreEnroller\Model\Table\EnrollmentAttributesTable; +use DOMDocument; class PetitionHelper extends Helper { @@ -82,7 +83,7 @@ public function populateAutoViewVars(): void } /** - * Get the table validation rules + * Get reference to the Table Object * * @param string $tableName * diff --git a/app/src/View/Helper/TabHelper.php b/app/src/View/Helper/TabHelper.php index 9bc78da5..71f31429 100644 --- a/app/src/View/Helper/TabHelper.php +++ b/app/src/View/Helper/TabHelper.php @@ -63,6 +63,8 @@ class TabHelper extends Helper public function constructLinkUrl(string $tab, string|int $curId, bool $isNested = false): array { $curController = $this->getView()->getRequest()->getParam('controller'); + $vv_associated_ids = $this->getView()->get('vv_associated_ids'); + $modelName = $tab; $controller = $modelName; $plugin = null; @@ -100,7 +102,15 @@ public function constructLinkUrl(string $tab, string|int $curId, bool $isNested ]; if ($action === 'index') { + $deepId = $this->getDeepNestedId($linkFilter); + If($deepId !== null) { + $linkFilterForeignKey = array_key_first($linkFilter); + $linkFilter[$linkFilterForeignKey] = $deepId; + } $url['?'] = $linkFilter; + } else if ($action === 'edit') { + // I will get the id from the associated ids table + $url[] = $vv_associated_ids[$controller]; } else { $url[] = $curId; } @@ -108,6 +118,49 @@ public function constructLinkUrl(string $tab, string|int $curId, bool $isNested return $url; } + + /** + * Retrieve the ID for a deeply nested association. + * + * @param array $linkFilter The link filter containing foreign key details. + * + * @return int|null The ID of the deeply nested associated model or null if not found. + * @since COmanage Registry v5.1.0 + */ + public function getDeepNestedId(array $linkFilter): ?int + { + $vv_associated_ids = $this->getView()->get('vv_associated_ids'); + + // Get the foreign from the linkFilter + $linkFilterForeignKey = array_key_first($linkFilter); + // Generate the ModelName and instantiate the linked Table + $modelName = StringUtilities::foreignKeyToClassName($linkFilterForeignKey); + $table = TableRegistry::getTableLocator()->get($modelName); + $linkFilterId = $vv_associated_ids[Inflector::pluralize($modelName)] ?? null; + if($linkFilterId !== null) { + return (int)$linkFilterId; + } + $foreignKeyId = -1; + $foreignKey = null; + // This means that we are working on deep nested associations and we need + // to fetch more data + $linkFilterSchema = $table->getSchema(); + foreach($linkFilterSchema->columns() as $column) { + // Check the foreign keys + if(str_ends_with($column, '_id')) { + $foreignKeytToTableName = Inflector::pluralize(StringUtilities::foreignKeyToClassName($column)); + if(isset($vv_associated_ids[$foreignKeytToTableName])) { + $foreignKeyId = $vv_associated_ids[$foreignKeytToTableName]; + $foreignKey = $column; + break; + } + } + } + $id = $table->find()->where([$foreignKey => $foreignKeyId])->first()->id; + + return(int)$id; + } + /** * Calculate the link Class * @@ -205,6 +258,7 @@ public function getCurrentId(string $tabName = null, bool $isNested = false): in TableUtilities::treeTraversalFromId($curController, (int)$tid, $results); } + $this->getView()->set('vv_associated_ids', $results); $tabAction = $this->getTabAction($tabName, $isNested); if( diff --git a/app/templates/Petitions/fields.inc b/app/templates/Petitions/fields.inc index 1665c168..5b488673 100644 --- a/app/templates/Petitions/fields.inc +++ b/app/templates/Petitions/fields.inc @@ -230,35 +230,40 @@ if (!empty($vv_obj?->petitioner_person?->id)) { - enrollment_flow->enrollment_flow_steps as $step): ?> - petition_step_results, "{n}[enrollment_flow_step_id=$step->id]"); - - if(!empty($result)) { - $resultLink = [ - 'controller' => 'petitions', - 'action' => 'result', - $vv_obj->id, - '?' => [ - 'enrollment_flow_step_id' => $step->id - ] - ]; - } - ?> - + petition_step_results, "{n}[enrollment_flow_step_id=$step->id]"); ?>
  • - description ?> + description ?>
    - Html->link($result[0]->comment, $resultLink) : "" ?> + comment : '' ?> +
  • +
  • +

    plugin ?>

    + plugin); + $elementName = lcfirst($pluginClass) . 'Step'; + + print $this->element("$pluginName.petition/$elementName", ['vv_step' => $step]); + ?> +
  • diff --git a/app/templates/element/subnavigation.php b/app/templates/element/subnavigation.php index 138d38e3..cd453a96 100644 --- a/app/templates/element/subnavigation.php +++ b/app/templates/element/subnavigation.php @@ -42,9 +42,9 @@ $curId = $this->request->getQuery($vv_primary_link); $linkFilter = [$vv_primary_link => $curId]; // For top-level nav - if(!empty($vv_person_id)) { - $curId = $vv_person_id; - $linkFilter = ['person_id' => $vv_person_id]; + if(!empty($vv_mvea_person_id)) { + $curId = $vv_mvea_person_id; + $linkFilter = ['person_id' => $vv_mvea_person_id]; } } elseif (!empty($vv_obj)) { // This will work for most top-level edit views @@ -55,8 +55,8 @@ // these have been explicitly set in the $subnav array in fields-nav.inc, so just use them. $curId = $tabsId; $navController = $tabsController; - } elseif(!empty($vv_person_id)) { - $curId = $vv_person_id; + } elseif(!empty($vv_mvea_person_id)) { + $curId = $vv_mvea_person_id; } elseif( ($active == 'plugin' || (!empty($vv_primary_link) && $vv_primary_link == 'enrollment_flow_id')) && !empty($vv_primary_link_obj) diff --git a/app/templates/element/subnavigation/statusBadge.php b/app/templates/element/subnavigation/statusBadge.php index 16a0ae5a..1cd6f6cb 100644 --- a/app/templates/element/subnavigation/statusBadge.php +++ b/app/templates/element/subnavigation/statusBadge.php @@ -35,7 +35,7 @@ return; } -$personId = $vv_person_id +$personId = $vv_mvea_person_id ?? $this->request->getQuery('person_id') ?? $vv_obj?->person_id ?? $vv_obj?->id; diff --git a/app/templates/element/subnavigation/supertitle.php b/app/templates/element/subnavigation/supertitle.php index b5f238df..c7354fa4 100644 --- a/app/templates/element/subnavigation/supertitle.php +++ b/app/templates/element/subnavigation/supertitle.php @@ -38,7 +38,7 @@ * Person with deep nested dependency */ -$person_id = (int)($vv_person_id ?? $vv_obj?->person_id ?? $this->getRequest()->getQuery('person_id')); +$person_id = (int)($vv_mvea_person_id ?? $vv_obj?->person_id ?? $this->getRequest()->getQuery('person_id')); if ($person_id) { $personFullName = $this->Tab->getPersonPrimaryName($person_id); } @@ -65,16 +65,22 @@ && $vv_subnavigation_tabs[0] !== StringUtilities::entityToClassName($vv_bc_parent_obj) ) { $object = $vv_obj ?? $$objectName?->first(); - // If we get here, it means that neither the request object nor its parent can give us a supertitle. - // We need to fetch all the ids and get the supertitle from the root tab/node - $results = []; - TableUtilities::treeTraversalFromId(StringUtilities::entityToClassName($object), (int)$object->id, $results); - $superTitleModelReference = $this->Tab->getModelTableReference($vv_subnavigation_tabs[0]); - $superTitleModelDisplayField = $superTitleModelReference->getDisplayField(); - $superTitleModelId = $results[$vv_subnavigation_tabs[0]]; + if ($object === null) { + // This is a deep nested association that has not been initialized yet. The controller name + // will become the supertitle + $vv_subnavigation_tabsSupertitle = Inflector::humanize($vv_controller); + } else { + // If we get here, it means that neither the request object nor its parent can give us a supertitle. + // We need to fetch all the ids and get the supertitle from the root tab/node + $results = []; + TableUtilities::treeTraversalFromId(StringUtilities::entityToClassName($object), (int)$object->id, $results); + $superTitleModelReference = $this->Tab->getModelTableReference($vv_subnavigation_tabs[0]); + $superTitleModelDisplayField = $superTitleModelReference->getDisplayField(); + $superTitleModelId = $results[$vv_subnavigation_tabs[0]]; - $root_obj = $superTitleModelReference->get($superTitleModelId); - $vv_subnavigation_tabsSupertitle = $root_obj->$superTitleModelDisplayField; + $root_obj = $superTitleModelReference->get($superTitleModelId); + $vv_subnavigation_tabsSupertitle = $root_obj->$superTitleModelDisplayField; + } } $supertitle = match (true) { diff --git a/app/webroot/css/co-base.css b/app/webroot/css/co-base.css index 92584f03..799fa3b0 100644 --- a/app/webroot/css/co-base.css +++ b/app/webroot/css/co-base.css @@ -1001,6 +1001,21 @@ ul.form-list li.alert-banner .co-alert { white-space: nowrap; margin-right: 0.5em; } +/* PETITION PREVIEW */ +a.cm-toggle { + float: right; + border: none; + background-color: transparent; +} +a.cm-toggle .material-symbols, +a.cm-toggle .material-symbols-outlined{ + color: var(--cmg-color-headings); +} +a.cm-toggle .material-symbols, +a.cm-toggle .material-symbols-outlined { + font-size: 34px; + line-height: 17px; +} /* PLATFORM NOTICE (for COmanage CO) */ #platform-notice { padding: 0.5em; diff --git a/app/webroot/js/comanage/comanage.js b/app/webroot/js/comanage/comanage.js index dd8b88ab..a6e331d2 100644 --- a/app/webroot/js/comanage/comanage.js +++ b/app/webroot/js/comanage/comanage.js @@ -423,4 +423,31 @@ function setApplicationState(value, elem, reload= false) { generateFlash("" + errorThrown + " (" + jqXHR.status + ")", 'error') } }); +} + +function stepCollapseToggle(event, item) { + /** + * Toggles the expanded or collapsed state of the step element. + * + * This function prevents the default action and stops the propagation of the event, + * then toggles the "collapsed" class for the given element. It also updates + * the `aria-expanded` attribute and changes the icon displayed within the element. + * + * - If the element is collapsed, it sets `aria-expanded` to "false" and updates + * the icon to "arrow_drop_down." + * - If the element is expanded, it sets `aria-expanded` to "true" and updates + * the icon to "arrow_drop_up." + * + * @param {Event} event - The event triggered, usually by a click action. + * @param {HTMLElement} item - The DOM element being toggled that represents the step. + */ + event.preventDefault(); + event.stopPropagation(); + if ($(item).hasClass("collapsed")) { + $(item).attr("aria-expanded","false") + $(item).find('em').text("arrow_drop_down"); + } else { + $(item).attr("aria-expanded","true") + $(item).find('em').text("arrow_drop_up"); + } } \ No newline at end of file