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.