Index: trunk/extensions/ContributionReporting/ContributionReporting.php |
— | — | @@ -115,6 +115,10 @@ |
116 | 116 | ), |
117 | 117 | ); |
118 | 118 | |
| 119 | +// The first year of statistics to make visible by default. |
| 120 | +// We normally don't show all of them by default, since it makes the chart extremely wide. |
| 121 | +$egFundraiserStatisticsFirstYearDefault = 2009; |
| 122 | + |
119 | 123 | // Thesholds for fundraiser statistics |
120 | 124 | $egFundraiserStatisticsMinimum = 1; |
121 | 125 | $egFundraiserStatisticsMaximum = 10000; |
Index: trunk/extensions/ContributionReporting/FundraiserStatistics_body.php |
— | — | @@ -1,6 +1,7 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | 4 | * Special Page for Contribution statistics extension |
| 5 | + * This page displays charts and tables related to donation statistics. |
5 | 6 | * |
6 | 7 | * @file |
7 | 8 | * @ingroup Extensions |
— | — | @@ -15,15 +16,22 @@ |
16 | 17 | } |
17 | 18 | |
18 | 19 | public function execute( $sub ) { |
19 | | - global $wgRequest, $wgOut, $wgLang, $wgScriptPath, $egFundraiserStatisticsFundraisers; |
| 20 | + global $wgRequest, $wgOut, $wgLang, $wgScriptPath, $egFundraiserStatisticsFundraisers, |
| 21 | + $egFundraiserStatisticsFirstYearDefault; |
20 | 22 | |
| 23 | + // Figure out what years to display initially |
21 | 24 | $showYear = array(); |
22 | 25 | foreach ( $egFundraiserStatisticsFundraisers as $fundraiser ) { |
23 | | - if ( $wgRequest->wasPosted() ) { |
24 | | - $showYear[$fundraiser['id']] = $wgRequest->getCheck( 'toogle'.$fundraiser['id'] ); |
| 26 | + // You can override the years to display by default via the query string. |
| 27 | + // For example, Special:FundraiserStatistics?2007=show&2010=hide |
| 28 | + $yearOverride = $wgRequest->getVal( $fundraiser['id'] ); |
| 29 | + if ( $yearOverride === "hide" ) { |
| 30 | + $showYear[$fundraiser['id']] = false; |
| 31 | + } else if ( $yearOverride === "show" ) { |
| 32 | + $showYear[$fundraiser['id']] = true; |
25 | 33 | } else { |
26 | | - // By default, show only the fundraising years after 2008 |
27 | | - if ( intval( $fundraiser['id'] ) > 2008 ) { |
| 34 | + // By default, show only the recent fundraising years |
| 35 | + if ( intval( $fundraiser['id'] ) >= $egFundraiserStatisticsFirstYearDefault ) { |
28 | 36 | $showYear[$fundraiser['id']] = true; |
29 | 37 | } else { |
30 | 38 | $showYear[$fundraiser['id']] = false; |
— | — | @@ -37,7 +45,6 @@ |
38 | 46 | 'totals' => array( |
39 | 47 | 'data' => array(), |
40 | 48 | 'index' => 1, |
41 | | - 'query' => 'dailyTotalMax', |
42 | 49 | 'precision' => 2, |
43 | 50 | 'label' => 'fundraiserstats-total', |
44 | 51 | 'max' => 1, |
— | — | @@ -45,7 +52,6 @@ |
46 | 53 | 'contributions' => array( |
47 | 54 | 'data' => array(), |
48 | 55 | 'index' => 2, |
49 | | - 'query' => 'contributionsMax', |
50 | 56 | 'precision' => 0, |
51 | 57 | 'label' => 'fundraiserstats-contributions', |
52 | 58 | 'max' => 1, |
— | — | @@ -53,7 +59,6 @@ |
54 | 60 | 'averages' => array( |
55 | 61 | 'data' => array(), |
56 | 62 | 'index' => 3, |
57 | | - 'query' => 'averagesMax', |
58 | 63 | 'precision' => 2, |
59 | 64 | 'label' => 'fundraiserstats-avg', |
60 | 65 | 'max' => 1, |
— | — | @@ -61,7 +66,6 @@ |
62 | 67 | 'maximums' => array( |
63 | 68 | 'data' => array(), |
64 | 69 | 'index' => 4, |
65 | | - 'query' => 'maximumsMax', |
66 | 70 | 'precision' => 2, |
67 | 71 | 'label' => 'fundraiserstats-max', |
68 | 72 | 'max' => 1, |
— | — | @@ -69,7 +73,6 @@ |
70 | 74 | 'ytd' => array( |
71 | 75 | 'data' => array(), |
72 | 76 | 'index' => 5, |
73 | | - 'query' => 'yearlyTotalMax', |
74 | 77 | 'precision' => 2, |
75 | 78 | 'label' => 'fundraiserstats-ytd', |
76 | 79 | 'max' => 1, |
— | — | @@ -85,10 +88,28 @@ |
86 | 89 | |
87 | 90 | $wgOut->addWikiMsg( 'contribstats-header' ); // Header (typically empty) |
88 | 91 | |
| 92 | + // The $fundraisingData array contains all of the fundraising data in the following scheme: |
| 93 | + // $fundraisingData[<fundraiserId>][<dayIndex>][<dataTypeIndex>] |
| 94 | + $fundraisingData = array(); |
| 95 | + |
| 96 | + foreach ( $egFundraiserStatisticsFundraisers as $fundraiserIndex => $fundraiser ) { |
| 97 | + |
| 98 | + // See if this is the most recent fundraiser or not |
| 99 | + if ( $fundraiserIndex == count( $egFundraiserStatisticsFundraisers ) - 1 ) { |
| 100 | + $mostRecent = true; |
| 101 | + } else { |
| 102 | + $mostRecent = false; |
| 103 | + } |
| 104 | + |
| 105 | + // Collect all the data |
| 106 | + $fundraisingData[$fundraiser['id']] = $this->query( $mostRecent, $fundraiser['start'], $fundraiser['end'] ); |
| 107 | + } |
| 108 | + |
89 | 109 | // Chart maximums |
90 | | - foreach ( $egFundraiserStatisticsFundraisers as $fundraiser ) { |
| 110 | + // We cycle through all the fundraisers with all the different chart types and collect the maximums. |
| 111 | + foreach ( $fundraisingData as $fundraiser ) { |
91 | 112 | foreach ( $charts as $name => $chart ) { |
92 | | - $chartMax = $this->query( $charts[$name]['query'], $fundraiser['start'], $fundraiser['end'] ); |
| 113 | + $chartMax = $this->getMaximum( $fundraiser, $chart['index'] ); |
93 | 114 | if ( $chartMax > $charts[$name]['max'] ) { |
94 | 115 | $charts[$name]['max'] = $chartMax; |
95 | 116 | } |
— | — | @@ -108,7 +129,7 @@ |
109 | 130 | foreach ( $egFundraiserStatisticsFundraisers as $fundraiserIndex => $fundraiser ) { |
110 | 131 | |
111 | 132 | // Get all the daily data for a particular fundraiser |
112 | | - $days = $this->query( 'dailyTotals', $fundraiser['start'], $fundraiser['end'] ); |
| 133 | + $days = $fundraisingData[$fundraiser['id']]; |
113 | 134 | |
114 | 135 | // See if this is the most recent fundraiser or not |
115 | 136 | if ( $fundraiserIndex == count( $egFundraiserStatisticsFundraisers ) - 1 ) { |
— | — | @@ -137,7 +158,7 @@ |
138 | 159 | |
139 | 160 | $height = $chart['factor'] * $day[$chart['index']]; |
140 | 161 | $style = "height:{$height}px;"; |
141 | | - if ( $showYear[$fundraiser['id']] !== true ) { |
| 162 | + if ( !$showYear[$fundraiser['id']] ) { |
142 | 163 | $style .= "display:none;"; |
143 | 164 | } |
144 | 165 | $attributes = array( |
— | — | @@ -212,8 +233,8 @@ |
213 | 234 | |
214 | 235 | $years = wfMsg( 'fundraiserstats-show-years' ).'<br/>'; |
215 | 236 | foreach ( $egFundraiserStatisticsFundraisers as $fundraiser ) { |
216 | | - $years .= Xml::check( 'toogle'.$fundraiser['id'], $showYear[$fundraiser['id']], array( 'id' => 'bar-'.$fundraiser['id'], 'class' => 'yeartoggle' ) ); |
217 | | - $years .= Xml::label( $fundraiser['id'], 'toogle'.$fundraiser['id'] ); |
| 237 | + $years .= Xml::check( 'toggle'.$fundraiser['id'], $showYear[$fundraiser['id']], array( 'id' => 'bar-'.$fundraiser['id'], 'class' => 'yeartoggle' ) ); |
| 238 | + $years .= Xml::label( $fundraiser['id'], 'toggle'.$fundraiser['id'] ); |
218 | 239 | $years .= "<br/>"; |
219 | 240 | } |
220 | 241 | $wgOut->addHTML( Xml::openElement( 'div', array( 'id' => 'configholder' ) ) ); |
— | — | @@ -285,16 +306,16 @@ |
286 | 307 | /** |
287 | 308 | * Retrieve the donation data from the database |
288 | 309 | * |
289 | | - * @param string $type Which type of query to do |
| 310 | + * @param boolean $mostRecent Is this query for the most recent fundraiser? |
290 | 311 | * @param string $start The start date for a fundraiser |
291 | 312 | * @param string $end The end date for a fundraiser |
292 | 313 | * @return an array of results or null |
293 | 314 | */ |
294 | | - private function query( $type, $start, $end ) { |
| 315 | + private function query( $mostRecent, $start, $end ) { |
295 | 316 | global $wgMemc, $egFundraiserStatisticsMinimum, $egFundraiserStatisticsMaximum, $egFundraiserStatisticsCacheTimeout; |
296 | 317 | |
297 | 318 | // Conctruct the key for memcached |
298 | | - $key = wfMemcKey( 'fundraiserstatistics', $type, $start, $end ); |
| 319 | + $key = wfMemcKey( 'fundraiserstatistics', $start, $end ); |
299 | 320 | |
300 | 321 | // If result exists in memcached, use that |
301 | 322 | $cache = $wgMemc->get( $key ); |
— | — | @@ -310,88 +331,60 @@ |
311 | 332 | 'converted_amount >= ' . $egFundraiserStatisticsMinimum, |
312 | 333 | 'converted_amount <= ' . $egFundraiserStatisticsMaximum |
313 | 334 | ); |
314 | | - switch ( $type ) { |
315 | | - case 'dailyTotals': |
316 | | - $select = $dbr->select( 'public_reporting', |
317 | | - array( |
318 | | - "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')", |
319 | | - 'sum(converted_amount)', |
320 | | - 'count(*)', |
321 | | - 'avg(converted_amount)', |
322 | | - 'max(converted_amount)', |
323 | | - ), |
324 | | - $conditions, |
325 | | - __METHOD__ . '-dailyTotals', |
326 | | - array( |
327 | | - 'ORDER BY' => 'received', |
328 | | - 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
329 | | - ) |
330 | | - ); |
331 | | - $result = array(); |
332 | | - $ytd = 0; |
333 | | - while ( $row = $dbr->fetchRow( $select ) ) { |
334 | | - // Insert the year-to-date amount as a record in the row (existing $ytd + sum) |
335 | | - $row[5] = $ytd += $row[1]; |
336 | | - $result[] = $row; |
337 | | - } |
338 | | - break; |
339 | | - case 'dailyTotalMax': |
340 | | - $result = $dbr->selectField( 'public_reporting', |
341 | | - array( 'sum(converted_amount) as sum' ), |
342 | | - $conditions, |
343 | | - __METHOD__ . '-dailyTotalMax', |
344 | | - array( |
345 | | - 'ORDER BY' => 'sum DESC', |
346 | | - 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
347 | | - ) |
348 | | - ); |
349 | | - break; |
350 | | - case 'yearlyTotalMax': |
351 | | - $result = $dbr->selectField( 'public_reporting', |
352 | | - array( 'sum(converted_amount) as sum' ), |
353 | | - $conditions, |
354 | | - __METHOD__ . '-yearlyTotalMax' |
355 | | - ); |
356 | | - break; |
357 | | - case 'contributionsMax': |
358 | | - $result = $dbr->selectField( 'public_reporting', |
359 | | - array( 'count(converted_amount) as sum' ), |
360 | | - $conditions, |
361 | | - __METHOD__ . '-contributionsMax', |
362 | | - array( |
363 | | - 'ORDER BY' => 'sum DESC', |
364 | | - 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
365 | | - ) |
366 | | - ); |
367 | | - break; |
368 | | - case 'averagesMax': |
369 | | - $result = $dbr->selectField( 'public_reporting', |
370 | | - array( 'avg(converted_amount) as sum' ), |
371 | | - $conditions, |
372 | | - __METHOD__ . '-averagesMax', |
373 | | - array( |
374 | | - 'ORDER BY' => 'sum DESC', |
375 | | - 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
376 | | - ) |
377 | | - ); |
378 | | - break; |
379 | | - case 'maximumsMax': |
380 | | - $result = $dbr->selectField( 'public_reporting', |
381 | | - array( 'max(converted_amount) as sum' ), |
382 | | - $conditions, |
383 | | - __METHOD__ . '-maximumsMax', |
384 | | - array( |
385 | | - 'ORDER BY' => 'sum DESC', |
386 | | - 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
387 | | - ) |
388 | | - ); |
389 | | - break; |
| 335 | + |
| 336 | + // Get the data for a fundraiser |
| 337 | + $select = $dbr->select( 'public_reporting', |
| 338 | + array( |
| 339 | + "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')", |
| 340 | + 'sum(converted_amount)', |
| 341 | + 'count(*)', |
| 342 | + 'avg(converted_amount)', |
| 343 | + 'max(converted_amount)', |
| 344 | + ), |
| 345 | + $conditions, |
| 346 | + __METHOD__, |
| 347 | + array( |
| 348 | + 'ORDER BY' => 'received', |
| 349 | + 'GROUP BY' => "DATE_FORMAT(FROM_UNIXTIME(received),'%Y-%m-%d')" |
| 350 | + ) |
| 351 | + ); |
| 352 | + $result = array(); |
| 353 | + $ytd = 0; |
| 354 | + while ( $row = $dbr->fetchRow( $select ) ) { |
| 355 | + // Insert the year-to-date amount as a record in the row (existing $ytd + sum) |
| 356 | + $row[5] = $ytd += $row[1]; |
| 357 | + $result[] = $row; |
390 | 358 | } |
| 359 | + |
391 | 360 | if ( isset( $result ) ) { |
392 | | - // Store the result in memcached |
393 | | - $wgMemc->set( $key, $result, $egFundraiserStatisticsCacheTimeout ); |
| 361 | + // Store the result in memcached. |
| 362 | + // If it's the most recent fundraiser, cache for a short period of time, otherwise |
| 363 | + // cache for 24 hours (since the query is expensive). |
| 364 | + if ( $mostRecent ) { |
| 365 | + $wgMemc->set( $key, $result, $egFundraiserStatisticsCacheTimeout ); |
| 366 | + } else { |
| 367 | + #$wgMemc->set( $key, $result, 86400 ); |
| 368 | + } |
394 | 369 | return $result; |
395 | 370 | } |
396 | 371 | return null; |
397 | 372 | } |
| 373 | + |
| 374 | + /** |
| 375 | + * Given a particular index, find the maximum for all values in a 2D array with that particular |
| 376 | + * index as the 2nd key. |
| 377 | + * |
| 378 | + * @param array $fundraiserDays A 2D array of daily data for a particular fundraiser |
| 379 | + * @param integer $comparisonIndex The index to find the maximum for |
| 380 | + * @return an integer |
| 381 | + */ |
| 382 | + private function getMaximum( $fundraiserDays, $comparisonIndex ) { |
| 383 | + $max = 0; |
| 384 | + foreach( $fundraiserDays as $day ) { |
| 385 | + if ( $day[$comparisonIndex] > $max ) { |
| 386 | + $max = $day[$comparisonIndex]; |
| 387 | + } |
| 388 | + } |
| 389 | + return $max; |
| 390 | + } |
398 | 391 | } |
Index: trunk/extensions/ContributionReporting/modules/ext.fundraiserstatistics.js |
— | — | @@ -33,9 +33,11 @@ |
34 | 34 | $j( '.fundraiserstats-current' ).each( function() { |
35 | 35 | replaceView( $j(this).attr( 'rel' ) ) |
36 | 36 | } ); |
| 37 | + // When someone clicks on a year, hide or show that year in the chart |
37 | 38 | $j( '#configholder .yeartoggle' ).click( function() { |
38 | 39 | $j('.fundraiserstats-'+$j(this).attr( 'id' )).toggle(); |
39 | 40 | } ); |
| 41 | + // When someone clicks on Customize, display pop-up menu and change arrow icon. |
40 | 42 | $j( '#configtoggle' ).click( function() { |
41 | 43 | $j('#configholder').toggle(); |
42 | 44 | if ($j( '#configtoggle a' ).css( 'background-position' ) == '0px -18px') { |
— | — | @@ -44,8 +46,5 @@ |
45 | 47 | $j( '#configtoggle a' ).css( 'background-position','0px -18px' ); |
46 | 48 | } |
47 | 49 | } ); |
48 | | - $j( '#timezone' ).change( function() { |
49 | | - $j('#configform').submit(); |
50 | | - } ); |
51 | 50 | |
52 | 51 | } ); |