-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathSWValidator.php
181 lines (166 loc) · 6.84 KB
/
SWValidator.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<?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;
}
}
?>