]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Bookmark/Bookmark.php
87715ecad621263fce7dbfd59742a0483907f4f3
[quix0rs-gnu-social.git] / plugins / Bookmark / Bookmark.php
1 <?php
2 /**
3  * Data class to mark notices as bookmarks
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) 2009, 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 /**
35  * For storing the fact that a notice is a bookmark
36  *
37  * @category Bookmark
38  * @package  StatusNet
39  * @author   Evan Prodromou <evan@status.net>
40  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
41  * @link     http://status.net/
42  *
43  * @see      DB_DataObject
44  */
45
46 class Bookmark extends Memcached_DataObject
47 {
48     public $__table = 'bookmark'; // table name
49     public $profile_id;           // int(4)  primary_key not_null
50     public $url;                  // varchar(255) primary_key not_null
51     public $title;                // varchar(255)
52     public $description;          // text
53     public $uri;                  // varchar(255)
54     public $url_crc32;            // int(4) not_null
55     public $created;              // datetime
56
57     /**
58      * Get an instance by key
59      *
60      * This is a utility method to get a single instance with a given key value.
61      *
62      * @param string $k Key to use to lookup (usually 'user_id' for this class)
63      * @param mixed  $v Value to lookup
64      *
65      * @return User_greeting_count object found, or null for no hits
66      *
67      */
68
69     function staticGet($k, $v=null)
70     {
71         return Memcached_DataObject::staticGet('Bookmark', $k, $v);
72     }
73
74     /**
75      * Get an instance by compound key
76      *
77      * This is a utility method to get a single instance with a given set of
78      * key-value pairs. Usually used for the primary key for a compound key; thus
79      * the name.
80      *
81      * @param array $kv array of key-value mappings
82      *
83      * @return Bookmark object found, or null for no hits
84      *
85      */
86
87     function pkeyGet($kv)
88     {
89         return Memcached_DataObject::pkeyGet('Bookmark', $kv);
90     }
91
92     /**
93      * return table definition for DB_DataObject
94      *
95      * DB_DataObject needs to know something about the table to manipulate
96      * instances. This method provides all the DB_DataObject needs to know.
97      *
98      * @return array array of column definitions
99      */
100
101     function table()
102     {
103         return array('profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
104                      'url' => DB_DATAOBJECT_STR,
105                      'title' => DB_DATAOBJECT_STR,
106                      'description' => DB_DATAOBJECT_STR,
107                      'uri' => DB_DATAOBJECT_STR,
108                      'url_crc32' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
109                      'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
110     }
111
112     /**
113      * return key definitions for DB_DataObject
114      *
115      * @return array list of key field names
116      */
117
118     function keys()
119     {
120         return array_keys($this->keyTypes());
121     }
122
123     /**
124      * return key definitions for Memcached_DataObject
125      *
126      * @return array associative array of key definitions
127      */
128
129     function keyTypes()
130     {
131         return array('profile_id' => 'K',
132                      'url' => 'K',
133                      'uri' => 'U');
134     }
135
136     /**
137      * Magic formula for non-autoincrementing integer primary keys
138      *
139      * @return array magic three-false array that stops auto-incrementing.
140      */
141
142     function sequenceKey()
143     {
144         return array(false, false, false);
145     }
146
147     /**
148      * Get a bookmark based on a notice
149      * 
150      * @param Notice $notice Notice to check for
151      *
152      * @return Bookmark found bookmark or null
153      */
154     
155     function getByNotice($notice)
156     {
157         return self::staticGet('uri', $notice->uri);
158     }
159
160     /**
161      * Get the bookmark that a user made for an URL
162      *
163      * @param Profile $profile Profile to check for
164      * @param string  $url     URL to check for
165      *
166      * @return Bookmark bookmark found or null
167      */
168      
169     static function getByURL($profile, $url)
170     {
171         return self::pkeyGet(array('profile_id' => $profile->id,
172                                    'url' => $url));
173         return null;
174     }
175
176     /**
177      * Get the bookmark that a user made for an URL
178      *
179      * @param Profile $profile Profile to check for
180      * @param integer $crc32   CRC-32 of URL to check for
181      *
182      * @return array Bookmark objects found (usually 1 or 0)
183      */
184      
185     static function getByCRC32($profile, $crc32)
186     {
187         $bookmarks = array();
188
189         $nb = new Bookmark();
190         
191         $nb->profile_id = $profile->id;
192         $nb->url_crc32  = $crc32;
193
194         if ($nb->find()) {
195             while ($nb->fetch()) {
196                 $bookmarks[] = clone($nb);
197             }
198         }
199
200         return $bookmarks;
201     }
202
203     /**
204      * Save a new notice bookmark
205      *
206      * @param Profile $profile     To save the bookmark for
207      * @param string  $title       Title of the bookmark
208      * @param string  $url         URL of the bookmark
209      * @param mixed   $rawtags     array of tags or string
210      * @param string  $description Description of the bookmark
211      * @param array   $options     Options for the Notice::saveNew()
212      *
213      * @return Notice saved notice
214      */
215
216     static function saveNew($profile, $title, $url, $rawtags, $description,
217                             $options=null)
218     {
219         $nb = self::getByURL($profile, $url);
220
221         if (!empty($nb)) {
222             throw new ClientException(_('Bookmark already exists.'));
223         }
224
225         if (empty($options)) {
226             $options = array();
227         }
228
229         if (array_key_exists('uri', $options)) {
230             $other = Bookmark::staticGet('uri', $options['uri']);
231             if (!empty($other)) {
232                 throw new ClientException(_('Bookmark already exists.'));
233             }
234         }
235
236         if (is_string($rawtags)) {
237             $rawtags = preg_split('/[\s,]+/', $rawtags);
238         }
239
240         $nb = new Bookmark();
241
242         $nb->profile_id  = $profile->id;
243         $nb->url         = $url;
244         $nb->title       = $title;
245         $nb->description = $description;
246         $nb->url_crc32   = crc32($nb->url);
247
248         if (array_key_exists('created', $options)) {
249             $nb->created = $options['created'];
250         } else {
251             $nb->created = common_sql_now();
252         }
253
254         if (array_key_exists('uri', $options)) {
255             $nb->uri = $options['uri'];
256         } else {
257             $dt = new DateTime($nb->created, new DateTimeZone('UTC'));
258
259             // I posit that it's sufficiently impossible
260             // for the same user to generate two CRC-32-clashing
261             // URLs in the same second that this is a safe unique identifier.
262             // If you find a real counterexample, contact me at acct:evan@status.net
263             // and I will publicly apologize for my hubris.
264
265             $created = $dt->format('YmdHis');
266
267             $crc32   = sprintf('%08x', $nb->url_crc32);
268
269             $nb->uri = common_local_url('showbookmark',
270                                         array('user' => $profile->id,
271                                               'created' => $created,
272                                               'crc32' => $crc32));
273         }
274
275         $nb->insert();
276
277         $tags    = array();
278         $replies = array();
279
280         // filter "for:nickname" tags
281
282         foreach ($rawtags as $tag) {
283             if (strtolower(mb_substr($tag, 0, 4)) == 'for:') {
284                 if (!array_key_exists('replies', $options)) { // skip if done by caller
285                     $nickname = mb_substr($tag, 4);
286                     $other    = common_relative_profile($profile,
287                                                         $nickname);
288                     if (!empty($other)) {
289                         $replies[] = $other->getUri();
290                     }
291                 }
292             } else {
293                 $tags[] = common_canonical_tag($tag);
294             }
295         }
296
297         $hashtags = array();
298         $taglinks = array();
299
300         foreach ($tags as $tag) {
301             $hashtags[] = '#'.$tag;
302             $attrs      = array('href' => Notice_tag::url($tag),
303                                 'rel'  => $tag,
304                                 'class' => 'tag');
305             $taglinks[] = XMLStringer::estring('a', $attrs, $tag);
306         }
307
308         // Use user's preferences for short URLs, if possible
309
310         $user = User::staticGet('id', $profile->id);
311
312         $shortUrl = File_redirection::makeShort($url, 
313                                                 empty($user) ? null : $user);
314
315         $content = sprintf(_('"%s" %s %s %s'),
316                            $title,
317                            $shortUrl,
318                            $description,
319                            implode(' ', $hashtags));
320
321         $rendered = sprintf(_('<span class="xfolkentry">'.
322                               '<a class="taggedlink" href="%s">%s</a> '.
323                               '<span class="description">%s</span> '.
324                               '<span class="meta">%s</span>'.
325                               '</span>'),
326                             htmlspecialchars($url),
327                             htmlspecialchars($title),
328                             htmlspecialchars($description),
329                             implode(' ', $taglinks));
330
331         $options = array_merge(array('urls' => array($url),
332                                      'rendered' => $rendered,
333                                      'tags' => $tags,
334                                      'replies' => $replies),
335                                $options);
336
337         if (!array_key_exists('uri', $options)) {
338             $options['uri'] = $nb->uri;
339         }
340
341         $saved = Notice::saveNew($profile->id,
342                                  $content,
343                                  array_key_exists('source', $options) ?
344                                  $options['source'] : 'web',
345                                  $options);
346
347         return $saved;
348     }
349 }