]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/QnA/classes/QnA_Question.php
Plugins with classes that extend Managed_DataObject get better code reuse
[quix0rs-gnu-social.git] / plugins / QnA / classes / QnA_Question.php
1 <?php
2 /**
3  * Data class to mark a notice as a question
4  *
5  * PHP version 5
6  *
7  * @category QnA
8  * @package  StatusNet
9  * @author   Zach Copley <zach@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) 2011, 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 a question
36  *
37  * @category QnA
38  * @package  StatusNet
39  * @author   Zach Copley <zach@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 class QnA_Question extends Managed_DataObject
46 {
47     const OBJECT_TYPE = 'http://activityschema.org/object/question';
48
49     public $__table = 'qna_question'; // table name
50     public $id;          // char(36) primary key not null -> UUID
51     public $uri;
52     public $profile_id;  // int -> profile.id
53     public $title;       // text
54     public $description; // text
55     public $closed;      // int (boolean) whether a question is closed
56     public $created;     // datetime
57
58     /**
59      * Get an instance by compound key
60      *
61      * This is a utility method to get a single instance with a given set of
62      * key-value pairs. Usually used for the primary key for a compound key; thus
63      * the name.
64      *
65      * @param array $kv array of key-value mappings
66      *
67      * @return Bookmark object found, or null for no hits
68      *
69      */
70     function pkeyGet($kv)
71     {
72         return Memcached_DataObject::pkeyGet('QnA_Question', $kv);
73     }
74
75     /**
76      * The One True Thingy that must be defined and declared.
77      */
78     public static function schemaDef()
79     {
80         return array(
81             'description' => 'Per-notice question data for QNA plugin',
82             'fields' => array(
83                 'id' => array(
84                     'type'        => 'char',
85                     'length'      => 36,
86                     'not null'    => true,
87                     'description' => 'UUID'
88                 ),
89                 'uri' => array(
90                     'type'     => 'varchar',
91                     'length'   => 255,
92                     'not null' => true
93                 ),
94                 'profile_id'  => array('type' => 'int'),
95                 'title'       => array('type' => 'text'),
96                 'closed'      => array('type' => 'int', 'size' => 'tiny'),
97                 'description' => array('type' => 'text'),
98                 'created'     => array(
99                     'type'     => 'datetime',
100                     'not null' => true
101                 ),
102             ),
103             'primary key' => array('id'),
104             'unique keys' => array(
105                 'question_uri_key' => array('uri'),
106             ),
107         );
108     }
109
110     /**
111      * Get a question based on a notice
112      *
113      * @param Notice $notice Notice to check for
114      *
115      * @return Question found question or null
116      */
117     function getByNotice($notice)
118     {
119         return self::staticGet('uri', $notice->uri);
120     }
121
122     function getNotice()
123     {
124         return Notice::staticGet('uri', $this->uri);
125     }
126
127     function bestUrl()
128     {
129         return $this->getNotice()->bestUrl();
130     }
131
132     function getProfile()
133     {
134         $profile = Profile::staticGet('id', $this->profile_id);
135         if (empty($profile)) {
136             // TRANS: Exception trown when getting a profile for a non-existing ID.
137             // TRANS: %s is the provided profile ID.
138             throw new Exception(sprintf(_m('No profile with ID %s'),$this->profile_id));
139         }
140         return $profile;
141     }
142
143     /**
144      * Get the answer from a particular user to this question, if any.
145      *
146      * @param Profile $profile
147      *
148      * @return Answer object or null
149      */
150     function getAnswer(Profile $profile)
151     {
152         $a = new QnA_Answer();
153         $a->question_id = $this->id;
154         $a->profile_id = $profile->id;
155         $a->find();
156         if ($a->fetch()) {
157             return $a;
158         } else {
159             return null;
160         }
161     }
162
163     function getAnswers()
164     {
165         $a = new QnA_Answer();
166         $a->question_id = $this->id;
167         $cnt = $a->find();
168         if (!empty($cnt)) {
169             return $a;
170         } else {
171             return null;
172         }
173     }
174
175     function countAnswers()
176     {
177         $a = new QnA_Answer();
178
179         $a->question_id = $this->id;
180
181         return $a->count();
182     }
183
184     static function fromNotice($notice)
185     {
186         return QnA_Question::staticGet('uri', $notice->uri);
187     }
188
189     function asHTML()
190     {
191         return self::toHTML($this->getProfile(), $this);
192     }
193
194     function asString()
195     {
196         return self::toString($this->getProfile(), $this);
197     }
198
199     static function toHTML($profile, $question)
200     {
201         $notice = $question->getNotice();
202
203         $out = new XMLStringer();
204
205         $cls = array('qna_question');
206
207         if (!empty($question->closed)) {
208             $cls[] = 'closed';
209         }
210
211         $out->elementStart('p', array('class' => implode(' ', $cls)));
212
213         if (!empty($question->description)) {
214             $out->elementStart('span', 'question-description');
215             $out->raw(common_render_text($question->description));
216             $out->elementEnd('span');
217         }
218
219         $cnt = $question->countAnswers();
220
221         if (!empty($cnt)) {
222             $out->elementStart('span', 'answer-count');
223             // TRANS: Number of given answers to a question.
224             // TRANS: %s is the number of given answers.
225             $out->text(sprintf(_m('%s answer','%s answers',$cnt), $cnt));
226             $out->elementEnd('span');
227         }
228
229         if (!empty($question->closed)) {
230             $out->elementStart('span', 'question-closed');
231             // TRANS: Notification that a question cannot be answered anymore because it is closed.
232             $out->text(_m('This question is closed.'));
233             $out->elementEnd('span');
234         }
235
236         $out->elementEnd('p');
237
238         return $out->getString();
239     }
240
241     static function toString($profile, $question, $answers)
242     {
243         return sprintf(htmlspecialchars($question->description));
244     }
245
246     /**
247      * Save a new question notice
248      *
249      * @param Profile $profile
250      * @param string  $question
251      * @param string  $title
252      * @param string  $description
253      * @param array   $option // and whatnot
254      *
255      * @return Notice saved notice
256      */
257     static function saveNew($profile, $title, $description, $options = array())
258     {
259         $q = new QnA_Question();
260
261         $q->id          = UUID::gen();
262         $q->profile_id  = $profile->id;
263         $q->title       = $title;
264         $q->description = $description;
265
266         if (array_key_exists('created', $options)) {
267             $q->created = $options['created'];
268         } else {
269             $q->created = common_sql_now();
270         }
271
272         if (array_key_exists('uri', $options)) {
273             $q->uri = $options['uri'];
274         } else {
275             $q->uri = common_local_url(
276                 'qnashowquestion',
277                 array('id' => $q->id)
278             );
279         }
280
281         common_log(LOG_DEBUG, "Saving question: $q->id $q->uri");
282         $q->insert();
283
284         if (Notice::contentTooLong($q->title . ' ' . $q->uri)) {
285             $max       = Notice::maxContent();
286             $uriLen    = mb_strlen($q->uri);
287             $targetLen = $max - ($uriLen + 15);
288             $title = mb_substr($q->title, 0, $targetLen) . '…';
289         }
290
291         $content = $title . ' ' . $q->uri;
292
293         $link = '<a href="' . htmlspecialchars($q->uri) . '">' . htmlspecialchars($q->title) . '</a>';
294         // TRANS: Rendered version of the notice content creating a question.
295         // TRANS: %s a link to the question as link description.
296         $rendered = sprintf(_m('Question: %s'), $link);
297
298         $tags    = array('question');
299         $replies = array();
300
301         $options = array_merge(
302             array(
303                 'urls'        => array(),
304                 'rendered'    => $rendered,
305                 'tags'        => $tags,
306                 'replies'     => $replies,
307                 'object_type' => self::OBJECT_TYPE
308             ),
309             $options
310         );
311
312         if (!array_key_exists('uri', $options)) {
313             $options['uri'] = $q->uri;
314         }
315
316         $saved = Notice::saveNew(
317             $profile->id,
318             $content,
319             array_key_exists('source', $options) ?
320             $options['source'] : 'web',
321             $options
322         );
323
324         return $saved;
325     }
326 }