Custom Form Validation Error Messages in CodeIgniter 2

<?php

class MY_Form_validation extends CI_Form_validation
{
    private $_custom_field_errors = array();

    public function _execute($row, $rules, $postdata = NULL, $cycles = 0)
    {
        // Execute the parent method from CI_Form_validation.
        parent::_execute($row, $rules, $postdata, $cycles);

        // Override any error messages for the current field.
        if (isset($this->_error_array[$row['field']])
            && isset($this->_custom_field_errors[$row['field']]))
        {
            $message = str_replace(
                '%s',
                !empty($row['label']) ? $row['label'] : $row['field'],
                $this->_custom_field_errors[$row['field']]);

            $this->_error_array[$row['field']] = $message;
            $this->_field_data[$row['field']]['error'] = $message;
        }
    }

    public function set_rules($field, $label = '', $rules = '', $message = '')
    {
        $rules = parent::set_rules($field, $label, $rules);

        if (!empty($message))
        {
            $this->_custom_field_errors[$field] = $message;
        }

        return $rules;
    }
}

?>

Include CodeIgniter Models using spl_autoload

CodeIgniter’s models may be added to autoload.php (which will always load them even if they’re not required) or must be manually loaded using code such as:

$this->load->model('views\account\logon');

While it’s only one line of code, it soon becomes tedious having to have a similar line across every action in every controller. Consequently, I created a CodeIgniter library (after taking inspiration from Doctrine’s ClassLoader) which uses spl_autoload. Class_loader automates the process of loading classes within a defined namespace and only requires a single line of configuration; therefore no changes to autoload.php or manual calls to load are required.

Class_loader.php:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Class_loader is a CodeIgniter library which uses SPL autoload to
 * automatically include classes within the defined namespace.
 * 
 * @author Andrew Mackrodt <andrew@ajmm.org>
 * @version 2011.06.23
 */
class Class_loader
{
    /**
     * @param string $namespace The namespace to apply the autoloader.
     * @param string $includePath
     *     The parent folder of the root namespace. Defaults to CodeIgniter's
     *     APPPATH if no value is given.
     */
    public function register($namespace, $includePath = null)
    {
        if (!empty($namespace) && $namespace[0] == '\\')
        {
            // Strip leading namespace separator.
            $namespace = substr($namespace, 1);
        }

        if (empty($includePath))
        {
            // Set the include path to the CI application folder.
            $includePath = APPPATH;
        }

        // Ensure the include path ends with the OS directory separator.
        $includePath = rtrim($includePath, '\\/').DIRECTORY_SEPARATOR;

        // Register the auto-loader.
        $classLoader = new _ClassLoader($namespace, $includePath);
        spl_autoload_register(array($classLoader, 'loadClass'));
    }
}

/**
 * A helper class to be used by Class_loader. 
 */
class _ClassLoader
{
    private $namespace;
    private $includePath;

    public function __construct($namespace = null, $includePath = null)
    {
        $this->namespace = $namespace;
        $this->includePath = $includePath;
    }

    public function loadClass($className)
    {
        if ($this->namespace !== null
                && strpos($className, $this->namespace.'\\') !== 0)
        {
            return false;
        }
        
        // Convert a namespace to a path using the OS directory separator.
        $classPath = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $className);
        
        require_once $this->includePath.$className.'.php';
        return true;
    }
}

Usage:

The classes you wish to autoload must contain a namespace and be located appropriately, e.g. I have a Script class which is located at APPPATH/models/views/shared/Script.php and has the namespace models\views\shared.

$this->class_loader->register('models\views', APPPATH);

Integrating Doctrine 2 with CodeIgniter 2

An easy to follow tutorial for integrating Doctrine 2 with CodeIgniter 2 is available at doctrine-project. Unfortunately, there are a few configuration problems which would prevent the proper loading of proxies if that configuration were to be used exactly as it is.

The problem is related to how the Proxies ClassLoader has been registered. PHP will attempt to load proxies which have the namespace Proxies from the directory {APPATH}/models/proxies/Proxies.

$proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
$proxiesClassLoader->register();

However, Doctrine has been configured to write proxies to the directory {APPATH}/models/proxies.

$config->setProxyDir(APPPATH.'/models/proxies');
$config->setProxyNamespace('Proxies');

Additionally, the suggested configuration registers a DefaultAnnotationDriver using the directory {APPPATH}/models/Entities which is unlikely to exist.

$driverImpl = $config->newDefaultAnnotationDriver(array(APPPATH.'models/Entities'));
$config->setMetadataDriverImpl($driverImpl);

The configuration and instructions shown below address these issues and contain some other useful notes on the integration.
Continue reading