5 * Copyright 2004, Anthony J. Pugliese
6 * Copyright 2009, Roland Mas
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.
24 require_once $gfcommon.'include/Error.class.php';
26 define('ARTIFACT_EXTRAFIELD_FILTER_INT','1,2,3,5,7');
27 define('ARTIFACT_EXTRAFIELDTYPE_SELECT',1);
28 define('ARTIFACT_EXTRAFIELDTYPE_CHECKBOX',2);
29 define('ARTIFACT_EXTRAFIELDTYPE_RADIO',3);
30 define('ARTIFACT_EXTRAFIELDTYPE_TEXT',4);
31 define('ARTIFACT_EXTRAFIELDTYPE_MULTISELECT',5);
32 define('ARTIFACT_EXTRAFIELDTYPE_TEXTAREA',6);
33 define('ARTIFACT_EXTRAFIELDTYPE_STATUS',7);
34 //define('ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE',8);
35 define('ARTIFACT_EXTRAFIELDTYPE_RELATION',9);
36 define('ARTIFACT_EXTRAFIELDTYPE_INTEGER',10);
38 class ArtifactExtraField extends Error {
41 * The artifact type object.
43 * @var object $ArtifactType.
45 var $ArtifactType; //object
48 * Array of artifact data.
50 * @var array $data_array.
55 * @param $ArtifactType
58 function __construct(&$ArtifactType, $data=false) {
61 //was ArtifactType legit?
62 if (!$ArtifactType || !is_object($ArtifactType)) {
63 $this->setError('ArtifactExtraField: No Valid ArtifactType');
66 //did ArtifactType have an error?
67 if ($ArtifactType->isError()) {
68 $this->setError('ArtifactExtraField: '.$ArtifactType->getErrorMessage());
71 $this->ArtifactType =& $ArtifactType;
74 if (is_array($data)) {
75 $this->data_array =& $data;
77 $this->fetchData($data);
83 * create - create a row in the table that stores box names for a
84 * a tracker. This function is only used to create rows for boxes
85 * configured by the admin.
87 * @param string Name of the extra field.
88 * @param int The type of field - radio, select, text, textarea
89 * @param int Attribute1 - for text (size) and textarea (rows)
90 * @param int Attribute2 - for text (maxlength) and textarea (cols)
91 * @param int is_required - true or false whether this is a required field or not.
92 * @param string alias - alias for this extra field (optional)
93 * @return true on success / false on failure.
95 function create($name,$field_type,$attribute1,$attribute2,$is_required=0,$alias='') {
100 $this->setError(_('a field name is required'));
104 $this->setError("Type of custom field not selected");
107 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
108 $this->setPermissionDeniedError();
112 $res = db_query_params ('SELECT field_name FROM artifact_extra_field_list WHERE field_name=$1 AND group_artifact_id=$2',
114 $this->ArtifactType->getID()));
115 if (db_numrows($res) > 0) {
116 $this->setError(_('Field name already exists'));
119 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_TEXT || $field_type == ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
120 if (!$attribute1 || !$attribute2 || $attribute2 < $attribute1) {
121 $this->setError("Invalid size/maxlength for text field");
125 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
126 if (!$attribute1 || !$attribute2) {
127 $this->setError("Invalid rows/cols for textarea field");
138 if (!($alias = $this->generateAlias($alias,$name))) {
143 $result = db_query_params ('INSERT INTO artifact_extra_field_list (group_artifact_id,field_name,field_type,attribute1,attribute2,is_required,alias)
144 VALUES ($1,$2,$3,$4,$5,$6,$7)',
145 array ($this->ArtifactType->getID(),
146 htmlspecialchars($name),
153 if ($result && db_affected_rows($result) > 0) {
155 $id=db_insertid($result,'artifact_extra_field_list','extra_field_id');
157 // Now set up our internal data structures
159 if (!$this->fetchData($id)) {
163 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
164 if (!$this->ArtifactType->setCustomStatusField($id)) {
169 // Must insert some default statuses for each artifact
171 $ao = new ArtifactExtraFieldElement($this);
172 if (!$ao || !is_object($ao)) {
173 $feedback .= 'Unable to create ArtifactExtraFieldElement Object';
177 if (!$ao->create('Open', '1')) {
178 $feedback .= _('Error inserting an element').': '.$ao->getErrorMessage();
183 if (!$ao->create('Closed', '2')) {
184 $feedback .= _('Error inserting an element').': '.$ao->getErrorMessage();
191 } elseif (strstr(ARTIFACT_EXTRAFIELD_FILTER_INT,$field_type) !== false) {
193 // Must insert some default 100 rows for the data table so None queries will work right
195 $resdefault = db_query_params ('INSERT INTO artifact_extra_field_data(artifact_id,field_data,extra_field_id)
196 SELECT artifact_id,100,$1 FROM artifact WHERE group_artifact_id=$2',
198 $this->ArtifactType->getID())) ;
206 $this->setError(db_error());
213 * fetchData - re-fetch the data for this ArtifactExtraField from the database.
215 * @param int $id ID of the Box.
216 * @return boolean success.
218 function fetchData($id) {
220 $res = db_query_params ('SELECT * FROM artifact_extra_field_list WHERE extra_field_id=$1',
223 if (!$res || db_numrows($res) < 1) {
224 $this->setError('ArtifactExtraField: Invalid ArtifactExtraField ID');
227 $this->data_array = db_fetch_array($res);
228 db_free_result($res);
233 * getArtifactType - get the ArtifactType Object this ArtifactExtraField is associated with.
235 * @return object ArtifactType.
237 function &getArtifactType() {
238 return $this->ArtifactType;
242 * getID - get this ArtifactExtraField ID.
244 * @return int The id #.
247 return $this->data_array['extra_field_id'];
251 * getName - get the name.
253 * @return string The name.
256 return $this->data_array['field_name'];
260 * getAttribute1 - get the attribute1 field.
262 * @return int The first attribute.
264 function getAttribute1() {
265 return $this->data_array['attribute1'];
269 * getAttribute2 - get the attribute2 field.
271 * @return int The second attribute.
273 function getAttribute2() {
274 return $this->data_array['attribute2'];
278 * getType - the type of field.
283 return $this->data_array['field_type'];
287 * getTypeName - the name of type of field.
289 * @return string type.
291 function getTypeName() {
292 $arr = $this->getAvailableTypes();
293 return $arr[$this->data_array['field_type']];
297 * isRequired - whether this field is required or not.
299 * @return boolean required.
301 function isRequired() {
302 return $this->data_array['is_required'];
306 * getAvailableTypes - the types of text fields and their names available.
308 * @return array types.
310 static function getAvailableTypes() {
314 3=>_('Radio Buttons'),
316 5=>_('Multi-Select Box'),
325 * getAlias - the alias that is used for this field
327 * @return string alias
329 function getAlias() {
330 return $this->data_array['alias'];
334 * getAvailableValues - Get the list of available values for this extra field
338 function getAvailableValues() {
339 $res = db_query_params ('SELECT * FROM artifact_extra_field_elements WHERE extra_field_id=$1',
340 array ($this->getID()));
342 while ($row = db_fetch_array($res)) {
349 * update - update a row in the table used to store box names
350 * for a tracker. This function is only to update rowsf
351 * for boxes configured by
354 * @param string Name of the field.
355 * @param int Attribute1 - for text (size) and textarea (rows)
356 * @param int Attribute2 - for text (maxlength) and textarea (cols)
357 * @param int is_required - true or false whether this is a required field or not.
358 * @param string Alias for this field
359 * @return boolean success.
361 function update($name,$attribute1,$attribute2,$is_required=0,$alias="") {
362 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
363 $this->setPermissionDeniedError();
370 $this->setError(_('a field name is required'));
373 $res = db_query_params ('SELECT field_name FROM artifact_extra_field_list
374 WHERE field_name=$1 AND group_artifact_id=$2 AND extra_field_id !=$3',
376 $this->ArtifactType->getID(),
378 if (db_numrows($res) > 0) {
379 $this->setError(_('Field name already exists'));
388 if (!($alias = $this->generateAlias($alias,$name))) {
392 $result = db_query_params ('UPDATE artifact_extra_field_list
398 WHERE extra_field_id=$6
399 AND group_artifact_id=$7',
400 array (htmlspecialchars($name),
406 $this->ArtifactType->getID())) ;
407 if ($result && db_affected_rows($result) > 0) {
410 $this->setError(db_error());
419 function delete($sure, $really_sure) {
420 if (!$sure || !$really_sure) {
421 $this->setMissingParamsError(_('Please tick all checkboxes.'));
424 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
425 $this->setPermissionDeniedError();
429 $result = db_query_params ('DELETE FROM artifact_extra_field_data WHERE extra_field_id=$1',
430 array ($this->getID())) ;
432 $result = db_query_params ('DELETE FROM artifact_extra_field_elements WHERE extra_field_id=$1',
433 array ($this->getID())) ;
435 $result = db_query_params ('DELETE FROM artifact_extra_field_list WHERE extra_field_id=$1',
436 array ($this->getID())) ;
438 if ($this->getType() == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
439 if (!$this->ArtifactType->setCustomStatusField(0)) {
447 $this->setError(db_error());
452 $this->setError(db_error());
457 $this->setError(db_error());
466 * Note that this function does not check for conflicts.
467 * @param string alias - alias to validate
468 * @return bool true if alias is valid, false otherwise and it sets the corresponding error
470 function validateAlias($alias) {
471 // these are reserved alias names
472 static $reserved_alias = array(
484 if (strlen($alias) == 0) return true; // empty alias
487 if (preg_match("/[^[:alnum:]_@\\-]/", $alias)) {
488 $this->setError(_('The alias contains invalid characters. Only letters, numbers, hypens (-), at sign (@) and underscores (_) allowed.'));
490 } elseif (in_array($alias, $reserved_alias)) { // alias is reserved?
491 $this->setError(sprintf(_('\'%1$s\' is a reserved alias. Please provide another name.'), $alias));
499 * Generate an alias for this field. The alias can be entered by the user or
500 * be generated automatically from the name of the field.
501 * @param string $alias Alias entered by the user
502 * @param string $name Name of the field entered by the user (it'll be used when $alias is empty)
505 function generateAlias($alias, $name) {
506 $alias = strtolower(trim($alias));
507 if (strlen($alias) == 0) { // no alias was entered, generate alias from $name
508 $name = strtolower(trim($name));
509 // Convert the original name to a valid alias (i.e., if the extra field is
510 // called "Quality test", make an alias called "quality_test").
511 // The alias can be seen as a "unix name" for this field
512 $alias = preg_replace("/ /", "_", $name);
513 $alias = preg_replace("/[^[:alnum:]_@]/", "", $alias);
514 $alias = strtolower($alias);
515 } elseif (!$this->validateAlias($alias)) {
516 // alias is invalid...
519 // check if the name conflicts with another alias in the same artifact type
520 // in that case append a serial number to the alias
524 if ($this->data_array['extra_field_id']) {
525 $res = db_query_params ('SELECT * FROM artifact_extra_field_list
526 WHERE LOWER (alias)=$1
527 AND group_artifact_id=$2
528 AND extra_field_id <> $3',
530 $this->ArtifactType->getID(),
531 $this->data_array['extra_field_id'])) ;
533 $res = db_query_params ('SELECT * FROM artifact_extra_field_list WHERE LOWER (alias)=$1 AND group_artifact_id=$2',
535 $this->ArtifactType->getID()));
538 $this->setError(db_error());
540 } elseif (db_numrows($res) > 0) { // found another field with the same alias
543 $alias = $alias.$serial;
549 // at this point, the alias is valid and unique
553 function updateOrder($element_id, $order) {
555 $result=db_query_params ('UPDATE artifact_extra_field_elements
557 WHERE element_id=$2',
560 if ($result && db_affected_rows($result) > 0) {
564 $this->setError(db_error());
569 function reorderValues($element_id, $new_pos) {
571 $res = db_query_params ('SELECT element_id FROM artifact_extra_field_elements WHERE extra_field_id=$1 ORDER BY element_pos ASC, element_id ASC',
572 array($this->getID()));
573 $max = db_numrows($res);
574 if ($new_pos < 1 || $new_pos > $max) {
575 $this->setError(_('Out of range value'));
581 if ($i == $new_pos) {
582 $data[] = $element_id;
585 if (($row = db_fetch_array($res)) && $row['element_id'] != $element_id) {
586 $data[] = $row['element_id'];
590 for ($i = 0; $i < count($data); $i++) {
591 if (! $this->updateOrder($data[$i], $i + 1))
598 function alphaorderValues() {
600 $res = db_query_params ('SELECT element_id FROM artifact_extra_field_elements WHERE extra_field_id=$1 ORDER BY element_name ASC',
601 array($this->getID()));
603 while ($row = db_fetch_array($res)) {
604 if (! $this->updateOrder($row['element_id'], $i))
616 // c-file-style: "bsd"