diff --git a/app/Lib/enum.php b/app/Lib/enum.php index d750cdec9..070c1ea3f 100644 --- a/app/Lib/enum.php +++ b/app/Lib/enum.php @@ -216,6 +216,20 @@ class DataFilterContextEnum const ProvisioningTarget = 'PT'; } +class NormalizerTypeEnum +{ + const TrimWhitespace = 'TW'; + const MixCase = 'MC'; + const PunctuationToSpace = 'PS'; + + // Each type maps to a function having the first letter lowercase + public static $type = array( + NormalizerTypeEnum::TrimWhitespace => 'TrimWhitespace', + NormalizerTypeEnum::MixCase => 'MixCase', + NormalizerTypeEnum::PunctuationToSpace => 'PunctuationToSpace' + ); +} + class DepartmentEnum { const Department = 'department'; const ResearchInstitute = 'researchinstitute'; diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php index eb4c4c4fb..59312cb62 100644 --- a/app/Model/AppModel.php +++ b/app/Model/AppModel.php @@ -1657,22 +1657,27 @@ public function validateEnumeration($coId, $attribute, $value) { * @param integer $coId CO ID * @param string $attribute Attribute, in Model.attribute form * @param string $value Value to normalize + * @param array $options Save options * @return string The normalized value */ - public function normalizeEnumeration($coId, $attribute, $value) { + public function normalizeEnumeration($coId, $attribute, $value, $options = array()) { // First, see if there is an enumeration defined for $coId + $attribute. $args = array(); + $args['joins'][0]['table'] = 'dictionaries'; + $args['joins'][0]['alias'] = 'Dictionary'; + $args['joins'][0]['type'] = 'INNER'; + $args['joins'][0]['conditions'][0] = 'AttributeEnumeration.dictionary_id=Dictionary.id'; $args['conditions']['AttributeEnumeration.co_id'] = $coId; $args['conditions']['AttributeEnumeration.attribute'] = $attribute; $args['conditions']['AttributeEnumeration.status'] = SuspendableStatusEnum::Active; $args['contain'] = false; $AttributeEnumeration = ClassRegistry::init('AttributeEnumeration'); - $attrEnum = $AttributeEnumeration->find('first', $args); + $has_dictionary = (boolean)$AttributeEnumeration->find('count', $args); - if(empty($attrEnum['AttributeEnumeration']['dictionary_id'])) { + if(!$has_dictionary) { // If there is no dictionary attached to the Attribute Enumeration // configuration then load the normalizer $this->Behaviors->load('Normalization'); @@ -1682,7 +1687,7 @@ public function normalizeEnumeration($coId, $attribute, $value) { $a = explode('.', $attribute, 2); $data[ $a[0] ][ $a[1] ] = $value; - $newdata = $this->normalize($data, $coId); + $newdata = $this->normalize($data, $coId, $options); $this->Behaviors->unload('Normalization'); diff --git a/app/Model/Behavior/NormalizationBehavior.php b/app/Model/Behavior/NormalizationBehavior.php index aa81affde..3c67e3711 100644 --- a/app/Model/Behavior/NormalizationBehavior.php +++ b/app/Model/Behavior/NormalizationBehavior.php @@ -35,8 +35,8 @@ class NormalizationBehavior extends ModelBehavior { * @throws RuntimeException */ - public function beforeValidate(Model $model, $options = array()) { - $model->data = $this->normalize($model, $model->data); + public function beforeSave(Model $model, $options = array()) { + $model->data = $this->normalize($model, $model->data, false, $options); return true; } @@ -48,13 +48,22 @@ public function beforeValidate(Model $model, $options = array()) { * @param Model $model Model instance * @param Array $data Data to normalize in usual format; need not belong to $model * @param Integer $coId CO ID data belongs to, or null for Org Identity data, or false to determine from $data ($data must then belong to $model) + * @param array List of Save options * @return boolean true on success * @throws RuntimeException */ - public function normalize(Model $model, $data, $coId = false) { + public function normalize(Model $model, $data, $coId = false, $options = array()) { $mname = $model->alias; - + + // Are there any types of normalization that we need to skip + $normalization_dis = array(); + foreach (DefaultNormalizerTypeEnum::$type as $key => $value) { + if(isset($options[$key]) && !$options[$key]) { + $normalization_dis[] = $key; + } + } + // If $coId is false, look for a CO ID. If we don't find one or if $coId is null, // we're dealing with org identity data, which normalizations don't currently support. @@ -113,7 +122,7 @@ public function normalize(Model $model, $data, $coId = false) { if($pluginModel->isPlugin('normalizer')) { try { - $data = $pluginModel->normalize($data); + $data = $pluginModel->normalize($data, $normalization_dis); } catch(Exception $e) { throw new RuntimeException($e->getMessage()); diff --git a/app/Model/CoPersonRole.php b/app/Model/CoPersonRole.php index ae3f21b07..da3da5e3c 100644 --- a/app/Model/CoPersonRole.php +++ b/app/Model/CoPersonRole.php @@ -375,7 +375,8 @@ public function beforeSave($options = array()) { // Normalize Enumeration $this->data[$this->alias][$a] = $this->normalizeEnumeration($coId, 'CoPersonRole.'.$a, - $this->data[$this->alias][$a]); + $this->data[$this->alias][$a], + $options); } } } diff --git a/app/Model/CoPipeline.php b/app/Model/CoPipeline.php index 066db2333..1be5ea4f5 100644 --- a/app/Model/CoPipeline.php +++ b/app/Model/CoPipeline.php @@ -1018,7 +1018,9 @@ protected function syncOrgIdentityToCoPerson($coPipeline, // We need to inject the CO so extended types can be saved $this->Co->CoPerson->CoPersonRole->validate['affiliation']['content']['rule'][1]['coid'] = $orgIdentity['OrgIdentity']['co_id']; - if(!$this->Co->CoPerson->CoPersonRole->save($newCoPersonRole, array("provision" => false, "safeties" => $safeties))) { + if(!$this->Co->CoPerson->CoPersonRole->save($newCoPersonRole, array("provision" => false, + "safeties" => $safeties, + NormalizerTypeEnum::MixCase => false))) { throw new RuntimeException(_txt('er.db.save-a', array('CoPersonRole'))); } @@ -1247,6 +1249,7 @@ protected function syncOrgIdentityToCoPerson($coPipeline, if(!$model->save($nr, array("provision" => false, "safeties" => $safeties, "skipAvailability" => true, + NormalizerTypeEnum::MixCase => !in_array($model, array('CoPersonRole', 'EnrolleeCoPersonRole')), "trustVerified" => $trustVerified))) { throw new RuntimeException(_txt('er.db.save-a', diff --git a/app/Plugin/DefaultNormalizer/Model/DefaultNormalizer.php b/app/Plugin/DefaultNormalizer/Model/DefaultNormalizer.php index 0a7809273..d34830c8a 100644 --- a/app/Plugin/DefaultNormalizer/Model/DefaultNormalizer.php +++ b/app/Plugin/DefaultNormalizer/Model/DefaultNormalizer.php @@ -52,51 +52,52 @@ public function cmPluginMenus() { * * @since COmanage Registry v0.9.2 * @param Array Data to be saved, in typical Cake format + * @param Array Type of normalizations that we will skip * @return Array Data in the same format */ - public function normalize($data) { + public function normalize($data, $normalization_dis = array()) { $ret = $data; $normalizations = array( 'Address' => array( - 'mixCase' => array('street', 'locality', 'state', 'country'), - 'trimWhitespace' => array('street', 'locality', 'state', 'postal_code', 'country') + NormalizerTypeEnum::MixCase => array('street', 'locality', 'state', 'country'), + NormalizerTypeEnum::TrimWhitespace => array('street', 'locality', 'state', 'postal_code', 'country') ), 'CoPersonRole' => array( - 'mixCase' => array('title', 'o', 'ou'), - 'trimWhitespace' => array('title', 'o', 'ou') + NormalizerTypeEnum::MixCase => array('title', 'o', 'ou'), + NormalizerTypeEnum::TrimWhitespace => array('title', 'o', 'ou') ), // We get passed the alias, not the model name during enrollment. // There's not an obvious generic way to figure the out, but for now this // only happens here, so we simply duplicate the rules. (CO-1550) 'EnrolleeCoPersonRole' => array( - 'mixCase' => array('title', 'o', 'ou'), - 'trimWhitespace' => array('title', 'o', 'ou') + NormalizerTypeEnum::MixCase => array('title', 'o', 'ou'), + NormalizerTypeEnum::TrimWhitespace => array('title', 'o', 'ou') ), 'EmailAddress' => array( // Note cake validation will likely prevent this from being called - 'trimWhitespace' => array('mail') + NormalizerTypeEnum::TrimWhitespace => array('mail') ), 'Identifier' => array( - 'trimWhiteSpace' => array('identifier') + NormalizerTypeEnum::TrimWhitespace => array('identifier') ), 'Name' => array( // For now, we don't mix case to avoid dealing with issues like people who // go by lowercase names, or McPherson-style capitalization - 'trimWhitespace' => array('honorific', 'given', 'middle', 'family', 'suffix') + NormalizerTypeEnum::TrimWhitespace => array('honorific', 'given', 'middle', 'family', 'suffix') ), 'TelephoneNumber' => array( // Following E.123 format, we only use spaces in telephone numbers // (the + and extension label get added by formatTelephone at rendering time) - 'punctuationToSpace' => array('country_code', 'area_code', 'number', 'extension'), - 'trimWhitespace' => array('country_code', 'area_code', 'number', 'extension') + NormalizerTypeEnum::PunctuationToSpace => array('country_code', 'area_code', 'number', 'extension'), + NormalizerTypeEnum::TrimWhitespace => array('country_code', 'area_code', 'number', 'extension') ), 'Url' => array( // We don't normalize an http:// prefix because cake validation will prevent // a URL from being submitted without a prefix (and we wouldn't know the // protocol anyway). - 'trimWhitespace' => array('url') + NormalizerTypeEnum::TrimWhitespace => array('url') ) ); @@ -134,7 +135,7 @@ public function normalize($data) { // We only trim whitespace since we can't say too much about the contents // of the extended attribute. - $normalizations[$model]['trimWhitespace'][] = $name; + $normalizations[$model][NormalizerTypeEnum::TrimWhitespace][] = $name; } } } @@ -147,9 +148,14 @@ public function normalize($data) { // Run the appropriate normalizations for each field within the model foreach(array_keys($normalizations[$model]) as $normalization) { + // Skip a normalization if found in the exception list + if(in_array($normalization, $normalization_dis)) { + continue; + } foreach($normalizations[$model][$normalization] as $field) { if(!empty($ret[$model][$field])) { - $ret[$model][$field] = $this->$normalization($ret[$model][$field], $field); + $func = lcfirst( (NormalizerTypeEnum::$type)[$normalization] ); + $ret[$model][$field] = $this->$func($ret[$model][$field], $field); } } }