]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Sitemap/Sitemap_notice_count.php
Merge branch '0.9.x' into 1.0.x
[quix0rs-gnu-social.git] / plugins / Sitemap / Sitemap_notice_count.php
1 <?php
2 /**
3  * Data class for counting notice postings by date
4  *
5  * PHP version 5
6  *
7  * @category Data
8  * @package  StatusNet
9  * @author   Evan Prodromou <evan@status.net>
10  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
11  * @link     http://status.net/
12  *
13  * StatusNet - the distributed open-source microblogging tool
14  * Copyright (C) 2010, StatusNet, Inc.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU Affero General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
24  * GNU Affero General Public License for more details.
25  *
26  * You should have received a copy of the GNU Affero General Public License
27  * along with this program. If not, see <http://www.gnu.org/licenses/>.
28  */
29
30 if (!defined('STATUSNET')) {
31     exit(1);
32 }
33
34 require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
35
36 /**
37  * Data class for counting notices by date
38  *
39  * We make a separate sitemap for each notice posted by date.
40  * To save ourselves some (not inconsiderable) processing effort,
41  * we cache this data in the sitemap_notice_count table. Each
42  * row represents a day since the site has been started, with a count
43  * of notices posted on that day. Since, after the end of the day,
44  * this number doesn't change, it's a good candidate for persistent caching.
45  *
46  * @category Data
47  * @package  StatusNet
48  * @author   Evan Prodromou <evan@status.net>
49  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
50  * @link     http://status.net/
51  *
52  * @see      DB_DataObject
53  */
54
55 class Sitemap_notice_count extends Memcached_DataObject
56 {
57     public $__table = 'sitemap_notice_count'; // table name
58
59     public $notice_date;                       // date primary_key not_null
60     public $notice_count;                      // int(4)
61     public $created;
62     public $modified;
63
64     /**
65      * Get an instance by key
66      *
67      * This is a utility method to get a single instance with a given key value.
68      *
69      * @param string $k Key to use to lookup (usually 'notice_id' for this class)
70      * @param mixed  $v Value to lookup
71      *
72      * @return Sitemap_notice_count object found, or null for no hits
73      *
74      */
75
76     function staticGet($k, $v=null)
77     {
78         return Memcached_DataObject::staticGet('Sitemap_notice_count', $k, $v);
79     }
80
81     /**
82      * return table definition for DB_DataObject
83      *
84      * DB_DataObject needs to know something about the table to manipulate
85      * instances. This method provides all the DB_DataObject needs to know.
86      *
87      * @return array array of column definitions
88      */
89
90     function table()
91     {
92         return array('notice_date' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_NOTNULL,
93                      'notice_count' => DB_DATAOBJECT_INT,
94                      'created'   => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
95                      'modified'  => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
96     }
97
98     /**
99      * return key definitions for DB_DataObject
100      *
101      * DB_DataObject needs to know about keys that the table has; this function
102      * defines them.
103      *
104      * @return array key definitions
105      */
106
107     function keys()
108     {
109         return array('notice_date' => 'K');
110     }
111
112     /**
113      * return key definitions for Memcached_DataObject
114      *
115      * Our caching system uses the same key definitions, but uses a different
116      * method to get them.
117      *
118      * @return array key definitions
119      */
120
121     function keyTypes()
122     {
123         return $this->keys();
124     }
125
126     static function getAll()
127     {
128         $noticeCounts = self::cacheGet('sitemap:notice:counts');
129
130         if ($noticeCounts === false) {
131
132             $snc = new Sitemap_notice_count();
133             $snc->orderBy('notice_date DESC');
134
135             // Fetch the first one to check up-to-date-itude
136
137             $n = $snc->find(true);
138
139             $today = self::today();
140             $noticeCounts = array();
141
142             if (!$n) { // No counts saved yet
143                 $noticeCounts = self::initializeCounts();
144             } else if ($snc->notice_date < $today) { // There are counts but not up to today
145                 $noticeCounts = self::fillInCounts($snc->notice_date);
146             } else if ($snc->notice_date == $today) { // Refresh today's
147                 $noticeCounts[$today] = self::updateToday();
148             }
149
150             // starts with second-to-last date
151
152             while ($snc->fetch()) {
153                 $noticeCounts[$snc->notice_date] = $snc->notice_count;
154             }
155
156             // Cache notice counts for 4 hours.
157
158             self::cacheSet('sitemap:notice:counts', $noticeCounts, null, time() + 4 * 60 * 60);
159         }
160
161         return $noticeCounts;
162     }
163
164     static function initializeCounts()
165     {
166         $firstDate = self::getFirstDate(); // awww
167         $today     = self::today();
168
169         $counts = array();
170
171         for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
172             $n = self::getCount($d);
173             self::insertCount($d, $n);
174             $counts[$d] = $n;
175         }
176
177         return $counts;
178     }
179
180     static function fillInCounts($lastDate)
181     {
182         $today = self::today();
183
184         $counts = array();
185
186         $n = self::getCount($lastDate);
187         self::updateCount($lastDate, $n);
188
189         $counts[$lastDate] = $n;
190
191         for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
192             $n = self::getCount($d);
193             self::insertCount($d, $n);
194         }
195
196         return $counts;
197     }
198
199     static function updateToday()
200     {
201         $today = self::today();
202
203         $n = self::getCount($today);
204         self::updateCount($today, $n);
205
206         return $n;
207     }
208
209     static function getCount($d)
210     {
211         $notice = new Notice();
212         $notice->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
213         $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
214         $n = $notice->count();
215
216         return $n;
217     }
218
219     static function insertCount($d, $n)
220     {
221         $snc = new Sitemap_notice_count();
222
223         $snc->notice_date = DB_DataObject_Cast::date($d);
224
225         $snc->notice_count      = $n;
226         $snc->created           = common_sql_now();
227         $snc->modified          = $snc->created;
228
229         if (!$snc->insert()) {
230             common_log(LOG_WARNING, "Could not save user counts for '$d'");
231         }
232     }
233
234     static function updateCount($d, $n)
235     {
236         $snc = Sitemap_notice_count::staticGet('notice_date', DB_DataObject_Cast::date($d));
237
238         if (empty($snc)) {
239             throw new Exception("No such registration date: $d");
240         }
241
242         $orig = clone($snc);
243
244         $snc->notice_date = DB_DataObject_Cast::date($d);
245
246         $snc->notice_count      = $n;
247         $snc->created           = common_sql_now();
248         $snc->modified          = $snc->created;
249
250         if (!$snc->update($orig)) {
251             common_log(LOG_WARNING, "Could not save user counts for '$d'");
252         }
253     }
254
255     static function incrementDay($d)
256     {
257         $dt = self::dateStrToInt($d);
258         return self::dateIntToStr($dt + 24 * 60 * 60);
259     }
260
261     static function dateStrToInt($d)
262     {
263         return strtotime($d.' 00:00:00');
264     }
265
266     static function dateIntToStr($dt)
267     {
268         return date('Y-m-d', $dt);
269     }
270
271     static function getFirstDate()
272     {
273         $n = new Notice();
274
275         $n->selectAdd();
276         $n->selectAdd('date(min(created)) as first_date');
277
278         if ($n->find(true)) {
279             return $n->first_date;
280         } else {
281             // Is this right?
282             return self::dateIntToStr(time());
283         }
284     }
285
286     static function today()
287     {
288         return self::dateIntToStr(time());
289     }
290 }