Hi, as you know I have put a lot effort to integrate Doctrine and Zend Framework together and I have written quite a lot about them recently. So it’s one of them. As you may know, Zend Framework has a component called Zend_Auth which is used to authenticate and authorize people. It contains lots of different adapters like Digest, Http or DbTable. However it does not have a Doctrine adapter yet. And this blog will mention you about it.

First of all don’t get frightened because it’s not rocket science. As you will see it does not contain a lot of code and you will be able reach them from my github. So let’s get down to the business.

class Kartaca_Auth_Adapter_Doctrine implements Zend_Auth_Adapter_Interface
{

    /**
     * @var Doctrine_Table
     */
    private $_table;

    /**
     * The field name which will be the identifier (username...)
     *
     * @var string
     */
    private $_identityCol;

    /**
     * The field name which will be used for credentials (password...)
     *
     * @var string
     */
    private $_credentialCol;

    /**
     * Actual identity value (my_all_known_username)
     *
     * @var string
     */
    private $_identity;

    /**
     * Actual credential value (my_secret_password)
     *
     * @var string
     */
    private $_credential;

    public function  __construct(Doctrine_Table $table, $identityCol, $credentialCol)
    {
        $this->_table = $table;
        $columnList = $this->_table->getColumnNames();
        //Check if the identity and credential are one of the column names...
        if (!in_array($identityCol, $columnList) || !in_array($credentialCol, $columnList)) {
            throw new Zend_Auth_Adapter_Exception("Invalid Column names are given as '{$identityCol}' and '{$credentialCol}'");
        }
        $this->_credentialCol = $credentialCol; //Assign the column names...
        $this->_identityCol = $identityCol;
    }

    /**
     * @param string $i
     */
    public function setIdentity($i)
    {
        $this->_identity = $i;
    }

    /**
     * @param string $c
     */
    public function setCredential($c)
    {
        $this->_credential = $c;
    }

    /**
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        //FIXME: Check if this querying actually works or not...
        $result = $this->_table
            ->createQuery("dctrn_find")
            ->where("{$this->_credentialCol} = ?", $this->_credential)
            ->andWhere("{$this->_identityCol} = ?", $this->_identity)
            ->execute(array());
        return new Zend_Auth_Result(
            $result[0]->id ? Zend_Auth_Result::SUCCESS : Zend_Auth_Result::FAILURE, //You may define different failure types, however this one is enough
            $result[0]->id ? $result[0] : null
        );
    }
}

That’s all folks. As you see there is nothing complicated. We have created a class name Kartaca_Auth_Adapter_Doctrine and implemented Zend_Auth_Adapter interface (you have to!). It might even have been something like “return 1″ :). What we made is to define identity and credential column names and their values later. Of course we had a Doctrine_Record instance which was being held as Identity. You might have used the id or the username, however to check something you had to query it again, so why not just save it as the Identity. That’s according to your own personal choices. I have used this way, it came easier and simpler.

The identity is kept on the session and you model instance will be serialized. You can customize this serialization by creating a function named “__sleep” and deserialization function with “__wakeup”.

To use it you have to write something like this:

class LoginController extends Zend_Controller_Action
{

    private $_adapter = null;

    public function init()
    {
        $this->_adapter = new Kartaca_Auth_Adapter_Doctrine(Doctrine_Manager::connection()->getTable("user"), "username", "password");
    }

    public function indexAction()
    {
        $this->_forward("login");
    }

    public function loginAction()
    {
        if ($this->getRequest()->isPost()) {
            $this->_adapter->setCredential(sha1($this->getRequest()->getParam("password")));
            $this->_adapter->setIdentity($this->getRequest()->getParam("username"));
            $auth = Zend_Auth::getInstance();
            $result = $auth->authenticate($this->_adapter);
            if ($result->isValid()) {
                $this->_redirect("index"); //Redirect to index with success...
            } else {
                //Show the login form with error message...
            }
        } else {
            //Show the login form
        }
    }

    public function logoutAction()
    {
        //Log him out!!
        Zend_Auth::getInstance()->clearIdentity();
        $this->_redirect("index");
    }
}

That’s it you have integrated Doctrine and Zend_Auth together. I told you it was not rocket science!

Update: In the comments below, it’s suggested that there was such a proposal about it which was doing nearly the same thing with what I did but with more options (like returning invalid password or ambigous rows where I had only returned an error). Check it here.

Kingdom of Roi: http://roysimkes.net/blog/2009/12/creating-doctrine-adapter-for-zend_auth/