]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Sitemap/Sitemap_notice_count.php
cb42edcbf6ecc62c1efd64371c4715a1445aeb30
[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 class Sitemap_notice_count extends Managed_DataObject
55 {
56     public $__table = 'sitemap_notice_count'; // table name
57
58     public $notice_date;                       // date primary_key not_null
59     public $notice_count;                      // int(4)
60     public $created;
61     public $modified;
62
63     /**
64      * return table definition for DB_DataObject
65      *
66      * DB_DataObject needs to know something about the table to manipulate
67      * instances. This method provides all the DB_DataObject needs to know.
68      *
69      * @return array array of column definitions
70      */
71     function table()
72     {
73         return array('notice_date' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_NOTNULL,
74                      'notice_count' => DB_DATAOBJECT_INT,
75                      'created'   => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
76                      'modified'  => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
77     }
78
79     /**
80      * return key definitions for DB_DataObject
81      *
82      * DB_DataObject needs to know about keys that the table has; this function
83      * defines them.
84      *
85      * @return array key definitions
86      */
87     function keys()
88     {
89         return array('notice_date' => 'K');
90     }
91
92     /**
93      * return key definitions for Memcached_DataObject
94      *
95      * Our caching system uses the same key definitions, but uses a different
96      * method to get them.
97      *
98      * @return array key definitions
99      */
100     function keyTypes()
101     {
102         return $this->keys();
103     }
104
105     static function getAll()
106     {
107         $noticeCounts = self::cacheGet('sitemap:notice:counts');
108
109         if ($noticeCounts === false) {
110             $snc = new Sitemap_notice_count();
111             $snc->orderBy('notice_date DESC');
112
113             // Fetch the first one to check up-to-date-itude
114
115             $n = $snc->find(true);
116
117             $today = self::today();
118             $noticeCounts = array();
119
120             if (!$n) { // No counts saved yet
121                 $noticeCounts = self::initializeCounts();
122             } else if ($snc->notice_date < $today) { // There are counts but not up to today
123                 $noticeCounts = self::fillInCounts($snc->notice_date);
124             } else if ($snc->notice_date == $today) { // Refresh today's
125                 $noticeCounts[$today] = self::updateToday();
126             }
127
128             // starts with second-to-last date
129
130             while ($snc->fetch()) {
131                 $noticeCounts[$snc->notice_date] = $snc->notice_count;
132             }
133
134             // Cache notice counts for 4 hours.
135
136             self::cacheSet('sitemap:notice:counts', $noticeCounts, null, time() + 4 * 60 * 60);
137         }
138
139         return $noticeCounts;
140     }
141
142     static function initializeCounts()
143     {
144         $firstDate = self::getFirstDate(); // awww
145         $today     = self::today();
146
147         $counts = array();
148
149         for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
150             $n = self::getCount($d);
151             self::insertCount($d, $n);
152             $counts[$d] = $n;
153         }
154
155         return $counts;
156     }
157
158     static function fillInCounts($lastDate)
159     {
160         $today = self::today();
161
162         $counts = array();
163
164         $n = self::getCount($lastDate);
165         self::updateCount($lastDate, $n);
166
167         $counts[$lastDate] = $n;
168
169         for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
170             $n = self::getCount($d);
171             self::insertCount($d, $n);
172         }
173
174         return $counts;
175     }
176
177     static function updateToday()
178     {
179         $today = self::today();
180
181         $n = self::getCount($today);
182         self::updateCount($today, $n);
183
184         return $n;
185     }
186
187     static function getCount($d)
188     {
189         $notice = new Notice();
190         $notice->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
191         $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
192         $n = $notice->count();
193
194         return $n;
195     }
196
197     static function insertCount($d, $n)
198     {
199         $snc = new Sitemap_notice_count();
200
201         $snc->notice_date = DB_DataObject_Cast::date($d);
202
203         $snc->notice_count      = $n;
204         $snc->created           = common_sql_now();
205         $snc->modified          = $snc->created;
206
207         if (!$snc->insert()) {
208             common_log(LOG_WARNING, "Could not save user counts for '$d'");
209         }
210     }
211
212     static function updateCount($d, $n)
213     {
214         $snc = Sitemap_notice_count::staticGet('notice_date', DB_DataObject_Cast::date($d));
215
216         if (empty($snc)) {
217             // TRANS: Exception
218             throw new Exception(_m("No such registration date: $d."));
219         }
220
221         $orig = clone($snc);
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->update($orig)) {
230             common_log(LOG_WARNING, "Could not save user counts for '$d'");
231         }
232     }
233
234     static function incrementDay($d)
235     {
236         $dt = self::dateStrToInt($d);
237         return self::dateIntToStr($dt + 24 * 60 * 60);
238     }
239
240     static function dateStrToInt($d)
241     {
242         return strtotime($d.' 00:00:00');
243     }
244
245     static function dateIntToStr($dt)
246     {
247         return date('Y-m-d', $dt);
248     }
249
250     static function getFirstDate()
251     {
252         $n = new Notice();
253
254         $n->selectAdd();
255         $n->selectAdd('date(min(created)) as first_date');
256
257         if ($n->find(true)) {
258             return $n->first_date;
259         } else {
260             // Is this right?
261             return self::dateIntToStr(time());
262         }
263     }
264
265     static function today()
266     {
267         return self::dateIntToStr(time());
268     }
269 }