*/
class QnA_Answer extends Managed_DataObject
{
- CONST ANSWER = 'http://activityschema.org/object/answer';
-
+ const OBJECT_TYPE = 'http://activityschema.org/object/answer';
+
public $__table = 'qna_answer'; // table name
public $id; // char(36) primary key not null -> UUID
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $question_id; // char(36) -> question.id UUID
public $profile_id; // int -> question.id
- public $best; // (int) boolean -> whether the question asker has marked this as the best answer
+ public $best; // (boolean) int -> whether the question asker has marked this as the best answer
+ public $revisions; // int -> count of revisions to this answer
+ public $content; // text -> response text
public $created; // datetime
- /**
- * Get an instance by key
- *
- * This is a utility method to get a single instance with a given key value.
- *
- * @param string $k Key to use to lookup
- * @param mixed $v Value to lookup
- *
- * @return QnA_Answer object found, or null for no hits
- *
- */
- function staticGet($k, $v=null)
- {
- return Memcached_DataObject::staticGet('QnA_Answer', $k, $v);
- }
-
- /**
- * Get an instance by compound key
- *
- * This is a utility method to get a single instance with a given set of
- * key-value pairs. Usually used for the primary key for a compound key; thus
- * the name.
- *
- * @param array $kv array of key-value mappings
- *
- * @return QA_Answer object found, or null for no hits
- *
- */
- function pkeyGet($kv)
- {
- return Memcached_DataObject::pkeyGet('QnA_Answer', $kv);
- }
-
/**
* The One True Thingy that must be defined and declared.
*/
'description' => 'Record of answers to questions',
'fields' => array(
'id' => array(
- 'type' => 'char',
- 'length' => 36,
- 'not null' => true, 'description' => 'UUID of the response'),
- 'uri' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => true,
- 'description' => 'UUID to the answer notice'
- ),
- 'question_id' => array(
- 'type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID of question being responded to'
- ),
- 'best' => array('type' => 'int', 'size' => 'tiny'),
- 'profile_id' => array('type' => 'int'),
- 'created' => array('type' => 'datetime', 'not null' => true),
+ 'type' => 'char',
+ 'length' => 36,
+ 'not null' => true, 'description' => 'UUID of the response',
+ ),
+ 'uri' => array(
+ 'type' => 'varchar',
+ 'length' => 191,
+ 'not null' => true,
+ 'description' => 'UUID to the answer notice',
+ ),
+ 'question_id' => array(
+ 'type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID of question being responded to',
+ ),
+ 'content' => array('type' => 'text'), // got a better name?
+ 'best' => array('type' => 'int', 'size' => 'tiny'),
+ 'revisions' => array('type' => 'int'),
+ 'profile_id' => array('type' => 'int'),
+ 'created' => array('type' => 'datetime', 'not null' => true),
),
'primary key' => array('id'),
'unique keys' => array(
*
* @return QnA_Answer found response or null
*/
- function getByNotice($notice)
+ static function getByNotice(Notice $notice)
{
- return self::staticGet('uri', $notice->uri);
+ $answer = self::getKV('uri', $notice->uri);
+ if (empty($answer)) {
+ throw new Exception("No answer with URI {$notice->uri}");
+ }
+ return $answer;
}
/**
*/
function getNotice()
{
- return Notice::staticGet('uri', $this->uri);
+ return Notice::getKV('uri', $this->uri);
}
- function bestUrl()
+ static function fromNotice(Notice $notice)
{
- return $this->getNotice()->bestUrl();
+ return QnA_Answer::getKV('uri', $notice->uri);
+ }
+
+ function getUrl()
+ {
+ return $this->getNotice()->getUrl();
}
/**
*/
function getQuestion()
{
- return Question::staticGet('id', $this->question_id);
+ $question = QnA_Question::getKV('id', $this->question_id);
+ if (empty($question)) {
+ // TRANS: Exception thown when getting a question with a non-existing ID.
+ // TRANS: %s is the non-existing question ID.
+ throw new Exception(sprintf(_m('No question with ID %s'),$this->question_id));
+ }
+ return $question;
+ }
+
+ function getProfile()
+ {
+ $profile = Profile::getKV('id', $this->profile_id);
+ if (empty($profile)) {
+ // TRANS: Exception thown when getting a profile with a non-existing ID.
+ // TRANS: %s is the non-existing profile ID.
+ throw new Exception(sprintf(_m('No profile with ID %s'),$this->profile_id));
+ }
+ return $profile;
+ }
+
+ function asHTML()
+ {
+ return self::toHTML(
+ $this->getProfile(),
+ $this->getQuestion(),
+ $this
+ );
+ }
+
+ function asString()
+ {
+ return self::toString(
+ $this->getProfile(),
+ $this->getQuestion(),
+ $this
+ );
+ }
+
+ static function toHTML(Profile $profile, $question, $answer)
+ {
+ $notice = $question->getNotice();
+
+ $out = new XMLStringer();
+
+ $cls = array('qna_answer');
+ if (!empty($answer->best)) {
+ $cls[] = 'best';
+ }
+
+ $out->elementStart('p', array('class' => implode(' ', $cls)));
+ $out->elementStart('span', 'answer-content');
+ $out->raw(common_render_text($answer->content));
+ $out->elementEnd('span');
+
+ if (!empty($answer->revisions)) {
+ $out->elementstart('span', 'answer-revisions');
+ $out->text(
+ htmlspecialchars(
+ // Notification of how often an answer was revised.
+ // TRANS: %s is the number of answer revisions.
+ sprintf(_m('%s revision','%s revisions',$answer->revisions), $answer->revisions)
+ )
+ );
+ $out->elementEnd('span');
+ }
+
+ $out->elementEnd('p');
+
+ return $out->getString();
+ }
+
+ static function toString($profile, $question, $answer)
+ {
+ // @todo FIXME: unused variable?
+ $notice = $question->getNotice();
+
+ return sprintf(
+ // TRANS: Text for a question that was answered.
+ // TRANS: %1$s is the user that answered, %2$s is the question title,
+ // TRANS: %2$s is the answer content.
+ _m('%1$s answered the question "%2$s": %3$s'),
+ htmlspecialchars($profile->getBestName()),
+ htmlspecialchars($question->title),
+ htmlspecialchars($answer->content)
+ );
}
/**
*
* @return Notice saved notice
*/
- static function saveNew($profile, $question, $options=null)
+ static function saveNew(Profile $profile, $question, $text, array $options = array())
{
- if (empty($options)) {
- $options = array();
- }
-
- $a = new Answer();
- $a->id = UUID::gen();
- $a->profile_id = $profile->id;
- $a->question_id = $question->id;
- $a->created = common_sql_now();
- $a->uri = common_local_url(
- 'showanswer',
- array('id' => $pr->id)
+ $answer = new QnA_Answer();
+ $answer->id = UUID::gen();
+ $answer->profile_id = $profile->id;
+ $answer->question_id = $question->id;
+ $answer->revisions = 0;
+ $answer->best = 0;
+ $answer->content = $text;
+ $answer->created = common_sql_now();
+ $answer->uri = common_local_url(
+ 'qnashowanswer',
+ array('id' => $answer->id)
);
-
- common_log(LOG_DEBUG, "Saving answer: $pr->id $pr->uri");
- $a->insert();
- // TRANS: Notice content answering a question.
- // TRANS: %s is the answer
+ common_debug("Saving answer: $answer->id, $answer->uri");
+ $answer->insert();
+
$content = sprintf(
+ // TRANS: Text for a question that was answered.
+ // TRANS: %s is the question title.
_m('answered "%s"'),
- $answer
+ $question->title
);
- $link = '<a href="' . htmlspecialchars($question->uri) . '">' . htmlspecialchars($answer) . '</a>';
+
+ $link = '<a href="' . htmlspecialchars($answer->uri) . '">' . htmlspecialchars($question->title) . '</a>';
// TRANS: Rendered version of the notice content answering a question.
// TRANS: %s a link to the question with question title as the link content.
$rendered = sprintf(_m('answered "%s"'), $link);
$options = array_merge(
array(
- 'urls' => array(),
- 'rendered' => $rendered,
- 'tags' => $tags,
- 'replies' => $replies,
- 'reply_to' => $question->getNotice()->id,
- 'object_type' => QnA::ANSWER_OBJECT),
- $options
- );
+ 'urls' => array(),
+ 'content' => $content,
+ 'rendered' => $rendered,
+ 'tags' => $tags,
+ 'replies' => $replies,
+ 'reply_to' => $question->getNotice()->id,
+ 'object_type' => self::OBJECT_TYPE
+ ),
+ $options
+ );
if (!array_key_exists('uri', $options)) {
- $options['uri'] = $pr->uri;
+ $options['uri'] = $answer->uri;
}
$saved = Notice::saveNew(