/** * @covers ValidatorControlledVocab */ public function testValidatorControlledVocab() { // Mock a ControlledVocab object $mockControlledVocab = $this->getMock('ControlledVocab', array('enumerate')); $mockControlledVocab->setId(1); $mockControlledVocab->setAssocType(ASSOC_TYPE_CITATION); $mockControlledVocab->setAssocId(333); $mockControlledVocab->setSymbolic('testVocab'); // Set up the mock enumerate() method $mockControlledVocab->expects($this->any())->method('enumerate')->will($this->returnValue(array(1 => 'vocab1', 2 => 'vocab2'))); // Mock the ControlledVocabDAO $mockControlledVocabDAO = $this->getMock('ControlledVocabDAO', array('getBySymbolic')); // Set up the mock getBySymbolic() method $mockControlledVocabDAO->expects($this->any())->method('getBySymbolic')->with('testVocab', ASSOC_TYPE_CITATION, 333)->will($this->returnValue($mockControlledVocab)); DAORegistry::registerDAO('ControlledVocabDAO', $mockControlledVocabDAO); $validator = new ValidatorControlledVocab('testVocab', ASSOC_TYPE_CITATION, 333); self::assertTrue($validator->isValid('1')); self::assertTrue($validator->isValid('2')); self::assertFalse($validator->isValid('3')); }
/** * Validate a given input against the property specification * * The given value must validate against at least one of the * allowed types. The first allowed type id will be returned as * validation result. If the given value fits none of the allowed * types, then we'll return 'false'. * * @param $value mixed the input to be validated * @param $locale string the locale to be used for validation * @return array|boolean an array with a single entry of the format * "type => additional type parameter" against which the value * validated or boolean false if not validated at all. */ function isValid($value, $locale = null) { // We never accept null values or arrays. if (is_null($value) || is_array($value)) { return false; } // Translate the locale. if (is_null($locale)) { $locale = ''; } // MetadataProperty::getSupportedTypes() returns an ordered // list of possible meta-data types with the most specific // type coming first so that we always correctly identify // specializations (e.g. a date is a specialized string). $allowedTypes = $this->getAllowedTypes(); foreach (MetadataProperty::getSupportedTypes() as $testedType) { if (isset($allowedTypes[$testedType])) { foreach ($allowedTypes[$testedType] as $allowedTypeParam) { // Type specific validation switch ($testedType) { case METADATA_PROPERTY_TYPE_COMPOSITE: // Composites can either be represented by a meta-data description // or by a string of the form AssocType:AssocId if the composite // has already been persisted in the database. switch (true) { // Test for MetadataDescription format case is_a($value, 'MetadataDescription'): $assocType = $value->getAssocType(); break; // Test for AssocType:AssocId format // Test for AssocType:AssocId format case is_string($value): $valueParts = explode(':', $value); if (count($valueParts) != 2) { break 2; } // break the outer switch list($assocType, $assocId) = $valueParts; if (!(is_numeric($assocType) && is_numeric($assocId))) { break 2; } // break the outer switch $assocType = (int) $assocType; break; default: // None of the allowed types break; } // Check that the association type matches // with the allowed association type (which // is configured as an additional type parameter). if (isset($assocType) && $assocType === $allowedTypeParam) { return array(METADATA_PROPERTY_TYPE_COMPOSITE => $assocType); } break; case METADATA_PROPERTY_TYPE_VOCABULARY: // Interpret the type parameter of this type like this: // symbolic[:assoc-type:assoc-id]. If no assoc type/id are // given then we assume :0:0 to represent site-wide vocabs. $vocabNameParts = explode(':', $allowedTypeParam); $vocabNamePartsCount = count($vocabNameParts); switch ($vocabNamePartsCount) { case 1: // assume a site-wide vocabulary $symbolic = $allowedTypeParam; $assocType = $assocId = 0; break; case 3: // assume a context-specific vocabulary list($symbolic, $assocType, $assocId) = $vocabNameParts; break; default: // Invalid configuration assert(false); } if (is_string($value)) { // Try to translate the string value into a controlled vocab entry $controlledVocabEntryDao =& DAORegistry::getDao('ControlledVocabEntryDAO'); /* @var $controlledVocabEntryDao ControlledVocabEntryDAO */ if (!is_null($controlledVocabEntryDao->getBySetting($value, $symbolic, $assocType, $assocId, 'name', $locale))) { // The string was successfully translated so mark it as "valid". return array(METADATA_PROPERTY_TYPE_VOCABULARY => $allowedTypeParam); } } if (is_integer($value)) { // Validate with controlled vocabulary validator import('lib.pkp.classes.validation.ValidatorControlledVocab'); $validator = new ValidatorControlledVocab($symbolic, $assocType, $assocId); if ($validator->isValid($value)) { return array(METADATA_PROPERTY_TYPE_VOCABULARY => $allowedTypeParam); } } break; case METADATA_PROPERTY_TYPE_URI: // Validate with the URI validator import('lib.pkp.classes.validation.ValidatorUri'); $validator = new ValidatorUri(); if ($validator->isValid($value)) { return array(METADATA_PROPERTY_TYPE_URI => null); } break; case METADATA_PROPERTY_TYPE_DATE: // We allow the following patterns: // YYYY-MM-DD, YYYY-MM and YYYY $datePattern = '/^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?$/'; if (!preg_match($datePattern, $value)) { break; } // Check whether the given string is really a valid date $dateParts = explode('-', $value); // Set the day and/or month to 1 if not set $dateParts = array_pad($dateParts, 3, 1); // Extract the date parts list($year, $month, $day) = $dateParts; // Validate the date (only leap days will pass unnoticed ;-) ) // Who invented this argument order? if (checkdate($month, $day, $year)) { return array(METADATA_PROPERTY_TYPE_DATE => null); } break; case METADATA_PROPERTY_TYPE_INTEGER: if (is_integer($value)) { return array(METADATA_PROPERTY_TYPE_INTEGER => null); } break; case METADATA_PROPERTY_TYPE_STRING: if (is_string($value)) { return array(METADATA_PROPERTY_TYPE_STRING => null); } break; default: // Unknown type. As we validate type in the setter, this // should be unreachable code. assert(false); } } } } // Return false if the value didn't validate against any // of the allowed types. return false; }
/** * Validate a given input against the property specification * * @param $value mixed the input to be validated * @return boolean validation success */ function isValid($value) { // We never accept null values or arrays. if (is_null($value) || is_array($value)) { return false; } // The value must validate against at least one type $isValid = false; foreach ($this->getTypes() as $type) { // Extract data from composite type if (is_array($type)) { assert(count($type) == 1 && key($type) == METADATA_PROPERTY_TYPE_COMPOSITE); $compositeType = $type[METADATA_PROPERTY_TYPE_COMPOSITE]; $type = METADATA_PROPERTY_TYPE_COMPOSITE; } // Type specific validation switch ($type) { case METADATA_PROPERTY_TYPE_STRING: if (is_string($value)) { $isValid = true; } break; case METADATA_PROPERTY_TYPE_VOCABULARY: // Interpret the name of this property as a controlled vocabulary triple $vocabNameParts = explode(':', $this->getName()); assert(count($vocabNameParts) == 3); list($symbolic, $assocType, $assocId) = $vocabNameParts; // Validate with controlled vocabulary validator import('validation.ValidatorControlledVocab'); $validator = new ValidatorControlledVocab($symbolic, $assocType, $assocId); if ($validator->isValid($value)) { $isValid = true; } break; case METADATA_PROPERTY_TYPE_URI: // Validate with the URI validator import('validation.ValidatorUri'); $validator = new ValidatorUri(); if ($validator->isValid($value)) { $isValid = true; } break; case METADATA_PROPERTY_TYPE_DATE: // We allow the following patterns: // YYYY-MM-DD, YYYY-MM and YYYY $datePattern = '/^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?$/'; if (!preg_match($datePattern, $value)) { break; } // Check whether the given string is really a valid date $dateParts = explode('-', $value); // Set the day and/or month to 1 if not set $dateParts = array_pad($dateParts, 3, 1); // Extract the date parts list($year, $month, $day) = $dateParts; // Validate the date (only leap days will pass unnoticed ;-) ) // Who invented this argument order? if (checkdate($month, $day, $year)) { $isValid = true; } break; case METADATA_PROPERTY_TYPE_INTEGER: if (is_integer($value)) { $isValid = true; } break; case METADATA_PROPERTY_TYPE_COMPOSITE: // Composites can either be represented by a meta-data description // or by a string of the form AssocType:AssocId if the composite // has already been persisted in the database. switch (true) { // Test for MetadataDescription format case is_a($value, 'MetadataDescription'): $assocType = $value->getAssocType(); break; // Test for AssocType:AssocId format // Test for AssocType:AssocId format case is_string($value): $valueParts = explode(':', $value); if (count($valueParts) != 2) { break 2; } // break the outer switch list($assocType, $assocId) = $valueParts; if (!(is_numeric($assocType) && is_numeric($assocId))) { break 2; } // break the outer switch $assocType = (int) $assocType; break; default: // None of the allowed types break; } // Check that the association type matches if (isset($assocType) && $assocType === $compositeType) { $isValid = true; } break; default: // Unknown type. As we validate type in the setter, this // should be unreachable code. assert(false); } // The value only has to validate against one of the given // types: No need to validate against subsequent allowed types. if ($isValid) { break; } } // Will return false if the value didn't validate against any // of the types, otherwise true. return $isValid; }