]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Sitemap/Sitemap_notice_count.php
2a375b3e48a35ecd821691116251b31a88b526bf
[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             self::cacheSet('sitemap:notice:counts', $noticeCounts);
157         }
158
159         return $noticeCounts;
160     }
161
162     static function initializeCounts()
163     {
164         $firstDate = self::getFirstDate(); // awww
165         $today     = self::today();
166
167         $counts = array();
168
169         for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
170             $n = self::getCount($d);
171             self::insertCount($d, $n);
172             $counts[$d] = $n;
173         }
174
175         return $counts;
176     }
177
178     static function fillInCounts($lastDate)
179     {
180         $today = self::today();
181
182         $counts = array();
183
184         $n = self::getCount($lastDate);
185         self::updateCount($lastDate, $n);
186
187         $counts[$lastDate] = $n;
188
189         for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
190             $n = self::getCount($d);
191             self::insertCount($d, $n);
192         }
193
194         return $counts;
195     }
196
197     static function updateToday()
198     {
199         $today = self::today();
200
201         $n = self::getCount($today);
202         self::updateCount($today, $n);
203
204         return $n;
205     }
206
207     static function getCount($d)
208     {
209         $notice = new Notice();
210         $notice->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
211         $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
212         $n = $notice->count();
213
214         return $n;
215     }
216
217     static function insertCount($d, $n)
218     {
219         $snc = new Sitemap_notice_count();
220
221         $snc->notice_date = DB_DataObject_Cast::date($d);
222
223         $snc->notice_count      = $n;
224         $snc->created           = common_sql_now();
225         $snc->modified          = $snc->created;
226
227         if (!$snc->insert()) {
228             common_log(LOG_WARNING, "Could not save user counts for '$d'");
229         }
230     }
231
232     static function updateCount($d, $n)
233     {
234         $snc = Sitemap_notice_count::staticGet('notice_date', DB_DataObject_Cast::date($d));
235
236         if (empty($snc)) {
237             throw new Exception("No such registration date: $d");
238         }
239
240         $orig = clone($snc);
241
242         $snc->notice_date = DB_DataObject_Cast::date($d);
243
244         $snc->notice_count      = $n;
245         $snc->created           = common_sql_now();
246         $snc->modified          = $snc->created;
247
248         if (!$snc->update($orig)) {
249             common_log(LOG_WARNING, "Could not save user counts for '$d'");
250         }
251     }
252
253     static function incrementDay($d)
254     {
255         $dt = self::dateStrToInt($d);
256         return self::dateIntToStr($dt + 24 * 60 * 60);
257     }
258
259     static function dateStrToInt($d)
260     {
261         return strtotime($d.' 00:00:00');
262     }
263
264     static function dateIntToStr($dt)
265     {
266         return date('Y-m-d', $dt);
267     }
268
269     static function getFirstDate()
270     {
271         $n = new Notice();
272
273         $n->selectAdd();
274         $n->selectAdd('date(min(created)) as first_date');
275
276         if ($n->find(true)) {
277             return $n->first_date;
278         } else {
279             // Is this right?
280             return self::dateIntToStr(time());
281         }
282     }
283
284     static function today()
285     {
286         return self::dateIntToStr(time());
287     }
288 }