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.
12 * FusionForge is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published
14 * by the Free Software Foundation; either version 2 of the License,
15 * or (at your option) any later version.
17 * FusionForge is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with FusionForge; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 * Standard Alcatel-Lucent disclaimer for contributing to open source
31 * "The Artifact ("Contribution") has not been tested and/or
32 * validated for release as or in products, combinations with products or
33 * other commercial use. Any use of the Contribution is entirely made at
34 * the user's own responsibility and the user can not rely on any features,
35 * functionalities or performances Alcatel-Lucent has attributed to the
38 * THE CONTRIBUTION BY ALCATEL-LUCENT IS PROVIDED AS IS, WITHOUT WARRANTY
39 * OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
40 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, COMPLIANCE,
41 * NON-INTERFERENCE AND/OR INTERWORKING WITH THE SOFTWARE TO WHICH THE
42 * CONTRIBUTION HAS BEEN MADE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
43 * ALCATEL-LUCENT BE LIABLE FOR ANY DAMAGES OR OTHER LIABLITY, WHETHER IN
44 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
45 * CONTRIBUTION OR THE USE OR OTHER DEALINGS IN THE CONTRIBUTION, WHETHER
46 * TOGETHER WITH THE SOFTWARE TO WHICH THE CONTRIBUTION RELATES OR ON A STAND
50 require_once $gfcommon.'include/Error.class.php';
52 define('ARTIFACT_QUERY_ASSIGNEE',1);
53 define('ARTIFACT_QUERY_STATE',2);
54 define('ARTIFACT_QUERY_MODDATE',3);
55 define('ARTIFACT_QUERY_EXTRAFIELD',4);
56 define('ARTIFACT_QUERY_SORTCOL',5);
57 define('ARTIFACT_QUERY_SORTORD',6);
58 define('ARTIFACT_QUERY_OPENDATE',7);
59 define('ARTIFACT_QUERY_CLOSEDATE',8);
60 define('ARTIFACT_QUERY_SUMMARY',9);
61 define('ARTIFACT_QUERY_DESCRIPTION',10);
62 define('ARTIFACT_QUERY_FOLLOWUPS',11);
64 require_once $gfcommon.'tracker/ArtifactType.class.php';
66 class ArtifactQuery extends Error {
68 * The artifact type object.
70 * @var object $ArtifactType.
72 var $ArtifactType; //object
75 * Array of artifact data.
77 * @var array $data_array.
82 * ArtifactQuery - Constructer
84 * @param object ArtifactType object.
86 * @return boolean success.
88 function ArtifactQuery(&$ArtifactType, $data = false) {
91 //was ArtifactType legit?
92 if (!$ArtifactType || !is_object($ArtifactType)) {
93 $this->setError('ArtifactQuery: No Valid ArtifactType');
96 //did ArtifactType have an error?
97 if ($ArtifactType->isError()) {
98 $this->setError('ArtifactQuery: '.$ArtifactType->getErrorMessage());
101 $this->ArtifactType =& $ArtifactType;
104 if (is_array($data)) {
105 $this->data_array =& $data;
108 if (!$this->fetchData($data)) {
118 * create - create a row in the table that stores a saved query for
121 * @param string Name of the saved query.
122 * @return true on success / false on failure.
124 function create($name,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange=0,$closedaterange=0,
125 $summary,$description,$followups,$query_type=0,$query_options=array()) {
130 $this->setMissingParamsError();
133 if (!session_loggedin()) {
134 $this->setError('Must Be Logged In');
138 if ($this->Exist(htmlspecialchars($name))) {
139 $this->setError(_('Query already exists'));
143 if ($query_type>0 && !$this->ArtifactType->userIsAdmin()) {
144 $this->setError( _('You must have tracker admin rights to set or update a project level query.'));
148 // Reset the project default query.
149 if ($query_type==2) {
150 $res = db_query_params ('UPDATE artifact_query SET query_type=1 WHERE query_type=2 AND group_artifact_id=$1',
151 array($this->ArtifactType->getID()));
153 $this->setError('Error Updating: '.db_error());
159 $result = db_query_params ('INSERT INTO artifact_query (group_artifact_id,query_name,user_id,query_type) VALUES ($1,$2,$3,$4)',
160 array ($this->ArtifactType->getID(),
161 htmlspecialchars($name),
164 if ($result && db_affected_rows($result) > 0) {
166 $id=db_insertid($result,'artifact_query','artifact_query_id');
168 $this->setError('Error getting id '.db_error());
172 if (!$this->insertElements($id,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups)) {
178 $this->setError(db_error());
183 // Now set up our internal data structures
185 if ($this->fetchData($id)) {
195 * fetchData - re-fetch the data for this ArtifactQuery from the database.
197 * @param int ID of saved query.
198 * @return boolean success.
200 function fetchData($id) {
201 $res = db_query_params ('SELECT * FROM artifact_query WHERE artifact_query_id=$1',
204 if (!$res || db_numrows($res) < 1) {
205 $this->setError('ArtifactQuery: Invalid ArtifactQuery ID'.db_error());
208 $this->data_array =& db_fetch_array($res);
209 db_free_result($res);
210 $res = db_query_params ('SELECT * FROM artifact_query_fields WHERE artifact_query_id=$1',
212 unset($this->element_array);
213 while ($arr = db_fetch_array($res)) {
215 // Some things may have been saved as comma-separated items
217 if (strstr($arr['query_field_values'],',')) {
218 $arr['query_field_values']=explode(',',$arr['query_field_values']);
220 $this->element_array[$arr['query_field_type']][$arr['query_field_id']]=$arr['query_field_values'];
226 * getArtifactType - get the ArtifactType Object this ArtifactExtraField is associated with.
228 * @return object ArtifactType.
230 function &getArtifactType() {
231 return $this->ArtifactType;
238 function insertElements($id,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups) {
239 $res = db_query_params ('DELETE FROM artifact_query_fields WHERE artifact_query_id=$1',
242 $this->setError('Deleting Old Elements: '.db_error());
246 $status = intval($status);
247 $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)',
249 ARTIFACT_QUERY_STATE,
252 $this->setError('Setting Status: '.db_error());
256 if (is_array($assignee)) {
257 for($e=0; $e<count($assignee); $e++) {
258 $assignee[$e]=intval($assignee[$e]);
260 $assignee=implode(',',$assignee);
262 $assignee = intval($assignee);
265 if (preg_match("/[^[:alnum:]_]/", $string)) {
266 $this->setError('ArtifactQuery: not valid sort_col');
270 if (preg_match("/[^[:alnum:]_]/", $string)) {
271 $this->setError('ArtifactQuery: not valid sort_ord');
275 //CSV LIST OF ASSIGNEES
276 $res = db_query_params ('INSERT INTO artifact_query_fields
277 (artifact_query_id,query_field_type,query_field_id,query_field_values)
278 VALUES ($1,$2,0,$3)',
280 ARTIFACT_QUERY_ASSIGNEE,
283 $this->setError('Setting Assignee: '.db_error());
287 //MOD DATE RANGE YYYY-MM-DD YYYY-MM-DD format
288 if ($moddaterange && !$this->validateDateRange($moddaterange)) {
289 $this->setError('Invalid Mod Date Range');
292 $res = db_query_params ('INSERT INTO artifact_query_fields
293 (artifact_query_id,query_field_type,query_field_id,query_field_values)
294 VALUES ($1,$2,0,$3)',
296 ARTIFACT_QUERY_MODDATE,
299 $this->setError('Setting Last Modified Date Range: '.db_error());
303 //OPEN DATE RANGE YYYY-MM-DD YYYY-MM-DD format
304 if ($opendaterange && !$this->validateDateRange($opendaterange)) {
305 $this->setError('Invalid Open Date Range');
308 $res = db_query_params ('INSERT INTO artifact_query_fields
309 (artifact_query_id,query_field_type,query_field_id,query_field_values)
310 VALUES ($1,$2,0,$3)',
312 ARTIFACT_QUERY_OPENDATE,
315 $this->setError('Setting Open Date Range: '.db_error());
319 //CLOSE DATE RANGE YYYY-MM-DD YYYY-MM-DD format
320 if ($closedaterange && !$this->validateDateRange($closedaterange)) {
321 $this->setError('Invalid Close Date Range');
324 $res = db_query_params ('INSERT INTO artifact_query_fields
325 (artifact_query_id,query_field_type,query_field_id,query_field_values)
326 VALUES ($1,$2,0,$3)',
328 ARTIFACT_QUERY_CLOSEDATE,
331 $this->setError('Setting Close Date Range: '.db_error());
336 $res = db_query_params ('INSERT INTO artifact_query_fields
337 (artifact_query_id,query_field_type,query_field_id,query_field_values)
338 VALUES ($1,$2,0,$3)',
340 ARTIFACT_QUERY_SORTCOL,
343 $this->setError('Setting Sort Col: '.db_error());
346 $res = db_query_params ('INSERT INTO artifact_query_fields
347 (artifact_query_id,query_field_type,query_field_id,query_field_values)
348 VALUES ($1,$2,0,$3)',
350 ARTIFACT_QUERY_SORTORD,
353 $this->setError('Setting Sort Order: '.db_error());
357 // Saving the summary value.
358 $res=db_query_params ('INSERT INTO artifact_query_fields
359 (artifact_query_id,query_field_type,query_field_id,query_field_values)
360 VALUES ($1,$2,$3,$4)',
362 ARTIFACT_QUERY_SUMMARY,
366 $this->setError('Setting Summary: '.db_error());
370 // Saving the description value.
371 $res=db_query_params ('INSERT INTO artifact_query_fields
372 (artifact_query_id,query_field_type,query_field_id,query_field_values)
373 VALUES ($1,$2,$3,$4)',
375 ARTIFACT_QUERY_DESCRIPTION,
379 $this->setError('Setting Description: '.db_error());
383 // Saving the followups value.
384 $res=db_query_params ('INSERT INTO artifact_query_fields
385 (artifact_query_id,query_field_type,query_field_id,query_field_values)
386 VALUES ($1,$2,$3,$4)',
388 ARTIFACT_QUERY_FOLLOWUPS,
392 $this->setError('Setting Followups: '.db_error());
396 if (!$extra_fields) {
397 $extra_fields=array();
400 $keys=array_keys($extra_fields);
401 $vals=array_values($extra_fields);
402 for ($i=0; $i<count($keys); $i++) {
407 // Checkboxes and multi-select may be arrays so store it comma-separated
409 if (is_array($vals[$i])) {
410 for($e=0; $e<count($vals[$i]); $e++) {
411 $vals[$i][$e]=intval($vals[$i][$e]);
413 $vals[$i]=implode(',',$vals[$i]);
416 $aef = new ArtifactExtraField($this->ArtifactType, $keys[$i]);
417 $type = $aef->getType();
418 if ($type == ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
419 if (!preg_match('/^[><= \-\+0-9%]+$/', $vals[$i])) {
420 $this->setError('Invalid Value for Integer type: '. $vals[$i]);
425 $res = db_query_params ('INSERT INTO artifact_query_fields
426 (artifact_query_id,query_field_type,query_field_id,query_field_values)
427 VALUES ($1,$2,$3,$4)',
429 ARTIFACT_QUERY_EXTRAFIELD,
433 $this->setError('Setting values: '.db_error());
441 * getID - get this ArtifactQuery ID.
443 * @return int The id #.
446 return $this->data_array['artifact_query_id'];
450 * getName - get the name.
452 * @return string The name.
455 return $this->data_array['query_name'];
459 * getUserId - get the user_id.
461 * @return string The user_id.
463 function getUserId() {
464 return $this->data_array['user_id'];
468 * getQueryType - get the type of the query
470 * @return string type of query (0: private, 1: project, 2: project&default)
472 function getQueryType() {
473 return $this->data_array['query_type'];
477 * getQueryOptions - get the options of the query
479 * @return array array of all activated options
481 function getQueryOptions() {
482 return explode('|', $this->data_array['query_options']);
486 * getSortCol - the column that you're sorting on
488 * @return string The column name.
490 function getSortCol() {
491 return $this->element_array[ARTIFACT_QUERY_SORTCOL][0];
495 * getSortOrd - ASC or DESC
497 * @return string ASC or DESC
499 function getSortOrd() {
500 return $this->element_array[ARTIFACT_QUERY_SORTORD][0];
504 * getModDateRange - get the range of dates to include in a query
506 * @return string mod date range.
508 function getModDateRange() {
509 if ($this->element_array[ARTIFACT_QUERY_MODDATE][0]) {
510 return $this->element_array[ARTIFACT_QUERY_MODDATE][0];
517 * getOpenDateRange - get the range of dates to include in a query
519 * @return string Open date range.
521 function getOpenDateRange() {
522 if ($this->element_array[ARTIFACT_QUERY_OPENDATE][0]) {
523 return $this->element_array[ARTIFACT_QUERY_OPENDATE][0];
530 * getCloseDateRange - get the range of dates to include in a query
532 * @return string Close date range.
534 function getCloseDateRange() {
535 if ($this->element_array[ARTIFACT_QUERY_CLOSEDATE][0]) {
536 return $this->element_array[ARTIFACT_QUERY_CLOSEDATE][0];
543 * getSummary - get the summary string to include in a query
545 * @return string Summary string.
547 function getSummary() {
548 if ($this->element_array[ARTIFACT_QUERY_SUMMARY][0]) {
549 return $this->element_array[ARTIFACT_QUERY_SUMMARY][0];
556 * getDescription - get the description string to include in a query
558 * @return string Description string.
560 function getDescription() {
561 if ($this->element_array[ARTIFACT_QUERY_DESCRIPTION][0]) {
562 return $this->element_array[ARTIFACT_QUERY_DESCRIPTION][0];
569 * getFollowups - get the followups string to include in a query
571 * @return string Folowups string.
573 function getFollowups() {
574 if ($this->element_array[ARTIFACT_QUERY_FOLLOWUPS][0]) {
575 return $this->element_array[ARTIFACT_QUERY_FOLLOWUPS][0];
584 * @return string Assignee ID
586 function getAssignee() {
587 return $this->element_array[ARTIFACT_QUERY_ASSIGNEE][0];
593 * @return string Status ID
595 function getStatus() {
596 return $this->element_array[ARTIFACT_QUERY_STATE][0];
600 * getExtraFields - complex multi-dimensional array of extra field IDs/Vals
602 * @return array Complex Array
604 function getExtraFields() {
605 return $this->element_array[ARTIFACT_QUERY_EXTRAFIELD];
609 * validateDateRange - validate a date range in this format '1999-05-01 1999-06-01'.
611 * @return boolean true/false.
613 function validateDateRange($daterange) {
614 return preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{4}-[0-9]{2}-[0-9]{2}/',$daterange);
618 * update - update a row in the table used to query names
621 * @param int Id of the saved query
622 * @param string The name of the saved query
623 * @return boolean success.
625 function update($name,$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange='',$closedaterange='',
626 $summary,$description,$followups,$query_type=0,$query_options=array()) {
628 $this->setMissingParamsError();
631 if (!session_loggedin()) {
632 $this->setError('Must Be Logged In');
635 if (!$this->Exist(htmlspecialchars($name))) {
636 $this->setError(_('Query does not exist'));
639 if ($query_type>0 && !$this->ArtifactType->userIsAdmin()) {
640 $this->setError(_('You must have tracker admin rights to set or update a project level query.'));
644 // Reset the project default query.
645 if ($query_type==2) {
646 $res = db_query_params ('UPDATE artifact_query SET query_type=1 WHERE query_type=2 AND group_artifact_id=$1',
647 array($this->ArtifactType->getID()));
649 $this->setError('Error Updating: '.db_error());
654 $result = db_query_params ('UPDATE artifact_query
658 WHERE artifact_query_id=$4',
659 array (htmlspecialchars($name),
661 join('|', $query_options),
663 if ($result && db_affected_rows($result) > 0) {
664 if (!$this->insertElements($this->getID(),$status,$assignee,$moddaterange,$sort_col,$sort_ord,$extra_fields,$opendaterange,$closedaterange,$summary,$description,$followups)) {
669 $this->fetchData($this->getID());
673 $this->setError('Error Updating: '.db_error());
680 * makeDefault - set this as the default query
682 * @return boolean success.
684 function makeDefault() {
685 if (!session_loggedin()) {
686 $this->setError('Must Be Logged In');
689 $usr =& session_get_user();
690 return $usr->setPreference('art_query'.$this->ArtifactType->getID(),$this->getID());
694 if ($this->ArtifactType->userIsAdmin()) {
695 $res = db_query_params ('DELETE FROM artifact_query WHERE artifact_query_id=$1 AND (user_id=$2 OR query_type>0)',
696 array ($this->getID(),
699 $res = db_query_params ('DELETE FROM artifact_query WHERE artifact_query_id=$1 AND user_id=$2',
700 array ($this->getID(),
703 $res = db_query_params ('DELETE FROM user_preferences WHERE preference_value=$1 AND preference_name =$2',
704 array ($this->getID(),
705 'art_query'.$this->ArtifactType->getID())) ;
706 unset($this->data_array);
707 unset($this->element_array);
711 * Exist - check if already exist a query with the same name , user_id and artifact_id
713 * @return boolean exist
715 function Exist($name) {
716 $user_id = user_getid();
717 $art_id = $this->ArtifactType->getID();
718 $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)',
722 if (db_numrows($res)>0) {
732 // c-file-style: "bsd"