Completed
Push — patch-1.0.7 ( fae9d3...71445b )
by Spuds
08:40
created

Stats_Controller::action_stats()   D

Complexity

Conditions 13
Paths 50

Size

Total Lines 84
Code Lines 44

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 84
rs 4.9922
cc 13
eloc 44
nc 50
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Provide a display for forum statistics
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This software is a derived product, based on:
11
 *
12
 * Simple Machines Forum (SMF)
13
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
14
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
15
 *
16
 * @version 1.0.7
17
 *
18
 */
19
20
if (!defined('ELK'))
21
	die('No access...');
22
23
/**
24
 * Statistics Controller
25
 */
26
class Stats_Controller extends Action_Controller
27
{
28
	/**
29
	 * Entry point for this class.
30
	 *
31
	 * @see Action_Controller::action_index()
32
	 */
33
	public function action_index()
34
	{
35
		// Call the right method... wait, we only know how to do
36
		// one thing (and do it well! :P)
37
		$this->action_stats();
38
	}
39
40
	/**
41
	 * Display some useful/interesting board statistics.
42
	 *
43
	 * What it does:
44
	 * - Gets all the statistics in order and puts them in.
45
	 * - Uses the Stats template and language file. (and main sub template.)
46
	 * - Requires the view_stats permission.
47
	 * - Accessed from ?action=stats.
48
	 *
49
	 * @uses Stats language file
50
	 * @uses Stats template, statistics sub template
51
	 */
52
	public function action_stats()
53
	{
54
		global $txt, $scripturl, $modSettings, $context;
55
56
		// You have to be able to see these
57
		isAllowedTo('view_stats');
58
59
		// Page disabled - redirect them out
60
		if (empty($modSettings['trackStats']))
61
			fatal_lang_error('feature_disabled', true);
62
63
		if (!empty($_REQUEST['expand']))
64
		{
65
			$context['robot_no_index'] = true;
66
67
			$month = (int) substr($_REQUEST['expand'], 4);
68
			$year = (int) substr($_REQUEST['expand'], 0, 4);
69
			if ($year > 1900 && $year < 2200 && $month >= 1 && $month <= 12)
70
				$_SESSION['expanded_stats'][$year][] = $month;
71
		}
72
		elseif (!empty($_REQUEST['collapse']))
73
		{
74
			$context['robot_no_index'] = true;
75
76
			$month = (int) substr($_REQUEST['collapse'], 4);
77
			$year = (int) substr($_REQUEST['collapse'], 0, 4);
78
			if (!empty($_SESSION['expanded_stats'][$year]))
79
				$_SESSION['expanded_stats'][$year] = array_diff($_SESSION['expanded_stats'][$year], array($month));
80
		}
81
82
		// Just a lil' help from our friend :P
83
		require_once(SUBSDIR . '/Stats.subs.php');
84
85
		// Handle the XMLHttpRequest.
86
		if (isset($_REQUEST['xml']))
87
		{
88
			if (empty($year) || empty($month))
89
			{
90
				redirectexit('action=stats');
91
			}
92
93
			// Collapsing stats only needs adjustments of the session variables.
94
			if (!empty($_REQUEST['collapse']))
95
				obExit(false);
96
97
			$context['sub_template'] = 'stats';
98
			getDailyStats('YEAR(date) = {int:year} AND MONTH(date) = {int:month}', array('year' => $year, 'month' => $month));
0 ignored issues
show
Bug introduced by
The variable $year does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $month does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
99
			$context['yearly'][$year]['months'][$month]['date'] = array(
100
				'month' => sprintf('%02d', $month),
101
				'year' => $year,
102
			);
103
104
			return;
105
		}
106
107
		// Stats it is
108
		loadLanguage('Stats');
109
		loadTemplate('Stats');
110
		loadJavascriptFile('stats.js');
111
112
		// Build the link tree......
113
		$context['linktree'][] = array(
114
			'url' => $scripturl . '?action=stats',
115
			'name' => $txt['stats_center']
116
		);
117
118
		// Prepare some things for the template page
119
		$context['page_title'] = $context['forum_name'] . ' - ' . $txt['stats_center'];
120
		$context['sub_template'] = 'statistics';
121
122
		// These are the templates that will be used to render the statistics
123
		$context['statistics_callbacks'] = array(
124
			'general_statistics',
125
			'top_statistics',
126
		);
127
128
		// Call each area of statics to load our friend $context
129
		$this->loadGeneralStatistics();
130
		$this->loadTopStatistics();
131
		$this->loadMontlyActivity();
132
133
		// Custom stats (just add a template_layer or another callback to add it to the page!)
134
		call_integration_hook('integrate_forum_stats');
135
	}
136
137
	/**
138
	 * Load some general statistics of the forum
139
	 */
140
	public function loadGeneralStatistics()
141
	{
142
		global $scripturl, $modSettings, $context;
143
144
		require_once(SUBSDIR . '/Boards.subs.php');
145
146
		// Get averages...
147
		$averages = getAverages();
148
149
		// This would be the amount of time the forum has been up... in days...
150
		$total_days_up = ceil((time() - strtotime($averages['date'])) / (60 * 60 * 24));
151
		$date = strftime('%Y-%m-%d', forum_time(false));
152
153
		// General forum stats
154
		$context['general_statistics']['left'] = array(
155
			'total_members' => allowedTo('view_mlist') ? '<a href="' . $scripturl . '?action=memberlist">' . comma_format($modSettings['totalMembers']) . '</a>' : comma_format($modSettings['totalMembers']),
156
			'total_posts' => comma_format($modSettings['totalMessages']),
157
			'total_topics' => comma_format($modSettings['totalTopics']),
158
			'total_cats' => comma_format(numCategories()),
159
			// How many users are online now.
160
			'users_online' => comma_format(onlineCount()),
161
			'most_online' => array(
162
				'number' => comma_format($modSettings['mostOnline']),
163
				'date' => standardTime($modSettings['mostDate'])
164
			),
165
			// Members online so far today.
166
			'users_online_today' => comma_format(mostOnline($date)),
167
		);
168
169
		if (!empty($modSettings['hitStats']))
170
			$context['general_statistics']['left'] += array(
171
				'num_hits' => comma_format($averages['hits'], 0)
172
			);
173
174
		$context['general_statistics']['right'] = array(
175
			'average_members' => comma_format(round($averages['registers'] / $total_days_up, 2)),
176
			'average_posts' => comma_format(round($averages['posts'] / $total_days_up, 2)),
177
			'average_topics' => comma_format(round($averages['topics'] / $total_days_up, 2)),
178
			// Statistics such as number of boards, categories, etc.
179
			'total_boards' => comma_format(countBoards('all', array('include_redirects' => false))),
180
			'latest_member' => &$context['common_stats']['latest_member'],
181
			'average_online' => comma_format(round($averages['most_on'] / $total_days_up, 2)),
182
			'emails_sent' => comma_format(round($averages['email'] / $total_days_up, 2))
183
		);
184
185
		if (!empty($modSettings['hitStats']))
186
			$context['general_statistics']['right'] += array(
187
				'average_hits' => comma_format(round($averages['hits'] / $total_days_up, 2)),
188
			);
189
	}
190
191
	/**
192
	 * Top posters, boards, replies, etc.
193
	 */
194
	public function loadTopStatistics()
195
	{
196
		global $context;
197
198
		// Poster top 10.
199
		$context['top']['posters'] = topPosters();
200
201
		// Board top 10.
202
		$context['top']['boards'] = topBoards();
203
204
		// Topic replies top 10.
205
		$context['top']['topics_replies'] = topTopicReplies();
206
207
		// Topic views top 10.
208
		$context['top']['topics_views'] = topTopicViews();
209
210
		// Topic poster top 10.
211
		$context['top']['starters'] = topTopicStarter();
212
213
		// Time online top 10.
214
		$context['top']['time_online'] = topTimeOnline();
215
	}
216
217
	/**
218
	 * Load the huge table of activity by month
219
	 */
220
	public function loadMontlyActivity()
221
	{
222
		global $context;
223
224
		// Activity by month.
225
		monthlyActivity();
226
227
		$context['collapsed_years'] = array();
228
		foreach ($context['yearly'] as $year => $data)
229
		{
230
			// This gets rid of the filesort on the query ;).
231
			krsort($context['yearly'][$year]['months']);
232
233
			// Yearly stats, topics, posts, members, etc
234
			$context['yearly'][$year]['new_topics'] = comma_format($data['new_topics']);
235
			$context['yearly'][$year]['new_posts'] = comma_format($data['new_posts']);
236
			$context['yearly'][$year]['new_members'] = comma_format($data['new_members']);
237
			$context['yearly'][$year]['most_members_online'] = comma_format($data['most_members_online']);
238
			$context['yearly'][$year]['hits'] = comma_format($data['hits']);
239
240
			// Keep a list of collapsed years.
241
			if (!$data['expanded'] && !$data['current_year'])
242
				$context['collapsed_years'][] = $year;
243
		}
244
245
		// Want to expand out the yearly stats
246
		if (empty($_SESSION['expanded_stats']))
247
			return;
248
249
		$condition_text = array();
250
		$condition_params = array();
251
		foreach ($_SESSION['expanded_stats'] as $year => $months)
252
			if (!empty($months))
253
			{
254
				$condition_text[] = 'YEAR(date) = {int:year_' . $year . '} AND MONTH(date) IN ({array_int:months_' . $year . '})';
255
				$condition_params['year_' . $year] = $year;
256
				$condition_params['months_' . $year] = $months;
257
			}
258
259
		// No daily stats to even look at?
260
		if (empty($condition_text))
261
			return;
262
263
		getDailyStats(implode(' OR ', $condition_text), $condition_params);
264
	}
265
}