Propel version 1.4.0 released

propel

Although I must admit I didn’t notice it, less than 2 months after it was decided to create a new version for Propel, it was actually released.

Last week, on the 8th of November, the new 1.4.0 version has been released for production use. Additionally they also set up a blog to prove Propel is still very much alive.

Propel 1.4 is a backwards compatible evolution of Propel 1.3. It offers lots of bug fixes, some very interesting new features, speed enhancements, and a very simple upgrade path: rebuild your model after updating Propel, and your application works as always. Except it works better…

It all sounds to good to be true!

A first migration of a project to this new version went smoothly: remember to remove the *-classmap.php file that was generated by 1.3.0 because it has been integrated in the main config file. It’s also recommendable to delete the /map sub-folder in your models folder because 1.4.0 generates newly named *TableMap.php files.

Also good to have: full query logging (Propel 1.3 switched to PDO and lost this feature but it’s back!).

I must also admit I have never actually implemented Doctrine, but that’s also because I haven’t found a reason while using Propel.

Propel site and Subversion repository down

The phpdb.org server seems to be unreachable since yesterday, together with the Propel and Creole Subversion repositories.

Well, I guess their host doesn’t work weekends so lets hope it will be back up on Monday.

In the meanwhile, you will probably also get a timeout error message when updating your projects which have the Propel repository linked with svn:externals. Here’s a list of the different options you have:

  • The easiest: don’t update the external libraries. On Windows, select “Update to revision…” in the TortoiseSVN right-click menu and check “Omit externals” instead of performing a normal “SVN Update”. Since you’ve probably linked to a tag it doesn’t need updating anyway (unless someone linked to a new version).
  • Create your own repository with the files you still have in your working copy: inside the external libraries folder, select “Export” in the TortoiseSVN menu and export to a new folder which you can then import into a new repository. That new repository can then be used as an svn:externals link.
  • Include the Propel files from option 2 inside your project instead of linking to them. But this takes away the flexibility svn:externals provides, so it is not preferable.

Luckily, most SVN servers have a good up-time record.

Zend_Pagination adapter for Propel

Like recently proposed by Jason Eisenmenger, I’ve written a Zend_Pagination adapter for Propel.

It uses the DbFinder symfony plugin (formerly sfPropelFinder) which mimics Doctrine’s way of performing queries. The strictlyPHP_Propel_Finder used below is just a wrapper around that plugin.

Please note: it can certainly be improved (and I’m not sure the Zend Framework coding standards are met).

class strictlyPHP_Paginator_Adapter_Propel implements
Zend_Paginator_Adapter_Interface
{
    /**
     * @var strictlyPHP_Propel_Finder
     */
    protected $_finder;

    /**
     * @var Criteria
     */
    protected $_criteria;

    /**
     * @var int
     */
    protected $_count;

    /**
     * Constructor
     * @param strictlyPHP_Propel_Finder $finder
     */
    public function __construct($finder)
    {
        $this->_finder = $finder;
        $this->_criteria = $finder->getCriteria();
    }

    /**
     * Get count
     * @return int
     */
    public function count()
    {
         if ($this->_count === null) {
             $this->_finder->setCriteria($this->_criteria);
            $this->_count = $this->_finder->count();
         }

        return $this->_count;
    }

    /**
     * Get items
     * @param int $pageNumber
     * @param int $itemCountPerPage
     * @return array
     */
    public function getItems($pageNumber, $itemCountPerPage)
    {
        $criteria = clone $this->_criteria;
        $criteria->setOffset($pageNumber);
        $criteria->setLimit($itemCountPerPage);
        return $this->_finder->setCriteria($criteria)->find();
    }
}

Zend_Log wrapper for Propel

Although Doctrine has its advantages, I still like Propel. It does its job and it does it fairly well.
If you integrate Propel with Zend Framework, you basically only need a Zend_Log wrapper that implements the BasicLogger interface Propel requires. This lets you use Zend_Log as the only log class in your application instead of creating one especially for Propel.

/**
 * Wrapper for Zend_Log for use as Propel log
 * @author Sam Hauglustaine
 */
class strictlyPHP_Propel_Log extends Zend_Log implements BasicLogger
{
    /**
     * Log
     * @var Zend_Log
     */
    private $_log;

    /**
     * Constructor
     * @param Zend_Log $log
     */
    public function __construct(Zend_Log $log) {
        $this->_log = $log;
    }

    /**
     * Log message of specified severity
     * @param string $message
     * @param int $severity
     */
    public function log($message, $severity = null) {
        $this->_log->log($message, $severity);
    }

    public function emergency($message) {
        $this->log($message, Zend_Log::EMERG);
    }
    public function alert($message) {
        $this->log($message, Zend_Log::ALERT);
    }
    public function crit($message) {
        $this->log($message, Zend_Log::CRIT);
    }
    public function err($message) {
        $this->log($message, Zend_Log::ERR);
    }
    public function warning($message) {
        $this->log($message, Zend_Log::WARN);
    }
    public function notice($message) {
        $this->log($message, Zend_Log::NOTICE);
    }
    public function info($message) {
        $this->log($message, Zend_Log::INFO);
    }
    public function debug($message) {
        $this->log($message, Zend_Log::DEBUG);
    }
}

(the Zend_Log priority constants nicely match their Propel equivalents.)
You then need to extend the main Propel class to do the wrapping:

/**
 * Wrapper for Propel
 * @author Sam Hauglustaine
 */
class strictlyPHP_Propel extends Propel
{
    /**
     * Set Propel log (required)
     * @param mixed $log
     * @return void
     */
    public static function setLog($log)
    {
        if($log instanceof Zend_Log)
            $log = new strictlyPHP_Propel_Log($log);

        parent::setLogger($log);
    }
}

That’s all. You can then call your Propel wrapper’s static methods in your bootstrap or a front controller plugin (I implemented that last option for a brand new project, a directory for stallion owners):

strictlyPHP_Propel::setLog($myLog);
strictlyPHP_Propel::init($myConfig);

Of course the bigger part is using the Propel class generator itself but that’s something for another post.