Skip to content

Add support for attribute collection fieldsets #244

Merged
Expand Up @@ -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.
Expand Down
Expand Up @@ -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'
Expand Down Expand Up @@ -155,7 +159,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',
Expand Down Expand Up @@ -404,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', [
Expand Down
1 change: 0 additions & 1 deletion app/plugins/CoreEnroller/src/config/plugin.json
Expand Up @@ -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 },
Expand Down
Expand Up @@ -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') {
Expand All @@ -54,83 +53,12 @@ foreach($vv_enrollment_attributes_sorted as $attr) {
continue;
}

// 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']]);
// Fieldset with legend for MVEAs
if(\in_array($attr->attribute, ['name', 'address', 'telephoneNumber'], true)) {
print $this->element('CoreEnroller.mveas/mvea-fieldset', compact('attr'));
continue;
}

// Print the element
print $this->element('form/listItem', [
'arguments' => $formArguments
]);
// Default
print $this->element('CoreEnroller.field', compact('attr'));
}
21 changes: 0 additions & 21 deletions app/plugins/CoreEnroller/templates/EnrollmentAttributes/fields.inc
Expand Up @@ -168,30 +168,9 @@ if (\in_array($attribute_type, ['adHocAttribute'], true)) {
}

/*
* Attribute Required field
* Attribute Language field
*
* Supported for attributes: name, address
*/
if(\in_array($attribute_type, ['name', '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)
]
]);
}


print $this->element('form/listItem', [
'arguments' => [
'fieldName' => 'attribute_language',
Expand Down
118 changes: 118 additions & 0 deletions app/plugins/CoreEnroller/templates/element/field.php
@@ -0,0 +1,118 @@
<?php
/**
* COmanage Registry Attribute Field
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.0.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/

declare(strict_types = 1);

use \Cake\Utility\Inflector;

// $attr: Obj

// Field Options array
$options = [];

// Get the static configuration of my attribute
$supportedAttributes = $this->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;
}

$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;

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
$attr->hidden && $hidden =>$this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]),
// Default use case
default => $this->element('form/listItem', ['arguments' => $formArguments])
};
@@ -0,0 +1,64 @@
<?php
/**
* COmanage Registry Fieldset Field Used for MVEAs
*
* Portions licensed to the University Corporation for Advanced Internet
* Development, Inc. ("UCAID") under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* UCAID licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @link https://www.internet2.edu/comanage COmanage Project
* @package registry
* @since COmanage Registry v5.0.0
* @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/


declare(strict_types = 1);

use \Cake\Utility\Inflector;

// $field: string
// $attr: object

$field = str_replace(' ', '_', Inflector::underscore($field));
$label = Inflector::humanize($field);
$isRequiredFromValidationRule = false;
$supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute);

if(isset($supportedAttributes['mveaModel'])) {
$supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute);
$modelTable = $this->Petition->getTable($supportedAttributes['mveaModel']);
$isRequiredFromValidationRule = !$modelTable->getValidator()->field($field)->isEmptyAllowed();
}

// 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-$field-$attr->id",
'fieldLabel' => $attr->label, // fieldLabel is only applicable to checkboxes
'fieldType' => $modelTable->getSchema()->getColumn($field)['type'],
'fieldNameAlias' => $attr->attribute // the field name to its enrollment attribute field name
];
?>

<div class="fieldset-field <?= "fields-$field"?>">
<label for="<?= $field ?>"><?= $label ?></label>
<?= $isRequiredFromValidationRule ? $this->element('form/requiredSpan') : ''?>
<?= $this->Field->formField(...$formArguments) ?>
</div>