5 * Copyright 2004, Anthony J. Pugliese
6 * Copyright 2009, Roland Mas
8 * This file is part of FusionForge.
10 * FusionForge is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License,
13 * or (at your option) any later version.
15 * FusionForge is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FusionForge; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 require_once $gfcommon.'include/Error.class.php';
28 define('ARTIFACT_EXTRAFIELD_FILTER_INT','1,2,3,5,7');
29 define('ARTIFACT_EXTRAFIELDTYPE_SELECT',1);
30 define('ARTIFACT_EXTRAFIELDTYPE_CHECKBOX',2);
31 define('ARTIFACT_EXTRAFIELDTYPE_RADIO',3);
32 define('ARTIFACT_EXTRAFIELDTYPE_TEXT',4);
33 define('ARTIFACT_EXTRAFIELDTYPE_MULTISELECT',5);
34 define('ARTIFACT_EXTRAFIELDTYPE_TEXTAREA',6);
35 define('ARTIFACT_EXTRAFIELDTYPE_STATUS',7);
36 //define('ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE',8);
37 define('ARTIFACT_EXTRAFIELDTYPE_RELATION',9);
38 define('ARTIFACT_EXTRAFIELDTYPE_INTEGER',10);
40 class ArtifactExtraField extends Error {
43 * The artifact type object.
45 * @var object $ArtifactType.
47 var $ArtifactType; //object
50 * Array of artifact data.
52 * @var array $data_array.
57 * ArtifactExtraField - Constructer
59 * @param object ArtifactType object.
60 * @param array (all fields from artifact_file_user_vw) OR id from database.
61 * @return boolean success.
63 function ArtifactExtraField(&$ArtifactType, $data=false) {
66 //was ArtifactType legit?
67 if (!$ArtifactType || !is_object($ArtifactType)) {
68 $this->setError('ArtifactExtraField: No Valid ArtifactType');
71 //did ArtifactType have an error?
72 if ($ArtifactType->isError()) {
73 $this->setError('ArtifactExtraField: '.$ArtifactType->getErrorMessage());
76 $this->ArtifactType =& $ArtifactType;
79 if (is_array($data)) {
80 $this->data_array =& $data;
83 if (!$this->fetchData($data)) {
93 * create - create a row in the table that stores box names for a
94 * a tracker. This function is only used to create rows for boxes
95 * configured by the admin.
97 * @param string Name of the extra field.
98 * @param int The type of field - radio, select, text, textarea
99 * @param int Attribute1 - for text (size) and textarea (rows)
100 * @param int Attribute2 - for text (maxlength) and textarea (cols)
101 * @param int is_required - true or false whether this is a required field or not.
102 * @param string alias - alias for this extra field (optional)
103 * @return true on success / false on failure.
105 function create($name,$field_type,$attribute1,$attribute2,$is_required=0,$alias='') {
110 $this->setError(_('a field name is required'));
114 $this->setError("Type of custom field not selected");
117 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
118 $this->setPermissionDeniedError();
122 $res = db_query_params ('SELECT field_name FROM artifact_extra_field_list WHERE field_name=$1 AND group_artifact_id=$2',
124 $this->ArtifactType->getID()));
125 if (db_numrows($res) > 0) {
126 $this->setError(_('Field name already exists'));
129 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_TEXT || $field_type == ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
130 if (!$attribute1 || !$attribute2 || $attribute2 < $attribute1) {
131 $this->setError("Invalid size/maxlength for text field");
135 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
136 if (!$attribute1 || !$attribute2) {
137 $this->setError("Invalid rows/cols for textarea field");
148 if (!($alias = $this->generateAlias($alias,$name))) {
153 $result = db_query_params ('INSERT INTO artifact_extra_field_list (group_artifact_id,field_name,field_type,attribute1,attribute2,is_required,alias)
154 VALUES ($1,$2,$3,$4,$5,$6,$7)',
155 array ($this->ArtifactType->getID(),
156 htmlspecialchars($name),
163 if ($result && db_affected_rows($result) > 0) {
165 $id=db_insertid($result,'artifact_extra_field_list','extra_field_id');
167 // Now set up our internal data structures
169 if (!$this->fetchData($id)) {
173 if ($field_type == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
174 if (!$this->ArtifactType->setCustomStatusField($id)) {
179 // Must insert some default statuses for each artifact
181 $ao = new ArtifactExtraFieldElement($this);
182 if (!$ao || !is_object($ao)) {
183 $feedback .= 'Unable to create ArtifactExtraFieldElement Object';
187 if (!$ao->create('Open', '1')) {
188 $feedback .= _('Error inserting an element').': '.$ao->getErrorMessage();
193 if (!$ao->create('Closed', '2')) {
194 $feedback .= _('Error inserting an element').': '.$ao->getErrorMessage();
201 } elseif (strstr(ARTIFACT_EXTRAFIELD_FILTER_INT,$field_type) !== false) {
203 // Must insert some default 100 rows for the data table so None queries will work right
205 $resdefault = db_query_params ('INSERT INTO artifact_extra_field_data(artifact_id,field_data,extra_field_id)
206 SELECT artifact_id,100,$1 FROM artifact WHERE group_artifact_id=$2',
208 $this->ArtifactType->getID())) ;
216 $this->setError(db_error());
223 * fetchData - re-fetch the data for this ArtifactExtraField from the database.
225 * @param int ID of the Box.
226 * @return boolean success.
228 function fetchData($id) {
230 $res = db_query_params ('SELECT * FROM artifact_extra_field_list WHERE extra_field_id=$1',
233 if (!$res || db_numrows($res) < 1) {
234 $this->setError('ArtifactExtraField: Invalid ArtifactExtraField ID');
237 $this->data_array = db_fetch_array($res);
238 db_free_result($res);
243 * getArtifactType - get the ArtifactType Object this ArtifactExtraField is associated with.
245 * @return object ArtifactType.
247 function &getArtifactType() {
248 return $this->ArtifactType;
252 * getID - get this ArtifactExtraField ID.
254 * @return int The id #.
257 return $this->data_array['extra_field_id'];
261 * getName - get the name.
263 * @return string The name.
266 return $this->data_array['field_name'];
270 * getAttribute1 - get the attribute1 field.
272 * @return int The first attribute.
274 function getAttribute1() {
275 return $this->data_array['attribute1'];
279 * getAttribute2 - get the attribute2 field.
281 * @return int The second attribute.
283 function getAttribute2() {
284 return $this->data_array['attribute2'];
288 * getType - the type of field.
293 return $this->data_array['field_type'];
297 * getTypeName - the name of type of field.
299 * @return string type.
301 function getTypeName() {
302 $arr=&$this->getAvailableTypes();
303 return $arr[$this->data_array['field_type']];
307 * isRequired - whether this field is required or not.
309 * @return boolean required.
311 function isRequired() {
312 return $this->data_array['is_required'];
316 * getAvailableTypes - the types of text fields and their names available.
318 * @return array types.
320 static function getAvailableTypes() {
324 3=>_('Radio Buttons'),
326 5=>_('Multi-Select Box'),
335 * getAlias - the alias that is used for this field
337 * @return string alias
339 function getAlias() {
340 return $this->data_array['alias'];
344 * getAvailableValues - Get the list of available values for this extra field
348 function getAvailableValues() {
349 $res = db_query_params ('SELECT * FROM artifact_extra_field_elements WHERE extra_field_id=$1',
350 array ($this->getID()));
352 while ($row = db_fetch_array($res)) {
359 * update - update a row in the table used to store box names
360 * for a tracker. This function is only to update rowsf
361 * for boxes configured by
364 * @param string Name of the field.
365 * @param int Attribute1 - for text (size) and textarea (rows)
366 * @param int Attribute2 - for text (maxlength) and textarea (cols)
367 * @param int is_required - true or false whether this is a required field or not.
368 * @param string Alias for this field
369 * @return boolean success.
371 function update($name,$attribute1,$attribute2,$is_required=0,$alias="") {
372 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
373 $this->setPermissionDeniedError();
380 $this->setError(_('a field name is required'));
383 $res = db_query_params ('SELECT field_name FROM artifact_extra_field_list
384 WHERE field_name=$1 AND group_artifact_id=$2 AND extra_field_id !=$3',
386 $this->ArtifactType->getID(),
388 if (db_numrows($res) > 0) {
389 $this->setError(_('Field name already exists'));
398 if (!($alias = $this->generateAlias($alias,$name))) {
402 $result = db_query_params ('UPDATE artifact_extra_field_list
408 WHERE extra_field_id=$6
409 AND group_artifact_id=$7',
410 array (htmlspecialchars($name),
416 $this->ArtifactType->getID())) ;
417 if ($result && db_affected_rows($result) > 0) {
420 $this->setError(db_error());
429 function delete($sure, $really_sure) {
430 if (!$sure || !$really_sure) {
431 $this->setMissingParamsError();
434 if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
435 $this->setPermissionDeniedError();
439 $result = db_query_params ('DELETE FROM artifact_extra_field_data WHERE extra_field_id=$1',
440 array ($this->getID())) ;
442 $result = db_query_params ('DELETE FROM artifact_extra_field_elements WHERE extra_field_id=$1',
443 array ($this->getID())) ;
445 $result = db_query_params ('DELETE FROM artifact_extra_field_list WHERE extra_field_id=$1',
446 array ($this->getID())) ;
448 if ($this->getType() == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
449 if (!$this->ArtifactType->setCustomStatusField(0)) {
457 $this->setError(db_error());
462 $this->setError(db_error());
467 $this->setError(db_error());
476 * Note that this function does not check for conflicts.
477 * @param string alias - alias to validate
478 * @return bool true if alias is valid, false otherwise and it sets the corresponding error
480 function validateAlias($alias) {
481 // these are reserved alias names
482 static $reserved_alias = array(
491 if (strlen($alias) == 0) return true; // empty alias
494 if (preg_match("/[^[:alnum:]_@\\-]/", $alias)) {
495 $this->setError(_('The alias contains invalid characters. Only letters, numbers, hypens (-), arobase (@) and underscores (_) allowed.'));
497 } else if (in_array($alias, $reserved_alias)) { // alias is reserved?
498 $this->setError(sprintf(_('\'%1$s\' is a reserved alias. Please provide another name.'), $alias));
506 * Generate an alias for this field. The alias can be entered by the user or
507 * be generated automatically from the name of the field.
508 * @param string Alias entered by the user
509 * @param string Name of the field entered by the user (it'll be used when $alias is empty)
512 function generateAlias($alias, $name) {
513 $alias = strtolower(trim($alias));
514 if (strlen($alias) == 0) { // no alias was entered, generate alias from $name
515 $name = strtolower(trim($name));
516 // Convert the original name to a valid alias (i.e., if the extra field is
517 // called "Quality test", make an alias called "quality_test").
518 // The alias can be seen as a "unix name" for this field
519 $alias = preg_replace("/ /", "_", $name);
520 $alias = preg_replace("/[^[:alnum:]_@]/", "", $alias);
521 $alias = strtolower($alias);
522 } elseif (!$this->validateAlias($alias)) {
523 // alias is invalid...
526 // check if the name conflicts with another alias in the same artifact type
527 // in that case append a serial number to the alias
531 if ($this->data_array['extra_field_id']) {
532 $res = db_query_params ('SELECT * FROM artifact_extra_field_list
533 WHERE LOWER (alias)=$1
534 AND group_artifact_id=$2
535 AND extra_field_id <> $3',
537 $this->ArtifactType->getID(),
538 $this->data_array['extra_field_id'])) ;
540 $res = db_query_params ('SELECT * FROM artifact_extra_field_list WHERE LOWER (alias)=$1 AND group_artifact_id=$2',
542 $this->ArtifactType->getID()));
545 $this->setError(db_error());
547 } else if (db_numrows($res) > 0) { // found another field with the same alias
550 $alias = $alias.$serial;
556 // at this point, the alias is valid and unique
560 function updateOrder($element_id, $order) {
562 $result=db_query_params ('UPDATE artifact_extra_field_elements
564 WHERE element_id=$2',
567 if ($result && db_affected_rows($result) > 0) {
571 $this->setError(db_error());
576 function reorderValues($element_id, $new_pos) {
578 $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',
579 array($this->getID()));
580 $max = db_numrows($res);
581 if ($new_pos < 1 || $new_pos > $max) {
582 $this->setError(_('Out of range value'));
587 if ($i == $new_pos) {
588 $data[] = $element_id;
591 if (($row = db_fetch_array($res)) && $row['element_id'] != $element_id) {
592 $data[] = $row['element_id'];
596 for ($i = 0; $i < count($data); $i++) {
597 if (! $this->updateOrder($data[$i], $i + 1))
604 function alphaorderValues($element_id) {
606 $res = db_query_params ('SELECT element_id FROM artifact_extra_field_elements WHERE extra_field_id=$1 ORDER BY element_name ASC',
607 array($this->getID()));
609 while ($row = db_fetch_array($res)) {
610 if (! $this->updateOrder($row['element_id'], $i))
622 // c-file-style: "bsd"