by Kevin Schroeder | 12:00 am

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

  1. Email subscriptions
  2. The addition of comments.
  3. A Twitter-based rating widget
  4. 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.

Rating with a tweet

When you tweet it will open up a new window with the shortened URL and the tags all set up.

Twitter output

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}

 

{$text}


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

 

{$text}


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...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.