[prev in list] [next in list] [prev in thread] [next in thread] 

List:       horde-dev
Subject:    [dev] Updated "Divot" thingy...
From:       "Jason M. Felice" <jfelice () cronosys ! com>
Date:       2005-08-11 14:36:42
Message-ID: 20050811103642.i4rvwyypfqkkgkss () staff ! cronosys ! com
[Download RAW message or body]

This message is in MIME format.


Attached is a somewhat cleaned-up piece of concept code, which now uses 
serialization instead of the memento pattern.

Also, it would now depend on the Horde registry to find divot class 
files that applications provide.  (Before you could specify a path, now 
you specify an app name.)

All comments appreciated.

I'm also beginning to think about the details of event dispatch.  I'm 
thinking the most functional way to do it is this:

Have a method Divot::trigger($callback, ...) which returns a URL which 
will call the specified method.  For example, in a derived class:

function render()
{
    return '<a href="' . $this->trigger('submit', 'ok') . '">OK</a>' .
           '<a href="' . $this->trigger('submit', 'cancel') . '">Cancel</a>';
}

function submit($type)
{
    if ($type == 'ok') {
       ...
    } else {
       ...
    }
}

(trigger() would use opaque keys to store callback name and parameters 
as well.)

-- 
Jason M. Felice
Cronosys, LLC <http://www.cronosys.com>
216-221-4600 x302

["Divot.php" (application/x-php)]

<?php
/**
 * Copyright (C) 2005 Cronosys, LLC <http://www.cronosys.com/>
 *
 * GNU GPL
 */
class Divot {

    /**
     * Hash of this divot's construction parameters
     * @var array $_params
     */
    var $_params;

    /**
     * This divot's singleton key
     * @var string $_singleton_key
     */
    var $_singleton_key;

    /**
     * Constructs a new Divot::
     *
     * Use ::factory(), ::singleton(), ::reconstitute()
     *
     * @access protected
     */
    function Divot($params = array(), $singleton_key)
    {
        $this->_params = $params;
        $this->_singleton_key = $singleton_key;
    }

    /**
     * Returns HTML rendering of this divot
     */
    function render()
    {
        return '';
    }

    /**
     * Returns HTML rendering of an action link
     */
    function renderActionLink($etype, $eparams)
    {
        // FIXME: make link with divot[to]=<singleton_key>&divot[event]=<etype>&divot[params]=<eparams>
    }

    function renderActionButton($etype, $eparams)
    {
        // FIXME:
    }

    /**
     * Saves the state which will be restored on callback
     *
     * @return null  Null, or PEAR_Error on failure.
     */
    function saveState()
    {
        // FIXME: freeze() mechanism
        $_SESSION['Divot']['states'][$this->_singleton_key] = serialize($this);
    }

    /**
     * Constructs a concrete Divot:: instance
     *
     * @static
     * @param mixed $driver   If a string, the name of divot subclass to load;
     *                        if an array, the first parameter is the
     *                        name of the application to load the class file
     *                        from (under <app>/lib/Divot) and the second
     *                        parameter is the subclass.
     * @param array $params   Driver-specific parameters.
     * @return object  A concrete Divot:: instance
     */
    function &factory($driver, $params = array())
    {
        $skey = Divot::_getSingletonKey($driver, $params);
        if (is_a($skey, 'PEAR_Error')) {
            return $skey;
        }
        return $ret = &Divot::_factory($driver, $params, $skey);
    }

    /**
     * Retrieves a concrete instance, creating it if necessary
     *
     * @static
     */
    function &singleton($driver, $params = array())
    {
        $skey = Divot::_getSingletonKey($driver, $params);
        if (is_a($skey, 'PEAR_Error')) {
            return $skey;
        }
        return $ret = &Divot::_singleton($driver, $params, $skey);
    }

    /**
     * Reconsitutes an object from its singleton key
     *
     * @static
     * @param string $skey  The singleton key.
     * @return object  The reconstituted divot, or PEAR_Error on failure.
     */
    function &reconstitute($skey)
    {
        if (!isset($_SESSION['Divot']['skey_param_map'][$skey])) {
            return PEAR::raiseError(sprintf(_("Parameters for key '%s' not found."), $skey));
        }

        list($driver, $params) = unserialize($_SESSION['skey_param_map'][$skey]);
        return $ret = &Divot::_singleton($driver, $params, $skey);
    }

    /**
     * @static
     * @access private
     */
    function &_factory($driver, $params, $singleton_key)
    {
        $app = null;
        if (is_array($driver)) {
            list($app, $driver) = $driver;
        }
        
        if (is_null($app)) {
            $path = dirname(__FILE__) . '/Divot/';
            $class = 'Divot_' . $driver;
        } else {
            $path = $GLOBALS['registry']->get('fileroot', $app) . '/lib/Divot/';
            $class = 'Divot_' . $app . '_' . $driver;
        }
        @include_once $path . $driver . '.php';
        if (!class_exists($class)) {
            return PEAR::raiseError(sprintf(_("Divot class '%s' not found!"),
                                            $class));
        }

        return $ret = &new $class($params, $singleton_key);
    }

    /**
     * @static
     * @access private
     */
    function &_singleton($driver, $params, $singleton_key)
    {
        static $cache = array();
        if (!isset($cache[$singleton_key])) {
            if (isset($_SESSION['Divot']['states'][$singleton_key])) {
                $obj = unserialize($_SESSION['Divot']['states'][$singleton_key]);
                // FIXME: thaw() mechanism.
            } else {
                $obj = &Divot::_factory($driver, $params, $singleton_key);
            }
            if (is_a($obj, 'PEAR_Error')) {
                return $obj;
            }
        }
        return $cache[$singleton_key];
    }

    /**
     * Creates an opaque key for an object's construction parameters
     *
     * Since we don't want to expose construction parameters to the users (who
     * could twiddle them), we use opaque keys for our callback mechanism and
     * store the opaque keys in the session.
     *
     * @access private
     * @param mixed $driver  A string or an array indicating the class.
     * @param array $params  Class-specific parameters.
     * @return string  The opaque key.
     */
    function _getSingletonKey($driver, $params = array())
    {
        $kk = serialize(array($driver, $params)); 
        if (!isset($_SESSION['Divot']['skeys'][$kk])) {
            $skey = uniqid('divot_', true);
            $_SESSION['Divot']['param_skey_map'][$kk] = $skey;
            $_SESSION['Divot']['skey_param_map'][$skey] = $kk;
        }
        return $_SESSION['Divot']['param_skey_map'][$kk];
    }

    function dispatch($event)
    {
        // FIXME: Implement.
    }

    /**
     * Finds divot events in this web environment and dispatch them.
     */
    function processEvents()
    {
        /* FIXME: divots should track their initial values, as well as their
         * current values.  That way if we need to reload the page for
         * something (an action link, for example), we can redisplay the
         * current values.
         *
         * So here, we need to read all divot-related edit fields and update
         * the objects. */

        /* From an action link or a post. */
        if (isset($_REQUEST['divot']['to'])) {
            $obj = &Divot::reconstitute($_REQUEST['divot']['to']);
            if (is_a($obj, 'PEAR_Error')) {
                return $result;
            }
            $result = $obj->dispatch($_REQUEST['divot']);
            if (is_a($result, 'PEAR_Error')) {
                return $result;
            }
        }
    }

    /**
     * Processes AJAX events.
     *
     * This is to be called from an ajax.php in Horde.  It will simply handle
     * an XML-RPC or SOAP request by dispatching it to the object and
     * returning the result.
     */
    function processAjaxEvents()
    {
        // FIXME:
    }

}



-- 
Horde developers mailing list - Join the hunt: http://horde.org/bounties/
Frequently Asked Questions: http://horde.org/faq/
To unsubscribe, mail: dev-unsubscribe@lists.horde.org


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic