SpiffyJr's Blogaroo

Happenings of the man known as SpiffyJr

  • Home
  • About
    • Inspiration
    • Resume
  • Projects
    • Blitzaroo
    • phpRaider
    • Zend Calendar
  • Docs
    • Blitzaroo API
    • SpiffyCalendar Docs
    • SpiffyDb Docs
  • Downloads
  • Technologies
    • Doctrine ORM
    • Dojo
    • PHP
    • Zend Framework
  • Other
    • License
Twitter RSS

dataStore and dataGrid view helpers.

Posted on March 10, 2010 by SpiffyJr
23 commentsLeave a comment

Introduction

Grid’s are used everywhere and one thing the Zend Framework really lacks is a useful view helper to quickly generate grids and their stores. I saw that  Matthew Weier O’Phinney had a proposal for a dojox.grid.DataGrid view helper but no work had been done on it. I send him a tweet and learned that he had intended to finish it but is currently too busy to work on it so I wrote a few view helpers to follow his proposal. The dataStore view helper is fairly simplistic but the dataGrid view helper has quite a bit to it. I plan on refactoring the dataGrid view helper to add support for enhancedGrid and treeGrid but I wanted to share what I had done already. Both view helpers follow the use-cases as presented by Matthew in his dojox.grid.DataGrid view helper proposal.

The dataStore() helper

The dataStore() helper provides support for generating programmatic/declarative data stores and requires an id as well as a dojoType.

Usage

<?=$this->dataStore('store', 'dojox.data.QueryReadStore', array('url' => '/path/to/json'));?>

Code

<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Dojo_View_Helper_DataStore
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id$
 */

/**
 * Zend_Calendar
 *
 * @category   Zend
 * @package    Zend_Dojo_View_Helper_DataStore
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Dojo_View_Helper_DataStore extends Zend_Dojo_View_Helper_Dijit
{
	/**
	 * DataStore view helper.
	 *
	 * @param string $id JavaScript id for the data store.
	 * @param string $dojoType DojoType of the data store (e.g., dojox.data.QueryReadStore)
	 * @param array $attribs Attributes for the data store.
	 */
	public function dataStore($id = '', $dojoType = '', array $attribs = array())
	{
		if (!$id || !$dojoType) {
			throw new Zend_Exception('Invalid arguments: required jsId and dojoType.');
		}

		$this->dojo->requireModule($dojoType);

		// Programmatic
		if ($this->_useProgrammatic()) {
			if (!$this->_useProgrammaticNoScript()) {
				$this->dojo->addJavascript('var ' . $id . ";\n");
				$js = $id . ' = ' . 'new ' . $dojoType . '(' . Zend_Json::encode($attribs) . ");";
				$this->dojo->_addZendLoad("function(){{$js}}");
			}
			return '';
		}

		// Set extra attribs for declarative
		if (!array_key_exists('id', $attribs)) {
			$attribs['id'] = $id;
		}

		if (!array_key_exists('jsId', $attribs)) {
			$attribs['jsId'] = $id;
		}

		if (!array_key_exists('dojoType', $attribs)) {
			$attribs['dojoType'] = $dojoType;
		}

		return '<div' . $this->_htmlAttribs($attribs) . "></div>\n";
	}
}

The dataGrid() helper

The dataGrid helper provides support for generating programmatic/declarative dataGrids. Currently, the only supported grid is dojox.grid.DataGrid but I’ll be adding EnhancedGrid and TreeGrid in the future.

Usage

<?php
echo $this->dataStore('store', 'dojox.data.QueryReadStore', array('url' => '/admin/articles/grid.json'));
$grid = $this->dataGrid('myGrid',
	array(
		'selectionMode' => 'none',
		'style' => 'height: 350px; width: 100%;',
		'store' => 'store',
		'fields' => array(
			array('field' => 'title', 'label' => 'Title', 'options' => array('formatter' => 'titleFormatter', 'width' => '60%')),
			array('field' => 'published', 'label' => 'Published', 'options' => array('formatter' => 'primaryFormatter', 'width' => '10%')),
			array('field' => 'updated_at', 'label' => 'Updated', 'options' => array('width' => '15%')),
			array('field' => 'created_at', 'label' => 'Created', 'options' => array('width' => '15%')))));
?>
<?php $grid->scriptCaptureStart('dojo/method', 'onMouseOver', array('args' => 'row'));?>
var g = dojo.byId("grid-menu-item-"+row.rowIndex);
if (g) { dojo.toggleClass(g, "hide-text"); }
<?php $grid->scriptCaptureEnd();?>
<?php $grid->scriptCaptureStart('dojo/method', 'onMouseOut', array('args' => 'row'));?>
var g = dojo.byId("grid-menu-item-"+row.rowIndex);
if (g) { dojo.toggleClass(g, "hide-text"); }
<?php $grid->scriptCaptureEnd();?>
<?php echo $grid;?>

Code

<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Dojo_View_Helper_DataGrid
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id$
 */

/**
 * Zend_Calendar
 *
 * @category   Zend
 * @package    Zend_Dojo_View_Helper_DataGrid
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Dojo_View_Helper_DataGrid extends Zend_Dojo_View_Helper_Dijit
{
	/**
	 * Ensures only one script capture is active at a time.
	 * @var bool
	 */
	protected $_captureLock = false;

	/**
	 * Holds the attributes for the grid.
	 * @var array
	 */
	protected $_attribs = array();

	/**
	 * Holds the field data.
	 * @var array
	 */
	protected $_fields = array();

	/**
	 * Holds the data for the current script capture.
	 */
	protected $_currentScript = array();

	/**
	 * Holds the data for script captures.
	 * @var array
	 */
	protected $_scriptCapture = array();

	/**
	 * Holds the tab character.
	 * @var string
	 */
	protected $_tab = '    ';

	/**
	 * Holds the current theme.
	 */
	protected static $_theme = 'tundra';

	/**
	 * Holds the base path for scripts.
	 */
	protected static $_scriptBase = null;

	/**
	 * __toString();
	 */
	public function __toString()
	{
		return $this->render();
	}

	/**
	 * DataGrid view helper.
	 *
	 * @param string $id JavaScript id for the data store.
	 * @param array $attribs Attributes for the data store.
	 */
	public function dataGrid($id = '', array $attribs = array())
	{
		if (!$id) {
			throw new Zend_Exception('Invalid arguments: required jsId.');
		}

		if (!array_key_exists('id', $attribs)) {
			$attribs['id'] = $id;
		}

		if (array_key_exists('fields', $attribs)) {
			foreach ($attribs['fields'] as $f) {
				$this->addField($f['field'], $f['label'], isset($f['options']) ? $f['options'] : array());
			}
			unset($attribs['fields']);
		}

		$this->_attribs = $attribs;

		return $this;
	}

	/**
	 * Static setter for theme.
	 * @param string $theme Name of the current them.
	 */
	public static function setTheme($theme)
	{
		self::$_theme = $theme;
	}

	/**
	 * Static getter for theme.
	 * @return string
	 */
	public static function getTheme()
	{
		return self::$_theme;
	}

	/**
	 * Static setting for script base.
	 * @param string $scriptBase Path to the base script directory.
	 */
	public static function setScriptBase($scriptBase)
	{
		self::$_scriptBase = $scriptBase;
	}

	/**
	 * Static getter for script base.
	 * @return string
	 */
	public static function getScriptBase()
	{
		return self::$_scriptBase;
	}

	/**
	 * Adds field data.
	 * @param string $field Field name.
	 * @param string $label Label of the field.
	 * $param array $attribs Optional parameters for the field.
	 */
	public function addField($field, $label, array $attribs = array())
	{
		$this->_fields[] = array(
			'label' => $label,
			'attribs' => array_merge(array('field' => $field), $attribs));
		return $this;
	}

	/**
	 * Adds script captures.
	 * @param array $data
	 */
	public function addScriptCapture(array $script = array())
	{
		if (!array_key_exists('data', $script)) {
			throw new Zend_Exception('Script data must include keys data and attribs');
		}

		$this->_scriptCapture[] = $script;
		return $this;
	}

	/**
	 * Begins script capturing.
	 */
	public function scriptCaptureStart($type, $event, array $attribs = array())
	{
		if ($this->_captureLock) {
			throw new Zend_Exception('Cannot nest captures.');
		}

		$this->_currentScript = array('type' => $type, 'event' => $event, 'attribs' => $attribs);

		$this->_captureLock = true;
		ob_start();
		return;
	}

	/**
	 * Ends script capturing.
	 */
	public function scriptCaptureEnd()
	{
		$data = ob_get_clean();
		$this->_captureLock = false;

		$this->_currentScript['data'] = $data;

		$this->addScriptCapture($this->_currentScript);
		$this->_currentScript = array();

		return true;
	}

	/**
	 * Renders the grid based on programmatic setting.
	 */
	public function render()
	{
		$this->dojo->requireModule('dojox.grid.DataGrid');

		// Setup the stylesheet base path
		if (null === self::getScriptBase()) {
			if ($this->dojo->useLocalPath()) {
				self::setScriptBase($this->dojo->getLocalPath());
			} else {
				self::setScriptBase($this->dojo->getCdnBase() . $this->dojo->getCdnVersion());
			}
		}

		$this->dojo->addStylesheet(self::getScriptBase() . '/dojox/grid/resources/Grid.css');
		$this->dojo->addStylesheet(
			self::getScriptBase() . '/dojox/grid/resources/' . self::getTheme() . 'Grid.css');

		// Programmatic
		if ($this->_useProgrammatic()) {
			if (!$this->_useProgrammaticNoScript()) {
				$this->_renderJavascript();
			}
			return '<div id="' . $this->_attribs['id'] . '"></div>';
		}

		return $this->_renderDeclarative();
	}

	/**
	 * Renders a table for declarative grids.
	 */
	protected function _renderDeclarative()
	{
		if (!array_key_exists('jsId', $this->_attribs)) {
			$this->_attribs['jsId'] = $this->_attribs['id'];
		}

		$table = '<table dojoType="dojox.grid.DataGrid"' . $this->_htmlAttribs($this->_attribs) . ">\n";

		foreach ($this->_scriptCapture as $s) {
			$attribs = array_merge($s['attribs'], array('event' => $s['event'], 'type' => $s['type']));
			$table .= "\t<script" . $this->_htmlAttribs($attribs) . ">\n";
			$table .= "\t\t" . $s['data'];
			$table .= "\t</script>\n";
		}

		$table .= "\t<thead>\n";
		$table .= "\t\t<tr>\n";

		foreach ($this->_fields as $f) {
			$table .= "\t\t\t<th" . $this->_htmlAttribs($f['attribs']) . '>' . $f['label'] . "</th>\n";
		}

		$table .= "\t\t</tr>\n";
		$table .= "\t</thead>\n";
		$table .= "</table>\n";

		return $table;
	}

	/**
	 * Renders javascript for programmatic declaration.
	 */
	protected function _renderJavascript()
	{
		$tab = $this->_tab;

		// Grid names
		$gridName = $this->_attribs['id'] . 'Grid';
		$layoutName = $this->_attribs['id'] . 'Layout';

		$this->dojo->addJavascript('var ' . $gridName . ";\n");

		// Setup layout
		$js = $tab . 'var ' . $layoutName . " = [\n";
		foreach ($this->_fields as $f) {
			$f['attribs']['name'] = $f['label'];

			$f['attribs'] = $this->_jsonExpr($f['attribs']);
			$js .= "{$tab}{$tab}{$tab}" . Zend_Json::encode($f['attribs'], false,
				array('enableJsonExprFinder' => true)) . ",\n";
		}

		$js = substr($js, 0, -2);
		$js .= "];\n\n";

		// Use expressions for structure, store, formatter, and get
		$this->_attribs = $this->_jsonExpr($this->_attribs);
		$this->_attribs['structure'] = new Zend_Json_Expr($layoutName);

		// Generate grid
		$js .= $tab . $tab . $gridName . ' = ' . 'new dojox.grid.DataGrid(' . Zend_Json::encode(
			$this->_attribs, false, array('enableJsonExprFinder' => true)) . "), document.createElement('div');\n";

		$js .= $tab . $tab . 'dojo.byId("' . $this->_attribs['id'] . '").appendChild(' . $gridName . '.domNode);' .
			 "\n";
		$js .= $tab . $tab . $gridName . ".startup();\n";

		// Generate connects for script captures
		foreach ($this->_scriptCapture as $s) {
			$s['data'] = trim($s['data'], "\r\n");
			$args = isset($s['attribs']['args']) ? $s['attribs']['args'] : '';

			$js .= "{$tab}{$tab}dojo.connect({$gridName}, \"{$s['event']}\", function({$args}){{$s['data']}});\n";
		}

		$this->dojo->_addZendLoad("function(){\n{$tab}{$js}\n{$tab}}");
	}

	/**
	 * Parses an array looking for keys that should be Zend_Json_Expr()'s and coverts them.
	 */
	protected function _jsonExpr(array $data)
	{
		$jsonExprAttr = array('formatter', 'get', 'query', 'store');

		foreach ($jsonExprAttr as $exp) {
			if (array_key_exists($exp, $data)) {
				$data[$exp] = new Zend_Json_Expr($data[$exp]);
			}
		}

		return $data;
	}
}

Final Thoughts

These view helpers are by no means complete but I will say that I’m currently using them in a production environment with no issues. I tested both declarative/programmatic usage and both functioned as expected. I also wanted to note that I’m by no means intending to step on Matthew’s toes but I know how busy he is with Zend Framework 2.0 (among other things). If anyone has any thoughts or use for this please comment below and, who knows, maybe I’ll make a proposal for it (or take over Matthew’s).

Reblog this post [with Zemanta]
GD Star Rating
loading...
dataStore and dataGrid view helpers., 6.4 out of 10 based on 7 ratings
Categories: Projects, Technologies, View Helpers, Zend Framework | Tags: BSD licenses, JavaScript, Languages, php, Programming, Scripts, Source code, Zend Framework

About SpiffyJr

View all posts by SpiffyJr→
Notice: This work is licensed under a BY-NC-SA. Permalink: dataStore and dataGrid view helpers.
Zend_Dojo_View_Helper_Dialog
Blitzaroo event view teaser

23 Responses to “dataStore and dataGrid view helpers.”

  1. ojjpo says:
    March 10, 2010 at 2:49 pm

    This looks cool. But the helper should be universal enough to support jQuery as well.

    GD Star Rating
    loading...
  2. SpiffyJr says:
    March 10, 2010 at 2:53 pm

    @Ojjpo:
    I disagree. jQuery is part of the extended Zend Framework and should have its own ZendX_jQuery_View_Helper.

    note: I suppose the above classes should be called Zend_Dojo_View_Helper_DataStore and Zend_Dojo_View_Helper_DataGrid.

    GD Star Rating
    loading...
  3. Cameron says:
    March 10, 2010 at 9:19 pm

    Your view helpers are much prettier than the grotesque crap I slopped together for my store and grid helpers, maybe I should use yours!

    GD Star Rating
    loading...
  4. SpiffyJr says:
    March 11, 2010 at 1:17 am

    There is still quite a bit of work to do yet. Most notably, stylesheets and expanding for the new grids in Dojo 1.4.

    GD Star Rating
    loading...
  5. Georgy says:
    March 24, 2010 at 7:49 pm

    Goog work!

    Have you any unit tests for these classes?
    It required for including to Zend Framework.

    GD Star Rating
    loading...
  6. SpiffyJr says:
    March 25, 2010 at 8:26 am

    No, this is why I’ve renamed the library to SZend in order to differentiate it from the Zend core framework. My plan is to submit a proposal for these (and other) view helpers.

    The updated source can be found at http://github.com/SpiffyJr/SZend

    GD Star Rating
    loading...
  7. Chris says:
    April 5, 2010 at 10:50 am

    Spiffy – in order to use this then we need to create the SZend directory structure? Or should we just rename all SZend to Zend in the code? Thanks!

    GD Star Rating
    loading...
  8. SpiffyJr says:
    April 5, 2010 at 10:52 am

    You can call them whatever you want as long as the helper path is setup properly.

    GD Star Rating
    loading...
  9. Chris says:
    April 5, 2010 at 11:05 am

    Ahhh.. Initially I just dumped them into the regular zend path, so clearly I did that wrong :) What should the path be?

    GD Star Rating
    loading...
  10. SpiffyJr says:
    April 5, 2010 at 11:07 am

    If the prefix for the classes is SZend then you need to put the files in SZend/View/Helper. If you rename them all to Zend dropping them in Zend/View/Helper will work just fine.

    For SZend, add the following to application.ini
    ———————————————————-
    resources.view.helperPath.SZend_View_Helper = “SZend/View/Helper”

    GD Star Rating
    loading...
  11. Chris says:
    April 5, 2010 at 11:16 am

    Awesomeness.

    GD Star Rating
    loading...
  12. Chris says:
    April 5, 2010 at 12:28 pm

    Well I can’t get the dialog or this to work :) With the dialog I am using your example:
    echo $this->dialog(‘myDialog’,…

    Nothing happens, no errors or changes in display. Dojo is already working on the view I am testing this with. With the grid, I get an error when i create the grid, but don’t put any data in it and then echo it.

    Fatal error: Call to undefined method Zend_Dojo_View_Helper_Dojo_Container::_addZendLoad() i

    GD Star Rating
    loading...
  13. SpiffyJr says:
    April 5, 2010 at 12:28 pm

    You should probably grab the latest code from http://www.github.com/spiffyjr/SZend.

    GD Star Rating
    loading...
  14. Chris says:
    April 5, 2010 at 12:39 pm

    yeah i did download the code from there last week thursday maybe? I think that is up to date.

    GD Star Rating
    loading...
  15. Chris says:
    April 5, 2010 at 2:48 pm

    is _addZendLoad() a valid function call? is there a better way to ask questions than spamming up your comments? :)

    GD Star Rating
    loading...
  16. SpiffyJr says:
    April 5, 2010 at 3:01 pm

    _addZendLoad() is a Zend Framework defined method. You can AIM me at SpiffyJr if you wish.

    GD Star Rating
    loading...
  17. Chris says:
    April 5, 2010 at 4:17 pm

    I sent you a msg on aim, but I commented out the code that uses programmatic, which then forces it to set up the rendering to use declarative. This works in displaying the grid headers at least.

    GD Star Rating
    loading...
  18. Tridem says:
    June 24, 2010 at 9:21 am

    Thanks for these great helpers. I found them before I started my own work.

    I would like to move the DataGrid and DataStore to my library’s components. The idea is to create objects by an extending a Model (like with mappers or DbTable) or using a Zend_Config (configs/DataGrid/foo.ini).

    Send me an email if you want me to keep you updated.

    Cheers

    GD Star Rating
    loading...
  19. Tridem says:
    December 23, 2010 at 2:30 am

    Have you done any refactoring yet? I’m excited about the enhancedGrid features.

    How about parsing an array to the ‘query’ parameter which will be automatically parsed to a json notation by the view helper?

    dataGrid(‘myGrid’,
    array(
    ‘query’ => array(‘Title’ => ‘*’)
    ));
    ?>

    parsed:
    query=”{ Title: ‘*’ }”

    GD Star Rating
    loading...
  20. Tridem says:
    December 23, 2010 at 6:05 am

    Another nice feature would be the translation lookup for the labels.

    Instead of defining it inside the template

    array(‘field’ => ‘Year’, ‘label’ => ‘Year’, ‘options’ => array(‘width’ => ’10%’))

    you could write
    array(‘field’ => ‘Year’, ‘label’ => ‘en_year_label_from_translation’, ‘options’ => array(‘width’ => ’10%’))

    GD Star Rating
    loading...
  21. Online Werbeagentur says:
    February 1, 2011 at 7:53 am

    Thanks for you code SpiffyJr. It is much appreciated.

    GD Star Rating
    loading...
  22. Sunil says:
    April 27, 2011 at 1:17 pm

    Thank you for the code. I am using this and have a question. When I move the mouse on the records, the color of the row doesn’t show up like how the grid would show by default. I just see a colored line. Any clue.

    Thank you!

    GD Star Rating
    loading...
  23. Ludri says:
    May 16, 2011 at 6:55 am

    Hi,

    Really nice helpers.
    Integrated these into my project.

    Some modifications i made for myself.

    1. If you have 2 grids in one controller the second one gets all the fields added from the 1.
    For removing this i empty the field list before adding new ones (Since no new DataGrid object is made)
    if (array_key_exists(‘fields’, $attribs)) {
    $this->_fields = array(); // Added
    foreach ($attribs['fields'] as $f) {
    $this->addField(
    }
    unset($attribs['fields']);
    }
    Maybe i just create the helpers the wrong way but worked for me :)

    2. I added Cell edditing js to a method aswell to support cell edditing :D

    Ty and all the best,
    Ludri

    GD Star Rating
    loading...

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

*

*


question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • Recent Posts

    • Keep your Git fork clean
    • Get started with Zend Framework 2 modules!
    • More Doctrine 2 and Zend Framework integration goodies!
    • Super sexy URLs with ZF and the joy of controller plugins!
    • Formatting your API to work with dojox.data.JsonRestStore (#dojo)
  • Categories

    • Other
      • Random
    • Projects
      • Blitzaroo
      • phpRaider
      • SpiffyDb
      • View Helpers
      • Zend Calendar
    • SpiffyJr
    • Technologies
      • Dojo
      • PHP
      • Zend Framework
  • Tag Cloud

      Ajax Algorithm api Blitzaroo Blog BSD licenses calendar Cascading Style Sheets CSS database Data Formats Dojo Dojo Toolkit event Framework game Google HTML HTML element JavaScript JQuery json Languages mapper Marketing mmorpg model php Programming Projects Scripts Source code Style sheet Style Sheets Twitter Website zend Zend Framework
  • Archives

    • December 2011
    • November 2011
    • July 2011
    • April 2011
    • March 2011
    • December 2010
    • November 2010
    • October 2010
    • March 2010
    • February 2010
    • November 2009
    • October 2009
    • September 2009
© SpiffyJr's Blogaroo. Proudly Powered by WordPress | Nest Theme by YChong