<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ybits &#187; Zend Framework</title>
	<atom:link href="http://ybits.net/tags/zend-framework/feed/" rel="self" type="application/rss+xml" />
	<link>http://ybits.net</link>
	<description>(why bits? because.)</description>
	<lastBuildDate>Thu, 12 Aug 2010 01:57:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Zend Framework Bundle for TextMate</title>
		<link>http://ybits.net/2009/10/zend-framework-bundle-for-textmate/</link>
		<comments>http://ybits.net/2009/10/zend-framework-bundle-for-textmate/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 02:36:03 +0000</pubDate>
		<dc:creator>ryan</dc:creator>
				<category><![CDATA[Newness]]></category>
		<category><![CDATA[Bundle]]></category>
		<category><![CDATA[TextMate]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://ybits.net/?p=201</guid>
		<description><![CDATA[I decided to start a Zend Framework bundle for TextMate. Then I decided to make a screencast of it. These are both firsts. Find out more about it.]]></description>
			<content:encoded><![CDATA[<p><img class="logo" src="/img/textmate.png" alt="TextMate Logo">I decided to start a Zend Framework bundle for TextMate. Then I decided to make a screencast of it. These are both firsts.</p>
<p><a href="http://ybits.net/zend-framework-textmate-bundle/">Find out more about it</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://ybits.net/2009/10/zend-framework-bundle-for-textmate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extending Zend_Db_Table_Row</title>
		<link>http://ybits.net/2009/09/extending-zend_db_table_row/</link>
		<comments>http://ybits.net/2009/09/extending-zend_db_table_row/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 01:01:18 +0000</pubDate>
		<dc:creator>ryan</dc:creator>
				<category><![CDATA[Newness]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Zend_Db_Table]]></category>

		<guid isPermaLink="false">http://ybits.net/?p=64</guid>
		<description><![CDATA[Zend_Db_Table and Zend_Db_Table_Row provide a great base for the &#8220;model&#8221; portion of the MVC paradigm implemented by the Zend Framework. Zend_Db_Table abstracts an underlying database table, and Zend_Db_Table_Row abstracts a row. They provide normalized functionality, are database agnostic, and offer other types of slickness that won&#8217;t be covered here. If you haven&#8217;t experimented with Zend_Db [...]]]></description>
			<content:encoded><![CDATA[<p><img class="logo" src="/img/zf.png" alt="Zend Framework Logo"><a href="http://framework.zend.com/manual/en/zend.db.table.html">Zend_Db_Table</a> and <a href="http://framework.zend.com/manual/en/zend.db.table.row.html">Zend_Db_Table_Row</a> provide a great base for the &#8220;model&#8221; portion of the MVC paradigm implemented by the Zend Framework. Zend_Db_Table abstracts an underlying database table, and Zend_Db_Table_Row abstracts a row. They provide normalized functionality, are database agnostic, and offer other types of slickness that won&#8217;t be covered here. </p>
<p>If you haven&#8217;t experimented with Zend_Db yet, here&#8217;s a simple example of the basic abstractions:</p>
<p>Insert a record:</p>
<pre class="brush:php">
if ($this->_request->isPost()) {
    $usersModel = new Users();
    $user = $usersModel->createRow();
    $user->name = $this->_request->getParam('name');
    $user->age = $this->_request->getParam('age');
    $user->save();
}
</pre>
<p>Update a record:</p>
<pre class="brush:php">
$id = (int)$this->_request->getParam('id');
$usersModel = new Users();
$user = $usersModel->getRow('id = ?', $id);
if (!empty($user)) {
    // Just set the name to uppercase..
    $user->name = strtoupper($user->name);
    $user->save();
}
</pre>
<p>Notice that when $row->save() is called, the appropriate insert/update is made depending upon whether the row is new or not.</p>
<p>The update method is even smart enough to only update fields that have been marked as modified.</p>
<p>But there <em>is</em> a small problem. Let&#8217;s have a look at <code>Zend_Db_Table_Row_Abstract::_set()</code> to see what happens when a value is set into a row:</p>
<pre class="brush:php">
public function __set($columnName, $value)
{
    $columnName = $this->_transformColumn($columnName);
    if (!array_key_exists($columnName, $this->_data)) {
        require_once 'Zend/Db/Table/Row/Exception.php';
	throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row");
    }
    $this->_data[$columnName] = $value;
    $this->_modifiedFields[$columnName] = true;
}
</pre>
<p>Observe at the marked lines that the column is marked modified <em>regardless of the value being set</em>. If the value passed in is already set for that column, it&#8217;s still marked modified even though technically it hasn&#8217;t been.</p>
<p>This may or may not be desirable given the context, but consider this: Data is always posted in a form, whether or not it changes on the client side. It doesn&#8217;t make sense to always compare each field with the column in the row to determine if the data has changed. Surely this can be done better.</p>
<p>What makes sense is for the row to do this check automatically. What makes even more sense is to make the modified columns and their values available, so that controller specific logic can be written to handle special cases when certain data has changed.</p>
<p>It all starts with that <code>Zend_Db_Table_Row_Abstract::_set()</code> function.</p>
<p>What we want is to make the <code>_set</code> function smarter, so that setting a value into a column that already has that value doesn&#8217;t also mark it modified. </p>
<p>Zend_Db_Table_Row_Abstract can be extended to add the functionality, then Zend_Db_Table_Abstract can be extended to use the new extended row class. When the model is defined, it will extend My_Db_Table_Abstract and inherit the new functionality.</p>
<p>An overloaded Zend_Db_Table_Row_Abstract:</p>
<pre class="brush:php">
class My_Db_Table_Row extends Zend_Db_Table_Row_Abstract
{
    // Return modifiedFields
    public function getModifiedFields()
    {
    	return $this->_modifiedFields;
    }

    // Return a hash of only modified field => value pairs
    public function getModifiedValues()
    {
    	$modifiedValues = array();
    	foreach ($this->_modifiedFields as $field => $value)
    	{
    	    $modifiedValues[$field] = $this->_data[$field];
    	}
    	return $modifiedValues;
    }

    //Override, don't allow unmodified fields to be marked...
    public function __set($columnName, $value)
    {
        $columnName = $this->_transformColumn($columnName);
        if (!array_key_exists($columnName, $this->_data)) {
            require_once 'Zend/Db/Table/Row/Exception.php';
            throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row");
        }

        $origData = $this->_data[$columnName];
        if ($origData != $value) {
            $this->_data[$columnName] = $value;
            $this->_modifiedFields[$columnName] = true;
        }

    }
}
</pre>
<p>An overloaded Zend_Db_Table_Abstract:</p>
<pre class="brush:php">
class My_Db_Table_Abstract extends Zend_Db_Table_Abstract {

    protected $_rowClass = 'My_Db_Table_Row';

    public function columnExists($column)
    {
        return in_array($column, $this->_cols);
    }
}
</pre>
<p>Portion of a controller script utilizing the new row:</p>
<pre class="brush:php">
$form = new MyForm();
$form->populate($this->_request()->getPost();
$id = (int)$this->_request->getParam('id');
$usersModel = new Users();
$user = $usersModel->getRow('id = ?', $id);
if (!empty($user)) {
    $user->name = $form->getElement['name']->getValue();
    $user->age = $form->getElement['age']->getValue();
    $mods = user->getModifiedValues();
    $user->save();

    foreach($mods as $mod) {
	// do something with the modified values;
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ybits.net/2009/09/extending-zend_db_table_row/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hybrid Zend Form</title>
		<link>http://ybits.net/2009/09/hybrid-zend-form/</link>
		<comments>http://ybits.net/2009/09/hybrid-zend-form/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 15:25:20 +0000</pubDate>
		<dc:creator>ryan</dc:creator>
				<category><![CDATA[Newness]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Zend_Form]]></category>

		<guid isPermaLink="false">http://ybits.net/?p=29</guid>
		<description><![CDATA[A Zend_Form is (or at least, can be) an unfortunate mish-mash of logical and visual rules. Instead of designing how the form will render visually using HTML in a .phtml file, like everything else that&#8217;s rendered, there are a bunch of programmatic hoops to jump through to set up the visual properties in code using [...]]]></description>
			<content:encoded><![CDATA[<p><img class="logo" src="/img/zf.png" alt="Zend Framework Logo">A <a href="http://framework.zend.com/manual/en/zend.form.html">Zend_Form</a> is (or at least, can be) an unfortunate mish-mash of logical and visual rules. Instead of designing how the form will render visually using HTML in a <code>.phtml</code> file, like everything else that&#8217;s rendered, there are a bunch of programmatic hoops to jump through to set up the visual properties in code using decorators. </p>
<p>The hoops aren&#8217;t so bad if the layout of the form is simple, for example a basic layout with all the labels to the left and all the elements on the right. But to create a complex form layout using tables (yes, we still use tables for tabular data), the table layout must be created in HTML anyway, and then back-fitted into code by breaking the structure apart and assigning different pieces to individual elements of the form.</p>
<p>This process is tedious, and twice the amount of work to get the same end result. Plus, to change something visually, either the template has to be modified until it&#8217;s right and then back-fitted again, or the visual properties have to be tweaked directly in code without the benefit of the template. The latter being the &#8220;hope for the best&#8221; method.</p>
<p>Mashing this visual structure into the form object itself:</p>
<ul>
<li>Encroaches on the role of the view.</li>
<li>Breaks separation of concerns.</li>
<li>Is harder than it should be.</li>
</ul>
<p>The hybrid approach to Zend_Form is to use all of its functionality <em>except</em> the decorators for visual layout. Instead, the form is laid out normally in a view script, and each element of the form is rendered individually where it needs to be.</p>
<p>This process provides the best of both worlds. The form object is still used to define the elements and do validations, but the actual layout is done (once) in HTML, which is easier to create, modify and maintain.</p>
<p>Here&#8217;s an example, with bits of a form object, controller, and view script:</p>
<p>MyForm.php:</p>
<pre class="brush:php">
class MyForm extends Zend_Form
{
    public function __construct($options = null)
    {
        parent::__construct($options);
        $this->setName('my_form');

        $textFilters = array(
            'StripTags',
            'StringTrim'
        );

        $options = array(
            'name' => 'name',
            'required' => true,
            'validators' => array('NotEmpty'),
            'filters' => $textFilters,
            'class' => 'form',
            'size' => 65,
            'required' => true
        ); 

        $input = new Zend_Form_Element_Text($options);
        $this->addElement($input);

        $options = array(
            'name' => 'age',
            'required' => false,
            'validators' => array('NotEmpty'),
            'filters' => $textFilters,
            'class' => 'form',
            'size' => 5,
            'required' => true
        ); 

        $input = new Zend_Form_Element_Text($options);
        $this->addElement($input);

        $element = new Zend_Form_Element_Submit('submitbtn');
        $element->setAttrib('id', 'submitbtn')
                      ->setAttrib('class', 'button')
                      ->setLabel('Save');
        $this->addElement($element);

        $this->setElementDecorators(array(
            'ViewHelper',
            'Errors'
         ));
    }
}
</pre>
<p>MyController.php:</p>
<pre class="brush:php">
public function showAction()
{
    $form = new MyForm();
    $form->populate($this->_request->getPost());
    $this->view->form = $form;
}
</pre>
<p>show.phtml:</p>
<pre class="brush:html">
&lt;form
name="&lt;?php echo $this-&gt;form-&gt;getName() ?&gt;"
id="&lt;?php echo $this-&gt;form-&gt;getName() ?&gt;"
method="post" enctype="application/x-www-form-urlencoded"
action=""
&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;?php echo $this-&gt;form-&gt;getElement('name')-&gt;getLabel() ?&gt;&lt;/td&gt;
&lt;td&gt;&lt;?php echo $this-&gt;form-&gt;getElement('name')?&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;?php echo $this-&gt;form-&gt;getElement('age')-&gt;getLabel() ?&gt;&lt;/td&gt;
&lt;td&gt;&lt;?php echo $this-&gt;form-&gt;getElement('age')?&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;?php echo $this-&gt;form-&gt;getElement('submitbtn')?&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
&lt;/form&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ybits.net/2009/09/hybrid-zend-form/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
