Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
CRAP | |
100.00% |
63 / 63 |
SWValidator | |
100.00% |
1 / 1 |
|
100.00% |
4 / 4 |
22 | |
100.00% |
63 / 63 |
validateAttribute($model,$attribute) | |
100.00% |
1 / 1 |
9 | |
100.00% |
26 / 26 |
|||
_getSWScenarioName($model,$nxtStatus) | |
100.00% |
1 / 1 |
3 | |
100.00% |
13 / 13 |
|||
_validatorMatches($validator,$swScenario) | |
100.00% |
1 / 1 |
6 | |
100.00% |
14 / 14 |
|||
_extractSwScenarioPattern($valScenario) | |
100.00% |
1 / 1 |
4 | |
100.00% |
10 / 10 |
<?php | |
/** | |
* <p> | |
* This validator should be used to validate the 'status' attribute for an active record | |
* object before it is saved. It tests if the transition that is about to occur is valid.<br/> | |
* Moreover, if <strong>$enableSwValidation</strong> is set to <b>true</b>, this validator applies all | |
* validators that may have been defined by the model for the scenario associated to the transition | |
* being done.<br/> | |
* Scenario names associated with a transition, have the following format : | |
* <pre> | |
* sw:[currentStatus]-[nextStatus] | |
* </pre> | |
* For instance, if the model being validated is currently in status 'A' and it is sent in status 'B', the | |
* corresponding scenario name is 'sw:A-B'. Note that if the destination status doesn't belong to the same | |
* workflow as the current status, [nextStatus] must be in the form 'workflowId/statusId' (e.g 'sw:A-workflow/B'). | |
* Eventually, when the model enters in a workflow, the scenario name is '-[nextStatus]' where 'nextStatus' | |
* includes the workflow Id (e.g 'sw:-workflowIs/statusId'). | |
* </p> | |
* <p> | |
* If this validator is initialized with parameter <b>match</b> set to TRUE, then transitions scenario defined | |
* for validators are assumed to be regular expressions. If the current transition matches, then the associated | |
* validator is executed.<br/> | |
* For instance, if validator 'required' for attribute A applies to scenarion 'sw:/S1_.?/' then each time the | |
* model leaves status S1, then the <em>required</em> validator will be applied. | |
* </p> | |
*/ | |
class SWValidator extends CValidator | |
{ | |
/** | |
* @var boolean (default FALSE) Enables simpleWorkflow Validation. When TRUE, the SWValidator not only | |
* validates status change for the model, but also applies all validators that may have been created and | |
* which are associated with the scenario for the transition being done. Such scenario names are based on | |
* both the current and the next status name. | |
*/ | |
public $enableSwValidation=false; | |
/** | |
* @var boolean (default FALSE) When true, the scenario name is evaluated as a regular expression that must | |
* match the transition name being done. | |
*/ | |
public $match=false; | |
const SW_SCENARIO_STATUS_SEPARATOR='-'; | |
const SW_SCENARIO_PREFIX='sw:'; | |
private $_lenPrefix=null; | |
/** | |
* Validate status change and applies all validators defined by the model for the current transition scenario if | |
* enableSwValidation is TRUE. If validator parameter 'match' is true, the transition scenario is matched | |
* against validator scenario (which are assumed to be regular expressions). | |
* | |
* @see validators/CValidator::validateAttribute() | |
* @param CModel $model the model to validate | |
* @param string $attribute the model attribute to validate | |
*/ | |
protected function validateAttribute($model,$attribute) | |
{ | |
$value=$model->$attribute; | |
if($model->swValidate($attribute,$value)==true and $this->enableSwValidation ===true){ | |
$swScenario=$this->_getSWScenarioName($model, $value); | |
if(!empty($swScenario)) | |
{ | |
if($this->match === true){ | |
// validator scenario are Regular Expression that must match the transition scenarion | |
// for the validator to be executed. | |
$validators=$model->getValidatorList(); | |
foreach($validators as $validator) | |
{ | |
if($this->_validatorMatches($validator,$swScenario)){ | |
$validator->validate($model); | |
} | |
} | |
}else { | |
$swScenario=SWValidator::SW_SCENARIO_PREFIX.$swScenario; | |
// execute only validator defined for the current transition scenario ($swScenario) | |
// getValidators returns validators with no scenario, and the ones | |
// that apply to the current scenario (swScenario). | |
$saveScenario=$model->getScenario(); | |
$model->setScenario($swScenario); | |
$validators=$model->getValidators(); | |
foreach($model->getValidators() as $validator) | |
{ | |
// only run validators that applies to the current (swScenario) scenario | |
if(isset($validator->on[$swScenario])){ | |
$validator->validate($model); | |
} | |
} | |
// restore original scenario so validation can continue. | |
$model->setScenario($saveScenario); | |
} | |
} | |
} | |
} | |
/** | |
* Create the scenario name for the current transition. Scenario name has following format : <br/> | |
* <pre> [currentStatus]-[nextStatus]</pre> | |
* | |
* @param CModel $model the model being validated | |
* @param string $nxtStatus the next status name (destination status for the model) | |
* @return string SW scenario name for this transition | |
* | |
*/ | |
private function _getSWScenarioName($model,$nxtStatus) | |
{ | |
$swScenario=null; | |
$nextNode=$model->swCreateNode($nxtStatus); | |
$curNode=$model->swGetStatus(); | |
if( $curNode != null ) | |
{ | |
$swScenario=$curNode->getId().SWValidator::SW_SCENARIO_STATUS_SEPARATOR; | |
if($curNode->getWorkflowId()!=$nextNode->getWorkflowId()){ | |
$swScenario.=$nextNode->toString(); | |
}else { | |
$swScenario.=$nextNode->getId(); | |
} | |
}else { | |
$swScenario=SWValidator::SW_SCENARIO_STATUS_SEPARATOR.$nextNode->toString(); | |
} | |
return $swScenario; | |
} | |
/** | |
* Check that a CValidator based object is defined for a scenario that matches | |
* the simple workflow scenario passed as argument. | |
* | |
* @param $validator CValidator validator to test | |
* @param $swScenario string simple workflow scenario defined as a regular expression | |
*/ | |
private function _validatorMatches($validator,$swScenario) | |
{ | |
$bResult=false; | |
if(isset($validator->on)){ | |
$validatorScenarios=(is_array($validator->on)?$validator->on:array($validator->on)); | |
foreach ($validatorScenarios as $valScenario) | |
{ | |
// SW Scenario validator must begin with a non-empty prefix (default 'sw:') | |
// and then define a valide regular expression | |
$re=$this->_extractSwScenarioPattern($valScenario); | |
if( $re != null ) | |
{ | |
if(preg_match($re, $swScenario)){ | |
$bResult=true; | |
break; | |
} | |
} | |
} | |
} | |
return $bResult; | |
} | |
/** | |
* Extract a regular expression pattern out of a simepleWorkflow scenario name | |
* | |
* @param $valScenario String validator scenario name (example : 'sw:/^status1-.*$/') | |
* @return String regular expression (example : '/^status1-.*$/') | |
*/ | |
private function _extractSwScenarioPattern($valScenario) | |
{ | |
$pattern=null; | |
if($this->_lenPrefix==null){ | |
$this->_lenPrefix=strlen(SWValidator::SW_SCENARIO_PREFIX); | |
} | |
if( $this->_lenPrefix != 0 && | |
strpos($valScenario, SWValidator::SW_SCENARIO_PREFIX) === 0) | |
{ | |
$pattern=substr($valScenario, $this->_lenPrefix); | |
} | |
return $pattern; | |
} | |
} | |
?> |