Complex classes like Tracker_FormElement_Field_List often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Tracker_FormElement_Field_List, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | abstract class Tracker_FormElement_Field_List extends Tracker_FormElement_Field implements Tracker_FormElement_Field_Shareable { |
||
24 | |||
25 | const NONE_VALUE = 100; |
||
26 | const NOT_INDICATED_VALUE = 0; |
||
27 | |||
28 | protected $bind; |
||
29 | |||
30 | /** |
||
31 | * @return array |
||
32 | */ |
||
33 | public function getFormElementDataForCreation($parent_id) { |
||
34 | $form_element_data = parent::getFormElementDataForCreation($parent_id); |
||
35 | |||
36 | if ($this->getBind()) { |
||
37 | $form_element_data['bind-type'] = $this->getBind()->getType(); |
||
38 | } |
||
39 | |||
40 | return $form_element_data; |
||
41 | } |
||
42 | |||
43 | /** |
||
44 | * Return true if submitted value is None |
||
45 | */ |
||
46 | abstract public function isNone($value); |
||
47 | |||
48 | /** |
||
49 | * @return Tracker_FormElement_Field_List_Bind |
||
50 | */ |
||
51 | public function getBind() { |
||
52 | if (!$this->bind) { |
||
53 | $this->bind = null; |
||
54 | //retrieve the type of the bind first... |
||
55 | $dao = new Tracker_FormElement_Field_ListDao(); |
||
56 | if ($row = $dao->searchByFieldId($this->id)->getRow()) { |
||
57 | //...and build the bind |
||
58 | $bf = new Tracker_FormElement_Field_List_BindFactory(); |
||
59 | $this->bind = $bf->getBind($this, $row['bind_type']); |
||
60 | } |
||
61 | } |
||
62 | return $this->bind; |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * @return array of Tracker_FormElement_Field_List_BindDecorator |
||
67 | */ |
||
68 | public function getDecorators() { |
||
71 | |||
72 | public function setBind($bind) { |
||
75 | |||
76 | /** |
||
77 | * Duplicate a field. If the field has custom properties, |
||
78 | * they should be propagated to the new one |
||
79 | * @param int $from_field_id |
||
80 | * @return array the mapping between old values and new ones |
||
81 | */ |
||
82 | public function duplicate($from_field_id) { |
||
83 | $dao = new Tracker_FormElement_Field_ListDao(); |
||
84 | if ($dao->duplicate($from_field_id, $this->id)) { |
||
85 | $bf = new Tracker_FormElement_Field_List_BindFactory(); |
||
86 | return $bf->duplicate($from_field_id, $this->id); |
||
87 | } |
||
88 | return array(); |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * @return boolean |
||
93 | */ |
||
94 | public function isMultiple() { |
||
97 | |||
98 | /** |
||
99 | * Get the "from" statement to allow search with this field |
||
100 | * You can join on 'c' which is a pseudo table used to retrieve |
||
101 | * the last changeset of all artifacts. |
||
102 | * |
||
103 | * @param Tracker_ReportCriteria $criteria |
||
104 | * |
||
105 | * @return string |
||
106 | */ |
||
107 | public function getCriteriaFrom($criteria) { |
||
108 | //Only filter query if field is used |
||
109 | if($this->isUsed()) { |
||
110 | return $this->getBind()->getCriteriaFrom($this->getCriteriaValue($criteria)); |
||
111 | } |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Get the "where" statement to allow search with this field |
||
116 | * |
||
117 | * @see getCriteriaFrom |
||
118 | * |
||
119 | * @param Tracker_ReportCriteria $criteria |
||
120 | * |
||
121 | * @return string |
||
122 | */ |
||
123 | public function getCriteriaWhere($criteria) { |
||
126 | |||
127 | /** |
||
128 | * Get the "select" statement to retrieve field values |
||
129 | * |
||
130 | * @see getQueryFrom |
||
131 | * |
||
132 | * @return string |
||
133 | */ |
||
134 | public function getQuerySelect() { |
||
137 | |||
138 | /** |
||
139 | * Get the "select" statement to retrieve field values with the RGB values of their decorator |
||
140 | * Has no sense for fields other than lists |
||
141 | * @return string |
||
142 | * @see getQueryFrom |
||
143 | */ |
||
144 | public function getQuerySelectWithDecorator() { |
||
147 | |||
148 | /** |
||
149 | * Get the "from" statement to retrieve field values |
||
150 | * You can join on artifact AS a, tracker_changeset AS c |
||
151 | * which tables used to retrieve the last changeset of matching artifacts. |
||
152 | * @return string |
||
153 | */ |
||
154 | public function getQueryFrom() { |
||
157 | |||
158 | /** |
||
159 | * Get the "from" statement to retrieve field values |
||
160 | * You can join on artifact AS a, tracker_changeset AS c |
||
161 | * which tables used to retrieve the last changeset of matching artifacts. |
||
162 | * @return string |
||
163 | */ |
||
164 | public function getQueryFromWithDecorator() { |
||
167 | |||
168 | /** |
||
169 | * Get the "order by" statement to retrieve field values |
||
170 | */ |
||
171 | public function getQueryOrderby() { |
||
174 | |||
175 | /** |
||
176 | * Get the "group by" statement to retrieve field values |
||
177 | */ |
||
178 | public function getQueryGroupby() { |
||
181 | |||
182 | /** |
||
183 | * Fetch sql snippets needed to compute aggregate functions on this field. |
||
184 | * |
||
185 | * @param array $functions The needed function. @see getAggregateFunctions |
||
186 | * |
||
187 | * @return array of the form array('same_query' => string(sql snippets), 'separate' => array(sql snippets)) |
||
188 | * example: |
||
189 | * array( |
||
190 | * 'same_query' => "AVG(R2_1234.value) AS velocity_AVG, STD(R2_1234.value) AS velocity_AVG", |
||
191 | * 'separate_queries' => array( |
||
192 | * array( |
||
193 | * 'function' => 'COUNT_GRBY', |
||
194 | * 'select' => "R2_1234.value AS label, count(*) AS value", |
||
195 | * 'group_by' => "R2_1234.value", |
||
196 | * ), |
||
197 | * //... |
||
198 | * ) |
||
199 | * ) |
||
200 | * |
||
201 | * Same query handle all queries that can be run concurrently in one query. Example: |
||
202 | * - numeric: avg, count, min, max, std, sum |
||
203 | * - selectbox: count |
||
204 | * Separate queries handle all queries that must be run spearately on their own. Example: |
||
205 | * - numeric: count group by |
||
206 | * - selectbox: count group by |
||
207 | * - multiselectbox: all (else it breaks other computations) |
||
208 | */ |
||
209 | public function getQuerySelectAggregate($functions) { |
||
212 | |||
213 | /** |
||
214 | * @return array the available aggreagate functions for this field. empty array if none or irrelevant. |
||
215 | */ |
||
216 | public function getAggregateFunctions() { |
||
219 | |||
220 | /** |
||
221 | * Return the dao of the criteria value used with this field. |
||
222 | * @return Tracker_Report_Criteria_List_ValueDao |
||
223 | */ |
||
224 | protected function getCriteriaDao() { |
||
227 | |||
228 | /** |
||
229 | * Display the field as a Changeset value. |
||
230 | * Used in report table |
||
231 | * @param int $artifact_id the corresponding artifact id |
||
232 | * @param int $changeset_id the corresponding changeset |
||
233 | * @param mixed $value the value of the field |
||
234 | * @return string |
||
235 | */ |
||
236 | public function fetchChangesetValue($artifact_id, $changeset_id, $value, $report=null, $from_aid = null) { |
||
237 | |||
238 | //We have to fetch all values of the changeset as we are a list of value |
||
239 | //This is the case only if we are multiple but an old changeset may |
||
240 | //contain multiple values |
||
241 | $values = array(); |
||
242 | foreach($this->getBind()->getChangesetValues($changeset_id) as $v) { |
||
243 | $val = $this->getBind()->formatChangesetValue($v); |
||
244 | if ($val != '') { |
||
245 | $values[] = $val; |
||
246 | } |
||
247 | } |
||
248 | return implode(', ', $values); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Display the field as a Changeset value. |
||
253 | * Used in CSV data export. |
||
254 | * |
||
255 | * @param int $artifact_id the corresponding artifact id |
||
256 | * @param int $changeset_id the corresponding changeset |
||
257 | * @param mixed $value the value of the field |
||
258 | * |
||
259 | * @return string |
||
260 | */ |
||
261 | public function fetchCSVChangesetValue($artifact_id, $changeset_id, $value, $report) { |
||
262 | $values = array(); |
||
263 | foreach($this->getBind()->getChangesetValues($changeset_id) as $v) { |
||
264 | $values[] = $this->getBind()->formatChangesetValueForCSV($v); |
||
265 | } |
||
266 | return implode(',', $values); |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * Search in the db the criteria value used to search against this field. |
||
271 | * @param Tracker_ReportCriteria $criteria |
||
272 | * @return mixed |
||
273 | */ |
||
274 | public function getCriteriaValue($criteria) { |
||
275 | if (empty($this->criteria_value) || empty($this->criteria_value[$criteria->report->id])) { |
||
276 | $this->criteria_value = array(); |
||
277 | |||
278 | if (empty($this->criteria_value[$criteria->report->id])) { |
||
279 | $this->criteria_value[$criteria->report->id] = array(); |
||
280 | |||
281 | if ($criteria->id > 0) { |
||
282 | foreach($this->getCriteriaDao()->searchByCriteriaId($criteria->id) as $row) { |
||
|
|||
283 | $this->criteria_value[$criteria->report->id][] = $row['value']; |
||
284 | } |
||
285 | } |
||
286 | } |
||
287 | |||
288 | } else if (in_array('', $this->criteria_value[$criteria->report->id])) { |
||
289 | return ''; |
||
290 | } |
||
291 | |||
292 | return $this->criteria_value[$criteria->report->id]; |
||
293 | } |
||
294 | |||
295 | public function setCriteriaValueFromSOAP(Tracker_Report_Criteria $criteria, StdClass $soap_criteria_value) { |
||
296 | $soap_criteria_values = explode(',', $soap_criteria_value->value); |
||
297 | $available_field_values = $this->getAllValues(); |
||
298 | $values = array(); |
||
299 | $criterias = array(); |
||
300 | |||
301 | foreach ($available_field_values as $field_value_id => $field_value) { |
||
302 | $values[$field_value->getLabel()] = $field_value_id; |
||
303 | } |
||
304 | |||
305 | foreach ($soap_criteria_values as $soap_criteria_value) { |
||
306 | // Check if the SOAP string only contains digits |
||
307 | if (ctype_digit($soap_criteria_value)) { |
||
308 | $criterias[] = $soap_criteria_value; |
||
309 | } else { |
||
310 | $field_value_id = $values[$soap_criteria_value]; |
||
311 | if ($field_value_id) { |
||
312 | $criterias[] = $field_value_id; |
||
313 | } |
||
314 | } |
||
315 | } |
||
316 | $this->setCriteriaValue($criterias, $criteria->report->id); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * @throws Tracker_Report_InvalidRESTCriterionException |
||
321 | */ |
||
322 | public function setCriteriaValueFromREST(Tracker_Report_Criteria $criteria, array $rest_criteria_value) { |
||
323 | $searched_field_values = $rest_criteria_value[Tracker_Report_REST::VALUE_PROPERTY_NAME]; |
||
324 | $operator = $rest_criteria_value[Tracker_Report_REST::OPERATOR_PROPERTY_NAME]; |
||
325 | |||
326 | if ($operator !== Tracker_Report_REST::OPERATOR_CONTAINS) { |
||
327 | throw new Tracker_Report_InvalidRESTCriterionException("Unallowed operator for criterion field '$this->name' ($this->id). Allowed operators: [" . Tracker_Report_REST::OPERATOR_CONTAINS . "]"); |
||
328 | } |
||
329 | |||
330 | if (is_numeric($searched_field_values)) { |
||
331 | $values_to_match = array((int) $searched_field_values); |
||
332 | } elseif(is_array($searched_field_values)) { |
||
333 | $values_to_match = $searched_field_values; |
||
334 | } else { |
||
335 | throw new Tracker_Report_InvalidRESTCriterionException("Invalid format for criterion field '$this->name' ($this->id)"); |
||
336 | } |
||
337 | |||
338 | $available_field_values = $this->getAllValues(); |
||
339 | $criterias = array(); |
||
340 | |||
341 | foreach ($values_to_match as $value_to_match) { |
||
342 | if (! is_numeric($value_to_match)) { |
||
343 | throw new Tracker_Report_InvalidRESTCriterionException("Invalid format for criterion field '$this->name' ($this->id)"); |
||
344 | } |
||
345 | |||
346 | if ($value_to_match == self::NONE_VALUE) { |
||
347 | continue; |
||
348 | } |
||
349 | |||
350 | if (! isset($available_field_values[$value_to_match])) { |
||
351 | continue; |
||
352 | } |
||
353 | |||
354 | $criterias[] = $value_to_match; |
||
355 | } |
||
356 | |||
357 | $this->setCriteriaValue($criterias, $criteria->report->id); |
||
358 | |||
359 | return count($criterias) > 0; |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Format the criteria value submitted by the user for storage purpose (dao or session) |
||
364 | * |
||
365 | * @param mixed $value The criteria value submitted by the user |
||
366 | * |
||
367 | * @return mixed |
||
368 | */ |
||
369 | public function getFormattedCriteriaValue($value) { |
||
370 | if ( empty($value['values']) ) { |
||
371 | $value['values'] = array(''); |
||
372 | } |
||
373 | return $value['values']; |
||
374 | } |
||
375 | |||
376 | /** |
||
377 | * Display the field value as a criteria |
||
378 | * @param Tracker_ReportCriteria $criteria |
||
379 | * @return string |
||
380 | * @see fetchCriteria |
||
381 | */ |
||
382 | public function fetchCriteriaValue($criteria) { |
||
383 | $hp = Codendi_HTMLPurifier::instance(); |
||
384 | $html = ''; |
||
385 | $criteria_value = $this->getCriteriaValue($criteria); |
||
386 | if ( ! is_array($criteria_value)) { |
||
387 | $criteria_value = array($criteria_value); |
||
388 | } |
||
389 | |||
390 | $multiple = ' '; |
||
391 | $size = ' '; |
||
392 | $prefix_name = "criteria[$this->id][values]"; |
||
393 | $name = $prefix_name . '[]'; |
||
394 | |||
395 | if ($criteria->is_advanced) { |
||
396 | $multiple = ' multiple="multiple" '; |
||
397 | $size = ' size="'. min(7, count($this->getBind()->getAllValues()) + 2) .'" '; |
||
398 | } |
||
399 | |||
400 | $html .= '<input type="hidden" name="'. $prefix_name .'" />'; |
||
401 | $html .= '<select id="tracker_report_criteria_'. ($criteria->is_advanced ? 'adv_' : '') . $this->id .'" |
||
402 | name="'. $name .'" '. |
||
403 | $size . |
||
404 | $multiple .'>'; |
||
405 | //Any value |
||
406 | $selected = count($criteria_value) && !in_array('', $criteria_value) ? '' : 'selected="selected"'; |
||
407 | $html .= '<option value="" '. $selected .' title="'. $GLOBALS['Language']->getText('global','any') .'">'. $GLOBALS['Language']->getText('global','any') .'</option>'; |
||
408 | //None value |
||
409 | $selected = in_array(Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID, $criteria_value) ? 'selected="selected"' : ''; |
||
410 | $html .= '<option value="'.Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID.'" '. $selected .' title="'. $GLOBALS['Language']->getText('global','none') .'">'. $GLOBALS['Language']->getText('global','none') .'</option>'; |
||
411 | //Field values |
||
412 | foreach($this->getBind()->getAllValues() as $id => $value) { |
||
413 | $selected = in_array($id, $criteria_value) ? 'selected="selected"' : ''; |
||
414 | $style = $this->getBind()->getSelectOptionInlineStyle($id); |
||
415 | $html .= '<option value="'. $id .'" title="'. $this->getBind()->formatCriteriaValue($id) .'" '. $selected .' style="'. $style .'">'; |
||
416 | $html .= $this->getBind()->formatCriteriaValue($id); |
||
417 | $html .= '</option>'; |
||
418 | } |
||
419 | $html .= '</select>'; |
||
420 | |||
421 | return $html; |
||
422 | } |
||
423 | |||
424 | /** |
||
425 | * Add some additionnal information beside the criteria. |
||
426 | * This is up to the field. It can be html or inline javascript |
||
427 | * to enhance the user experience |
||
428 | * @return string |
||
429 | */ |
||
430 | public function fetchCriteriaAdditionnalInfo() { |
||
433 | /** |
||
434 | * Add some additionnal information beside the field in the artifact form. |
||
435 | * This is up to the field. It can be html or inline javascript |
||
436 | * to enhance the user experience |
||
437 | * @return string |
||
438 | */ |
||
439 | public function fetchArtifactAdditionnalInfo($value, $submitted_values = null) { |
||
442 | |||
443 | /** |
||
444 | * Add some additionnal information beside the field in the submit new artifact form. |
||
445 | * This is up to the field. It can be html or inline javascript |
||
446 | * to enhance the user experience |
||
447 | * @return string |
||
448 | */ |
||
449 | public function fetchSubmitAdditionnalInfo($submitted_values) { |
||
452 | |||
453 | /** |
||
454 | * @return bool |
||
455 | */ |
||
456 | protected function criteriaCanBeAdvanced() { |
||
459 | |||
460 | /** |
||
461 | * Fetch the value |
||
462 | * @param mixed $value the value of the field |
||
463 | * @return string |
||
464 | */ |
||
465 | public function fetchRawValue($value) { |
||
468 | |||
469 | /** |
||
470 | * Fetch the value in a specific changeset |
||
471 | * @param Tracker_Artifact_Changeset $changeset |
||
472 | * @return string |
||
473 | */ |
||
474 | public function fetchRawValueFromChangeset($changeset) { |
||
477 | |||
478 | /** |
||
479 | * @return Tracker_FormElement_Field_Value_ListDao |
||
480 | */ |
||
481 | protected function getValueDao() { |
||
484 | |||
485 | /** |
||
486 | * Fetch the html code to display the field value in new artifact submission form |
||
487 | * |
||
488 | * @return string html |
||
489 | */ |
||
490 | protected function fetchSubmitValue($submitted_values = array()) { |
||
491 | $selected_values = isset($submitted_values[$this->id]) ? $submitted_values[$this->id] : array(); |
||
492 | $default_values = $this->getSubmitDefaultValues(); |
||
493 | |||
494 | return $this->_fetchField( |
||
495 | 'tracker_field_'. $this->id, |
||
496 | 'artifact['. $this->id .']', |
||
497 | $default_values, |
||
498 | $selected_values |
||
499 | ); |
||
500 | } |
||
501 | |||
502 | private function getSubmitDefaultValues() { |
||
503 | if ($this->fieldHasEnableWorkflow()) { |
||
504 | return array(); |
||
505 | } |
||
506 | |||
507 | return $this->getBind()->getDefaultValues(); |
||
508 | } |
||
509 | |||
510 | /** |
||
511 | * Fetch the html code to display the field value in masschange submission form |
||
512 | * |
||
513 | * @return string html |
||
514 | */ |
||
515 | protected function fetchSubmitValueMasschange() { |
||
518 | /** |
||
519 | * Fetch the html code to display the field value in artifact |
||
520 | * |
||
521 | * @param Tracker_Artifact $artifact The artifact |
||
522 | * @param Tracker_Artifact_ChangesetValue $value The actual value of the field |
||
523 | * @param array $submitted_values The value already submitted by the user |
||
524 | * |
||
525 | * @return string |
||
526 | */ |
||
527 | protected function fetchArtifactValue(Tracker_Artifact $artifact, Tracker_Artifact_ChangesetValue $value = null, $submitted_values = array()) { |
||
537 | |||
538 | /** |
||
539 | * Fetch the field value in artifact to be displayed in mail |
||
540 | * |
||
541 | * @param Tracker_Artifact $artifact The artifact |
||
542 | * @param PFUser $user The user who will receive the email |
||
543 | * @param Tracker_Artifact_ChangesetValue $value The actual value of the field |
||
544 | * @param string $format mail format |
||
545 | * |
||
546 | * @return string |
||
547 | */ |
||
548 | public function fetchMailArtifactValue(Tracker_Artifact $artifact, PFUser $user, Tracker_Artifact_ChangesetValue $value = null, $format='text') { |
||
549 | $output = ''; |
||
550 | switch($format) { |
||
551 | case 'html': |
||
552 | if ( empty($value) || !$value->getListValues()) { |
||
553 | return '-'; |
||
554 | } |
||
555 | $output = $this->fetchArtifactValueReadOnly($artifact, $value); |
||
556 | break; |
||
557 | default: |
||
558 | $tablo = array(); |
||
559 | $selected_values = !empty($value) ? $value->getListValues() : array(); |
||
560 | foreach ($selected_values as $value) { |
||
561 | $tablo[] = $this->getBind()->formatMailArtifactValue($value->getId()); |
||
562 | } |
||
563 | $output = implode(', ', $tablo); |
||
564 | break; |
||
565 | } |
||
566 | return $output; |
||
567 | } |
||
568 | |||
569 | /** |
||
570 | * Fetch the html code to display the field value in artifact in read only mode |
||
571 | * |
||
572 | * @param Tracker_Artifact $artifact The artifact |
||
573 | * @param Tracker_Artifact_ChangesetValue $value The actual value of the field |
||
574 | * |
||
575 | * @return string |
||
576 | */ |
||
577 | public function fetchArtifactValueReadOnly(Tracker_Artifact $artifact, Tracker_Artifact_ChangesetValue $value = null) { |
||
592 | |||
593 | public function fetchArtifactValueWithEditionFormIfEditable(Tracker_Artifact $artifact, Tracker_Artifact_ChangesetValue $value = null, $submitted_values = array()) { |
||
596 | |||
597 | /** |
||
598 | * Indicate if a workflow is defined and enabled on a field_id. |
||
599 | * @param $id the field_id |
||
600 | * @return boolean, true if a workflow is defined and enabled on the field_id |
||
601 | */ |
||
602 | public function fieldHasEnableWorkflow(){ |
||
603 | $workflow = $this->getWorkflow(); |
||
604 | if(!empty($workflow) && $workflow->is_used){ |
||
605 | return $workflow->field_id===$this->id; |
||
606 | } |
||
607 | return false; |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Indicate if a workflow is defined on a field_id. |
||
612 | * @param $id the field_id |
||
613 | * @return boolean, true if a workflow is defined on the field_id |
||
614 | */ |
||
615 | public function fieldHasDefineWorkflow(){ |
||
616 | $workflow = $this->getWorkflow(); |
||
617 | if(!empty($workflow)){ |
||
618 | return $workflow->field_id===$this->id; |
||
619 | } |
||
620 | return false; |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * Get the workflow of the tracker. |
||
625 | * @return Workflow Object |
||
626 | */ |
||
627 | public function getWorkflow(){ |
||
630 | |||
631 | /** |
||
632 | * Validate a value |
||
633 | * @param Tracker_Artifact $artifact |
||
634 | * @param mixed $value data coming from the request. May be string or array. |
||
635 | * |
||
636 | * @return bool true if the value is considered ok |
||
637 | */ |
||
638 | protected function validate(Tracker_Artifact $artifact, $value) { |
||
639 | $valid = true; |
||
640 | $field_value_to = null; |
||
641 | |||
642 | if ($this->fieldHasEnableWorkflow()) { |
||
643 | |||
644 | $last_changeset = $artifact->getLastChangeset(); |
||
645 | |||
646 | try { |
||
647 | $field_value_to = $this->getBind()->getValue($value); |
||
648 | if (!$last_changeset) { |
||
649 | if (!$this->isTransitionValid(null, $field_value_to)) { |
||
650 | $this->has_errors = true; |
||
651 | $valid = false; |
||
652 | } |
||
653 | } else { |
||
654 | if ($last_changeset->getValue($this)!=null) { |
||
655 | foreach ($last_changeset->getValue($this)->getListValues() as $id => $value) { |
||
656 | if ($value != $field_value_to) { |
||
657 | if (!$this->isTransitionValid($value, $field_value_to)) { |
||
658 | $this->has_errors = true; |
||
659 | $valid = false; |
||
660 | } |
||
661 | } |
||
662 | } |
||
663 | } else { |
||
664 | if (!$this->isTransitionValid(null, $field_value_to)) { |
||
665 | $this->has_errors = true; |
||
666 | $valid = false; |
||
667 | } |
||
668 | } |
||
669 | } |
||
670 | } catch (Tracker_FormElement_InvalidFieldValueException $exexption) { |
||
671 | $valid = false; |
||
672 | } |
||
673 | |||
674 | if ($valid) { |
||
675 | //Check permissions on transition |
||
676 | if (!$last_changeset || $last_changeset->getValue($this) == null) { |
||
677 | $from = null; |
||
678 | $to = $value; |
||
679 | } else { |
||
680 | list(, $from) = each ($last_changeset->getValue($this)->getListValues()); |
||
681 | if (!is_string($value)) { |
||
682 | $to = $value->getId(); |
||
683 | }else { |
||
684 | $to = $value; |
||
685 | } |
||
686 | } |
||
687 | $transition_id = $this->getTransitionId($from, $to); |
||
688 | if (!$this->userCanMakeTransition($transition_id)) { |
||
689 | $valid = false; |
||
690 | } |
||
691 | } |
||
692 | } |
||
693 | |||
694 | if ($valid) { |
||
695 | return true; |
||
696 | } else { |
||
697 | if ($field_value_to !== null) { |
||
698 | $GLOBALS['Response']->addFeedback('error', $GLOBALS['Language']->getText('plugin_tracker_common_artifact', 'transition_not_valid', array($field_value_to->getLabel()))); |
||
699 | } else { |
||
700 | $GLOBALS['Response']->addFeedback('error', $GLOBALS['Language']->getText('plugin_tracker_common_artifact', 'transition_to_none')); |
||
701 | } |
||
702 | return false; |
||
703 | } |
||
704 | } |
||
705 | |||
706 | |||
707 | protected function isTransitionValid($field_value_from, $field_value_to){ |
||
708 | if (!$this->fieldHasEnableWorkflow()) { |
||
709 | return true; |
||
710 | }else { |
||
711 | $workflow = $this->getWorkflow(); |
||
712 | if ($workflow->isTransitionExist($field_value_from, $field_value_to)) { |
||
713 | return true; |
||
714 | }else return false; |
||
715 | } |
||
716 | } |
||
717 | |||
718 | protected function getSelectedValue($selected_values) { |
||
729 | |||
730 | /** |
||
731 | * @return array of BindValues |
||
732 | */ |
||
733 | public function getAllValues() { |
||
736 | |||
737 | /** |
||
738 | * @return array of BindValues that are not hidden + none value if any |
||
739 | */ |
||
740 | public function getVisibleValuesPlusNoneIfAny() { |
||
741 | $values = $this->getAllValues(); |
||
742 | foreach ($values as $key => $value) { |
||
743 | if ($value->isHidden()) { |
||
744 | unset($values[$key]); |
||
745 | } |
||
746 | } |
||
747 | if ($values) { |
||
748 | if (! $this->isRequired()) { |
||
749 | $none = new Tracker_FormElement_Field_List_Bind_StaticValue_None(); |
||
750 | $values = array($none->getId() => $none) + $values; |
||
751 | } |
||
752 | } |
||
753 | return $values; |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * @return Tracker_FormElement_Field_List_Value or null if not found |
||
758 | */ |
||
759 | public function getListValueById($value_id) { |
||
760 | foreach ($this->getVisibleValuesPlusNoneIfAny() as $value) { |
||
761 | if ($value->getId() == $value_id) { |
||
762 | return $value; |
||
763 | } |
||
764 | } |
||
765 | } |
||
766 | |||
767 | /** |
||
768 | * |
||
769 | * @param Tracker_Artifact_Changeset $changeset |
||
770 | * @return string |
||
771 | */ |
||
772 | public function getFirstValueFor(Tracker_Artifact_Changeset $changeset) { |
||
773 | if ($this->userCanRead()) { |
||
774 | $value = $changeset->getValue($this); |
||
775 | if ($value && ($last_values = $value->getListValues())) { |
||
776 | // let's assume there is no more that one status |
||
777 | if ($label = array_shift($last_values)->getLabel()) { |
||
778 | return $label; |
||
779 | } |
||
780 | } |
||
781 | } |
||
782 | } |
||
783 | |||
784 | protected function _fetchField($id, $name, $selected_values, $submitted_values = array()) { |
||
785 | $html = ''; |
||
786 | $purifier = Codendi_HTMLPurifier::instance(); |
||
787 | |||
788 | if ($name) { |
||
789 | if ($this->isMultiple()) { |
||
790 | $name .= '[]'; |
||
791 | } |
||
792 | $name = 'name="'. $purifier->purify($name) .'"'; |
||
793 | } |
||
794 | |||
795 | if ($id) { |
||
796 | $id = 'id="'. $id .'"'; |
||
797 | } |
||
798 | |||
799 | $html .= $this->fetchFieldContainerStart($id, $name); |
||
800 | |||
801 | $from = $this->getSelectedValue($selected_values); |
||
802 | if ($from == null && !isset($submitted_values)) { |
||
803 | $none_is_selected = isset($selected_values[Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID]); |
||
804 | } else { |
||
805 | $none_is_selected = ($submitted_values==Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID); |
||
806 | } |
||
807 | |||
808 | if (!$this->fieldHasEnableWorkflow()) { |
||
809 | $none_value = new Tracker_FormElement_Field_List_Bind_StaticValue_None(); |
||
810 | $html .= $this->fetchFieldValue($none_value, $name, $none_is_selected); |
||
811 | } |
||
812 | |||
813 | if (($submitted_values) && !is_array($submitted_values)) { |
||
814 | $submitted_values_array[] = $submitted_values; |
||
815 | $submitted_values = $submitted_values_array; |
||
816 | } |
||
817 | |||
818 | foreach($this->getBind()->getAllValues() as $id => $value) { |
||
819 | $transition_id = null; |
||
820 | if ($this->isTransitionValid($from, $value)) { |
||
821 | $transition_id = $this->getTransitionId($from, $value->getId()); |
||
822 | if (!empty($submitted_values)) { |
||
823 | $is_selected = in_array($id, array_values($submitted_values)); |
||
824 | } else { |
||
825 | $is_selected = isset($selected_values[$id]); |
||
826 | } |
||
827 | if ($this->userCanMakeTransition($transition_id)) { |
||
828 | if (!$value->isHidden()) { |
||
829 | $html .= $this->fetchFieldValue($value, $name, $is_selected); |
||
830 | } |
||
831 | } |
||
832 | } |
||
833 | } |
||
834 | |||
835 | $html .= $this->fetchFieldContainerEnd(); |
||
836 | return $html; |
||
837 | } |
||
838 | |||
839 | protected function fetchFieldContainerStart($id, $name) { |
||
840 | $html = ''; |
||
841 | $multiple = ''; |
||
842 | $size = ''; |
||
843 | if ($this->isMultiple()) { |
||
844 | $multiple = 'multiple="multiple"'; |
||
845 | $size = 'size="'. min($this->getMaxSize(), count($this->getBind()->getAllValues()) + 2) .'"'; |
||
846 | } |
||
847 | $html .= "<select $id $name $multiple $size>"; |
||
848 | return $html; |
||
849 | } |
||
850 | |||
851 | protected function fetchFieldValue(Tracker_FormElement_Field_List_Value $value, $name, $is_selected) { |
||
852 | $id = $value->getId(); |
||
853 | if ($id == Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID) { |
||
854 | $label = $value->getLabel(); |
||
855 | } else { |
||
856 | $label = $this->getBind()->formatArtifactValue($id); |
||
857 | } |
||
858 | $style = $this->getBind()->getSelectOptionInlineStyle($id); |
||
859 | $selected = $is_selected ? 'selected="selected"' : ''; |
||
860 | return '<option value="'. $id .'" '. $selected .' title="'. $label .'" style="'. $style .'">'. $label .'</option>'; |
||
861 | } |
||
862 | |||
863 | protected function fetchFieldContainerEnd() { |
||
866 | |||
867 | |||
868 | protected function _fetchFieldMasschange($id, $name, $selected_values) { |
||
869 | $html = ''; |
||
870 | $multiple = ' '; |
||
871 | $size = ' '; |
||
872 | if ($this->isMultiple()) { |
||
873 | $multiple = ' multiple="multiple" '; |
||
874 | $size = ' size="'. min($this->getMaxSize(), count($this->getBind()->getAllValues()) + 2) .'" '; |
||
875 | if ($name) { |
||
876 | $name .= '[]'; |
||
877 | } |
||
878 | } |
||
879 | $html .= '<select '; |
||
880 | if ($id) { |
||
881 | $html .= 'id="'. $id .'" '; |
||
882 | } |
||
883 | if ($name) { |
||
884 | $html .= 'name="'. $name .'" '; |
||
885 | } |
||
886 | $html .= $size . $multiple .'>'; |
||
887 | |||
888 | //if ( $this->fieldHasEnableWorkflow() ) { |
||
889 | $html .= '<option value="'.$GLOBALS['Language']->getText('global','unchanged').'" selected="selected">'. $GLOBALS['Language']->getText('global','unchanged') .'</option>'; |
||
890 | $html .= '<option value="'.Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID.'">'. $GLOBALS['Language']->getText('global','none') .'</option>'; |
||
891 | //} |
||
892 | |||
893 | foreach($this->getBind()->getAllValues() as $id => $value) { |
||
894 | if (!$value->isHidden()) { |
||
895 | $style = $this->getBind()->getSelectOptionInlineStyle($id); |
||
896 | $html .= '<option value="'. $id .'" title="'. $this->getBind()->formatArtifactValue($id) .'" style="'. $style .'">'; |
||
897 | $html .= $this->getBind()->formatArtifactValue($id); |
||
898 | $html .= '</option>'; |
||
899 | } |
||
900 | } |
||
901 | |||
902 | $html .= '</select>'; |
||
903 | return $html; |
||
904 | } |
||
905 | |||
906 | |||
907 | protected function getMaxSize() { |
||
910 | |||
911 | /** |
||
912 | * Fetch the changes that has been made to this field in a followup |
||
913 | * @param Tracker_ $artifact |
||
914 | * @param array $from the value(s) *before* |
||
915 | * @param array $to the value(s) *after* |
||
916 | */ |
||
917 | public function fetchFollowUp($artifact, $from, $to) { |
||
918 | $html = ''; |
||
919 | $values = array(); |
||
920 | if ($from && isset($from['changeset_id'])) { |
||
921 | foreach($this->getBind()->getChangesetValues($from['changeset_id']) as $v) { |
||
922 | if ($v['id'] != Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID) { |
||
923 | $values[] = $this->getBind()->formatChangesetValue($v); |
||
924 | } |
||
925 | } |
||
926 | $from_value = implode(', ', $values); |
||
927 | } |
||
928 | |||
929 | if (!$from_value) { |
||
930 | $html .= $GLOBALS['Language']->getText('plugin_tracker_artifact','set_to').' '; |
||
931 | } else { |
||
932 | $html .= ' '.$GLOBALS['Language']->getText('plugin_tracker_artifact','changed_from').' '. $from_value .' '.$GLOBALS['Language']->getText('plugin_tracker_artifact','to').' '; |
||
933 | } |
||
934 | |||
935 | $values = array(); |
||
936 | foreach($this->getBind()->getfChangesetValues($to['changeset_id']) as $v) { |
||
937 | $values[] = $this->getBind()->formatChangesetValue($v); |
||
938 | } |
||
939 | $html .= implode(', ', $values); |
||
940 | return $html; |
||
941 | } |
||
942 | |||
943 | /** |
||
944 | * Display the html field in the admin ui |
||
945 | * @return string html |
||
946 | */ |
||
947 | protected function fetchAdminFormElement() { |
||
948 | $html = ''; |
||
949 | $html .= $this->_fetchField('', '', $this->getBind()->getDefaultValues()); |
||
950 | return $html; |
||
951 | } |
||
952 | |||
953 | /** |
||
954 | * Fetch the html code to display the field value in tooltip |
||
955 | * @param Tracker_Artifact $artifact |
||
956 | * @param Tracker_Artifact_ChangesetValue_List $value The changeset value of this field |
||
957 | * @return string The html code to display the field value in tooltip |
||
958 | */ |
||
959 | protected function fetchTooltipValue(Tracker_Artifact $artifact, Tracker_Artifact_ChangesetValue $value = null) { |
||
960 | $html = ''; |
||
961 | if ($value) { |
||
962 | $html .= $this->fetchChangesetValue($artifact->id, $artifact->getLastChangeset()->id, $value); |
||
963 | } |
||
964 | return $html; |
||
965 | } |
||
966 | |||
967 | /** |
||
968 | * @see Tracker_FormElement_Field::fetchCardValue() |
||
969 | */ |
||
970 | public function fetchCardValue(Tracker_Artifact $artifact, Tracker_CardDisplayPreferences $display_preferences) { |
||
971 | $html = ''; |
||
972 | //We have to fetch all values of the changeset as we are a list of value |
||
973 | //This is the case only if we are multiple but an old changeset may |
||
974 | //contain multiple values |
||
975 | $values = array(); |
||
976 | foreach($this->getBind()->getChangesetValues($artifact->getLastChangeset()->id) as $v) { |
||
977 | $val = $this->getBind()->formatCardValue($v, $display_preferences); |
||
978 | if ($val != '') { |
||
979 | $values[] = $val; |
||
980 | } |
||
981 | } |
||
982 | $html .= implode(' ', $values); |
||
983 | return $html; |
||
984 | } |
||
985 | |||
986 | /** |
||
987 | * Update the form element. |
||
988 | * Override the parent function to handle binds |
||
989 | * |
||
990 | * @return void |
||
991 | */ |
||
992 | protected function processUpdate(TrackerManager $tracker_manager, $request, $current_user) { |
||
993 | $redirect = false; |
||
994 | if ($request->exist('bind')) { |
||
995 | $redirect = $this->getBind()->process($request->get('bind'), $no_redirect = true); |
||
996 | } |
||
997 | parent::processUpdate($tracker_manager, $request, $current_user, $redirect); |
||
998 | } |
||
999 | |||
1000 | /** |
||
1001 | * Hook called after a creation of a field |
||
1002 | * |
||
1003 | * @param array $data The data used to create the field |
||
1004 | * |
||
1005 | * @return void |
||
1006 | */ |
||
1007 | public function afterCreate($formElement_data) { |
||
1018 | |||
1019 | /** |
||
1020 | * Transforms FormElement_List into a SimpleXMLElement |
||
1021 | */ |
||
1022 | public function exportToXml( |
||
1023 | SimpleXMLElement $root, |
||
1024 | &$xmlMapping, |
||
1025 | $project_export_context, |
||
1026 | UserXMLExporter $user_xml_exporter |
||
1027 | ) { |
||
1028 | parent::exportToXML($root, $xmlMapping, $project_export_context, $user_xml_exporter); |
||
1029 | if ($this->getBind() && $this->shouldBeBindXML()) { |
||
1030 | $child = $root->addChild('bind'); |
||
1031 | $bf = new Tracker_FormElement_Field_List_BindFactory(); |
||
1032 | $child->addAttribute('type', $bf->getType($this->getBind())); |
||
1033 | $this->getBind()->exportToXML($child, $xmlMapping, $project_export_context, $user_xml_exporter); |
||
1034 | } |
||
1035 | } |
||
1036 | |||
1037 | /** |
||
1038 | * Say if we export the bind in the XML |
||
1039 | * |
||
1040 | * @return bool |
||
1041 | */ |
||
1042 | public function shouldBeBindXML() { |
||
1045 | |||
1046 | /** |
||
1047 | * Continue the initialisation from an xml (FormElementFactory is not smart enough to do all stuff. |
||
1048 | * Polymorphism rulez!!! |
||
1049 | * |
||
1050 | * @param SimpleXMLElement $xml containing the structure of the imported Tracker_FormElement |
||
1051 | * @param array &$xmlMapping where the newly created formElements indexed by their XML IDs are stored (and values) |
||
1052 | * |
||
1053 | * @return void |
||
1054 | */ |
||
1055 | public function continueGetInstanceFromXML( |
||
1056 | $xml, |
||
1057 | &$xmlMapping, |
||
1058 | User\XML\Import\IFindUserFromXMLReference $user_finder |
||
1059 | ) { |
||
1060 | parent::continueGetInstanceFromXML($xml, $xmlMapping, $user_finder); |
||
1061 | // if field is a list add bind |
||
1062 | if ($xml->bind) { |
||
1063 | $bind = $this->getBindFactory()->getInstanceFromXML($xml->bind, $this, $xmlMapping, $user_finder); |
||
1064 | $this->setBind($bind); |
||
1065 | } |
||
1066 | } |
||
1067 | |||
1068 | /** |
||
1069 | * Callback called after factory::saveObject. Use this to do post-save actions |
||
1070 | * |
||
1071 | * @param Tracker $tracker The tracker |
||
1072 | * |
||
1073 | * @return void |
||
1074 | */ |
||
1075 | public function afterSaveObject(Tracker $tracker) { |
||
1076 | $bind = $this->getBind(); |
||
1077 | $this->getListDao()->save($this->getId(), $this->getBindFactory()->getType($bind)); |
||
1078 | $bind->saveObject(); |
||
1079 | } |
||
1080 | |||
1081 | /** |
||
1082 | * Get an instance of Tracker_FormElement_Field_ListDao |
||
1083 | * |
||
1084 | * @return Tracker_FormElement_Field_ListDao |
||
1085 | */ |
||
1086 | public function getListDao() { |
||
1089 | |||
1090 | /** |
||
1091 | * Get an instance of Tracker_FormElement_Field_List_BindFactory |
||
1092 | * |
||
1093 | * @return Tracker_FormElement_Field_List_BindFactory |
||
1094 | */ |
||
1095 | function getBindFactory() { |
||
1098 | |||
1099 | /** |
||
1100 | * Save the value and return the id |
||
1101 | * |
||
1102 | * @param Tracker_Artifact $artifact The artifact |
||
1103 | * @param int $changeset_value_id The id of the changeset_value |
||
1104 | * @param mixed $value The value submitted by the user |
||
1105 | * @param Tracker_Artifact_ChangesetValue $previous_changesetvalue The data previously stored in the db |
||
1106 | * |
||
1107 | * @return boolean |
||
1108 | */ |
||
1109 | protected function saveValue($artifact, $changeset_value_id, $value, Tracker_Artifact_ChangesetValue $previous_changesetvalue = null) { |
||
1112 | |||
1113 | /** |
||
1114 | * Get the value of this field |
||
1115 | * |
||
1116 | * @param Tracker_Artifact_Changeset $changeset The changeset (needed in only few cases like 'lud' field) |
||
1117 | * @param int $value_id The id of the value |
||
1118 | * @param boolean $has_changed If the changeset value has changed from the rpevious one |
||
1119 | * |
||
1120 | * @return Tracker_Artifact_ChangesetValue or null if not found |
||
1121 | */ |
||
1122 | public function getChangesetValue($changeset, $value_id, $has_changed) { |
||
1123 | $changeset_value = null; |
||
1124 | $value_ids = $this->getValueDao()->searchById($value_id, $this->id); |
||
1125 | $bindvalue_ids = array(); |
||
1126 | foreach($value_ids as $v) { |
||
1127 | $bindvalue_ids[] = $v['bindvalue_id']; |
||
1128 | } |
||
1129 | $bind_values = array(); |
||
1130 | if (count($bindvalue_ids)) { |
||
1131 | $bind_values = $this->getBind()->getBindValues($bindvalue_ids); |
||
1132 | } |
||
1133 | $changeset_value = new Tracker_Artifact_ChangesetValue_List($value_id, $this, $has_changed, $bind_values); |
||
1134 | return $changeset_value; |
||
1135 | } |
||
1136 | |||
1137 | /** |
||
1138 | * Get available values of this field for SOAP usage |
||
1139 | * Fields like int, float, date, string don't have available values |
||
1140 | * |
||
1141 | * @return mixed The values or null if there are no specific available values |
||
1142 | */ |
||
1143 | public function getSoapAvailableValues() { |
||
1144 | $values = null; |
||
1145 | $bind = $this->getBind(); |
||
1146 | if ($bind != null) { |
||
1147 | $values = $bind->getSoapAvailableValues(); |
||
1148 | } |
||
1149 | return $values; |
||
1150 | } |
||
1151 | |||
1152 | public function getSoapBindingProperties() { |
||
1156 | |||
1157 | public function getFieldDataFromRESTValue(array $value, Tracker_Artifact $artifact = null) { |
||
1158 | if (array_key_exists('bind_value_ids', $value) && is_array($value['bind_value_ids'])) { |
||
1159 | return array_map('intval', $value['bind_value_ids']); |
||
1160 | } |
||
1161 | throw new Tracker_FormElement_InvalidFieldValueException('List fields values must be passed as an array of ids (integer) in \'bind_value_ids\'' |
||
1162 | . ' Example: {"field_id": 1548, "bind_value_ids": [457]}'); |
||
1163 | } |
||
1164 | |||
1165 | public function getFieldDataFromRESTValueByField($value, Tracker_Artifact $artifact = null) { |
||
1168 | |||
1169 | public function getFieldDataFromSoapValue(stdClass $soap_value, Tracker_Artifact $artifact = null) { |
||
1184 | |||
1185 | /** |
||
1186 | * Get the field data for artifact submission |
||
1187 | * |
||
1188 | * @param string the soap field value |
||
1189 | * |
||
1190 | * @return mixed the field data corresponding to the soap_value for artifact submision |
||
1191 | */ |
||
1192 | public function getFieldData($soap_value) { |
||
1209 | |||
1210 | /** |
||
1211 | * Check if there are changes between old and new value for this field |
||
1212 | * |
||
1213 | * @param Tracker_Artifact_ChangesetValue $previous_changesetvalue The data stored in the db |
||
1214 | * @param mixed $new_value May be string or array |
||
1215 | * |
||
1216 | * @return bool true if there are differences |
||
1217 | */ |
||
1218 | public function hasChanges($previous_changesetvalue, $new_value) { |
||
1219 | if (!is_array($new_value)) { |
||
1220 | $new_value = array($new_value); |
||
1221 | } |
||
1222 | if (empty($new_value)) { |
||
1223 | $new_value = array(Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID); |
||
1224 | } |
||
1225 | if ($previous_changesetvalue) { |
||
1226 | $old_value = $previous_changesetvalue->getValue(); |
||
1227 | } |
||
1228 | if (empty($old_value)) { |
||
1229 | $old_value = array(Tracker_FormElement_Field_List_Bind_StaticValue_None::VALUE_ID); |
||
1230 | } |
||
1231 | sort($old_value); |
||
1232 | sort($new_value); |
||
1233 | return $old_value != $new_value; |
||
1234 | } |
||
1235 | |||
1236 | /** |
||
1237 | * Say if this fields suport notifications |
||
1238 | * |
||
1239 | * @return bool |
||
1240 | */ |
||
1241 | public function isNotificationsSupported() { |
||
1242 | if ($b = $this->getBind()) { |
||
1243 | return $b->isNotificationsSupported(); |
||
1244 | } |
||
1245 | return false; |
||
1246 | } |
||
1247 | |||
1248 | protected function permission_is_authorized($type, $transition_id, $user_id, $group_id) { |
||
1249 | include_once 'www/project/admin/permissions.php'; |
||
1250 | |||
1251 | return permission_is_authorized($type, $transition_id, $user_id, $group_id); |
||
1252 | } |
||
1253 | |||
1254 | /** |
||
1255 | * Check if the user can make the transition |
||
1256 | * |
||
1257 | * @param int $transition_id The id of the transition |
||
1258 | * @param PFUser $user The user. If null, take the current user |
||
1259 | * |
||
1260 | *@return boolean true if user has permission on this field |
||
1261 | */ |
||
1262 | public function userCanMakeTransition($transition_id, PFUser $user = null) { |
||
1263 | if ($transition_id) { |
||
1264 | $group_id = $this->getTracker()->getGroupId(); |
||
1265 | |||
1266 | if (!$user) { |
||
1267 | $user = $this->getCurrentUser(); |
||
1268 | } |
||
1269 | return $this->permission_is_authorized('PLUGIN_TRACKER_WORKFLOW_TRANSITION', $transition_id, $user->getId(), $group_id); |
||
1270 | } |
||
1271 | return true; |
||
1272 | } |
||
1273 | |||
1274 | /** |
||
1275 | * Get a recipients list for notifications. This is filled by users fields for example. |
||
1276 | * |
||
1277 | * @param Tracker_Artifact_ChangesetValue $changeset_value The changeset |
||
1278 | * |
||
1279 | * @return array |
||
1280 | */ |
||
1281 | public function getRecipients(Tracker_Artifact_ChangesetValue $changeset_value) { |
||
1284 | |||
1285 | protected function getTransitionId($from, $to) { |
||
1288 | |||
1289 | public function getDefaultValue() { |
||
1290 | $default_array = $this->getBind()->getDefaultValues(); |
||
1291 | if (! $default_array) { |
||
1292 | return array(Tracker_FormElement_Field_List_Bind::NONE_VALUE); |
||
1293 | } |
||
1294 | return array_keys($default_array); |
||
1295 | } |
||
1296 | |||
1297 | |||
1298 | public function getDefaultRESTValue() { |
||
1301 | |||
1302 | /** |
||
1303 | * Say if the value is valid. If not valid set the internal has_error to true. |
||
1304 | * |
||
1305 | * @param Tracker_Artifact $artifact The artifact |
||
1306 | * @param mixed $value data coming from the request. May be string or array. |
||
1307 | * |
||
1308 | * @return bool true if the value is considered ok |
||
1309 | */ |
||
1310 | public function isValid(Tracker_Artifact $artifact, $value) { |
||
1311 | $this->has_errors = ! ($this->isPossibleValue($value) && $this->validate($artifact, $value)); |
||
1312 | |||
1313 | return ! $this->has_errors; |
||
1314 | } |
||
1315 | |||
1316 | /** |
||
1317 | * @return bool |
||
1318 | */ |
||
1319 | protected function isPossibleValue($value) { |
||
1333 | |||
1334 | /** |
||
1335 | * @return bool |
||
1336 | */ |
||
1337 | protected function checkValueExists($value_id, array $all_possible_values) { |
||
1338 | return array_key_exists($value_id, $all_possible_values) || |
||
1339 | $value_id == Tracker_FormElement_Field_List::NONE_VALUE || |
||
1340 | $value_id == Tracker_FormElement_Field_List::NOT_INDICATED_VALUE; |
||
1341 | } |
||
1342 | |||
1343 | /** |
||
1344 | * Validate a required field |
||
1345 | * |
||
1346 | * @param Tracker_Artifact $artifact The artifact to check |
||
1347 | * @param mixed $value The submitted value |
||
1348 | * |
||
1349 | * @return boolean true on success or false on failure |
||
1350 | */ |
||
1351 | public function isValidRegardingRequiredProperty(Tracker_Artifact $artifact, $value) { |
||
1352 | $this->has_errors = false; |
||
1353 | |||
1354 | if ($this->isEmpty($value, $artifact) && $this->isRequired()) { |
||
1355 | $this->addRequiredError(); |
||
1356 | } |
||
1357 | |||
1358 | return ! $this->has_errors; |
||
1359 | } |
||
1360 | |||
1361 | public function isEmpty($value, Tracker_Artifact $artifact) { |
||
1364 | |||
1365 | /** |
||
1366 | * @see Tracker_FormElement_Field_Shareable |
||
1367 | */ |
||
1368 | public function fixOriginalValueIds(array $value_mapping) { |
||
1371 | |||
1372 | /** |
||
1373 | * @see Tracker_FormElement::process() |
||
1374 | */ |
||
1375 | public function process(Tracker_IDisplayTrackerLayout $layout, $request, $current_user) { |
||
1376 | parent::process($layout, $request, $current_user); |
||
1377 | if ($request->get('func') == 'get-values') { |
||
1378 | $GLOBALS['Response']->sendJSON($this->getBind()->fetchFormattedForJson()); |
||
1379 | } |
||
1380 | } |
||
1381 | |||
1382 | public function fetchFormattedForJson() { |
||
1383 | $json = parent::fetchFormattedForJson(); |
||
1384 | $json['values'] = $this->getBind()->fetchFormattedForJson(); |
||
1385 | return $json; |
||
1386 | } |
||
1387 | |||
1388 | public function getRESTAvailableValues() { |
||
1389 | $values = null; |
||
1390 | $bind = $this->getBind(); |
||
1391 | if ($bind != null) { |
||
1392 | $values = $bind->getRESTAvailableValues(); |
||
1393 | } |
||
1394 | return $values; |
||
1395 | } |
||
1396 | |||
1397 | /** |
||
1398 | * @param string $new_value |
||
1399 | * |
||
1400 | * @return int | null |
||
1401 | */ |
||
1402 | public function addBindValue($new_value) { |
||
1405 | } |
||
1406 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.