5 * Copyright 2005, Anthony J. Pugliese
6 * Copyright 2005, GForge, LLC
7 * Copyright 2009, Roland Mas
8 * Copyright 2009, Alcatel-Lucent
10 * This file is part of FusionForge. FusionForge is free software;
11 * you can redistribute it and/or modify it under the terms of the
12 * GNU General Public License as published by the Free Software
13 * Foundation; either version 2 of the Licence, or (at your option)
16 * FusionForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * Standard Alcatel-Lucent disclaimer for contributing to open source
29 * "The Artifact ("Contribution") has not been tested and/or
30 * validated for release as or in products, combinations with products or
31 * other commercial use. Any use of the Contribution is entirely made at
32 * the user's own responsibility and the user can not rely on any features,
33 * functionalities or performances Alcatel-Lucent has attributed to the
36 * THE CONTRIBUTION BY ALCATEL-LUCENT IS PROVIDED AS IS, WITHOUT WARRANTY
37 * OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
38 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, COMPLIANCE,
39 * NON-INTERFERENCE AND/OR INTERWORKING WITH THE SOFTWARE TO WHICH THE
40 * CONTRIBUTION HAS BEEN MADE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
41 * ALCATEL-LUCENT BE LIABLE FOR ANY DAMAGES OR OTHER LIABLITY, WHETHER IN
42 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
43 * CONTRIBUTION OR THE USE OR OTHER DEALINGS IN THE CONTRIBUTION, WHETHER
44 * TOGETHER WITH THE SOFTWARE TO WHICH THE CONTRIBUTION RELATES OR ON A STAND
48 require_once $gfcommon.'include/Error.class.php';
50 define('ARTIFACT_QUERY_ASSIGNEE',1);
51 define('ARTIFACT_QUERY_STATE',2);
52 define('ARTIFACT_QUERY_MODDATE',3);
53 define('ARTIFACT_QUERY_EXTRAFIELD',4);
54 define('ARTIFACT_QUERY_SORTCOL',5);
55 define('ARTIFACT_QUERY_SORTORD',6);
56 define('ARTIFACT_QUERY_OPENDATE',7);
57 define('ARTIFACT_QUERY_CLOSEDATE',8);
58 define('ARTIFACT_QUERY_SUMMARY',9);
59 define('ARTIFACT_QUERY_DESCRIPTION',10);
60 define('ARTIFACT_QUERY_FOLLOWUPS',11);
62 require_once $gfcommon.'tracker/ArtifactType.class.php';
64 class ArtifactQuery extends Error {
66 * The artifact type object.
68 * @var object $ArtifactType.
70 var $ArtifactType; //object
73 * Array of artifact data.
75 * @var array $data_array.
80 * Array of query conditions
82 * @var array $element_array.
87 * ArtifactQuery - Constructer
89 * @param object ArtifactType object.
91 * @return boolean success.
93 function ArtifactQuery(&$ArtifactType, $data = false) {
96 //was ArtifactType legit?
97 if (!$ArtifactType || !is_object($ArtifactType)) {
98 $this->setError('ArtifactQuery: No Valid ArtifactType');
101 //did ArtifactType have an error?
102 if ($ArtifactType->isError()) {
103 $this->setError('ArtifactQuery: '.$ArtifactType->getErrorMessage());
106 $this->ArtifactType =& $ArtifactType;
109 if (is_array($data)) {
110 $this->data_array =& $data;
113 if (!$this->fetchData($data)) {
123 * create - create a row in the table that stores a saved query for
126 * @param string Name of the saved query.
127 * @return true on success / false on failure.
129 function create($name,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange=0,$closedaterange=0,
130 $summary,$description,$followups,$query_type=0,$query_options=array()) {
135 $this->setMissingParamsError();
138 if (!session_loggedin()) {
139 $this->setError('Must Be Logged In');
143 if ($this->Exist(htmlspecialchars($name))) {
144 $this->setError(_('Query already exists'));
148 if ($query_type>0 && !forge_check_perm ('tracker', $this->ArtifactType->getID(), 'manager')) {
149 $this->setError( _('You must have tracker admin rights to set or update a project level query.'));
153 // Reset the project default query.
154 if ($query_type==2) {
155 $res = db_query_params ('UPDATE artifact_query SET query_type=1 WHERE query_type=2 AND group_artifact_id=$1',
156 array($this->ArtifactType->getID()));
158 $this->setError('Error Updating: '.db_error());
164 $result = db_query_params ('INSERT INTO artifact_query (group_artifact_id,query_name,user_id,query_type) VALUES ($1,$2,$3,$4)',
165 array ($this->ArtifactType->getID(),
166 htmlspecialchars($name),
169 if ($result && db_affected_rows($result) > 0) {
171 $id=db_insertid($result,'artifact_query','artifact_query_id');
173 $this->setError('Error getting id '.db_error());
177 if (!$this->insertElements($id,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups)) {
183 $this->setError(db_error());
188 // Now set up our internal data structures
190 if ($this->fetchData($id)) {
200 * fetchData - re-fetch the data for this ArtifactQuery from the database.
202 * @param int ID of saved query.
203 * @return boolean success.
205 function fetchData($id) {
206 $res = db_query_params ('SELECT * FROM artifact_query WHERE artifact_query_id=$1',
209 if (!$res || db_numrows($res) < 1) {
210 $this->setError('ArtifactQuery: Invalid ArtifactQuery ID'.db_error());
213 $this->data_array = db_fetch_array($res);
214 db_free_result($res);
215 $res = db_query_params ('SELECT * FROM artifact_query_fields WHERE artifact_query_id=$1',
217 unset($this->element_array);
218 while ($arr = db_fetch_array($res)) {
220 // Some things may have been saved as comma-separated items
222 if (strstr($arr['query_field_values'],',')) {
223 $arr['query_field_values']=explode(',',$arr['query_field_values']);
225 $this->element_array[$arr['query_field_type']][$arr['query_field_id']]=$arr['query_field_values'];
231 * getArtifactType - get the ArtifactType Object this ArtifactExtraField is associated with.
233 * @return object ArtifactType.
235 function &getArtifactType() {
236 return $this->ArtifactType;
243 function insertElements($id,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups) {
244 $res = db_query_params ('DELETE FROM artifact_query_fields WHERE artifact_query_id=$1',
247 $this->setError('Deleting Old Elements: '.db_error());
251 $status = intval($status);
252 $res = db_query_params ('INSERT INTO artifact_query_fields (artifact_query_id,query_field_type,query_field_id,query_field_values) VALUES ($1,$2,0,$3)',
254 ARTIFACT_QUERY_STATE,
257 $this->setError('Setting Status: '.db_error());
261 if (is_array($assignee)) {
262 for($e=0; $e<count($assignee); $e++) {
263 $assignee[$e]=intval($assignee[$e]);
265 $assignee=implode(',',$assignee);
267 $assignee = intval($assignee);
270 if (preg_match("/[^[:alnum:]_]/", $sort_col)) {
271 $this->setError('ArtifactQuery: not valid sort_col');
275 if (preg_match("/[^[:alnum:]_]/", $sort_ord)) {
276 $this->setError('ArtifactQuery: not valid sort_ord');
280 //CSV LIST OF ASSIGNEES
281 $res = db_query_params ('INSERT INTO artifact_query_fields
282 (artifact_query_id,query_field_type,query_field_id,query_field_values)
283 VALUES ($1,$2,0,$3)',
285 ARTIFACT_QUERY_ASSIGNEE,
288 $this->setError('Setting Assignee: '.db_error());
292 //MOD DATE RANGE YYYY-MM-DD YYYY-MM-DD format
293 if ($moddaterange && !$this->validateDateRange($moddaterange)) {
294 $this->setError('Invalid Mod Date Range');
297 $res = db_query_params ('INSERT INTO artifact_query_fields
298 (artifact_query_id,query_field_type,query_field_id,query_field_values)
299 VALUES ($1,$2,0,$3)',
301 ARTIFACT_QUERY_MODDATE,
304 $this->setError('Setting Last Modified Date Range: '.db_error());
308 //OPEN DATE RANGE YYYY-MM-DD YYYY-MM-DD format
309 if ($opendaterange && !$this->validateDateRange($opendaterange)) {
310 $this->setError('Invalid Open Date Range');
313 $res = db_query_params ('INSERT INTO artifact_query_fields
314 (artifact_query_id,query_field_type,query_field_id,query_field_values)
315 VALUES ($1,$2,0,$3)',
317 ARTIFACT_QUERY_OPENDATE,
320 $this->setError('Setting Open Date Range: '.db_error());
324 //CLOSE DATE RANGE YYYY-MM-DD YYYY-MM-DD format
325 if ($closedaterange && !$this->validateDateRange($closedaterange)) {
326 $this->setError('Invalid Close Date Range');
329 $res = db_query_params ('INSERT INTO artifact_query_fields
330 (artifact_query_id,query_field_type,query_field_id,query_field_values)
331 VALUES ($1,$2,0,$3)',
333 ARTIFACT_QUERY_CLOSEDATE,
336 $this->setError('Setting Close Date Range: '.db_error());
341 $res = db_query_params ('INSERT INTO artifact_query_fields
342 (artifact_query_id,query_field_type,query_field_id,query_field_values)
343 VALUES ($1,$2,0,$3)',
345 ARTIFACT_QUERY_SORTCOL,
348 $this->setError('Setting Sort Col: '.db_error());
351 $res = db_query_params ('INSERT INTO artifact_query_fields
352 (artifact_query_id,query_field_type,query_field_id,query_field_values)
353 VALUES ($1,$2,0,$3)',
355 ARTIFACT_QUERY_SORTORD,
358 $this->setError('Setting Sort Order: '.db_error());
362 // Saving the summary value.
363 $res=db_query_params ('INSERT INTO artifact_query_fields
364 (artifact_query_id,query_field_type,query_field_id,query_field_values)
365 VALUES ($1,$2,$3,$4)',
367 ARTIFACT_QUERY_SUMMARY,
371 $this->setError('Setting Summary: '.db_error());
375 // Saving the description value.
376 $res=db_query_params ('INSERT INTO artifact_query_fields
377 (artifact_query_id,query_field_type,query_field_id,query_field_values)
378 VALUES ($1,$2,$3,$4)',
380 ARTIFACT_QUERY_DESCRIPTION,
384 $this->setError('Setting Description: '.db_error());
388 // Saving the followups value.
389 $res=db_query_params ('INSERT INTO artifact_query_fields
390 (artifact_query_id,query_field_type,query_field_id,query_field_values)
391 VALUES ($1,$2,$3,$4)',
393 ARTIFACT_QUERY_FOLLOWUPS,
397 $this->setError('Setting Followups: '.db_error());
401 if (!$extra_fields) {
402 $extra_fields=array();
405 $keys=array_keys($extra_fields);
406 $vals=array_values($extra_fields);
407 for ($i=0; $i<count($keys); $i++) {
412 // Checkboxes and multi-select may be arrays so store it comma-separated
414 if (is_array($vals[$i])) {
415 for($e=0; $e<count($vals[$i]); $e++) {
416 $vals[$i][$e]=intval($vals[$i][$e]);
418 $vals[$i]=implode(',',$vals[$i]);
421 $aef = new ArtifactExtraField($this->ArtifactType, $keys[$i]);
422 $type = $aef->getType();
423 if ($type == ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
424 if (!preg_match('/^[><= \-\+0-9%]+$/', $vals[$i])) {
425 $this->setError('Invalid Value for Integer type: '. $vals[$i]);
430 $res = db_query_params ('INSERT INTO artifact_query_fields
431 (artifact_query_id,query_field_type,query_field_id,query_field_values)
432 VALUES ($1,$2,$3,$4)',
434 ARTIFACT_QUERY_EXTRAFIELD,
438 $this->setError('Setting values: '.db_error());
446 * getID - get this ArtifactQuery ID.
448 * @return int The id #.
451 return $this->data_array['artifact_query_id'];
455 * getName - get the name.
457 * @return string The name.
460 return $this->data_array['query_name'];
464 * getUserId - get the user_id.
466 * @return string The user_id.
468 function getUserId() {
469 return $this->data_array['user_id'];
473 * getQueryType - get the type of the query
475 * @return string type of query (0: private, 1: project, 2: project&default)
477 function getQueryType() {
478 return $this->data_array['query_type'];
482 * getQueryOptions - get the options of the query
484 * @return array array of all activated options
486 function getQueryOptions() {
487 if (isset($this->data_array['query_options'])) {
488 return explode('|', $this->data_array['query_options']);
495 * getSortCol - the column that you're sorting on
497 * @return string The column name.
499 function getSortCol() {
500 if (!isset($this->element_array))
502 return $this->element_array[ARTIFACT_QUERY_SORTCOL][0];
506 * getSortOrd - ASC or DESC
508 * @return string ASC or DESC
510 function getSortOrd() {
511 if (!isset($this->element_array))
513 return $this->element_array[ARTIFACT_QUERY_SORTORD][0];
517 * getModDateRange - get the range of dates to include in a query
519 * @return string mod date range.
521 function getModDateRange() {
522 if (!isset($this->element_array))
524 if ($this->element_array[ARTIFACT_QUERY_MODDATE][0]) {
525 return $this->element_array[ARTIFACT_QUERY_MODDATE][0];
532 * getOpenDateRange - get the range of dates to include in a query
534 * @return string Open date range.
536 function getOpenDateRange() {
537 if (!isset($this->element_array))
539 if ($this->element_array[ARTIFACT_QUERY_OPENDATE][0]) {
540 return $this->element_array[ARTIFACT_QUERY_OPENDATE][0];
547 * getCloseDateRange - get the range of dates to include in a query
549 * @return string Close date range.
551 function getCloseDateRange() {
552 if (!isset($this->element_array))
554 if ($this->element_array[ARTIFACT_QUERY_CLOSEDATE][0]) {
555 return $this->element_array[ARTIFACT_QUERY_CLOSEDATE][0];
562 * getSummary - get the summary string to include in a query
564 * @return string Summary string.
566 function getSummary() {
567 if (!isset($this->element_array[ARTIFACT_QUERY_SUMMARY][0])) {
570 return $this->element_array[ARTIFACT_QUERY_SUMMARY][0];
574 * getDescription - get the description string to include in a query
576 * @return string Description string.
578 function getDescription() {
579 if (!isset($this->element_array[ARTIFACT_QUERY_DESCRIPTION][0])) {
582 return $this->element_array[ARTIFACT_QUERY_DESCRIPTION][0];
586 * getFollowups - get the followups string to include in a query
588 * @return string Folowups string.
590 function getFollowups() {
591 if (!isset($this->element_array[ARTIFACT_QUERY_FOLLOWUPS][0])) {
594 return $this->element_array[ARTIFACT_QUERY_FOLLOWUPS][0];
600 * @return string Assignee ID
602 function getAssignee() {
603 if (!isset($this->element_array))
605 return $this->element_array[ARTIFACT_QUERY_ASSIGNEE][0];
611 * @return string Status ID
613 function getStatus() {
614 if (!isset($this->element_array))
616 return $this->element_array[ARTIFACT_QUERY_STATE][0];
620 * getExtraFields - complex multi-dimensional array of extra field IDs/Vals
622 * @return array Complex Array
624 function getExtraFields() {
625 if (!isset($this->element_array))
627 if (! isset ($this->element_array[ARTIFACT_QUERY_EXTRAFIELD])) {
628 $this->element_array[ARTIFACT_QUERY_EXTRAFIELD] = array () ;
630 return $this->element_array[ARTIFACT_QUERY_EXTRAFIELD];
634 * validateDateRange - validate a date range in this format '1999-05-01 1999-06-01'.
636 * @return boolean true/false.
638 function validateDateRange($daterange) {
639 return preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{4}-[0-9]{2}-[0-9]{2}/',$daterange);
643 * update - update a row in the table used to query names
646 * @param int Id of the saved query
647 * @param string The name of the saved query
648 * @return boolean success.
650 function update($name,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange='',$closedaterange='',
651 $summary,$description,$followups,$query_type=0,$query_options=array()) {
653 $this->setMissingParamsError();
656 if (!session_loggedin()) {
657 $this->setError('Must Be Logged In');
660 if (!$this->Exist(htmlspecialchars($name))) {
661 $this->setError(_('Query does not exist'));
664 if ($query_type>0 && !forge_check_perm ('tracker', $this->ArtifactType->getID(), 'manager')) {
665 $this->setError(_('You must have tracker admin rights to set or update a project level query.'));
669 // Reset the project default query.
670 if ($query_type==2) {
671 $res = db_query_params ('UPDATE artifact_query SET query_type=1 WHERE query_type=2 AND group_artifact_id=$1',
672 array($this->ArtifactType->getID()));
674 $this->setError('Error Updating: '.db_error());
679 $result = db_query_params ('UPDATE artifact_query
683 WHERE artifact_query_id=$4',
684 array (htmlspecialchars($name),
686 join('|', $query_options),
688 if ($result && db_affected_rows($result) > 0) {
689 if (!$this->insertElements($this->getID(),$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups)) {
694 $this->fetchData($this->getID());
698 $this->setError('Error Updating: '.db_error());
705 * makeDefault - set this as the default query
707 * @return boolean success.
709 function makeDefault() {
710 if (!session_loggedin()) {
711 $this->setError('Must Be Logged In');
714 $usr =& session_get_user();
715 return $usr->setPreference('art_query'.$this->ArtifactType->getID(),$this->getID());
719 * delete - delete query
721 * @return boolean success.
724 if (forge_check_perm ('tracker', $this->ArtifactType->getID(), 'manager')) {
725 $res = db_query_params ('DELETE FROM artifact_query WHERE artifact_query_id=$1 AND (user_id=$2 OR query_type>0)',
726 array ($this->getID(),
732 $res = db_query_params ('DELETE FROM artifact_query WHERE artifact_query_id=$1 AND user_id=$2',
733 array ($this->getID(),
739 $res = db_query_params ('DELETE FROM user_preferences WHERE preference_value=$1 AND preference_name =$2',
740 array ($this->getID(),
741 'art_query'.$this->ArtifactType->getID())) ;
742 unset($this->data_array);
743 unset($this->element_array);
748 * Exist - check if already exist a query with the same name , user_id and artifact_id
750 * @return boolean exist
752 function Exist($name) {
753 $user_id = user_getid();
754 $art_id = $this->ArtifactType->getID();
755 $res = db_query_params ('SELECT * FROM artifact_query WHERE group_artifact_id = $1 AND query_name = $2 AND (user_id = $3 OR query_type>0)',
759 if (db_numrows($res)>0) {
769 // c-file-style: "bsd"