A brief response to Sam Anderson’s “In Defense of Distraction”

May 20th, 2009

This article in New York magazine made for a good morning read to get the juices flowing.

The point the author fails to drive home, however, is that multitasking is quite simply an adaptive response to a dramatic increase in the amount of information available, the increased rate of change on all levels, and, most importantly, latency. All of these phenomena are caused by advances in technology, especially networking but also mobile computing. Multitasking is simply unavoidable in order to remain competitive and operate effectively in the modern world. Making use of time spent sitting on hold, waiting at the doctor’s office, waiting for files to download, software to install, clients and co-workers to respond to emails, etc. is the only way to stay productive in this world.

Case in point - I wrote this post while waiting for a software prototyping tool to download & install. I have to reboot my computer now of course, since this is Windows. Luckily I have my iphone so I can catch up on my email during the reboot. :-)

Authentication with Zend Framework and Doctrine

May 16th, 2009

At my new job, we’re using some pretty cool cutting edge object-oriented PHP technology: Zend Framework for MVC and Doctrine for ORM. If you don’t know what those acronyms mean, you probably shouldn’t bother reading the rest of this post. :-)

As an exercise to ramp up on these two technologies, I modified the code from the Zend Framework quick start to authenticate users against a MySQL table using Doctrine.

I found a pretty good tutorial on Zend_Auth authentication adapter. The author of the tutorial says “I’m not going to go into specifics on this, as the documentation covers them, and your needs will vary based on your site.”. Well, the Zend documentation doesn’t cover them all that well, so it took me a while to figure this out. Surprisingly, I was unable to find any examples anywhere. I did find this proposal for an implementation, but it’s not quite copmlete. I figured I’d save someone else the trouble and post my solution here.

Here’s the adapter:

class MPSAuthAdapter implements Zend_Auth_Adapter_Interface
{
	private $_username;
	private $_password;

    /**
     * Sets username and password for authentication
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        $this->_username = $username;
        $this->_password = $password;
    }

    /**
     * Performs an authentication attempt using Doctrine User class.
     *
     * @throws Zend_Auth_Adapter_Exception If authentication cannot
     *                                     be performed
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
    	$result = null;

    	try {
			$q = Doctrine_Query::create()
			    ->from('User u')
			    ->where('u.username = ?', $this->_username);

			$user = $q->fetchOne();
			if ($user == NULL) {
				$result = new Zend_Auth_Result(
			            Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
			            null,
			            array('sorry, login ' . $this->_username . ' was not found'));
			} else {
				if ($user->getPassword() != $this->_password) {
					$result = new Zend_Auth_Result(
				            Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
				            $user,
				            array('sorry, the password you entered was invalid for user ' .
                                                    $this->_username));
				} else {
					$result = new Zend_Auth_Result(
				            Zend_Auth_Result::SUCCESS,
				            $user,
				            array());
				}
			}
			return $result;
    	} catch(Exception $e) {
    		throw new Zend_Auth_Adapter_Exception($e->getMessage());
    	}
    }
}

… and here’s my version of LoginController.php:

// based on Matthew Weier O'Phinney's tutorial
// http://weierophinney.net/matthew/archives/165-Login-and-Authentication-with-Zend-Framework.html
require "MPSAuthAdapter.php";
require "BaseController.php";

class LoginController extends BaseController
{
    public function getForm()
    {
    	// MPS: note I had to change this classname
    	// to work with the Zend autoloader:
        return new Default_Form_Login(array(
            'action' => '/login/process',
            'method' => 'post',
        ));
    }

    public function getAuthAdapter(array $params)
    {
        return new MPSAuthAdapter($params['username'],$params['password']);
    }

    public function indexAction()
    {
        $this->view->form = $this->getForm();
    }   

    public function processAction()
    {
        $request = $this->getRequest();

        // Check if we have a POST request
        if (!$request->isPost()) {
            return $this->_helper->redirector('index');
        }

        // Get our form and validate it
        $form = $this->getForm();
        if (!$form->isValid($request->getPost())) {
            // Invalid entries
            $this->view->form = $form;
            return $this->render('index'); // re-render the login form
        }

        // Get our authentication adapter and check credentials
        $adapter = $this->getAuthAdapter($form->getValues());
        $auth    = Zend_Auth::getInstance();
        $result  = $auth->authenticate($adapter);
        if (!$result->isValid()) {
            // Invalid credentials
            $form->setDescription(array_shift($result->getMessages()) .
                                                           "
please try again.”); $this->view->form = $form; return $this->render(’index’); // re-render the login form } // We’re authenticated! Redirect to the home page $this->_helper->redirector(’index’, ‘index’); } public function logoutAction() { Zend_Auth::getInstance()->clearIdentity(); $this->_helper->redirector(’index’); // back to login page } }

To ensure that all of the pages in the app are authenticated, I created a BaseController class that handles authentication, and derived all of my controller classes from it. Here’s that class:


class BaseController extends Zend_Controller_Action
{
    public function preDispatch()
    {
        if (!Zend_Auth::getInstance()->hasIdentity()) {
            if ('/login' != $this->getRequest()->getPathInfo() &&
                'login' != $this->getRequest()->getControllerName()) {
    			$_redirector = $this->_helper->getHelper('Redirector');
                $_redirector->gotoUrl('/login');
            }
        }
    }	

}

I’m still pretty new to all this, so I’m very interested in any comments.