3 * FusionForge Effort Units
5 * Copyright 2016, Stéphane-Eymeric Bredthauer
6 * http://fusionforge.org
8 * This file is part of FusionForge. FusionForge is free software;
9 * you can redistribute it and/or modify it under the terms of the
10 * GNU General Public License as published by the Free Software
11 * Foundation; either version 2 of the Licence, or (at your option)
14 * FusionForge is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 require_once $gfcommon.'include/FFError.class.php';
24 require_once $gfcommon.'tracker/EffortUnitSet.class.php';
26 class EffortUnit extends FFError {
29 * @var EffortUnitSet $EffortUnitSet Effort unit set to which the unit belongs.
31 private $EffortUnitSet;
34 * @var array $data_array Associative array of data from db.
39 * EffortUnit - EffortUnit object constructor
41 * @param EffortUnitSet $EffortUnitSet Required - Effort Unit Set.
42 * @param integer|boolean $id Required - Id of the Effort Unit you want to instantiate.
43 * @param integer|boolean $res Database result from select query OR associative array of all columns.
45 function __construct(&$EffortUnitSet, $id = false, $res = false) {
46 parent::__construct();
48 $this->EffortUnitSet = &$EffortUnitSet;
51 //setting up an empty object
52 //probably going to call create()
56 if (!$this->fetchData($id)) {
61 // Assoc array was passed in
64 $this->data_array =& $res;
66 if (db_numrows($res) < 1) {
67 //function in class we extended
68 $this->setError(_('Effort Unit Not Found'));
69 $this->data_array = array();
72 //set up an associative array for use by other functions
73 $this->data_array = db_fetch_array_by_row($res, 0);
80 * fetchData - May need to refresh database fields if an update occurred.
82 * @param integer $unit_id The unit_id.
83 * @return boolean success or not
85 function fetchData($unit_id) {
86 $res = db_query_params ('SELECT * FROM effort_unit WHERE unit_id=$1',
88 if (!$res || db_numrows($res) < 1) {
89 $this->setError(sprintf('fetchData(): %s', db_error()));
92 $this->data_array = db_fetch_array($res);
97 * create - Create new Effort Unit in the database.
99 * @param string $name The name of the unit.
100 * @param integer $conversion_factor The conversion factor to define the current unit.
101 * @param integer $to_unit The unity used for the definition of the current unit.
102 * @param integer $unit_position The position of the unit when listed.
103 * @param boolean $is_base_unit True if this unit is a base unit.
104 * @param array $importData For import
105 * @return bool success or not
107 function create($name, $conversion_factor, $to_unit, $unit_position = false, $is_base_unit = false, $importData = array()) {
108 if (!ctype_digit(strval($conversion_factor)) || $conversion_factor<1) {
109 $this->setError(_('Conversion factor must be an integer greater or equal to 1'));
114 $this->setError(_('An Unit name is required'));
117 $res = db_query_params('SELECT 1 FROM effort_unit WHERE is_deleted <> 1 AND unit_name = $1 AND unit_set_id = $2', array(htmlspecialchars($name), $this->EffortUnitSet->GetID()));
118 if (db_numrows($res) > 0) {
119 $this->setError(sprintf(_('Unit name %s already exists'),$name));
124 if(array_key_exists('user', $importData)){
125 $user = $importData['user'];
127 $user = ((session_loggedin()) ? user_getid() : 100);
129 if (array_key_exists('time',$importData)){
130 $time = $importData['time'];
138 if (!$unit_position) {
139 $res = db_query_params('SELECT MAX(unit_position) AS max_position FROM effort_unit WHERE unit_set_id = $1', array($this->EffortUnitSet->GetID()));
140 if (db_numrows($res) > 0) {
141 $unit_position = db_result($res, 0, 'max_position') + 1;
146 $res = db_query_params('INSERT INTO effort_unit(unit_set_id, unit_name, conversion_factor, to_unit, unit_position, is_base_unit, created_date, created_by, modified_date, modified_by) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)',
147 array($this->EffortUnitSet->GetID(), htmlspecialchars($name), $conversion_factor, $to_unit, $unit_position, ($is_base_unit?1:0), $time, $user, $time, $user));
148 if (!$res || db_affected_rows($res) < 1) {
149 $this->setError(_('Error')._(':').' '._('Cannot create Effort Unit')._(':').' '.db_error());
153 $id = db_insertid($res, 'effort_unit', 'unit_id');
155 $this->setError(_('Error')._(':').' '._('Cannot get Effort Unit id')._(':').' '.db_error());
159 if (!$this->fetchData($id)) {
164 $res = db_query_params('UPDATE effort_unit SET to_unit = $1 WHERE unit_id = $2',
166 if (!$res || db_affected_rows($res) < 1) {
167 $this->setError(_('Error')._(':').' '._('Cannot create Effort Unit')._(':').' '.db_error());
177 * getID - get this Effort Unit ID.
179 * @return integer The unit_id.
182 return $this->data_array['unit_id'];
186 * getName - get this Effort Unit name.
188 * @return string The name.
191 return $this->data_array['unit_name'];
195 * getBase - get this Effort Unit base ID.
197 * @return integer unit base ID.
199 function getToUnit() {
200 return $this->data_array['to_unit'];
204 * getToUnitName - get unit name use to define this unit.
206 * @return string unit name use to define this unit.
208 function getToUnitName() {
209 if (!empty($this->data_array['to_unit'])) {
210 $toUnit = new EffortUnit($this->EffortUnitSet, $this->data_array['to_unit']);
211 return $toUnit->getName();
217 * getConversionFactor - get conversion factor that define this unit .
219 * @return integer conversion factor.
221 function getConversionFactor() {
222 return $this->data_array['conversion_factor'];
226 * getPosition - get this Effort Unit display position.
228 * @return integer unit display position.
230 function getPosition() {
231 return $this->data_array['unit_position'];
235 * getEffortUnitSet - get Effort Unit Set of this unit.
237 * @return EffortUnitSet Effort Unit Set.
239 function &getEffortUnitSet(){
240 return $this->EffortUnitSet;
244 * isDeleted - this Effort Unit is or not deleted.
246 * @return boolean is or not deleted.
248 function isDeleted() {
249 return ($this->data_array['is_deleted']?true:false);
253 * isBaseUnit - this Effort Unit is or not the base unit.
255 * @return boolean is or not base unit.
257 function isBaseUnit() {
258 return ($this->data_array['is_base_unit']?true:false);
262 * delete - delete this Effort Unit.
263 * @param array $importData For import
265 * @return boolean success or not.
267 function delete($importData = array()) {
269 if(array_key_exists('user', $importData)){
270 $user = $importData['user'];
272 $user = ((session_loggedin()) ? user_getid() : 100);
274 if (array_key_exists('time',$importData)){
275 $time = $importData['time'];
279 $res = db_query_params ('UPDATE effort_unit SET is_deleted=1, modified_date=$1, modified_by=$2 WHERE unit_id=$3',
280 array ($time, $user, $this->getID())) ;
282 $this->setError(_('Error deleting Effort Unit')._(': ').db_error());
287 // Update unit define with this unit
288 $res = db_query_params('UPDATE effort_unit AS eu1
289 SET conversion_factor = eu1.conversion_factor*eu2.conversion_factor,
290 to_unit = eu2.to_unit
291 FROM effort_unit AS eu2
293 eu1.to_unit = eu2.unit_id AND
295 array($this->getID()));
297 $this->setError(_('Error deleting Effort Unit')._(': ').db_error());
302 // Update extra_field data using this unit
303 $res = db_query_params('WITH t AS (
305 FROM artifact_extra_field_data
306 INNER JOIN artifact_extra_field_list USING (extra_field_id)
307 INNER JOIN artifact_group_list USING (group_artifact_id)
310 field_data like $2 AND
313 UPDATE artifact_extra_field_data AS d
314 SET field_data = CAST(SUBSTRING(field_data FROM \'#"%#"U%\' FOR \'#\') AS INTEGER) || \'U\' || $4
316 WHERE d.data_id = t.data_id',
317 array(ARTIFACT_EXTRAFIELDTYPE_EFFORT,'%U'.$this->getID(), $this->getEffortUnitSet()->getID(), $this->getToUnit()));
319 $this->setError(_('Error deleting Effort Unit')._(': ').db_error());
323 $data_array['is_deleted'] = 1;
329 * update - update this Effort Unit, name or definition.
330 * @param string $name The name of the unit.
331 * @param integer $conversion_factor The conversion factor to define the current unit.
332 * @param integer $to_unit The unity used for the definition of the current unit.
333 * @param array $importData For import
335 * @return boolean success or not.
337 function update($name, $conversion_factor, $to_unit, $importData = array()){
338 if (!ctype_digit(strval($conversion_factor)) || $conversion_factor<1) {
339 $this->setError(_('Conversion factor must be an integer greater or equal to 1'));
344 $this->setError(_('An Unit name is required'));
347 $res = db_query_params('SELECT 1 FROM effort_unit WHERE is_deleted <> 1 AND unit_name = $1 AND unit_id <> $2 AND unit_set_id = $3', array(htmlspecialchars($name), $this->getID(), $this->EffortUnitSet->GetID()));
348 if (db_numrows($res) > 0) {
349 $this->setError(sprintf(_('Unit name %s already exists'),$name));
353 if(array_key_exists('user', $importData)){
354 $user = $importData['user'];
356 $user = ((session_loggedin()) ? user_getid() : 100);
358 if (array_key_exists('time',$importData)){
359 $time = $importData['time'];
363 // get conversion factor for base unit before update
364 $old_factor = $this->getConversionFactorForBaseUnit();
365 // get depenfing units before update
366 $units = array_merge(array($this), $this->getUnitsDependingOn());
367 $res = db_query_params('UPDATE effort_unit SET unit_name=$1, conversion_factor=$2, to_unit=$3, modified_date=$4, modified_by=$5 WHERE unit_id=$6',
368 array(htmlspecialchars($name), $conversion_factor, $to_unit, $time, $user, $this->getID()));
369 if (!$res || db_affected_rows($res) < 1) {
370 $this->setError(_('Error')._(':').' '._('Cannot update Effort Unit')._(':').' '.db_error());
374 if (!$this->fetchData($this->getID())) {
378 // get conversion factor for base unit after update
379 $new_factor = $this->getConversionFactorForBaseUnit();
380 if ($old_factor != $new_factor) {
381 foreach ($units as $unit) {
382 $res = db_query_params('WITH t AS (
384 FROM artifact_extra_field_data
385 INNER JOIN artifact_extra_field_list USING (extra_field_id)
386 INNER JOIN artifact_group_list USING (group_artifact_id)
389 field_data like $2 AND
392 UPDATE artifact_extra_field_data AS d
393 SET field_data = (CAST(SUBSTRING(field_data FROM \'#"%#"U%\' FOR \'#\') AS INTEGER)*$4)/$5 || \'U\' || $6
395 WHERE d.data_id = t.data_id',
396 array(ARTIFACT_EXTRAFIELDTYPE_EFFORT,'%U'.$unit->getID(), $this->EffortUnitSet->getID(), $new_factor, $old_factor, $unit->getID()));
398 $this->setError(_('Error')._(':').' '._('Cannot update Effort Unit (artifacts data update)')._(':').' '.db_error());
400 $this->fetchData($this->getID());
403 $res = db_query_params('WITH t AS (
405 FROM artifact_extra_field_default
406 INNER JOIN artifact_extra_field_list USING (extra_field_id)
407 INNER JOIN artifact_group_list USING (group_artifact_id)
410 default_value like $2 AND
413 UPDATE artifact_extra_field_default AS d
414 SET default_value = (CAST(SUBSTRING(default_value FROM \'#"%#"U%\' FOR \'#\') AS INTEGER)*$4)/$5 || \'U\' || $6
416 WHERE d.default_id = t.default_id',
417 array(ARTIFACT_EXTRAFIELDTYPE_EFFORT,'%U'.$unit->getID(), $this->EffortUnitSet->getID(), $new_factor, $old_factor, $unit->getID()));
419 $this->setError(_('Error')._(':').' '._('Cannot update Effort Unit (default value update)')._(':').' '.db_error());
421 $this->fetchData($this->getID());
431 * updatePosition - Update this Effort Unit dispaly position.
432 * @param integer $unit_position new position
434 * @return boolean success or not.
436 function updatePosition($unit_position) {
437 $result=db_query_params ('UPDATE effort_unit SET unit_position= $1 WHERE unit_id=$2',
438 array($unit_position, $this->getID()));
439 if ($result && db_affected_rows($result) > 0) {
443 $this->setError(db_error());
449 * reorderUnits - Reorder all units.
450 * @param integer $new_position new position of this unit
452 * @return boolean success or not.
454 function reorderUnits($new_position) {
455 $unitFactory = new EffortUnitFactory($this->EffortUnitSet);
456 $unitsData = $unitFactory->getUnitsData();
457 $max = count($unitsData);
458 if ($new_position < 1 || $new_position > $max) {
459 $this->setError(_('Out of range value'));
464 for ($i = 0; $i < $max; $i++) {
465 if ($pos == $new_position) {
466 $data[$pos] = $this->getID();
469 if ($unitsData[$i]['unit_id'] != $this->getID()) {
470 $data[$pos] = $unitsData[$i]['unit_id'];
474 if ($pos == $new_position) {
475 $data[$pos] = $this->getID();
478 for ($pos = 1; $pos <= count($data); $pos++) {
479 $unit = new EffortUnit($this->EffortUnitSet,$data[$pos]);
480 if (! $unit->updatePosition($pos))
487 * copy - copy definition from an other unit.
488 * @param EffortUnit $from_unit Unit to be copied
490 * @return boolean success or not.
492 function copy($from_unit) {
494 $name = $from_unit->getName();
495 $conversion_factor = $from_unit->getConversionFactor();
496 $position = $from_unit->getPosition();
497 $is_base_unit = $from_unit->isBaseUnit();
498 if (!$is_base_unit) {
499 $to_unit_name = $from_unit->getToUnitName();
500 $effortUnitFactory = new EffortUnitFactory($this->EffortUnitSet);
501 $to_unit_id = $effortUnitFactory->getUnitByName($to_unit_name)->getID();
505 $id = $this->create($name, $conversion_factor, $to_unit_id, $position, $is_base_unit);
507 // Update artifacts data
508 $res = db_query_params('WITH t AS (
510 FROM artifact_extra_field_data
511 INNER JOIN artifact_extra_field_list USING (extra_field_id)
512 INNER JOIN artifact_group_list USING (group_artifact_id)
515 field_data like $2 AND
518 UPDATE artifact_extra_field_data AS d
519 SET field_data = CAST(SUBSTRING(field_data FROM \'#"%#"U%\' FOR \'#\') AS INTEGER) || \'U\' || $4
521 WHERE d.data_id = t.data_id',
522 array(ARTIFACT_EXTRAFIELDTYPE_EFFORT,'%U'.$from_unit->getID(), $from_unit->getEffortUnitSet()->getID(), $id));
524 $this->setError(_('Error coping Effort Unit')._(': ').db_error());
528 // Update default values
529 $res = db_query_params('WITH t AS (
531 FROM artifact_extra_field_default
532 INNER JOIN artifact_extra_field_list USING (extra_field_id)
533 INNER JOIN artifact_group_list USING (group_artifact_id)
536 default_value like $2 AND
539 UPDATE artifact_extra_field_default AS d
540 SET default_value = CAST(SUBSTRING(default_value FROM \'#"%#"U%\' FOR \'#\') AS INTEGER) || \'U\' || $4
542 WHERE d.default_id = t.default_id',
543 array(ARTIFACT_EXTRAFIELDTYPE_EFFORT,'%U'.$from_unit->getID(), $from_unit->getEffortUnitSet()->getID(), $id));
545 $this->setError(_('Error')._(':').' '._('Cannot update Effort Unit (default value update)')._(':').' '.db_error());
555 * getConversionFactorForBaseUnit - get conversion factor for Base Unit.
557 * @return integer conversion factor.
559 function getConversionFactorForBaseUnit() {
560 $factor = $this->getConversionFactor();
561 $toUnitId = $this->getToUnit();
562 $toUnit = new EffortUnit($this->EffortUnitSet,$toUnitId);
563 if (!$toUnit->isBaseUnit()) {
564 $factor *= $toUnit->getConversionFactorForBaseUnit();
570 * getUnitsDependingOn - get array of units depending on this unit.
572 * @return array array of EffortUnit depending on this unit.
574 function getUnitsDependingOn(){
575 $unitsDependingOn = array();
576 $effortUnitFactory = new EffortUnitFactory($this->EffortUnitSet);
577 $units = $effortUnitFactory->getUnits();
578 foreach ($units as $unit) {
579 if ($unit->getToUnit()==$this->getID()) {
580 $unitsDependingOn[] = $unit;
581 $unitsDependingOn = array_merge($unitsDependingOn, $unit->getUnitsDependingOn());
584 return $unitsDependingOn;
588 * isEquivalentTo - test if this unit is equivalent to the other.
589 * @param EffortUnit $effortUnit Unit to compare to
591 * @return boolean success or not.
593 function isEquivalentTo($effortUnit){
594 if ($this->getName() != $effortUnit->getName()) {
597 if ($this->getConversionFactor() != $effortUnit->getConversionFactor()) {
600 if ($this->isBaseUnit() && $effortUnit->isBaseUnit()) {
603 $thisToUnit = new EffortUnit($this->EffortUnitSet, $this->getToUnit());
604 $toUnit = new EffortUnit($effortUnit->EffortUnitSet, $effortUnit->getToUnit());
605 if (!$toUnit->isEquivalentTo($thisToUnit)) {
611 function getEffortUnitById($unit_id){
612 $res = db_query_params ('SELECT * FROM effort_unit INNER JOIN effort_unit_set USING (unit_set_id) WHERE unit_id=$1',
614 if (!$res || db_numrows($res) < 1) {
617 $data_array = db_fetch_array($res);
618 switch ($data_array['level']) {
619 case EFFORTUNITSET_FORGE_LEVEL:
622 case EFFORTUNITSET_PROJECT_LEVEL:
623 $object= new Group($data_array['group_id']);
625 case EFFORTUNITSET_TRACKER_LEVEL:
626 $Group = new Group($data_array['group_id']);
627 $object= new ArtifactType($Group, $data_array['group_artifact_id']);
632 $effortUnitSet = new EffortUnitSet($object, $data_array['unit_set_id']);
633 $effortUnit = new EffortUnit($effortUnitSet, $unit_id);