~hartmut-php/eventum/no-mysql-functions

« back to all changes in this revision

Viewing changes to lib/eventum/class.issue.php

  • Committer: Elan Ruusamäe
  • Date: 2011-04-20 14:21:01 UTC
  • Revision ID: glen@delfi.ee-20110420142101-43l6v4geuplrbrbf
Separate search methods to new Search class

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 * system, such as adding or updating them or listing them in the grid mode.
34
34
 *
35
35
 * @author  João Prado Maia <jpm@mysql.com>
36
 
 * @version $Revision: 1.114 $
37
36
 */
38
37
 
39
38
class Issue
76
75
     * Method used to get the list of column heading titles for the
77
76
     * CSV export functionality of the issue listing screen.
78
77
     *
79
 
     * @access  public
80
78
     * @param   integer $prj_id The project ID
81
79
     * @return  array The list of column heading titles
82
80
     */
83
 
    function getColumnHeadings($prj_id)
 
81
    public static function getColumnHeadings($prj_id)
84
82
    {
85
83
        $headings = array(
86
84
            'Priority',
236
234
     * @param   integer $issue_id The issue ID
237
235
     * @return  integer The customer ID associated with the issue
238
236
     */
239
 
    function getCustomerID($issue_id)
 
237
    public static function getCustomerID($issue_id)
240
238
    {
241
239
        static $returns;
242
240
 
2364
2362
        return $issue_id;
2365
2363
    }
2366
2364
 
2367
 
 
2368
 
    /**
2369
 
     * Method used to get a specific parameter in the issue listing cookie.
2370
 
     *
2371
 
     * @access  public
2372
 
     * @param   string $name The name of the parameter
2373
 
     * @return  mixed The value of the specified parameter
2374
 
     */
2375
 
    function getParam($name)
2376
 
    {
2377
 
        $profile = Search_Profile::getProfile(Auth::getUserID(), Auth::getCurrentProject(), 'issue');
2378
 
 
2379
 
        if (isset($_GET[$name])) {
2380
 
            return $_GET[$name];
2381
 
        } elseif (isset($_POST[$name])) {
2382
 
            return $_POST[$name];
2383
 
        } elseif (isset($profile[$name])) {
2384
 
            return $profile[$name];
2385
 
        } else {
2386
 
            return "";
2387
 
        }
2388
 
    }
2389
 
 
2390
 
 
2391
 
    /**
2392
 
     * Method used to save the current search parameters in a cookie.
2393
 
     *
2394
 
     * @access  public
2395
 
     * @return  array The search parameters
2396
 
     */
2397
 
    function saveSearchParams()
2398
 
    {
2399
 
        $sort_by = self::getParam('sort_by');
2400
 
        $sort_order = self::getParam('sort_order');
2401
 
        $rows = self::getParam('rows');
2402
 
        $hide_closed = self::getParam('hide_closed');
2403
 
        if ($hide_closed === '') {
2404
 
            $hide_closed = 1;
2405
 
        }
2406
 
        $search_type = self::getParam('search_type');
2407
 
        if (empty($search_type)) {
2408
 
            $search_type = 'all_text';
2409
 
        }
2410
 
        $custom_field = self::getParam('custom_field');
2411
 
        if (is_string($custom_field)) {
2412
 
            $custom_field = unserialize(urldecode($custom_field));
2413
 
        }
2414
 
        $cookie = array(
2415
 
            'rows'           => Misc::escapeInteger($rows ? $rows : APP_DEFAULT_PAGER_SIZE),
2416
 
            'pagerRow'       => Misc::escapeInteger(self::getParam('pagerRow')),
2417
 
            'hide_closed'    => $hide_closed,
2418
 
            "sort_by"        => Misc::stripHTML($sort_by ? $sort_by : "pri_rank"),
2419
 
            "sort_order"     => Misc::stripHTML($sort_order ? $sort_order : "ASC"),
2420
 
            "customer_id"    => Misc::escapeInteger(self::getParam('customer_id')),
2421
 
            // quick filter form
2422
 
            'keywords'       => self::getParam('keywords'),
2423
 
            'search_type'    => Misc::stripHTML($search_type),
2424
 
            'users'          => Misc::escapeInteger(self::getParam('users')),
2425
 
            'status'         => Misc::escapeInteger(self::getParam('status')),
2426
 
            'priority'       => Misc::escapeInteger(self::getParam('priority')),
2427
 
            'category'       => Misc::escapeInteger(self::getParam('category')),
2428
 
            'customer_email' => Misc::stripHTML(self::getParam('customer_email')),
2429
 
            // advanced search form
2430
 
            'show_authorized_issues'        => Misc::escapeInteger(self::getParam('show_authorized_issues')),
2431
 
            'show_notification_list_issues' => Misc::escapeInteger(self::getParam('show_notification_list_issues')),
2432
 
            'reporter'       => Misc::escapeInteger(self::getParam('reporter')),
2433
 
            // other fields
2434
 
            'release'        => Misc::escapeInteger(self::getParam('release')),
2435
 
            // custom fields
2436
 
            'custom_field'   => Misc::stripHTML($custom_field)
2437
 
        );
2438
 
        // now do some magic to properly format the date fields
2439
 
        $date_fields = array(
2440
 
            'created_date',
2441
 
            'updated_date',
2442
 
            'last_response_date',
2443
 
            'first_response_date',
2444
 
            'closed_date'
2445
 
        );
2446
 
        foreach ($date_fields as $field_name) {
2447
 
            $field = Misc::stripHTML(self::getParam($field_name));
2448
 
            if (empty($field)) {
2449
 
                continue;
2450
 
            }
2451
 
            if (@$field['filter_type'] == 'in_past') {
2452
 
                @$cookie[$field_name] = array(
2453
 
                    'filter_type'   =>  'in_past',
2454
 
                    'time_period'   =>  $field['time_period']
2455
 
                );
2456
 
            } else {
2457
 
                $end_field_name = $field_name . '_end';
2458
 
                $end_field = Misc::stripHTML(self::getParam($end_field_name));
2459
 
                @$cookie[$field_name] = array(
2460
 
                    'past_hour'   => $field['past_hour'],
2461
 
                    'Year'        => $field['Year'],
2462
 
                    'Month'       => $field['Month'],
2463
 
                    'Day'         => $field['Day'],
2464
 
                    'start'       => $field['Year'] . '-' . $field['Month'] . '-' . $field['Day'],
2465
 
                    'filter_type' => $field['filter_type'],
2466
 
                    'end'         => $end_field['Year'] . '-' . $end_field['Month'] . '-' . $end_field['Day']
2467
 
                );
2468
 
                @$cookie[$end_field_name] = array(
2469
 
                    'Year'        => $end_field['Year'],
2470
 
                    'Month'       => $end_field['Month'],
2471
 
                    'Day'         => $end_field['Day']
2472
 
                );
2473
 
            }
2474
 
        }
2475
 
        Search_Profile::save(Auth::getUserID(), Auth::getCurrentProject(), 'issue', $cookie);
2476
 
        return $cookie;
2477
 
    }
2478
 
 
2479
 
 
2480
 
    /**
2481
 
     * Method used to get the current sorting options used in the grid layout
2482
 
     * of the issue listing page.
2483
 
     *
2484
 
     * @access  public
2485
 
     * @param   array $options The current search parameters
2486
 
     * @return  array The sorting options
2487
 
     */
2488
 
    function getSortingInfo($options)
2489
 
    {
2490
 
 
2491
 
        $custom_fields = Custom_Field::getFieldsToBeListed(Auth::getCurrentProject());
2492
 
 
2493
 
        // default order for last action date, priority should be descending
2494
 
        // for textual fields, like summary, ascending is reasonable
2495
 
        $fields = array(
2496
 
            "pri_rank" => "desc",
2497
 
            "iss_id" => "desc",
2498
 
            "iss_customer_id" => "desc",
2499
 
            "prc_title" => "asc",
2500
 
            "sta_rank" => "asc",
2501
 
            "iss_created_date" => "desc",
2502
 
            "iss_summary" => "asc",
2503
 
            "last_action_date" => "desc",
2504
 
            "usr_full_name" => "asc",
2505
 
            "iss_expected_resolution_date" => "desc",
2506
 
            "pre_title" => "asc",
2507
 
            "assigned" => "asc",
2508
 
        );
2509
 
 
2510
 
        foreach ($custom_fields as $fld_id => $fld_name) {
2511
 
            $fields['custom_field_' . $fld_id] = "desc";
2512
 
        }
2513
 
 
2514
 
        $sortfields = array_combine(array_keys($fields), array_keys($fields));
2515
 
        $sortfields["pre_title"] = "pre_scheduled_date";
2516
 
        $sortfields["assigned"] = "isu_usr_id";
2517
 
 
2518
 
        $items = array(
2519
 
            "links"  => array(),
2520
 
            "images" => array()
2521
 
        );
2522
 
        foreach ($sortfields as $field => $sortfield) {
2523
 
            $sort_order = $fields[$field];
2524
 
            if ($options["sort_by"] == $sortfield) {
2525
 
                $items["images"][$field] = "images/" . strtolower($options["sort_order"]) . ".gif";
2526
 
                if (strtolower($options["sort_order"]) == "asc") {
2527
 
                    $sort_order = "desc";
2528
 
                } else {
2529
 
                    $sort_order = "asc";
2530
 
                }
2531
 
            }
2532
 
            $items["links"][$field] = $_SERVER["PHP_SELF"] . "?sort_by=" . $sortfield . "&sort_order=" . $sort_order;
2533
 
        }
2534
 
        return $items;
2535
 
    }
2536
 
 
2537
 
 
2538
2365
    /**
2539
2366
     * Returns the list of action date fields appropriate for the
2540
2367
     * current user ID.
2541
2368
     *
2542
 
     * @access  public
2543
2369
     * @return  array The list of action date fields
2544
2370
     */
2545
 
    function getLastActionFields()
 
2371
    public static function getLastActionFields()
2546
2372
    {
2547
2373
        $last_action_fields = array(
2548
2374
            "iss_last_public_action_date"
2559
2385
 
2560
2386
 
2561
2387
    /**
2562
 
     * Method used to get the list of issues to be displayed in the grid layout.
2563
 
     *
2564
 
     * @access  public
2565
 
     * @param   integer $prj_id The current project ID
2566
 
     * @param   array $options The search parameters
2567
 
     * @param   integer $current_row The current page number
2568
 
     * @param   integer $max The maximum number of rows per page. 'ALL' for unlimited.
2569
 
     * @return  array The list of issues to be displayed
2570
 
     */
2571
 
    function getListing($prj_id, $options, $current_row = 0, $max = 5)
2572
 
    {
2573
 
        if (strtoupper($max) == "ALL") {
2574
 
            $max = 9999999;
2575
 
        }
2576
 
        $start = $current_row * $max;
2577
 
        // get the current user's role
2578
 
        $usr_id = Auth::getUserID();
2579
 
        $role_id = User::getRoleByUser($usr_id, $prj_id);
2580
 
 
2581
 
        // get any custom fields that should be displayed
2582
 
        $custom_fields = Custom_Field::getFieldsToBeListed($prj_id);
2583
 
 
2584
 
        $stmt = "SELECT
2585
 
                    iss_id,
2586
 
                    iss_grp_id,
2587
 
                    iss_prj_id,
2588
 
                    iss_sta_id,
2589
 
                    iss_customer_id,
2590
 
                    iss_customer_contract_id,
2591
 
                    iss_created_date,
2592
 
                    iss_updated_date,
2593
 
                    iss_last_response_date,
2594
 
                    iss_closed_date,
2595
 
                    iss_last_customer_action_date,
2596
 
                    iss_usr_id,
2597
 
                    iss_summary,
2598
 
                    pri_title,
2599
 
                    prc_title,
2600
 
                    sta_title,
2601
 
                    sta_color status_color,
2602
 
                    sta_id,
2603
 
                    iqu_status,
2604
 
                    grp_name `group`,
2605
 
                    pre_title,
2606
 
                    iss_last_public_action_date,
2607
 
                    iss_last_public_action_type,
2608
 
                    iss_last_internal_action_date,
2609
 
                    iss_last_internal_action_type,
2610
 
                    " . self::getLastActionFields() . ",
2611
 
                    IF(iss_last_internal_action_date > iss_last_public_action_date, 'internal', 'public') AS action_type,
2612
 
                    iss_private,
2613
 
                    usr_full_name,
2614
 
                    iss_percent_complete,
2615
 
                    iss_dev_time,
2616
 
                    iss_expected_resolution_date
2617
 
                 FROM
2618
 
                    (
2619
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue,
2620
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "user";
2621
 
        // join custom fields if we are searching by custom fields
2622
 
        if ((is_array($options['custom_field'])) && (count($options['custom_field']) > 0)) {
2623
 
            foreach ($options['custom_field'] as $fld_id => $search_value) {
2624
 
                if (empty($search_value)) {
2625
 
                    continue;
2626
 
                }
2627
 
                $field = Custom_Field::getDetails($fld_id);
2628
 
                if (($field['fld_type'] == 'date') && ((empty($search_value['Year'])) || (empty($search_value['Month'])) || (empty($search_value['Day'])))) {
2629
 
                    continue;
2630
 
                }
2631
 
                if (($field['fld_type'] == 'integer') && empty($search_value['value'])) {
2632
 
                    continue;
2633
 
                }
2634
 
                if ($field['fld_type'] == 'multiple') {
2635
 
                    $search_value = Misc::escapeInteger($search_value);
2636
 
                    foreach ($search_value as $cfo_id) {
2637
 
                        $stmt .= ",\n" . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field as cf" . $fld_id . '_' . $cfo_id . "\n";
2638
 
                    }
2639
 
                } else {
2640
 
                    $stmt .= ",\n" . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field as cf" . $fld_id . "\n";
2641
 
                }
2642
 
            }
2643
 
        }
2644
 
        $stmt .= ")";
2645
 
        // check for the custom fields we want to sort by
2646
 
        if (strstr($options['sort_by'], 'custom_field') !== false) {
2647
 
            $fld_id = str_replace("custom_field_", '', $options['sort_by']);
2648
 
            $stmt .= "\n LEFT JOIN \n" .
2649
 
                APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field as cf_sort
2650
 
                ON
2651
 
                    (cf_sort.icf_iss_id = iss_id AND cf_sort.icf_fld_id = $fld_id) \n";
2652
 
        }
2653
 
        if (!empty($options["users"]) || $options["sort_by"] === "isu_usr_id") {
2654
 
            $stmt .= "
2655
 
                 LEFT JOIN
2656
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
2657
 
                 ON
2658
 
                    isu_iss_id=iss_id";
2659
 
        }
2660
 
        if ((!empty($options["show_authorized_issues"])) || (($role_id == User::getRoleID("Reporter")) && (Project::getSegregateReporters($prj_id)))) {
2661
 
            $stmt .= "
2662
 
                 LEFT JOIN
2663
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user_replier
2664
 
                 ON
2665
 
                    iur_iss_id=iss_id";
2666
 
        }
2667
 
        if (!empty($options["show_notification_list_issues"])) {
2668
 
            $stmt .= "
2669
 
                 LEFT JOIN
2670
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "subscription
2671
 
                 ON
2672
 
                    sub_iss_id=iss_id";
2673
 
        }
2674
 
        $stmt .= "
2675
 
                 LEFT JOIN
2676
 
                    " . APP_DEFAULT_DB . ".`" . APP_TABLE_PREFIX . "group`
2677
 
                 ON
2678
 
                    iss_grp_id=grp_id
2679
 
                 LEFT JOIN
2680
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "project_category
2681
 
                 ON
2682
 
                    iss_prc_id=prc_id
2683
 
                 LEFT JOIN
2684
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "project_release
2685
 
                 ON
2686
 
                    iss_pre_id = pre_id
2687
 
                 LEFT JOIN
2688
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "status
2689
 
                 ON
2690
 
                    iss_sta_id=sta_id
2691
 
                 LEFT JOIN
2692
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "project_priority
2693
 
                 ON
2694
 
                    iss_pri_id=pri_id
2695
 
                 LEFT JOIN
2696
 
                    " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_quarantine
2697
 
                 ON
2698
 
                    iss_id=iqu_iss_id AND
2699
 
                    (iqu_expiration > '" . Date_Helper::getCurrentDateGMT() . "' OR iqu_expiration IS NULL)
2700
 
                 WHERE
2701
 
                    iss_prj_id= " . Misc::escapeInteger($prj_id);
2702
 
        $stmt .= self::buildWhereClause($options);
2703
 
 
2704
 
        if (strstr($options["sort_by"], 'custom_field') !== false) {
2705
 
            $fld_details = Custom_Field::getDetails($fld_id);
2706
 
            $sort_by = 'cf_sort.' . Custom_Field::getDBValueFieldNameByType($fld_details['fld_type']);
2707
 
        } else {
2708
 
            $sort_by = Misc::escapeString($options["sort_by"]);
2709
 
        }
2710
 
 
2711
 
        $stmt .= "
2712
 
                 GROUP BY
2713
 
                    iss_id
2714
 
                 ORDER BY
2715
 
                    " . $sort_by . " " . Misc::escapeString($options["sort_order"]) . ",
2716
 
                    iss_id DESC";
2717
 
        $total_rows = Pager::getTotalRows($stmt);
2718
 
        $stmt .= "
2719
 
                 LIMIT
2720
 
                    " . Misc::escapeInteger($start) . ", " . Misc::escapeInteger($max);
2721
 
        $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC);
2722
 
        if (PEAR::isError($res)) {
2723
 
            Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
2724
 
            return array(
2725
 
                "list" => "",
2726
 
                "info" => ""
2727
 
            );
2728
 
        } else {
2729
 
            if (count($res) > 0) {
2730
 
                self::getAssignedUsersByIssues($res);
2731
 
                Time_Tracking::getTimeSpentByIssues($res);
2732
 
                // need to get the customer titles for all of these issues...
2733
 
                if (Customer::hasCustomerIntegration($prj_id)) {
2734
 
                    Customer::getCustomerTitlesByIssues($prj_id, $res);
2735
 
                    Customer::getSupportLevelsByIssues($prj_id, $res);
2736
 
                }
2737
 
                self::formatLastActionDates($res);
2738
 
                self::getLastStatusChangeDates($prj_id, $res);
2739
 
            } elseif ($current_row > 0) {
2740
 
                // if there are no results, and the page is not the first page reset page to one and reload results
2741
 
                Auth::redirect("list.php?pagerRow=0&rows=$max");
2742
 
            }
2743
 
            $groups = Group::getAssocList($prj_id);
2744
 
            $categories = Category::getAssocList($prj_id);
2745
 
            $column_headings = self::getColumnHeadings($prj_id);
2746
 
            if (count($custom_fields) > 0) {
2747
 
                $column_headings = array_merge($column_headings,$custom_fields);
2748
 
            }
2749
 
            $csv[] = @implode("\t", $column_headings);
2750
 
            for ($i = 0; $i < count($res); $i++) {
2751
 
                $res[$i]["time_spent"] = Misc::getFormattedTime($res[$i]["time_spent"]);
2752
 
                $res[$i]["iss_created_date"] = Date_Helper::getFormattedDate($res[$i]["iss_created_date"]);
2753
 
                $res[$i]["iss_expected_resolution_date"] = Date_Helper::getSimpleDate($res[$i]["iss_expected_resolution_date"], false);
2754
 
                $fields = array(
2755
 
                    $res[$i]['pri_title'],
2756
 
                    $res[$i]['iss_id'],
2757
 
                    $res[$i]['usr_full_name'],
2758
 
                );
2759
 
                // hide the group column from the output if no
2760
 
                // groups are available in the database
2761
 
                if (count($groups) > 0) {
2762
 
                    $fields[] = $res[$i]['group'];
2763
 
                }
2764
 
                $fields[] = $res[$i]['assigned_users'];
2765
 
                $fields[] = $res[$i]['time_spent'];
2766
 
                // hide the category column from the output if no
2767
 
                // categories are available in the database
2768
 
                if (count($categories) > 0) {
2769
 
                    $fields[] = $res[$i]['prc_title'];
2770
 
                }
2771
 
                if (Customer::hasCustomerIntegration($prj_id)) {
2772
 
                    $fields[] = @$res[$i]['customer_title'];
2773
 
                    // check if current user is acustomer and has a per incident contract.
2774
 
                    // if so, check if issue is redeemed.
2775
 
                    if (User::getRoleByUser($usr_id, $prj_id) == User::getRoleID('Customer')) {
2776
 
                        if ((Customer::hasPerIncidentContract($prj_id, self::getCustomerID($res[$i]['iss_id'])) &&
2777
 
                                (Customer::isRedeemedIncident($prj_id, $res[$i]['iss_id'])))) {
2778
 
                            $res[$i]['redeemed'] = true;
2779
 
                        }
2780
 
                    }
2781
 
                }
2782
 
                $fields[] = $res[$i]['sta_title'];
2783
 
                $fields[] = $res[$i]["status_change_date"];
2784
 
                $fields[] = $res[$i]["last_action_date"];
2785
 
                $fields[] = $res[$i]['iss_dev_time'];
2786
 
                $fields[] = $res[$i]['iss_summary'];
2787
 
                $fields[] = $res[$i]['iss_expected_resolution_date'];
2788
 
 
2789
 
                if (count($custom_fields) > 0) {
2790
 
                    $res[$i]['custom_field'] = array();
2791
 
                    $custom_field_values = Custom_Field::getListByIssue($prj_id, $res[$i]['iss_id']);
2792
 
                    foreach ($custom_field_values as $this_field) {
2793
 
                        if (!empty($custom_fields[$this_field['fld_id']])) {
2794
 
                            $res[$i]['custom_field'][$this_field['fld_id']] = $this_field['value'];
2795
 
                            $fields[] = $this_field['value'];
2796
 
                        }
2797
 
                    }
2798
 
                }
2799
 
 
2800
 
                $csv[] = @implode("\t", $fields);
2801
 
            }
2802
 
            $total_pages = ceil($total_rows / $max);
2803
 
            $last_page = $total_pages - 1;
2804
 
            return array(
2805
 
                "list" => $res,
2806
 
                "info" => array(
2807
 
                    "current_page"  => $current_row,
2808
 
                    "start_offset"  => $start,
2809
 
                    "end_offset"    => $start + count($res),
2810
 
                    "total_rows"    => $total_rows,
2811
 
                    "total_pages"   => $total_pages,
2812
 
                    "previous_page" => ($current_row == 0) ? "-1" : ($current_row - 1),
2813
 
                    "next_page"     => ($current_row == $last_page) ? "-1" : ($current_row + 1),
2814
 
                    "last_page"     => $last_page,
2815
 
                    "custom_fields" => $custom_fields
2816
 
                ),
2817
 
                "csv" => @implode("\n", $csv)
2818
 
            );
2819
 
        }
2820
 
    }
2821
 
 
2822
 
 
2823
 
    /**
2824
2388
     * Processes a result set to format the "Last Action Date" column.
2825
2389
     *
2826
 
     * @access  public
2827
2390
     * @param   array $result The result set
2828
2391
     */
2829
 
    function formatLastActionDates(&$result)
 
2392
    public static function formatLastActionDates(&$result)
2830
2393
    {
2831
2394
        for ($i = 0; $i < count($result); $i++) {
2832
2395
            if (($result[$i]['action_type'] == "internal") &&
2848
2411
    /**
2849
2412
     * Retrieves the last status change date for the given issue.
2850
2413
     *
2851
 
     * @access  public
2852
2414
     * @param   integer $prj_id The project ID
2853
2415
     * @param   array $result The associative array of data
2854
 
     * @see     self::getListing()
 
2416
     * @see     Search::getListing()
2855
2417
     */
2856
 
    function getLastStatusChangeDates($prj_id, &$result)
 
2418
    public static function getLastStatusChangeDates($prj_id, &$result)
2857
2419
    {
2858
2420
        $ids = array();
2859
2421
        for ($i = 0; $i < count($result); $i++) {
2887
2449
 
2888
2450
 
2889
2451
    /**
2890
 
     * Method used to get the list of issues to be displayed in the grid layout.
2891
 
     *
2892
 
     * @access  public
2893
 
     * @param   array $options The search parameters
2894
 
     * @return  string The where clause
2895
 
     */
2896
 
    function buildWhereClause($options)
2897
 
    {
2898
 
        $usr_id = Auth::getUserID();
2899
 
        $prj_id = Auth::getCurrentProject();
2900
 
        $role_id = User::getRoleByUser($usr_id, $prj_id);
2901
 
 
2902
 
        $stmt = ' AND iss_usr_id = usr_id';
2903
 
        if ($role_id == User::getRoleID('Customer')) {
2904
 
            $stmt .= " AND iss_customer_id=" . User::getCustomerID($usr_id);
2905
 
        } elseif (($role_id == User::getRoleID("Reporter")) && (Project::getSegregateReporters($prj_id))) {
2906
 
            $stmt .= " AND (
2907
 
                        iss_usr_id = $usr_id OR
2908
 
                        iur_usr_id = $usr_id
2909
 
                        )";
2910
 
        }
2911
 
 
2912
 
        if (!empty($options["users"])) {
2913
 
            $stmt .= " AND (\n";
2914
 
            if (stristr($options["users"], "grp") !== false) {
2915
 
                $chunks = explode(":", $options["users"]);
2916
 
                $stmt .= 'iss_grp_id = ' . Misc::escapeInteger($chunks[1]);
2917
 
            } else {
2918
 
                if ($options['users'] == '-1') {
2919
 
                    $stmt .= 'isu_usr_id IS NULL';
2920
 
                } elseif ($options['users'] == '-2') {
2921
 
                    $stmt .= 'isu_usr_id IS NULL OR isu_usr_id=' . $usr_id;
2922
 
                } elseif ($options['users'] == '-3') {
2923
 
                    $stmt .= 'isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id);
2924
 
                } elseif ($options['users'] == '-4') {
2925
 
                    $stmt .= 'isu_usr_id IS NULL OR isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id);
2926
 
                } else {
2927
 
                    $stmt .= 'isu_usr_id =' . Misc::escapeInteger($options["users"]);
2928
 
                }
2929
 
            }
2930
 
            $stmt .= ')';
2931
 
        }
2932
 
        if (!empty($options["reporter"])) {
2933
 
            $stmt .= " AND iss_usr_id = " . Misc::escapeInteger($options["reporter"]);
2934
 
        }
2935
 
        if (!empty($options["show_authorized_issues"])) {
2936
 
            $stmt .= " AND (iur_usr_id=$usr_id)";
2937
 
        }
2938
 
        if (!empty($options["show_notification_list_issues"])) {
2939
 
            $stmt .= " AND (sub_usr_id=$usr_id)";
2940
 
        }
2941
 
        if (!empty($options["keywords"])) {
2942
 
            $stmt .= " AND (\n";
2943
 
            if (($options['search_type'] == 'all_text') && (APP_ENABLE_FULLTEXT)) {
2944
 
                $stmt .= "iss_id IN(" . join(', ', self::getFullTextIssues($options)) . ")";
2945
 
            } elseif (($options['search_type'] == 'customer') && (Customer::hasCustomerIntegration($prj_id))) {
2946
 
                // check if the user is trying to search by customer email
2947
 
                $customer_ids = Customer::getCustomerIDsLikeEmail($prj_id, $options['keywords']);
2948
 
                if (count($customer_ids) > 0) {
2949
 
                    $stmt .= " iss_customer_id IN (" . implode(', ', $customer_ids) . ")";
2950
 
                } else {
2951
 
                    // no results, kill query
2952
 
                    $stmt .= " iss_customer_id = -1";
2953
 
                }
2954
 
            } else {
2955
 
                $stmt .= "(" . Misc::prepareBooleanSearch('iss_summary', $options["keywords"]);
2956
 
                $stmt .= " OR " . Misc::prepareBooleanSearch('iss_description', $options["keywords"]) . ")";
2957
 
            }
2958
 
            $stmt .= "\n) ";
2959
 
        }
2960
 
        if (!empty($options['customer_id'])) {
2961
 
            $stmt .= " AND iss_customer_id=" . Misc::escapeInteger($options["customer_id"]);
2962
 
        }
2963
 
        if (!empty($options["priority"])) {
2964
 
            $stmt .= " AND iss_pri_id=" . Misc::escapeInteger($options["priority"]);
2965
 
        }
2966
 
        if (!empty($options["status"])) {
2967
 
            $stmt .= " AND iss_sta_id=" . Misc::escapeInteger($options["status"]);
2968
 
        }
2969
 
        if (!empty($options["category"])) {
2970
 
            if (!is_array($options['category'])) {
2971
 
                $options['category'] = array($options['category']);
2972
 
            }
2973
 
            $stmt .= " AND iss_prc_id IN(" . join(', ', Misc::escapeInteger($options["category"])) . ")";
2974
 
        }
2975
 
        if (!empty($options["hide_closed"])) {
2976
 
            $stmt .= " AND sta_is_closed=0";
2977
 
        }
2978
 
        if (!empty($options['release'])) {
2979
 
            $stmt .= " AND iss_pre_id = " . Misc::escapeInteger($options['release']);
2980
 
        }
2981
 
        // now for the date fields
2982
 
        $date_fields = array(
2983
 
            'created_date',
2984
 
            'updated_date',
2985
 
            'last_response_date',
2986
 
            'first_response_date',
2987
 
            'closed_date'
2988
 
        );
2989
 
        foreach ($date_fields as $field_name) {
2990
 
            if (!empty($options[$field_name])) {
2991
 
                switch ($options[$field_name]['filter_type']) {
2992
 
                    case 'greater':
2993
 
                        $stmt .= " AND iss_$field_name >= '" . Misc::escapeString($options[$field_name]['start']) . "'";
2994
 
                        break;
2995
 
                    case 'less':
2996
 
                        $stmt .= " AND iss_$field_name <= '" . Misc::escapeString($options[$field_name]['start']) . "'";
2997
 
                        break;
2998
 
                    case 'between':
2999
 
                        $stmt .= " AND iss_$field_name BETWEEN '" . Misc::escapeString($options[$field_name]['start']) . "' AND '" . Misc::escapeString($options[$field_name]['end']) . "'";
3000
 
                        break;
3001
 
                    case 'null':
3002
 
                        $stmt .= " AND iss_$field_name IS NULL";
3003
 
                        break;
3004
 
                    case 'in_past':
3005
 
                        if (strlen($options[$field_name]['time_period']) == 0) {
3006
 
                            $options[$field_name]['time_period'] = 0;
3007
 
                        }
3008
 
                        $stmt .= " AND (UNIX_TIMESTAMP('" . Date_Helper::getCurrentDateGMT() . "') - UNIX_TIMESTAMP(iss_$field_name)) <= (" .
3009
 
                            Misc::escapeInteger($options[$field_name]['time_period']) . "*3600)";
3010
 
                        break;
3011
 
                }
3012
 
            }
3013
 
        }
3014
 
        // custom fields
3015
 
        if ((is_array($options['custom_field'])) && (count($options['custom_field']) > 0)) {
3016
 
            foreach ($options['custom_field'] as $fld_id => $search_value) {
3017
 
                if (empty($search_value)) {
3018
 
                    continue;
3019
 
                }
3020
 
                $field = Custom_Field::getDetails($fld_id);
3021
 
                $fld_db_name = Custom_Field::getDBValueFieldNameByType($field['fld_type']);
3022
 
                if (($field['fld_type'] == 'date') &&
3023
 
                        ((empty($search_value['Year'])) || (empty($search_value['Month'])) || (empty($search_value['Day'])))) {
3024
 
                    continue;
3025
 
                }
3026
 
                if (($field['fld_type'] == 'integer') && empty($search_value['value'])) {
3027
 
                    continue;
3028
 
                }
3029
 
 
3030
 
                if ($field['fld_type'] == 'multiple') {
3031
 
                    $search_value = Misc::escapeInteger($search_value);
3032
 
                    foreach ($search_value as $cfo_id) {
3033
 
                        $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . ".icf_iss_id = iss_id";
3034
 
                        $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . ".icf_fld_id = $fld_id";
3035
 
                        $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . "." . $fld_db_name . " = $cfo_id";
3036
 
                    }
3037
 
                } elseif ($field['fld_type'] == 'date') {
3038
 
                    if ((empty($search_value['Year'])) || (empty($search_value['Month'])) || (empty($search_value['Day']))) {
3039
 
                        continue;
3040
 
                    }
3041
 
                    $search_value = $search_value['Year'] . "-" . $search_value['Month'] . "-" . $search_value['Day'];
3042
 
                    $stmt .= " AND\n (iss_id = cf" . $fld_id . ".icf_iss_id AND
3043
 
                        cf" . $fld_id . "." . $fld_db_name . " = '" . Misc::escapeString($search_value) . "')";
3044
 
                } else if ($field['fld_type'] == 'integer') {
3045
 
                    $value = $search_value['value'];
3046
 
                    switch ($search_value['filter_type']) {
3047
 
                    case 'ge':
3048
 
                        $cmp = '>=';
3049
 
                        break;
3050
 
                    case 'le':
3051
 
                        $cmp = '<=';
3052
 
                        break;
3053
 
                    case 'gt':
3054
 
                        $cmp = '>';
3055
 
                        break;
3056
 
                    case 'lt':
3057
 
                        $cmp = '<';
3058
 
                        break;
3059
 
                    default:
3060
 
                        $cmp = '=';
3061
 
                        break;
3062
 
                    }
3063
 
                    $stmt .= " AND\n (iss_id = cf" . $fld_id . ".icf_iss_id";
3064
 
                    $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = $fld_id";
3065
 
                    $stmt .= " AND cf" . $fld_id . "." . $fld_db_name . $cmp . Misc::escapeString($value) . ')';
3066
 
                } else {
3067
 
                    $stmt .= " AND\n (iss_id = cf" . $fld_id . ".icf_iss_id";
3068
 
                    $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = $fld_id";
3069
 
                    if ($field['fld_type'] == 'combo') {
3070
 
                        $stmt .= " AND cf" . $fld_id . "." . $fld_db_name . " IN(" . join(', ', Misc::escapeInteger($search_value)) . ")";
3071
 
                    } else {
3072
 
                        $stmt .= " AND cf" . $fld_id . "." . $fld_db_name . " LIKE '%" . Misc::escapeString($search_value) . "%'";
3073
 
                    }
3074
 
                    $stmt .= ')';
3075
 
                }
3076
 
            }
3077
 
        }
3078
 
        // clear cached full-text values if we are not searching fulltext anymore
3079
 
        if ((APP_ENABLE_FULLTEXT) && (@$options['search_type'] != 'all_text')) {
3080
 
            Session::set('fulltext_string', '');
3081
 
            Session::set('fulltext_issues', '');
3082
 
        }
3083
 
        return $stmt;
3084
 
    }
3085
 
 
3086
 
 
3087
 
    /**
3088
2452
     * Method used to get the previous and next issues that are available
3089
2453
     * according to the current search parameters.
3090
2454
     *
3185
2549
                    iss_pri_id=pri_id
3186
2550
                 WHERE
3187
2551
                    iss_prj_id=" . Auth::getCurrentProject();
3188
 
        $stmt .= self::buildWhereClause($options);
 
2552
        $stmt .= Search::buildWhereClause($options);
3189
2553
        if (strstr($options["sort_by"], 'custom_field') !== false) {
3190
2554
            $fld_details = Custom_Field::getDetails($fld_id);
3191
2555
            $sort_by = 'cf_sort.' . Custom_Field::getDBValueFieldNameByType($fld_details['fld_type']);
3310
2674
     * @param   array $result The result set
3311
2675
     * @return  void
3312
2676
     */
3313
 
    function getAssignedUsersByIssues(&$result)
 
2677
    public static function getAssignedUsersByIssues(&$result)
3314
2678
    {
3315
2679
        $ids = array();
3316
2680
        for ($i = 0; $i < count($result); $i++) {
4113
3477
        }
4114
3478
    }
4115
3479
 
4116
 
 
4117
 
    /**
4118
 
     * Returns an array of issues based on full text search results.
4119
 
     *
4120
 
     * @param   array $options An array of search options
4121
 
     * @return  array An array of issue IDS
4122
 
     */
4123
 
    function getFullTextIssues($options)
4124
 
    {
4125
 
        // check if a list of issues for this full text search is already cached
4126
 
        $fulltext_string = Session::get('fulltext_string');
4127
 
        if ((!empty($fulltext_string)) && ($fulltext_string == $options['keywords'])) {
4128
 
            return Session::get('fulltext_issues');
4129
 
        }
4130
 
 
4131
 
        // no pre-existing list, generate them
4132
 
        $stmt = "(SELECT
4133
 
                    DISTINCT(iss_id)
4134
 
                 FROM
4135
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue
4136
 
                 WHERE
4137
 
                     MATCH(iss_summary, iss_description) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)
4138
 
                 ) UNION (
4139
 
                 SELECT
4140
 
                    DISTINCT(not_iss_id)
4141
 
                 FROM
4142
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "note
4143
 
                 WHERE
4144
 
                     MATCH(not_note) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)
4145
 
                 ) UNION (
4146
 
                 SELECT
4147
 
                    DISTINCT(ttr_iss_id)
4148
 
                 FROM
4149
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "time_tracking
4150
 
                 WHERE
4151
 
                     MATCH(ttr_summary) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)
4152
 
                 ) UNION (
4153
 
                 SELECT
4154
 
                    DISTINCT(phs_iss_id)
4155
 
                 FROM
4156
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "phone_support
4157
 
                 WHERE
4158
 
                     MATCH(phs_description) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)
4159
 
                 ) UNION (
4160
 
                 SELECT
4161
 
                     DISTINCT(sup_iss_id)
4162
 
                 FROM
4163
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "support_email,
4164
 
                     " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "support_email_body
4165
 
                 WHERE
4166
 
                     sup_id = seb_sup_id AND
4167
 
                     MATCH(seb_body) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)
4168
 
                 )";
4169
 
        $res = DB_Helper::getInstance()->getCol($stmt);
4170
 
        if (PEAR::isError($res)) {
4171
 
            Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
4172
 
            return array(-1);
4173
 
        } else {
4174
 
            $stmt = "SELECT
4175
 
                        DISTINCT(icf_iss_id)
4176
 
                    FROM
4177
 
                        " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_custom_field
4178
 
                    WHERE
4179
 
                        MATCH (icf_value) AGAINST ('" . Misc::escapeString($options['keywords']) . "' IN BOOLEAN MODE)";
4180
 
            $custom_res = DB_Helper::getInstance()->getCol($stmt);
4181
 
            if (PEAR::isError($custom_res)) {
4182
 
                Error_Handler::logError(array($custom_res->getMessage(), $custom_res->getDebugInfo()), __FILE__, __LINE__);
4183
 
                return array(-1);
4184
 
            }
4185
 
            $issues = array_merge($res, $custom_res);
4186
 
            // we kill the query results on purpose to flag that no
4187
 
            // issues could be found with fulltext search
4188
 
            if (count($issues) < 1) {
4189
 
                $issues = array(-1);
4190
 
            }
4191
 
            Session::set('fulltext_string', $options['keywords']);
4192
 
            Session::set('fulltext_issues', $issues);
4193
 
            return $issues;
4194
 
        }
4195
 
    }
4196
 
 
4197
 
 
4198
3480
    /**
4199
3481
     * Method to determine if user can access a particular issue
4200
3482
     *