GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Tracker_Report::addRendererInSession()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 3
1
<?php
2
/**
3
 * Copyright (c) Enalean, 2011, 2012, 2013, 2014. All Rights Reserved.
4
 * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
5
 *
6
 * This file is a part of Tuleap.
7
 *
8
 * Tuleap is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Tuleap is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Tuleap. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
/**
23
 * Tracker_ report.
24
 * Set of criteria + set of Renderer to search and display artifacts
25
 */
26
class Tracker_Report extends Error implements Tracker_Dispatchable_Interface {
27
28
    const ACTION_SAVE         = 'report-save';
29
    const ACTION_SAVEAS       = 'report-saveas';
30
    const ACTION_REPLACE      = 'report-replace';
31
    const ACTION_DELETE       = 'report-delete';
32
    const ACTION_SCOPE        = 'report-scope';
33
    const ACTION_DEFAULT      = 'report-default';
34
    const ACTION_CLEANSESSION = 'clean-session';
35
    const TYPE_CRITERIA       = 'criteria';
36
    const TYPE_TABLE          = 'table';
37
38
    public $id;
39
    public $name;
40
    public $description;
41
    public $current_renderer_id;
42
    public $parent_report_id;
43
    public $user_id;
44
    public $group_id;
45
    public $is_default;
46
    public $tracker_id;
47
    public $is_query_displayed;
48
    public $updated_by;
49
    public $updated_at;
50
51
    public $renderers;
52
    public $criteria;
53
54
    /**
55
     * Constructor
56
     *
57
     * @param int     $id The id of the report
58
     * @param string  $name The name of the report
59
     * @param string  $description The description of the report
60
     * @param int     $current_renderer_id The current Renderer id to display
61
     * @param int     $parent_report_id The parent report if this report is temporary (null else)
62
     * @param int     $user_id The owner of the report (null if scope = project)
63
     * @param bool    $is_default true if the report is the default one
64
     * @param int     $tracker_id The id of the tracker to which this Tracker_Report is associated.
65
     */
66
    function __construct($id, $name, $description, $current_renderer_id, $parent_report_id, $user_id, $is_default, $tracker_id, $is_query_displayed, $updated_by, $updated_at) {
67
        parent::__construct();
68
        $this->id                  = $id;
69
        $this->name                = $name;
70
        $this->description         = $description;
71
        $this->current_renderer_id = $current_renderer_id;
72
        $this->parent_report_id    = $parent_report_id;
73
        $this->user_id             = $user_id;
74
        $this->is_default          = $is_default;
75
        $this->tracker_id          = $tracker_id;
76
        $this->is_query_displayed  = $is_query_displayed;
77
        $this->updated_by          = $updated_by;
78
        $this->updated_at          = $updated_at;
79
    }
80
81
    public function setProjectId($id) {
82
        $this->group_id = $id;
83
    }
84
85
    protected function getProjectId() {
86
        if (!$this->group_id) {
87
            $this->group_id = $this->tracker->getGroupId();
88
        }
89
        return $this->group_id;
90
    }
91
92
    public function registerInSession() {
93
        $this->report_session = new Tracker_Report_Session($this->id);
94
    }
95
96
    protected function getCriteriaDao() {
97
        return new Tracker_Report_CriteriaDao();
98
    }
99
100
    /** @return Tracker_Report_Criteria[] */
101
    public function getCriteria() {
102
        $session_criteria = null;
103
        if (isset($this->report_session)) {
104
            $session_criteria = &$this->report_session->getCriteria();
105
        }
106
107
        $this->criteria = array();
108
        $ff = $this->getFormElementFactory();
109
        //there is previously stored
110
        if ($session_criteria) {
111
            $rank = 0;
112
            foreach ($session_criteria as $key => $value) {
113
                if ($value['is_removed'] == 0) {
114
                    $is_advanced = isset($value['is_advanced']) ? $value['is_advanced'] : 0 ;
115
                    if ($formElement = $ff->getUsedFormElementById($key)) {
116
                        if ($formElement->userCanRead()) {
117
                            $formElement->setCriteriaValue( (!empty($value['value']) ? $value['value']: ''), $this->id ) ;
118
                            $this->criteria[$key] = new Tracker_Report_Criteria(
119
                                    0,
120
                                    $this,
121
                                    $formElement,
122
                                    $rank,
123
                                    $is_advanced
124
                            );
125
                            $rank++;
126
                        }
127
                    }
128
                }
129
            }
130
        } else {
131
            //retrieve data from database
132
            foreach($this->getCriteriaDao()->searchByReportId($this->id) as $row) {
0 ignored issues
show
Bug introduced by
The expression $this->getCriteriaDao()-...chByReportId($this->id) of type false|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
133
                if ($formElement = $ff->getFormElementFieldById($row['field_id'])) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $formElement is correct as $ff->getFormElementFieldById($row['field_id']) (which targets Tracker_FormElementFacto...tFormElementFieldById()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
134
                    if ($formElement->userCanRead()) {
135
                        $this->criteria[$row['field_id']] = new Tracker_Report_Criteria(
136
                                $row['id'],
137
                                $this,
138
                                $formElement,
139
                                $row['rank'],
140
                                $row['is_advanced']
141
                        );
142
                        $criterion_value = $formElement->getCriteriaValue($this->criteria[$row['field_id']]);
143
                        $criterion_opts['is_advanced'] = $row['is_advanced'];
144
                        if (isset($this->report_session)) {
145
                            $this->report_session->storeCriterion($row['field_id'], $criterion_value, $criterion_opts );
146
                        }
147
                    }
148
                }
149
            }
150
        }
151
        return $this->criteria;
152
    }
153
154
    public function getCriteriaFromDb() {
155
        $this->criteria = array();
156
        $ff = $this->getFormElementFactory();
157
        //retrieve data from database
158
        foreach($this->getCriteriaDao()->searchByReportId($this->id) as $row) {
0 ignored issues
show
Bug introduced by
The expression $this->getCriteriaDao()-...chByReportId($this->id) of type false|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
159
            if ($formElement = $ff->getFormElementById($row['field_id'])) {
160
                if ($formElement->userCanRead()) {
161
                    $this->criteria[$row['field_id']] = new Tracker_Report_Criteria(
162
                            $row['id'],
163
                            $this,
164
                            $formElement,
165
                            $row['rank'],
166
                            $row['is_advanced']
167
                    );
168
                }
169
            }
170
        }
171
        return $this->criteria;
172
    }
173
174
    public function getFormElementFactory() {
175
        return Tracker_FormElementFactory::instance();
176
    }
177
    /**
178
     * Sets or adds a criterion to the global report search criteria list
179
     * @param integer $field_id criterion id to be added or set
180
     * @return Tracker_Report_Criteria
181
     * @TODO refactor : must be renamed after addCriterion, and return the current criterion
182
     */
183
    protected function setCriteria($field_id) {
184
        $ff = $this->getFormElementFactory();
185
        $formElement = $ff->getFormElementById($field_id);
186
        $this->criteria[$field_id] = new Tracker_Report_Criteria(
187
                                0,
188
                                $this,
189
                                $formElement,
190
                                0,
191
                                0
192
                            );
193
        return $this->criteria[$field_id];
194
    }
195
196
    protected $current_user;
197
    protected function getCurrentUser() {
198
        if (!$this->current_user) {
199
            $this->current_user = UserManager::instance()->getCurrentUser();
200
        }
201
        return $this->current_user;
202
    }
203
204
    protected $permissions_manager;
205
    private function getPermissionsManager() {
206
        if (!$this->permissions_manager) {
207
            $this->permissions_manager = PermissionsManager::instance();
208
        }
209
        return $this->permissions_manager;
210
    }
211
212
    protected $matching_ids;
213
    public function getMatchingIds($request = null, $use_data_from_db = false) {
214
        if (!$this->matching_ids) {
215
            $user = $this->getCurrentUser();
216
            if ($use_data_from_db) {
217
                $criteria = $this->getCriteriaFromDb();
218
            } else {
219
                $criteria = $this->getCriteria();
220
            }
221
            $this->matching_ids = $this->getMatchingIdsInDb($this->getDao(), $this->getPermissionsManager(), $this->getTracker(), $user, $criteria);
222
223
            $additional_criteria = $this->getAdditionalCriteria();
224
            $result              = array();
225
            $search_performed    = false;
226
            EventManager::instance()->processEvent(
227
                TRACKER_EVENT_REPORT_PROCESS_ADDITIONAL_QUERY,
228
                array(
229
                    'request'              => $request,
230
                    'result'               => &$result,
231
                    'search_performed'     => &$search_performed,
232
                    'tracker'              => $this->getTracker(),
233
                    'additional_criteria'  => $additional_criteria,
234
                    'user'                 => $user,
235
                    'form_element_factory' => $this->getFormElementFactory()
236
                )
237
            );
238
            if ($search_performed) {
239
                $joiner = new Tracker_Report_ResultJoiner();
240
241
                $this->matching_ids = $this->implodeMatchingIds(
242
                    $joiner->joinResults(
243
                        $this->getLastChangesetIdByArtifactId($this->matching_ids),
244
                        $result
245
                    )
246
                );
247
            }
248
        }
249
250
        return $this->matching_ids;
251
    }
252
253
    /**
254
     * Given the output of getMatchingIds() which returns an array containing 'artifacts ids' and  'Last changeset ids'
255
     * as two strings with comma separated values, this method would format such output to an array with artifactIds in keys
256
     * and last changeset ids in values.
257
     * @see Tracker_Report::getMatchingIds() for usage
258
     *
259
     * @return Array
260
     */
261
    private function getLastChangesetIdByArtifactId($matching_ids) {
262
        $artifact_ids       = explode(',', $matching_ids['id']);
263
        $last_changeset_ids = explode(',', $matching_ids['last_changeset_id']);
264
265
        $formatted_matching_ids = array();
266
        foreach ($artifact_ids as $key => $artifactId) {
267
            $formatted_matching_ids[$artifactId] = $last_changeset_ids[$key];
268
        }
269
        return $formatted_matching_ids;
270
    }
271
272
    /**
273
     * This method is the opposite of getLastChangesetIdByArtifactId().
274
     * Given an array with artifactIds in keys and lastChangesetIds on values it would return and array with two elements of type string
275
     * the first contains comma separated "artifactIds" and the second contains comma separated "lastChangesetIds".
276
     * @see Tracker_Report::getMatchingIds() for usage
277
     *
278
     * @param Array $formattedMatchingIds Matching Id's that will get converted in that format
279
     *
280
     * @return Array
281
     */
282
    private function implodeMatchingIds($formattedMatchingIds) {
283
        $matchingIds['id']                = '';
284
        $matchingIds['last_changeset_id'] = '';
285
        foreach ($formattedMatchingIds as $artifactId => $lastChangesetId) {
286
            $matchingIds['id']                .= $artifactId.',';
287
            $matchingIds['last_changeset_id'] .= $lastChangesetId.',';
288
        }
289
        if (substr($matchingIds['id'], -1) === ',') {
290
            $matchingIds['id'] = substr($matchingIds['id'], 0, -1);
291
        }
292
        if (substr($matchingIds['last_changeset_id'], -1) === ',') {
293
            $matchingIds['last_changeset_id'] = substr($matchingIds['last_changeset_id'], 0, -1);
294
        }
295
        return $matchingIds;
296
    }
297
298
    protected function getMatchingIdsInDb(DataAccessObject $dao, PermissionsManager $permissionManager, Tracker $tracker, PFUser $user, array $criteria) {
299
        $dump_criteria = array();
300
        foreach ($criteria as $c) {
301
            $dump_criteria[$c->field->getName()] = $c->field->getCriteriaValue($c);
302
        }
303
        $dao->logStart(__METHOD__, json_encode(array(
304
            'user'     => $user->getUserName(),
305
            'project'  => $tracker->getGroupId(),
306
            'query'    => $dump_criteria,
307
            'trackers' => array($tracker->getId()),
308
        )));
309
310
        $matching_ids = array();
311
312
        $group_id             = $tracker->getGroupId();
313
        $permissions          = $permissionManager->getPermissionsAndUgroupsByObjectid($tracker->getId());
314
        $contributor_field    = $tracker->getContributorField();
315
        $contributor_field_id = $contributor_field ? $contributor_field->getId() : null;
316
317
        $additional_from  = array();
318
        $additional_where = array();
319
        foreach($criteria as $c) {
320
            if ($f = $c->getFrom()) {
321
                $additional_from[]  = $f;
322
            }
323
324
            if ($w = $c->getWhere()) {
325
                $additional_where[] = $w;
326
            }
327
        }
328
        $matching_ids['id']                = '';
329
        $matching_ids['last_changeset_id'] = '';
330
        $matching_ids_result = $dao->searchMatchingIds($group_id, $tracker->getId(), $additional_from, $additional_where, $user, $permissions, $contributor_field_id);
331
        if ($matching_ids_result) {
332
            $matching_ids = $matching_ids_result->getRow();
333
            if ($matching_ids) {
334
                if (substr($matching_ids['id'], -1) === ',') {
335
                    $matching_ids['id'] = substr($matching_ids['id'], 0, -1);
336
                }
337
                if (substr($matching_ids['last_changeset_id'], -1) === ',') {
338
                    $matching_ids['last_changeset_id'] = substr($matching_ids['last_changeset_id'], 0, -1);
339
                }
340
            }
341
        }
342
343
        $nb_matching = $matching_ids['id'] ? substr_count($matching_ids['id'], ',') + 1 : 0;
344
        $dao->logEnd(__METHOD__, $nb_matching);
345
346
        return $matching_ids;
347
    }
348
349
    /**
350
     * @return boolean true if the report has been modified since the last checkout
351
     */
352
    public function isObsolete() {
353
        return isset($this->report_session) && $this->updated_at && ($this->report_session->get('checkout_date') < $this->updated_at);
354
    }
355
356
    /**
357
     * @return string html the user who has modified the report. Or false if the report has not been modified
358
     */
359
    public function getLastUpdaterUserName() {
360
        if ($this->isObsolete()) {
361
            return UserHelper::instance()->getLinkOnUserFromUserId($this->updated_by);
362
        }
363
        return '';
364
    }
365
366
    protected function displayHeader(Tracker_IFetchTrackerSwitcher $layout, $request, $current_user, $report_can_be_modified) {
367
        $header_builder = new Tracker_Report_HeaderRenderer(
368
            Tracker_ReportFactory::instance(),
369
            Codendi_HTMLPurifier::instance(),
370
            $this->getTemplateRenderer()
371
        );
372
        $header_builder->displayHeader($layout, $request, $current_user, $this, $report_can_be_modified);
373
    }
374
375
    public function nbPublicReport($reports) {
376
        $i = 0;
377
        foreach ($reports as $report) {
378
            if ($report->user_id == null) {
379
              $i++;
380
            }
381
        }
382
        return $i;
383
    }
384
385
    public function fetchDisplayQuery(array $criteria, array $additional_criteria, $report_can_be_modified, PFUser $current_user) {
386
        $hp              = Codendi_HTMLPurifier::instance();
387
388
        $html  = '';
389
        $html .= '<div id="tracker_report_query" data-report-id="'.$this->id.'">';
390
        $html .= '<form action="" method="POST" id="tracker_report_query_form">';
391
        $html .= '<input type="hidden" name="report" value="' . $this->id . '" />';
392
        $id = 'tracker_report_query_' . $this->id;
393
        $html .= '<h4 class="backlog-planning-search-title ' . Toggler::getClassname($id, $this->is_query_displayed ? true : false) . '" id="' . $id . '">';
394
395
        //  Query title
396
        $html .= $GLOBALS['Language']->getText('plugin_tracker_report', 'search').'</h4>';
397
        $used = array();
398
        $criteria_fetched = array();
399
        foreach ($criteria as $criterion) {
400
            if ($criterion->field->isUsed()) {
401
                $li  = '<li id="tracker_report_crit_' . $criterion->field->getId() . '">';
402
                if ($current_user->isAnonymous()) {
403
                    $li .= $criterion->fetchWithoutExpandFunctionnality();
404
                } else {
405
                    $li .= $criterion->fetch();
406
                }
407
                $li .= '</li>';
408
                $criteria_fetched[] = $li;
409
                $used[$criterion->field->getId()] = $criterion->field;
410
            }
411
        }
412
        if ($report_can_be_modified && ! $current_user->isAnonymous()) {
413
            $html .= '<div class="pull-right">';
414
            $html .= $this->getAddCriteriaDropdown($used);
415
            $html .= '</div>';
416
        }
417
418
        $array_of_html_criteria = array();
419
        EventManager::instance()->processEvent(
420
            TRACKER_EVENT_REPORT_DISPLAY_ADDITIONAL_CRITERIA,
421
            array(
422
                'array_of_html_criteria' => &$array_of_html_criteria,
423
                'tracker'                => $this->getTracker(),
424
                'additional_criteria'    => $additional_criteria,
425
                'user'                   => $current_user,
426
            )
427
        );
428
        foreach ($array_of_html_criteria as $additional_criteria) {
429
            $criteria_fetched[] = '<li>'. $additional_criteria .'</li>';
430
        }
431
        $html .= '<ul id="tracker_query">' . implode('', $criteria_fetched).'</ul>';
432
433
        $html .= '<div align="center">';
434
        $html .= '<button type="submit" name="tracker_query_submit" class="btn btn-primary">';
435
        $html .= '<i class="icon-search"></i> ';
436
        $html .= $GLOBALS['Language']->getText('global', 'btn_search');
437
        $html .= '</button>';
438
        $html .= '</div>';
439
        $html .= '</form>';
440
        $html .= '</div>';
441
        return $html;
442
    }
443
444
    private function getAddCriteriaDropdown($used) {
445
        $add_criteria_presenter = new Templating_Presenter_ButtonDropdownsMini(
446
            'tracker_report_add_criteria_dropdown',
447
            $GLOBALS['Language']->getText('plugin_tracker_report', 'toggle_criteria'),
448
            $this->getFieldsAsDropdownOptions('tracker_report_add_criterion', $used, self::TYPE_CRITERIA)
449
        );
450
        $add_criteria_presenter->setIcon('icon-eye-close');
451
452
        return $this->getTemplateRenderer()->renderToString('button_dropdowns',  $add_criteria_presenter);
453
    }
454
455
    public function getFieldsAsDropdownOptions($id_prefix, array $used, $dropdown_type) {
456
        $fields_for_criteria = array();
457
        $fields_for_sort     = array();
458
459
        foreach($this->getFormElementFactory()->getFields($this->getTracker()) as $field) {
460
            if ($dropdown_type === self::TYPE_CRITERIA && ! $field->canBeUsedAsReportCriterion()) {
461
                continue;
462
            }
463
464
            if ($field->userCanRead() && $field->isUsed()) {
465
                $fields_for_criteria[$field->getId()] = $field;
466
                $fields_for_sort[$field->getId()] = strtolower($field->getLabel());
467
            }
468
        }
469
        asort($fields_for_sort);
470
        $criteria_options = array();
471
        foreach ($fields_for_sort as $id => $nop) {
472
            $option = new Templating_Presenter_ButtonDropdownsOption(
473
                $id_prefix.'_'.$id,
474
                $fields_for_criteria[$id]->getLabel(),
475
                isset($used[$id]),
476
                '#'
477
            );
478
            $option->setLiParameters(
479
                array(
480
                    'data-field-id'      => $id,
481
                    'data-field-is-used' => intval(isset($used[$id])),
482
                )
483
            );
484
            $criteria_options[] = $option;
485
        }
486
        return $criteria_options;
487
    }
488
489
    public function getTemplateRenderer() {
490
        return TemplateRendererFactory::build()->getRenderer(
491
            array(
492
                TRACKER_TEMPLATE_DIR.'/report',
493
                ForgeConfig::get('codendi_dir').'/src/templates/common'
494
            )
495
        );
496
    }
497
498
    public function display(Tracker_IDisplayTrackerLayout $layout, $request, $current_user) {
499
500
        $link_artifact_id       = (int)$request->get('link-artifact-id');
501
        $report_can_be_modified = !$link_artifact_id;
502
503
        $hp = Codendi_HTMLPurifier::instance();
504
        $current_user = UserManager::instance()->getCurrentUser();
505
        $renderer_preference_key = 'tracker_'. $this->tracker_id .'_report_'. $this->id .'_last_renderer';
506
507
        if ($link_artifact_id) {
508
            //Store in user preferences
509
            if ($current_user->getPreference('tracker_'. $this->tracker_id .'_last_report') != $this->id) {
510
                $current_user->setPreference('tracker_'. $this->tracker_id .'_last_report', $this->id);
511
            }
512
        }
513
514
        $renderers = $this->getRenderers();
515
        $current_renderer = null;
516
        //search for the current renderer
517
        if (is_array($request->get('renderer'))) {
518
            list($renderer_id, ) = each($request->get('renderer'));
0 ignored issues
show
Bug introduced by
$request->get('renderer') cannot be passed to each() as the parameter $array expects a reference.
Loading history...
519
            if (isset($renderers[$renderer_id])) {
520
                $current_renderer = $renderers[$renderer_id];
521
            }
522
        }
523
        if (!$current_renderer) {
524
            foreach($renderers as $r) {
525
                if (!$current_renderer || ($request->get('renderer') == $r->id)
526
                                       || (!$request->get('renderer') && $r->id == $this->current_renderer_id)
527
                                       || (!$request->get('renderer') && $r->id == $current_user->getPreference($renderer_preference_key))) {
528
                    $current_renderer = $r;
529
                }
530
            }
531
        }
532
        if (!$current_renderer) {
533
            list(,$current_renderer) = each($renderers);
534
        }
535
        if ($current_renderer && $current_user->getPreference($renderer_preference_key) != $current_renderer->id) {
536
            $current_user->setPreference($renderer_preference_key, $current_renderer->id);
537
        }
538
539
        // We need an ArtifactLinkable renderer for ArtifactLink
540
        if ($link_artifact_id && !is_a($current_renderer, 'Tracker_Report_Renderer_ArtifactLinkable')) {
541
            foreach($renderers as $r) {
542
                if (is_a($r, 'Tracker_Report_Renderer_ArtifactLinkable')) {
543
                    $current_renderer = $r;
544
                    break;
545
                }
546
            }
547
        }
548
        if ($request->get('only-renderer')) {
549
            echo $current_renderer->fetch($this->getMatchingIds($request, false), $request, $report_can_be_modified, $current_user);
550
        } else {
551
            $this->displayHeader($layout, $request, $current_user, $report_can_be_modified);
0 ignored issues
show
Compatibility introduced by
$layout of type object<Tracker_IDisplayTrackerLayout> is not a sub-type of object<Tracker_IFetchTrackerSwitcher>. It seems like you assume a child interface of the interface Tracker_IDisplayTrackerLayout to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
552
553
            $html = '';
554
555
            //Display Criteria
556
            $registered_criteria = array();
557
            $this->getCriteria();
558
            $session_criteria = $this->report_session->getCriteria();
559
            if ($session_criteria) {
560
                foreach ($session_criteria as $key => $session_criterion) {
561
                    if (!empty($session_criterion['is_removed'])) {
562
                        continue;
563
                    }
564
                    if (!empty($this->criteria[$key])) {
565
                        $registered_criteria[] = $this->criteria[$key];
566
                    }
567
                }
568
            }
569
            $additional_criteria = $this->getAdditionalCriteria();
570
571
            $html .= $this->fetchDisplayQuery($registered_criteria, $additional_criteria, $report_can_be_modified, $current_user);
572
573
            //Display Renderers
574
            $html .= '<div>';
575
            $html .= '<ul id="tracker_report_renderers" class="nav nav-tabs">';
576
577
            foreach($renderers as $r) {
578
                $active = $r->id == $current_renderer->id ? 'tracker_report_renderers-current active dropdown' : '';
579
                if ($active || !$link_artifact_id || is_a($r, 'Tracker_Report_Renderer_ArtifactLinkable')) {
580
                    $parameters = array(
581
                        'report'   => $this->id,
582
                        'renderer' => $r->id
583
                    );
584
                    if ($request->existAndNonEmpty('pv')) {
585
                        $parameters['pv'] = (int)$request->get('pv');
586
                    }
587
                    if ($link_artifact_id) {
588
                        $parameters['link-artifact-id'] = (int)$link_artifact_id;
589
                        $parameters['only-renderer']    = 1;
590
                    }
591
592
                    $url = $active ? '#' : '?'. http_build_query($parameters);
593
                    $html .= '<li id="tracker_report_renderer_'. $r->id .'"
594
                                  class="'. $active .'
595
                                            tracker_report_renderer_tab
596
                                            tracker_report_renderer_tab_'. $r->getType() .'">
597
                              <a href="'. $url .'" title="'.  $hp->purify($r->description, CODENDI_PURIFIER_CONVERT_HTML)  .'" '. ($active ? 'class="dropdown-toggle" data-toggle="dropdown"' : '') .'>';
598
                    $html .= '<input type="hidden" name="tracker_report_renderer_rank" value="'.(int)$r->rank.'" />';
599
                    $html .= '<i class="'. $r->getIcon() .'"></i>';
600
                    $html .= ' '. $hp->purify($r->name, CODENDI_PURIFIER_CONVERT_HTML) ;
601
                    if ($active) {
602
                        //Check that user can update the renderer
603
                        if ($report_can_be_modified && ! $current_user->isAnonymous()) {
604
                            $html .= ' <b class="caret" id="tracker_renderer_updater_handle"></b>';
605
                        }
606
                    }
607
                    $html .= '</a>';
608
                    if ($report_can_be_modified && ! $current_user->isAnonymous()) {
609
                        $html .= '<div class="dropdown-menu">'. $this->fetchUpdateRendererForm($r) .'</div>';
610
                    }
611
                    $html .= '</li>';
612
                }
613
            }
614
615
            if ($report_can_be_modified && ! $current_user->isAnonymous()) {
616
                $html .= '<li class="tracker_report_renderers-add dropdown">
617
                    <a id="tracker_renderer_add_handle"
618
                       href="#"
619
                       class="dropdown-toggle"
620
                       data-toggle="dropdown">';
621
                $html .=  '<i class="icon-plus"></i>' ;
622
                $html .= '</a>';
623
                $html .= '<div class="dropdown-menu">'. $this->fetchAddRendererForm($current_renderer) .'</div>';
624
                $html .= '</li>';
625
            }
626
627
            $html .= '</ul>';
628
629
630
            if ($current_renderer) {
631
                $html .= '<div class="tracker_report_renderer"
632
                               id="tracker_report_renderer_current"
633
                               data-renderer-id="'. $current_renderer->getId() .'"
634
                               data-report-id="'. $this->id .'"
635
                               data-renderer-func="renderer"
636
                          >';
637
638
                if ($current_renderer->description) {
639
                    $html .= '<p class="tracker_report_renderer_description">';
640
                    $html .= '<span>'. $GLOBALS['Language']->getText('plugin_tracker', 'Description:') .' </span>';
641
                    $html .= $hp->purify($current_renderer->description, CODENDI_PURIFIER_BASIC);
642
                    $html .= '</p>';
643
                }
644
645
                //  Options menu
646
                if ($report_can_be_modified && ($options = $current_renderer->getOptionsMenuItems())) {
647
                    $html .= '<div id="tracker_renderer_options">';
648
                    $html .= implode(' ', $options);
649
                    $html .= '</div>';
650
                }
651
652
                //Warning about Full text in Tracker Report...
653
                $fts_warning = '';
654
                $params = array('html' => &$fts_warning, 'request' => $request, 'group_id' => $this->getProjectId());
655
                EventManager::instance()->processEvent('tracker_report_followup_warning', $params);
656
                $html .= $fts_warning;
657
658
                $html .= $current_renderer->fetch($this->getMatchingIds($request, false), $request, $report_can_be_modified, $current_user);
659
                $html .= '</div>';
660
            }
661
            $html .= '</div>';
662
            echo $html;
663
664
            if ($report_can_be_modified) {
665
                $this->getTracker()->displayFooter($layout);
666
                exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method display() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
667
            }
668
        }
669
    }
670
671
    public function getRenderers() {
672
        return Tracker_Report_RendererFactory::instance()->getReportRenderersByReport($this);
673
    }
674
675
    protected function orderRenderersByRank($renderers) {
676
        $array_rank = array();
677
        foreach($renderers as $field_id => $properties) {
678
            $array_rank[$field_id] = $properties->rank;
679
        }
680
        asort($array_rank);
681
        $renderers_sort = array();
682
        foreach ($array_rank as $id => $rank) {
683
            $renderers_sort[$id] = $renderers[$id];
684
        }
685
        return  $renderers_sort;
686
    }
687
688
    protected function getRendererFactory() {
689
        return Tracker_Report_RendererFactory::instance();
690
    }
691
692
    protected function _fetchAddCriteria($used) {
693
        $html = '';
694
695
        $options = '';
696
        foreach($this->getTracker()->getFormElements() as $formElement) {
0 ignored issues
show
Bug introduced by
The expression $this->getTracker()->getFormElements() of type object<Tracker_FormElement> is not traversable.
Loading history...
697
            if ($formElement->userCanRead()) {
698
                $options .= $formElement->fetchAddCriteria($used);
699
            }
700
        }
701
        if ($options) {
702
            $html .= '<select name="add_criteria" id="tracker_report_add_criteria" autocomplete="off">';
703
            $html .= '<option selected="selected" value="">'. '-- '.$GLOBALS['Language']->getText('plugin_tracker_report', 'toggle_criteria').'</option>';
704
            $html .= $options;
705
            $html .= '</select>';
706
        }
707
        return $html;
708
    }
709
710
    /**
711
     * Say if the report is public
712
     *
713
     * @return bool
714
     */
715
    public function isPublic() {
716
        return empty($this->user_id);
717
    }
718
719
    /**
720
     * Only owners of a report can update it.
721
     * owner = report->user_id
722
     * or if null, owner = tracker admin or site admins
723
     * @param PFUser $user the user who wants to update the report
724
     * @return boolean
725
     */
726
    public function userCanUpdate($user) {
727
        if (! $this->isBelongingToATracker()) {
728
            return false;
729
        }
730
731
        if ($this->user_id) {
732
            return $this->user_id == $user->getId();
733
        } else {
734
            $tracker = $this->getTracker();
735
            return $user->isSuperUser() || $tracker->userIsAdmin($user);
736
        }
737
    }
738
739
    private function isBelongingToATracker() {
740
        return $this->getTracker() != null;
741
    }
742
743
    protected $tracker;
744
    public function getTracker() {
745
        if (!$this->tracker) {
746
            $this->tracker = TrackerFactory::instance()->getTrackerById($this->tracker_id);
747
        }
748
        return $this->tracker;
749
    }
750
751
    public function setTracker(Tracker $tracker) {
752
        $this->tracker    = $tracker;
753
        $this->tracker_id = $tracker->getId();
754
    }
755
756
    /**
757
     * hide or show the criteria
758
     */
759
    public function toggleQueryDisplay() {
760
        $this->is_query_displayed = !$this->is_query_displayed;
761
        return $this;
762
    }
763
764
    /**
765
     * Remove a formElement from criteria
766
     * @param int $formElement_id the formElement used for the criteria
767
     */
768
    public function removeCriteria($formElement_id) {
769
        $criteria = $this->getCriteria();
770
        if (isset($criteria[$formElement_id])) {
771
            if ($this->getCriteriaDao()->delete($this->id, $formElement_id)) {
772
                $criteria[$formElement_id]->delete();
773
                unset($criteria[$formElement_id]);
774
            }
775
        }
776
        return $this;
777
    }
778
779
    /**
780
     * Add a criteria
781
     *
782
     * @param Tracker_Report_Criteria the formElement used for the criteria
783
     *
784
     * @return int the id of the new criteria
785
     */
786
    public function addCriteria( Tracker_Report_Criteria $criteria ) {
787
        $id = $this->getCriteriaDao()->create($this->id, $criteria->field->id, $criteria->is_advanced);
0 ignored issues
show
Bug introduced by
It seems like $criteria->is_advanced can also be of type boolean; however, Tracker_Report_CriteriaDao::create() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
788
        return $id;
789
    }
790
791
    public function deleteAllCriteria() {
792
        $this->getCriteriaDao()->deleteAll($this->id);
793
    }
794
795
    /**
796
     * Toggle the state 'is_advanced' of a criteria
797
     * @param int $formElement_id the formElement used for the criteria
798
     */
799
    public function toggleAdvancedCriterion($formElement_id) {
800
        $advanced = 1;
801
        $session_criterion = $this->report_session->getCriterion($formElement_id);
802
        if ( !empty($session_criterion['is_advanced']) ) {
803
            $advanced = 0;
804
        }
805
        $this->report_session->updateCriterion($formElement_id, '', array('is_advanced'=>$advanced));
806
        return $this;
807
    }
808
809
    /**
810
     * Store the criteria value
811
     * NOTICE : if a criterion does not exist it is not created
812
     * @param array $criteria_values
813
     */
814
    public function updateCriteriaValues($criteria_values) {
815
        $ff = $this->getFormElementFactory();
816
        foreach($criteria_values as $formElement_id => $new_value) {
817
            $session_criterion = $this->report_session->getCriterion($formElement_id);
818
            if ( $session_criterion ) {
819
                if ($field = $ff->getFormElementById($formElement_id)) {
820
                    $this->report_session->storeCriterion($formElement_id, $field->getFormattedCriteriaValue($new_value));
821
                }
822
            }
823
        }
824
    }
825
826
    public function updateAdditionalCriteriaValues($additional_criteria_values) {
827
        foreach($additional_criteria_values as $key => $new_value) {
828
            $additional_criterion = new Tracker_Report_AdditionalCriterion($key, $new_value);
829
            $this->report_session->storeAdditionalCriterion($additional_criterion);
830
        }
831
    }
832
833
    /**
834
     * Process the request for the specified renderer
835
     * @param int $renderer_id
836
     * @param Request $request
837
     * @return ReportRenderer
838
     */
839
    public function processRendererRequest($renderer_id, Tracker_IDisplayTrackerLayout $layout, $request, $current_user, $store_in_session = true) {
840
        $rrf = Tracker_Report_RendererFactory::instance();
841
        if ($renderer = $rrf->getReportRendererByReportAndId($this, $renderer_id, $store_in_session)) {
842
            $renderer->process($layout, $request, $current_user);
843
        }
844
    }
845
846
    /**
847
     * Delete a renderer from the report
848
     * @param mixed the renderer to remove (Tracker_Report_Renderer or the id as int)
849
     */
850
    public function deleteRenderer($renderer) {
851
        $rrf = Tracker_Report_RendererFactory::instance();
852
        if (!is_a($renderer, 'Tracker_Report_Renderer')) {
853
            $renderer_id = (int)$renderer;
854
            $renderer = $rrf->getReportRendererByReportAndId($this, $renderer_id);
855
        }
856
        if ($renderer) {
857
            $renderer_id = $renderer->id;
858
            $renderer->delete();
859
            $rrf->delete($renderer_id);
860
        }
861
        return $this;
862
    }
863
864
    /**
865
     * Move a renderer at a specific position
866
     *
867
     * @param mixed $renderer the renderer to remove (Tracker_Report_Renderer or the id as int)
868
     * @param int   $position the new position
869
     */
870
    public function moveRenderer($renderer, $position) {
871
        $rrf = Tracker_Report_RendererFactory::instance();
872
        if (!is_a($renderer, 'Tracker_Report_Renderer')) {
873
            $renderer_id = (int)$renderer;
874
            $renderer = $rrf->getReportRendererByReportAndId($this, $renderer_id);
875
        }
876
        if ($renderer) {
877
            $rrf->move($renderer->id, $this, $position);
878
        }
879
        return $this;
880
    }
881
882
    /**
883
     * Add a new renderer to the report
884
     *
885
     * @param string $name
886
     * @param string $description
887
     *
888
     * @return int the id of the new renderer
889
     */
890
    public function addRenderer($name, $description, $type) {
891
        $rrf = Tracker_Report_RendererFactory::instance();
892
        return $rrf->create($this, $name, $description, $type);
893
    }
894
895
    public function addRendererInSession($name, $description, $type) {
896
        $rrf = Tracker_Report_RendererFactory::instance();
897
        return $rrf->createInSession($this, $name, $description, $type);
898
    }
899
900
901
    public function process(Tracker_IDisplayTrackerLayout $layout, $request, $current_user) {
902
        if ($this->isObsolete()) {
903
            header('X-Codendi-Tracker-Report-IsObsolete: '. $this->getLastUpdaterUserName());
904
        }
905
        $hp      = Codendi_HTMLPurifier::instance();
906
        $tracker = $this->getTracker();
907
908
        if ($request->exist('tracker') && $request->get('tracker') != $tracker->getId()) {
909
            $GLOBALS['Response']->addFeedback(
910
                Feedback::ERROR,
911
                $GLOBALS['Language']->getText('plugin_tracker_admin', 'invalid_request')
912
            );
913
914
            $GLOBALS['Response']->redirect('?'. http_build_query(array(
915
                'tracker'   => $tracker->getId()
916
            )));
917
        }
918
919
        switch ($request->get('func')) {
920
            case 'display-masschange-form':
921
                if ($tracker->userIsAdmin($current_user)) {
922
                    $masschange_aids = array();
923
                    $renderer_table  =  $request->get('renderer_table');
924
925
                    if ( !empty($renderer_table['masschange_checked']) ) {
926
                        $masschange_aids = $request->get('masschange_aids');
927
                    } else if (!empty($renderer_table['masschange_all'])) {
928
                        $masschange_aids = $request->get('masschange_aids_all');
929
                    }
930
931
                    if( empty($masschange_aids) ) {
932
                        $GLOBALS['Response']->addFeedback('error', $GLOBALS['Language']->getText('plugin_tracker_masschange_detail', 'no_items_selected'));
933
                        $GLOBALS['Response']->redirect(TRACKER_BASE_URL.'/?tracker='. $tracker->getId());
934
                    }
935
                    $tracker->displayMasschangeForm($layout, $masschange_aids);
936
                } else {
937
                    $GLOBALS['Response']->addFeedback('error', $GLOBALS['Language']->getText('plugin_tracker_admin', 'access_denied'));
938
                    $GLOBALS['Response']->redirect(TRACKER_BASE_URL.'/?tracker='. $tracker->getId());
939
                }
940
                break;
941
             case 'update-masschange-aids':
942
                $masschange_updater = new Tracker_MasschangeUpdater($tracker, $this);
943
                $masschange_updater->updateArtifacts($current_user, $request);
944
                break;
945
           case 'remove-criteria':
946
                if ($request->get('field') && ! $current_user->isAnonymous()) {
947
                    $this->report_session->removeCriterion($request->get('field'));
948
                    $this->report_session->setHasChanged();
949
                }
950
                break;
951
            case 'add-criteria':
952
                if ($request->get('field') && ! $current_user->isAnonymous()) {
953
                    //TODO: make sure that the formElement exists and the user can read it
954
                    if ($request->isAjax()) {
955
                        $criteria = $this->getCriteria();
956
                        $field_id = $request->get('field');
957
                        $this->setCriteria($field_id);
958
                        $this->report_session->storeCriterion($field_id, '', array('is_advanced'=>0));
959
                        $this->report_session->setHasChanged();
960
                        echo $this->criteria[$field_id]->fetch();
961
                    }
962
                }
963
                break;
964
            case 'toggle-advanced':
965
                if ($request->get('field') && ! $current_user->isAnonymous()) {
966
                    $this->toggleAdvancedCriterion($request->get('field'));
967
                    $this->report_session->setHasChanged();
968
                    if ($request->isAjax()) {
969
                        $criteria = $this->getCriteria();
970
                        if (isset($criteria[$request->get('field')])) {
971
                            echo $criteria[$request->get('field')]->fetch();
972
                        }
973
                    }
974
                }
975
                break;
976
            case self::ACTION_CLEANSESSION:
977
                $this->report_session->clean();
978
                $GLOBALS['Response']->redirect('?'. http_build_query(array(
979
                        'tracker'   => $this->tracker_id
980
                )));
981
                break;
982
            case 'renderer':
983
                if ($request->get('renderer')) {
984
                    $store_in_session = true;
985
                    if ($request->exist('store_in_session')) {
986
                        $store_in_session = (bool)$request->get('store_in_session');
987
                    }
988
                    $this->processRendererRequest($request->get('renderer'), $layout, $request, $current_user, $store_in_session);
989
                }
990
                break;
991
            case 'rename-renderer':
992
                if ($request->get('new_name') == '') {
993
                    $GLOBALS['Response']->addFeedback('error', $GLOBALS['Language']->getText('plugin_tracker_report','renderer_name_mandatory'));
994
                } else if (! $current_user->isAnonymous() && (int)$request->get('renderer') && trim($request->get('new_name'))) {
995
                    $this->report_session->renameRenderer((int)$request->get('renderer'), trim($request->get('new_name')), trim($request->get('new_description')));
996
                    $this->report_session->setHasChanged();
997
                }
998
                $GLOBALS['Response']->redirect('?'. http_build_query(array(
999
                                                            'report'   => $this->id
1000
                                                            )));
1001
                break;
1002
            case 'delete-renderer':
1003
                if (! $current_user->isAnonymous() && (int)$request->get('renderer')) {
1004
                    $this->report_session->removeRenderer((int)$request->get('renderer'));
1005
                    $this->report_session->setHasChanged();
1006
                    $GLOBALS['Response']->redirect('?'. http_build_query(array(
1007
                                                            'report'   => $this->id
1008
                                                            )));
1009
                }
1010
                break;
1011
            case 'move-renderer':
1012
                if (! $current_user->isAnonymous() && (int)$request->get('renderer')) {
1013
                    if ($request->isAjax()) {
1014
                        $this->report_session->moveRenderer($request->get('tracker_report_renderers'));
1015
                        $this->report_session->setHasChanged();
1016
                    } else {
1017
                        if ( $request->get('move-renderer-direction')) {
1018
                            $this->moveRenderer((int)$request->get('renderer'), $request->get('move-renderer-direction'));
1019
                            $GLOBALS['Response']->redirect('?'. http_build_query(array(
1020
                                                                    'report'   => $this->id
1021
                                                                    )));
1022
                        }
1023
                    }
1024
                }
1025
                break;
1026
            case 'add-renderer':
1027
                $new_name        = trim($request->get('new_name'));
1028
                $new_description = trim($request->get('new_description'));
1029
                $new_type        = trim($request->get('new_type'));
1030
                if (! $current_user->isAnonymous() && $new_name) {
1031
                    $new_renderer_id = $this->addRendererInSession($new_name, $new_description, $new_type);
1032
                    $GLOBALS['Response']->redirect('?'. http_build_query(array(
1033
                                                            'report'   => $this->id,
1034
                                                            'renderer' => $new_renderer_id ? $new_renderer_id : ''
1035
                                                            )));
1036
                }
1037
                break;
1038
            case self::ACTION_SAVE:
1039
                Tracker_ReportFactory::instance()->save($this);
1040
                $this->saveCriteria();
1041
                $this->saveAdditionalCriteria();
1042
                $this->saveRenderers();
1043
                //Clean session
1044
                $this->report_session->cleanNamespace();
1045
1046
                $GLOBALS['Response']->addFeedback('info', '<a href="?report='. $this->id .'">'. $hp->purify($this->name, CODENDI_PURIFIER_CONVERT_HTML) .'</a> has been saved.', CODENDI_PURIFIER_DISABLED);
1047
                $GLOBALS['Response']->redirect('?'. http_build_query(array(
1048
                    'report'   => $this->id
1049
                )));
1050
                break;
1051
            case self::ACTION_SAVEAS:
1052
                $redirect_to_report_id = $this->id;
1053
                $report_copy_name = trim($request->get('report_copy_name'));
1054
                if ($report_copy_name) {
1055
                    $new_report = Tracker_ReportFactory::instance()->duplicateReportSkeleton($this, $this->tracker_id, $current_user->getId());
1056
                    //Set the name
1057
                    $new_report->name = $report_copy_name;
1058
                    //The new report is individual
1059
                    $new_report->user_id = $current_user->getId();
1060
                    Tracker_ReportFactory::instance()->save($new_report);
1061
                    $GLOBALS['Response']->addFeedback('info', '<a href="?report='. $new_report->id .'">'. $hp->purify($new_report->name, CODENDI_PURIFIER_CONVERT_HTML) .'</a> has been created.', CODENDI_PURIFIER_DISABLED);
1062
                    $redirect_to_report_id = $new_report->id;
1063
                    //copy parent tracker session content
1064
                    $this->report_session->copy($this->id, $redirect_to_report_id);
1065
                    //clean current session namespace
1066
                    $this->report_session->cleanNamespace();
1067
                    //save session content into db
1068
                    $new_report->saveCriteria();
1069
                    $new_report->saveAdditionalCriteria();
1070
                    $new_report->saveRenderers();
1071
                    $new_report->report_session->cleanNamespace();
1072
                } else {
1073
                    $GLOBALS['Response']->addFeedback('error', 'Invalid copy name', CODENDI_PURIFIER_DISABLED);
1074
                }
1075
1076
1077
                $GLOBALS['Response']->redirect('?'. http_build_query(array(
1078
                    'report'   => $redirect_to_report_id
1079
                )));
1080
                break;
1081
            case self::ACTION_DELETE:
1082
                $this->delete();
1083
                $GLOBALS['Response']->redirect('?'. http_build_query(array(
1084
                    'tracker'   => $this->tracker_id
1085
                )));
1086
                break;
1087
            case self::ACTION_SCOPE:
1088
                if ($this->getTracker()->userIsAdmin($current_user) && (!$this->user_id || $this->user_id == $current_user->getId())) {
1089
                    if ($request->exist('report_scope_public')) {
1090
                        $old_user_id = $this->user_id;
1091
                        if ($request->get('report_scope_public') && $this->user_id == $current_user->getId()) {
1092
                            $this->user_id = null;
1093
                        } else if (!$request->get('report_scope_public') && !$this->user_id) {
1094
                            $this->user_id = $current_user->getId();
1095
                        }
1096
                        if ($this->user_id != $old_user_id) {
1097
                            Tracker_ReportFactory::instance()->save($this);
1098
                        }
1099
                    }
1100
                }
1101
            case self::ACTION_DEFAULT:
1102
                if ($this->getTracker()->userIsAdmin($current_user)) {
1103
                    if ($request->exist('report_default')) {
1104
                        $old_user_id = $this->user_id;
1105
                        if ($request->get('report_default')) {
1106
                            $this->is_default = '1';
1107
                        } else {
1108
                            $this->is_default = '0';
1109
                        }
1110
                    }
1111
                    $this->setDefaultReport();
1112
                    $GLOBALS['Response']->redirect('?'. http_build_query(array(
1113
                        'report'   => $this->id
1114
                    )));
1115
                    break;
1116
                }
1117
            default:
1118
                if ($request->exist('tracker_query_submit')) {
1119
                    $criteria_values = $request->get('criteria');
1120
                    if (!empty($criteria_values)) {
1121
                        $this->updateCriteriaValues($criteria_values);
1122
                    }
1123
1124
                    $additional_criteria_values = $request->get('additional_criteria');
1125
                    if (!empty($additional_criteria_values)) {
1126
                        $this->updateAdditionalCriteriaValues($additional_criteria_values);
1127
                    }
1128
1129
                    $this->report_session->setHasChanged();
1130
                }
1131
                $this->display($layout, $request, $current_user);
1132
                break;
1133
        }
1134
    }
1135
1136
    public function setDefaultReport() {
1137
        $default_report = Tracker_ReportFactory::instance()->getDefaultReportByTrackerId($this->tracker_id);
1138
        if ($default_report) {
1139
            $default_report->is_default = '0';
1140
            Tracker_ReportFactory::instance()->save($default_report);
1141
        }
1142
        Tracker_ReportFactory::instance()->save($this);
1143
1144
    }
1145
    /**
1146
     * NOTICE: make sure you are in the correct session namespace
1147
     */
1148
    public function saveCriteria() {
1149
        //populate $this->criteria
1150
        $this->getCriteria();
1151
        //Delete criteria value
1152
        foreach($this->criteria as $c) {
1153
            if ($c->field->getCriteriaValue($c)) {
1154
                $c->field->delete($c->id);
1155
            }
1156
        }
1157
        //Delete criteria in the db
1158
        $this->deleteAllCriteria();
1159
1160
        $session_criteria = $this->report_session->getCriteria();
1161
        if (is_array($session_criteria)) {
1162
            foreach($session_criteria as $key=>$session_criterion) {
1163
                if ( !empty($session_criterion['is_removed'])) {
1164
                    continue;
1165
                }
1166
1167
                if (isset($this->criteria[$key])) {
1168
                    $c  = $this->criteria[$key];
1169
                    $id = $this->addCriteria($c);
1170
                    $c->setId($id);
1171
                    $c->updateValue($session_criterion['value']);
1172
                }
1173
            }
1174
        }
1175
    }
1176
1177
    public function saveAdditionalCriteria() {
1178
        $additional_criteria = $this->getAdditionalCriteria();
1179
        EventManager::instance()->processEvent(
1180
            TRACKER_EVENT_REPORT_SAVE_ADDITIONAL_CRITERIA,
1181
            array(
1182
                'additional_criteria'    => $additional_criteria,
1183
                'report'                 => $this,
1184
            )
1185
        );
1186
    }
1187
1188
    /**
1189
     * Save report renderers
1190
     * NOTICE: make sure you are in the correct session namespace
1191
     *
1192
     * @return void
1193
     */
1194
    public function saveRenderers() {
1195
        $rrf = Tracker_Report_RendererFactory::instance();
1196
1197
        //Get the renderers in the session and in the db
1198
        $renderers_session = $this->getRenderers();
1199
        $renderers_db      = $rrf->getReportRenderersByReportFromDb($this);
1200
1201
        //Delete renderers in db if they are deleted in the session
1202
        foreach ($renderers_db as $renderer_db_key => $renderer_db) {
1203
            if ( ! isset($renderers_session[$renderer_db_key]) ) {
1204
                $this->deleteRenderer($renderer_db_key);
1205
            }
1206
        }
1207
1208
        //Create or update renderers in db
1209
        if(is_array($renderers_session)) {
1210
            foreach ($renderers_session as $renderer_key => $renderer) {
1211
                if( ! isset($renderers_db[$renderer_key]) ) {
1212
                    // this is a new renderer
1213
                    $renderer->create();
1214
                } else {
1215
                    // this is an old renderer
1216
                    $rrf->save($renderer);
1217
                    $renderer->update();
1218
                }
1219
            }
1220
        }
1221
    }
1222
1223
    /**
1224
     * Delete the report and its renderers
1225
     */
1226
    protected function delete() {
1227
        //Delete user preferences
1228
        $dao = new UserPreferencesDao();
1229
        $dao->deleteByPreferenceNameAndValue('tracker_'. $this->tracker_id .'_last_report', $this->id);
1230
1231
        //Delete criteria
1232
        foreach($this->getCriteria() as $criteria) {
1233
            $this->removeCriteria($criteria->field->id);
1234
        }
1235
1236
        //Delete renderers
1237
        foreach($this->getRenderers() as $renderer) {
1238
            $this->deleteRenderer($renderer);
1239
        }
1240
1241
        //clean session
1242
        $this->report_session->cleanNamespace();
1243
1244
        //Delete me
1245
        return Tracker_ReportFactory::instance()->delete($this->id);
1246
    }
1247
1248
    public function duplicate($from_report, $formElement_mapping) {
1249
        //Duplicate criteria
1250
        Tracker_Report_CriteriaFactory::instance()->duplicate($from_report, $this, $formElement_mapping);
1251
1252
        //Duplicate renderers
1253
        Tracker_Report_RendererFactory::instance()->duplicate($from_report, $this, $formElement_mapping);
1254
    }
1255
1256
    /**
1257
     * Transforms Report into a SimpleXMLElement
1258
     *
1259
     * @param SimpleXMLElement $root the node to which the Report is attached (passed by reference)
0 ignored issues
show
Bug introduced by
There is no parameter named $root. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1260
     */
1261
    public function exportToXml(SimpleXMLElement $roott, $xmlMapping) {
1262
        $root = $roott->addChild('report');
1263
        // if old ids are important, modify code here
1264
        if (false) {
1265
            $root->addAttribute('id', $this->id);
1266
            $root->addAttribute('tracker_id', $this->tracker_id);
1267
            $root->addAttribute('current_renderer_id', $this->current_renderer_id);
1268
            $root->addAttribute('user_id', $this->user_id);
1269
            $root->addAttribute('parent_report_id', $this->parent_report_id);
1270
        }
1271
        // only add if different from default values
1272
        if (!$this->is_default) {
1273
            $root->addAttribute('is_default', $this->is_default);
1274
        }
1275
        if (!$this->is_query_displayed) {
1276
            $root->addAttribute('is_query_displayed', $this->is_query_displayed);
1277
        }
1278
        $root->addChild('name', $this->name);
1279
        // only add if not empty
1280
        if ($this->description) {
1281
            $root->addChild('description', $this->description);
1282
        }
1283
        $child = $root->addChild('criterias');
1284
        foreach($this->getCriteria() as $criteria) {
1285
            if ($criteria->field->isUsed()) {
1286
                $grandchild = $child->addChild('criteria');
1287
                $criteria->exportToXML($grandchild, $xmlMapping);
1288
            }
1289
        }
1290
        $child = $root->addChild('renderers');
1291
        foreach($this->getRenderers() as $renderer) {
1292
            $grandchild = $child->addChild('renderer');
1293
            $renderer->exportToXML($grandchild, $xmlMapping);
1294
        }
1295
    }
1296
1297
    /**
1298
     * Convert the current report to its SOAP representation
1299
     *
1300
     * @return Array
1301
     */
1302
    public function exportToSoap() {
1303
        return array(
1304
            'id'          => (int)$this->id,
1305
            'name'        => (string)$this->name,
1306
            'description' => (string)$this->description,
1307
            'user_id'     => (int)$this->user_id,
1308
            'is_default'  => (bool)$this->is_default,
1309
        );
1310
    }
1311
1312
    protected $dao;
1313
    /**
1314
     * @return Tracker_ReportDao
1315
     */
1316
    public function getDao() {
1317
        if (!$this->dao) {
1318
            $this->dao = new Tracker_ReportDao();
1319
        }
1320
        return $this->dao;
1321
    }
1322
1323
    public function getId() {
1324
        return $this->id;
1325
    }
1326
1327
    public function getName() {
1328
        return $this->name;
1329
    }
1330
1331
    public function getAdditionalCriteria() {
1332
        $session_additional_criteria = null;
1333
        if (isset($this->report_session)) {
1334
            $session_additional_criteria = &$this->report_session->getAdditionalCriteria();
1335
        }
1336
1337
        $additional_criteria = array();
1338
        if ($session_additional_criteria) {
1339
            foreach ($session_additional_criteria as $key => $additional_criterion_value) {
1340
                $additional_criterion      = new Tracker_Report_AdditionalCriterion($key, $additional_criterion_value['value']);
1341
                $additional_criteria[$key] = $additional_criterion;
1342
            }
1343
        } else {
1344
            $additional_criteria_values = array();
1345
            EventManager::instance()->processEvent(
1346
                TRACKER_EVENT_REPORT_LOAD_ADDITIONAL_CRITERIA,
1347
                array(
1348
                    'additional_criteria_values' => &$additional_criteria_values,
1349
                    'report'                     => $this,
1350
                )
1351
            );
1352
            foreach ($additional_criteria_values as $key => $additional_criterion_value) {
1353
                $additional_criterion      = new Tracker_Report_AdditionalCriterion($key, $additional_criterion_value['value']);
1354
                $additional_criteria[$key] = $additional_criterion;
1355
                if (isset($this->report_session)) {
1356
                    $this->report_session->storeAdditionalCriterion($additional_criterion);
1357
                }
1358
            }
1359
        }
1360
1361
        return $additional_criteria;
1362
    }
1363
1364
    private function fetchUpdateRendererForm(Tracker_Report_Renderer $renderer) {
1365
        $hp = Codendi_HTMLPurifier::instance();
1366
1367
        $update_renderer  = '';
1368
        $update_renderer .= '<form action="" method="POST">';
1369
        $update_renderer .= '<input type="hidden" name="report" value="'. $this->id .'" />';
1370
        $update_renderer .= '<input type="hidden" name="renderer" value="'. (int)$renderer->id .'" />';
1371
        $update_renderer .= '
1372
            <label class="radio">
1373
                <input type="radio" name="func" value="rename-renderer" id="tracker_renderer_updater_rename" />
1374
                '. $GLOBALS['Language']->getText('plugin_tracker_report','update') .'
1375
            </label>
1376
            <div class="tracker-renderer-details">
1377
               <label for="tracker_renderer_updater_rename_name">'. $GLOBALS['Language']->getText('plugin_tracker_report','name') .'</label>
1378
               <input type="text"
1379
                      name="new_name"
1380
                      id="tracker_renderer_updater_rename_name"
1381
                      value="'.  $hp->purify($renderer->name, CODENDI_PURIFIER_CONVERT_HTML)  .'" /><br />
1382
               <label for="tracker_renderer_updater_rename_description">'. $GLOBALS['Language']->getText('plugin_tracker_report','description') .'</label>
1383
               <textarea
1384
                      name="new_description"
1385
                      rows="5"
1386
                      cols="30"
1387
                      id="tracker_renderer_updater_rename_description"
1388
                      >'.  $hp->purify($renderer->description, CODENDI_PURIFIER_CONVERT_HTML)  .'</textarea>
1389
            </div>
1390
        ';
1391
        $update_renderer .= '<label class="radio"><input type="radio" name="func" value="delete-renderer" id="tracker_renderer_updater_delete" />'. $GLOBALS['Language']->getText('plugin_tracker_report', 'delete') .'</label>';
1392
        $update_renderer .= '<br/>';
1393
        $update_renderer .= '<input type="submit" class="btn btn-primary" value="'.  $hp->purify($GLOBALS['Language']->getText('global', 'btn_submit'), CODENDI_PURIFIER_CONVERT_HTML)  .'" onclick="if ($(\'tracker_renderer_updater_delete\').checked) return confirm(\''. $GLOBALS['Language']->getText('plugin_tracker_report', 'confirm_delete_renderer') .'\');"/> ';
1394
        $update_renderer .= '</form>';
1395
1396
        return $update_renderer;
1397
    }
1398
1399
    private function fetchAddRendererForm($current_renderer) {
1400
        $hp = Codendi_HTMLPurifier::instance();
1401
1402
        $current_renderer_id = ($current_renderer) ? (int)$current_renderer->id : '';
1403
1404
        $add_renderer  = '';
1405
        $add_renderer .= '<form action="" method="POST">';
1406
        $add_renderer .= '<input type="hidden" name="report" value="'. $this->id .'" />';
1407
        $add_renderer .= '<input type="hidden" name="renderer" value="'. $current_renderer_id .'" />';
1408
        $add_renderer .= '<input type="hidden" name="func" value="add-renderer" />';
1409
        $rrf = Tracker_Report_RendererFactory::instance();
1410
        $types = $rrf->getTypes();
1411
        if (count($types) > 1) { //No need to ask for type if there is only one
1412
            $type = '<select name="new_type" id="tracker_renderer_add_type">';
1413
            foreach($types as $key => $label) {
1414
                $type .= '<option value="'. $key .'">'.  $hp->purify($label, CODENDI_PURIFIER_CONVERT_HTML)  .'</option>';
1415
            }
1416
            $type .= '</select>';
1417
        } else {
1418
            list(,$type) = each($types);
1419
        }
1420
        $add_renderer .= '<p><strong>' . $GLOBALS['Language']->getText('plugin_tracker_report','add_new') . ' ' . $type .'</strong></p>';
1421
        $add_renderer .= '<p>';
1422
        $add_renderer .= '<label for="tracker_renderer_add_name">'. $GLOBALS['Language']->getText('plugin_tracker_report','name') .'</label>
1423
                         <input type="text" name="new_name" value="" id="tracker_renderer_add_name" />';
1424
1425
        $add_renderer .= '<label for="tracker_renderer_add_description">'. $GLOBALS['Language']->getText('plugin_tracker_report','description') .'</label>
1426
                         <textarea
1427
                            name="new_description"
1428
                            id="tracker_renderer_add_description"
1429
                            rows="5"
1430
                            cols="30"></textarea>';
1431
1432
        $add_renderer .= '</p>';
1433
        $add_renderer .= '<input type="submit" class="btn btn-primary" value="'.  $hp->purify($GLOBALS['Language']->getText('global', 'btn_submit'), CODENDI_PURIFIER_CONVERT_HTML)  .'" onclick="if (!$(\'tracker_renderer_add_name\').getValue()) { alert(\''. $GLOBALS['Language']->getText('plugin_tracker_report','name_mandatory') .'\'); return false;}"/> ';
1434
        $add_renderer .= '</form>';
1435
1436
        return $add_renderer;
1437
    }
1438
}
1439