Well another week, another set of changes. There are 4 primary changes that I've made to the site since last week. They are, in no particular order
- Email subscriptions
- The addition of comments.
- A Twitter-based rating widget
- Related links
Related Links
The first is related links. What it basically does is allow me to enter in links that I think might be pertinent to various articles on this site. Each link can be tagged and any place where an article is displayed that has the same tags the related links will be displayed. But it doesn't end there. When I submit a link I make a request off to bit.ly to get the short URL for it. This allows you to share that URL easily over Twitter or Facebook. But my purpose is actually tracking. Bit.ly tracks individual URLs according to who submitted them, not just based off of the URL. So what that allows me to do is see how many times someone went to a given page because of me. Perhaps it's narcissistic, but this is the web where narcissism abounds.
But because I am depending on a third party web service I don't want to be handling errors or slow web service requests in my main web request. If there's a timeout or something on the web service end it could end up timing out on the browser end and I don't want that. To solve that problem I used, TADA!, the Job Queue. I swear, after having implemented my earlier task system I have gone Job Queue crazy. The code for making this call is
class Admin_Task_InsertLink extends Esc_Queue_TaskAbstract
{
private $_link;
private $_tags;
public function __construct($link, $tags)
{
$this->_link = $link;
$this->_tags = $tags;
}
public function _execute(Zend_Application $app)
{
$dom = new DOMDocument();
$dom->loadHTML(file_get_contents($this->_link));
$xpath = new DOMXPath($dom);
$ns = $xpath->query('/html/head/title');
if ($ns->length) {
$title = $ns->item(0);
if (!$title) {
return;
}
$title = $title->nodeValue;
$api = new Esc_Api_Bitly($app->getOption('bitly'));
$lt = new Model_DbTable_Link();
$l = $lt->fetchNew();
$l->setBitly($api->getShortUrl($this->_link));
$l->setTitle($title);
$l->save();
... Plus a bunch of stuff for saving the tags
}
}
}
The API class is defined as
class Esc_Api_Bitly
{
private $_options = array();
public function __construct(array $options)
{
if (!isset($options['login']) || !isset($options['key']) ) {
throw new Esc_ApiException('login and key are required options');
}
$this->_options = $options;
}
public function getShortUrl($url)
{
$url = 'http://api.bit.ly/shorten?version=2.0.1&longUrl='
. urlencode($url)
. '&login='
. $this->_options['login']
. '&apiKey='
. $this->_options['key']
. '&format=json';
$results = json_decode(
file_get_contents($url),
true
);
if (!$results['errorCode']) {
$res = array_shift($results['results']);
return $res['shortUrl'];
}
return null;
}
}
I found myself using the bit.ly API all over the place so I just created a simple API class that I can re-use.
So when I post a link I simply invoke the code
$ilTask = new Admin_Task_InsertLink(
$this->_request->getPost('link'),
$this->_request->getPost('tags')
);
$ilTask->execute($this->getInvokeArg('bootstrap')->getApplication());
It sends it off to the Job Queue and does all the necessary processing offline.
Twitter based rating widget
If you look at the top part of the side bar you will see a slider.
When you tweet it will open up a new window with the shortened URL and the tags all set up.
Since I will be doing another post on this later on, that's the extent of the details I will provide at this time. Do, however, use it. But be kind.
Comments
Comments are easy. Comments with @#^$@#$^ CSS is hard. If you notice, all of the comments have a "notify". So basically, if you make a comment, after a comment has been approved, an email is going to be sent out to everyone who asked to be notified. But do we want to wait while all of the commenters are notified? Of course not! Job Queue!!
class Admin_Task_SendArticleCommentNotification extends Esc_Queue_TaskAbstract
{
private $_commentKey;
public function __construct($commentKey)
{
$this->_commentKey = $commentKey;
}
protected function _execute (Zend_Application $app)
{
$ct = new Model_DbTable_Comment();
$c = $ct->find($this->_commentKey)->current();
if ($c) {
$options = $app->getOption('site');
if (!$options['baseurl']) return;
/* @var $c Model_Comment */
$content = $c->getContent();
/* @var $content Model_Content */
$mail = new Zend_Mail();
$link = $content->getPageId();
$title = $content->getTitle();
$mail->setSubject('New comment: ' . $title);
$text = $c->getText();
$text = "
A new comment has been made
{$title}
Read more at {$title}
";
$mail->setBodyHtml(
$text
);
$mail->setFrom($options['email'], $options['title']);
$subRs = $content->getCommentsWithNotifications();
$addr = array();
foreach ($subRs as $sub) {
/* @var $sub Model_Comment */
$addr[$sub->getEmail()] = 1;
}
$thisEmail = $c->getEmail();
foreach (array_keys($addr) as $addr) {
if ($addr == $thisEmail) continue;
$email = clone $mail;
$email->addTo($addr);
$email->send();
}
}
}
}
If you get email notifications don't worry. All of the text is filtered.
Subscriptions
Last but not least, some people like to get emailed when a new post is made instead of getting it with Atom. I'm cool with that. So I added the ability to subscribe to the site via email. So as soon as a new post goes out it will be sent to everyone who is a subscriber. Once again; Job Queue!!! In fact, one of the reasons for this post is to test this functionality out. I've already tested it in dev and staging but now production.
class Admin_Task_SendNewArticleNotification extends Esc_Queue_TaskAbstract
{
private $_contentKey;
public function __construct($contentKey)
{
$this->_contentKey = $contentKey;
}
protected function _execute (Zend_Application $app)
{
$ct = new Model_DbTable_Content();
$c = $ct->find($this->_contentKey)->current();
if ($c) {
$options = $app->getOption('site');
if (!$options['baseurl']) return;
/* @var $c Model_Content */
$mail = new Zend_Mail();
$link = $c->getPageId();
$title = $c->getTitle();
$mail->setSubject('New post: ' . $title);
$text = $c->getContentSnip(2048);
$text = "
A new posting has been made
{$title}
Article Preview
Read more at {$title}
";
$mail->setBodyHtml(
$text
);
$mail->setFrom($options['email'], $options['title']);
$st = new Model_DbTable_Subscriber();
$subRs = $st->fetchAll();
foreach ($subRs as $sub) {
/* @var $sub Model_Subscriber */
$email = clone $mail;
$email->addTo($sub->getEmail());
$email->send();
}
}
}
}
Whew! That's a lot of stuff. Plus, it's relatively new. So there might be some bugs in it. But even so it was fun to build and more fun will be had in the near future.
Comments
No comments yet...