<?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>SpinOneSolutions &#187; PHP</title>
	<atom:link href="http://www.spinonesolutions.com/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.spinonesolutions.com</link>
	<description>I waste my time so that you don't have to...</description>
	<lastBuildDate>Mon, 16 May 2011 17:01:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Magento Admin Form POST with form_key</title>
		<link>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/</link>
		<comments>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 16:40:18 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Admin]]></category>
		<category><![CDATA[Form]]></category>
		<category><![CDATA[Post]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=685</guid>
		<description><![CDATA[The other day I was trying to help someone create a Form in the admin side of Magento that would simply POST to a Controller and capture some data. I thought it&#8217;d be fairly simple, I&#8217;ve done it before; I thought. Turns out I had done it before, but I&#8217;ve always used the built in [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I was trying to help someone create a Form in the admin side of Magento that would simply POST to a Controller and capture some data.  I thought it&#8217;d be fairly simple, I&#8217;ve done it before; I thought.</p>
<p>Turns out I had done it before, but I&#8217;ve always used the built in Magento Form widgets, never specified a custom .phtml template and actually tried to write the Form code by hand.  It&#8217;s a little more tricky than I anticipated, but we struggled through it and finally found the catch.</p>
<p>The &#8220;catch&#8221;, as it were, is that you have to send a hidden &#8220;form_key&#8221;.  This lets Magento know that you are who you say you are and not some spoofer posting malicious code to your backend.  Let&#8217;s get started.</p>
<p>Let&#8217;s presume that I&#8217;ve got a Module <strong>Spinonesolutions_Helloworld</strong> in it I&#8217;m going to make a block:</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/Block/Adminhtml/Adminform.php</strong></p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Block_Adminhtml_Adminform extends Mage_Adminhtml_Block_Template {
public function __construct() {
    parent::__construct();
    $this-&gt;setTemplate('helloworld/form.phtml');
    $this-&gt;setFormAction(Mage::getUrl('*/*/new'));
  }
}</pre>
<p>It&#8217;s easily seen that I&#8217;m referencing a .phtml template within my Block for the presentation so let&#8217;s make that file as well:</p>
<p><strong>/app/design/adminhtml/default/default/template/hellworld/form.phtml</strong></p>
<pre class="html" name="code">&lt;form action="&lt;? echo $this-&gt;getFormAction(); ?&gt;" method="POST"&gt;
&lt;input type="text" id="var1" name="var1" /&gt;
&lt;input type="submit" id="submit" name="submit" /&gt;
&lt;/form&gt;</pre>
<p>Lastly we need a Controller to handle the POST and to render our Block:</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/controllers/Adminhtml/AdminformController.php</strong></p>
<pre class="php" name="code">class Spinonesolutions_Helloworld_Adminhtml_AdminformController extends Mage_Adminhtml_Controller_Action {

public function indexAction() {
  $this-&gt;loadLayout();
  $block = $this-&gt;getLayout()-&gt;createBlock('spinonesolutions_helloworld/adminhtml_adminform','admin_form');
  $this-&gt;getLayout()-&gt;getBlock('content')-&gt;append($block);
  $this-&gt;renderLayout();
}

public function newAction() {
  die('here I am!');
}
}</pre>
<p>OK, that&#8217;s it for the architecture.  Let&#8217;s wire it all up with some XML in <strong>config.xml</strong>.  Note this is partial, not a full module definition:</p>
<pre class="xml" name="code">&lt;blocks&gt;
&lt;spinonesolutions_helloworld&gt;
&lt;class&gt;Spinonesolutions_Helloworld_Block&lt;/class&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;/blocks&gt;
&lt;admin&gt;
&lt;routers&gt;

&lt;adminhtml&gt;
&lt;args&gt;
&lt;modules&gt;
&lt;Spinonesolutions_Helloworld before="Mage_Adminhtml"&gt;Spinonesolutions_Helloworld_Adminhtml&lt;/Spinonesolutions_Helloworld&gt;
&lt;/modules&gt;
&lt;/args&gt;
&lt;/adminhtml&gt;
&lt;/routers&gt;
&lt;/admin&gt;</pre>
<p>Now, if you visit */admin/adminform/index you should see your super simple Form.  If you hit submit your Form will certainly post, but instead of seeing the die output you&#8217;ll be redirected to the Dashboard.  This because we haven&#8217;t sent through the authentication required by Magento&#8217;s internal routing system that will validate our form.  Let&#8217;s change <strong>form.phtml</strong> so that we can POST successfully.</p>
<pre class="html" name="code">&lt;form action="&lt;? echo $this-&gt;getFormAction(); ?&gt;" method="POST"&gt;
&lt;input type="hidden" name="form_key" value="&lt;? echo $this-&gt;getFormKey(); ?&gt;" /&gt;
&lt;input type="text" id="var1" name="var1" /&gt;
&lt;input type="submit" id="submit" name="submit" /&gt;
&lt;/form&gt;</pre>
<p>That&#8217;s all there is to it!  Notice the &#8220;form_key&#8221; hidden variable.  That&#8217;s the key to submitting Forms in the Magento admin.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2011/01/admin-form-post-form_key/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Drupal sess_read() causes logout</title>
		<link>http://www.spinonesolutions.com/2011/01/drupal-sess_read-causes-logout/</link>
		<comments>http://www.spinonesolutions.com/2011/01/drupal-sess_read-causes-logout/#comments</comments>
		<pubDate>Fri, 28 Jan 2011 15:21:30 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Drupal]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=702</guid>
		<description><![CDATA[Affects: Drupal 6.20 If you try to read a value from a session that has not been set your Drupal user will be logged out. Example: sess_write('myValue',TRUE); echo sess_read('myValue'); OK echo sess_read('myValue'); NOT OK, user is logged out.]]></description>
			<content:encoded><![CDATA[<p><em>Affects: Drupal 6.20</em></p>
<p>If you try to read a value from a session that has not been set your Drupal user will be logged out.</p>
<p>Example:</p>
<pre class="php" name="code">sess_write('myValue',TRUE);
echo sess_read('myValue');
</pre>
<p>OK</p>
<pre class="php" name="code">echo sess_read('myValue');
</pre>
<p>NOT OK, user is logged out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2011/01/drupal-sess_read-causes-logout/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento – Create a globally available static function</title>
		<link>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/</link>
		<comments>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/#comments</comments>
		<pubDate>Thu, 30 Dec 2010 15:00:43 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[lib]]></category>
		<category><![CDATA[static]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=608</guid>
		<description><![CDATA[Sometimes, you&#8217;ve got a situation where you want to have a globally available static function.  Most often this occurs (for me) in a debugging context.  Recently I wanted to have FirePHP available from anywhere in my project so I made use of the lib folder. Unlike just about every other article on this site, for [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes, you&#8217;ve got a situation where you want to have a globally available static function.  Most often this occurs (for me) in a debugging context.  Recently I wanted to have FirePHP available from anywhere in my project so I made use of the <strong>lib</strong> folder.</p>
<p>Unlike just about every other article on this site, for this one we&#8217;re going to be considering the folder <strong>/lib</strong>.  Note that this folder is NOT within local, but resident in the root.  As such changes here should be put within their own sub-folders so that they too will survive an upgrade.</p>
<p>It&#8217;s really quite easy to create your class, just follow the usual Magento naming conventions. I&#8217;m going to create <strong>Spinonesolutions_Devel_FirePHP</strong> so all I do is create the file: <strong>/lib/Spinonesolutions/Devel/FirePHP.php</strong>.  Note the similarity to Model naming.</p>
<p>In here I create my class definition:</p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Devel_FirePHP {
  public static function send($var, $label = "DEBUG", $style = "LOG") {
    if (Mage::getIsDeveloperMode()) {
      $request = new Zend_Controller_Request_Http();
      $response = new Zend_Controller_Response_Http();
      $channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
      $channel-&gt;setRequest($request);
      $channel-&gt;setResponse($response);

      /*
      * Start output buffering
      */
      ob_start();

      Zend_Wildfire_Plugin_FirePhp::send($var, $label, $style);

      /*
      Style     Description
      LOG     Displays a plain log message
      INFO     Displays an info log message
      WARN     Displays a warning log message
      ERROR     Displays an error log message that increments Firebug?s error count
      TRACE     Displays a log message with an expandable stack trace
      EXCEPTION     Displays an error long message with an expandable stack trace
      TABLE     Displays a log message with an expandable table
      */

      /*
      * Flush log data to browser
      */
      $channel-&gt;flush();
      $response-&gt;sendHeaders();
    } else {
      return null;
    }
  }
}</pre>
<p>Now I can call <strong>Spinonesolutions_Devel_FirePHP:send()</strong> anywhere in my project.  Sweet!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/12/magento-create-a-globally-available-static-function/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Magento config.xml Cron Job</title>
		<link>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/</link>
		<comments>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/#comments</comments>
		<pubDate>Wed, 15 Dec 2010 15:00:27 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[cron]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=606</guid>
		<description><![CDATA[It&#8217;s possible to setup process to run on a schedule provided that your server is setup to run cron. All internal cron jobs are run from a single page/script call. You&#8217;ll need to setup your server to either; make a request to /cron.php or execute /cron.sh. The time delta that you set here will be [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s possible to setup process to run on a schedule provided that your server is setup to run cron.  All internal cron jobs are run from a single page/script call.  You&#8217;ll need to setup your server to either; make a request to <strong>/cron.php</strong> or execute <strong>/cron.sh</strong>.</p>
<p>The time delta that you set here will be the minimum delta for your Magento jobs.  IE: If your server&#8217;s cron  requests <strong>/cron.php</strong> every ten minutes and you create a cron job within Magento to run every five minutes, you shouldn&#8217;t be surprised to see it running every ten minutes instead of every five.</p>
<p>This won&#8217;t be a huge deal for all of you who are administering your own box, but for those of you on a shared box; you&#8217;ll likely be limited to a certain minimum delta which you&#8217;ll want to be aware of.</p>
<p>Setting up a cron job is actually really simple so lets take a look.  The configuration lives in <strong>config.xml</strong>, which shouldn&#8217;t be a surprise for you module developers.  Using my default example module <strong>Spinonesolutions_Helloworld:</strong></p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">&lt;config&gt;
...
&lt;crontab&gt;
&lt;jobs&gt;
&lt;spinonesolutions_helloworld&gt;
&lt;schedule&gt;&lt;cron_expr&gt;*/10 * * * *&lt;/cron_expr&gt;&lt;/schedule&gt;
&lt;run&gt;&lt;model&gt;spinonesolutions_helloworld/observer::foobar&lt;/model&gt;&lt;/run&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;/jobs&gt;
&lt;/crontab&gt;
...
&lt;/config&gt;</pre>
<p>You can do a Google search on cron schedules in order to figure that part out, it&#8217;s outside the scope of this article.  The only other piece that deserves explanation is the static method call between the <strong>run</strong> tag.  As you&#8217;d expect my example call is referencing <strong>Spinonesolutions_Helloworld_Model_Observer</strong> <strong>(/app/code/local/Spinonesolutions/Helloworld/Model/Observer.php).</strong> This file doesn&#8217;t need to contain anything except for a class definition and a static method.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/Observer.php</strong></p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_Helloworld_Model_Observer {
  public static function foobar() {
  }
}</pre>
<p>That&#8217;s it.  Your static method will now be called on the schedule that you set!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/12/magento-config-xml-cron-job/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Magento SQL Setup</title>
		<link>http://www.spinonesolutions.com/2010/11/magento-sql-setup/</link>
		<comments>http://www.spinonesolutions.com/2010/11/magento-sql-setup/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 15:00:31 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=604</guid>
		<description><![CDATA[One of the many aspects to good module development is packaging everything up in such a way that the module is as standalone as possible.  The goal is to provide a third-party with a single package that can take care of itself.  Many modules will make use of custom database tables and/or Magento storage mechanisms. [...]]]></description>
			<content:encoded><![CDATA[<p>One of the many aspects to good module development is packaging everything up in such a way that the module is as standalone as possible.  The goal is to provide a third-party with a single package that can take care of itself.  Many modules will make use of custom database tables and/or Magento storage mechanisms.</p>
<p>The Varien team has provided ways for your module to manage these stores automatically through the &#8220;setup&#8221; functionality.  Let&#8217;s check it out.</p>
<p>First, you have to let Magento know where your setup code is going to live and what version your module is currently at.  You do this in <strong>config.xml. </strong> As an example I&#8217;ll use a module called Helloworld.  You may recognize this Module from the <a title="Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">first article</a>.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">&lt;global&gt;
...
&lt;spinonesolutions_helloworld_setup&gt;
&lt;setup&gt;
&lt;module&gt;Spinonesolutions_Helloworld&lt;/module&gt;
&lt;/setup&gt;
&lt;/spinonesolutions_helloworld_setup&gt;
...
&lt;/global&gt;</pre>
<p>The <strong>setup</strong> tag is going to cause Magento to look for a folder within the module called ..<strong>/sql/setup (/Spinonesolutions/Helloworld/sql/setup).</strong> We can change the name of the target folder by changing the tag.  Example: <strong>&lt;foobar_setup&gt;&lt;/foobar_setup&gt;</strong> would prompt Magento to look for ..<strong>/sql/foobar_setup</strong>.</p>
<p>The files that fall within this folder need to follow a strict naming scheme:</p>
<p><strong>mysql4-install-{version}.php</strong></p>
<p><strong>mysql4-upgrade-{versionFrom}-{versionTo}.php</strong></p>
<p>What happens is that Magento will run each file, in succession, until it reaches the version number specified in your <strong>config.xml</strong>.</p>
<p>If you ever need to check to see what version of a module Magento THINKS is installed, browse your database for the table <strong>core_resource</strong> and scan the <strong>codes</strong> till you find your module&#8217;s <strong>code</strong>.</p>
<p>If you ever need to have Magento re-run your setup scripts, just remove the entry from <strong>core_resource</strong> and refresh; the module will then be &#8220;reinstalled&#8221;.</p>
<p>Now lets take a look at some common things to do in a install/upgrade script.  One of the best resources for figuring this stuff out is Varien&#8217;s own codebase.  If you go through some modules in <strong>../core/Mage</strong> you&#8217;ll find all sorts of great material  to copy into your own module.</p>
<h2>Install/Update Wrapper</h2>
<p><strong>../sql/setup/mysql4-install-1.0.0.php</strong></p>
<pre class="php" name="code">&lt;?php
$installer = $this;
/* @var $installer Mage_Core_Model_Resource_Setup */
$connection = $installer-&gt;getConnection();
/* @var $connection Varien_Db_Adapter_Pdo_Mysql */

$installer-&gt;startSetup();
YOUR CODE GOES HERE

$installer-&gt;endSetup();</pre>
<h2>DataBase Table</h2>
<pre name="code" class="php">$installer-&gt;run("
DROP TABLE IF EXISTS {$installer-&gt;getTable('spinonesolutions_helloworld/foo')};
CREATE TABLE {$installer-&gt;getTable('spinonesolutions_helloworld/foo')} (
id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
created_at DATETIME NOT NULL,
modified_at DATETIME NOT NULL,
store_id int(5) UNSIGNED NOT NULL,
PRIMARY KEY (id)
)
ENGINE = InnoDB;
");</pre>
<p>Not much to explain other than the <strong>getTable</strong> function.  The parameter refers to <strong>config.xml -&gt; global -&gt; models -&gt; {resourceModel} -&gt; entities</strong>.</p>
<p><strong>/app/code/local/Spinonesolutions/Helloworld/etc/config.xml (partial)</strong></p>
<pre class="xml" name="code">...
&lt;global&gt;
&lt;models&gt;
...
&lt;spinonesolutions_helloworld&gt;
&lt;class&gt;Spinonesolutions_Helloworld&lt;/class&gt;
&lt;resourceModel&gt;spinonesolutions_helloworld_mysql4&lt;/resourceModel&gt;
&lt;/spinonesolutions_helloworld&gt;
&lt;toms_bluehornet_mysql4&gt;
&lt;class&gt;Spinonesolutions_Helloworld_Model_Mysql4&lt;/class&gt;
&lt;entities&gt;
&lt;foo&gt;&lt;table&gt;spinonesolutions_helloworld_foo&lt;/table&gt;&lt;/foo&gt;
&lt;/entities&gt;
&lt;/toms_bluehornet_mysql4&gt;
...
&lt;/models&gt;
&lt;/global&gt;
...</pre>
<h2>New Attribute</h2>
<pre class="php" name="code">$installer-&gt;addAttribute('catalog_product', 'is_recurring', array(
'group'             =&gt; 'Recurring Profile',
'type'              =&gt; 'int',
'backend'           =&gt; '',
'frontend'          =&gt; '',
'label'             =&gt; 'Enable Recurring Profile',
'note'              =&gt; 'Products with recurring profile participate in catalog as nominal items.',
'input'             =&gt; 'select',
'class'             =&gt; '',
'source'            =&gt; 'eav/entity_attribute_source_boolean',
'global'            =&gt; Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'visible'           =&gt; true,
'required'          =&gt; false,
'user_defined'      =&gt; false,
'default'           =&gt; '',
'searchable'        =&gt; false,
'filterable'        =&gt; false,
'comparable'        =&gt; false,
'visible_on_front'  =&gt; false,
'unique'            =&gt; false,
'apply_to'          =&gt; 'simple,virtual',
'is_configurable'   =&gt; false
));</pre>
<h2>Mage_Eav_Model_Entity_Setup</h2>
<p><strong>Mage_Eav_Model_Entity_Setup</strong> has tons of useful methods to call from your setup script.  The installer itself is an object of type <strong>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</strong> which extends <strong>Mage_Eav_Model_Entity_Setup</strong> thus all the instance methods are available from <strong>$this</strong> or <strong>$installer </strong>if you use a wrapper like the one shown above.</p>
<p>Questions and comments welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/11/magento-sql-setup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Drupal json_server Bug Fix</title>
		<link>http://www.spinonesolutions.com/2010/11/drupal-json_server-bug-fix/</link>
		<comments>http://www.spinonesolutions.com/2010/11/drupal-json_server-bug-fix/#comments</comments>
		<pubDate>Mon, 08 Nov 2010 15:00:32 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Drupal]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[json_server]]></category>
		<category><![CDATA[services]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=600</guid>
		<description><![CDATA[I wanted to use the json_server module in conjunction with Drupal&#8217;s services module to enable JSON communications instead of just XMLRPC.  I ran into a couple of issues however: first, the JSON packet wasn&#8217;t being encoded correctly and second, the &#8216;#&#8217; in the array keys was causing issues with the array lookups. I ended up [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to use the <a href="http://drupal.org/project/json_server">json_server</a> module in conjunction with Drupal&#8217;s <a href="http://drupal.org/project/services">services</a> module to enable JSON communications instead of just XMLRPC.  I ran into a couple of issues however: first, the JSON packet wasn&#8217;t being encoded correctly and second, the &#8216;#&#8217; in the array keys was causing issues with the array lookups.</p>
<p>I ended up writing a super simple module that overrides json_server and corrects the issues.</p>
<p>If you compare the two module&#8217;s contents you&#8217;ll see I only made a couple of really minor tweaks.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/spinonesolutions.rar">You can download it here.</a></p>
<h2>Install</h2>
<p>Download and extract.</p>
<p>Copy the module folder to <strong>/sites/all/modules</strong> or <strong>/sites/{preferred-site}/modules</strong>.</p>
<p>Navigate to Site Building -&gt; Modules.</p>
<p>Scroll down to SpinOneSolutions -&gt; JSON Server and Enable.</p>
<p>Hit Save</p>
<p>Developed on Drupal 6.16</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/11/drupal-json_server-bug-fix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento Custom Widget</title>
		<link>http://www.spinonesolutions.com/2010/10/magento-custom-widget/</link>
		<comments>http://www.spinonesolutions.com/2010/10/magento-custom-widget/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 17:00:24 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Module]]></category>
		<category><![CDATA[Widget]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=602</guid>
		<description><![CDATA[With the latest release of Magento admins now have the ability to create custom “widgets” that can be dropped anywhere on the site to provide additional functionality.  The most common type of widget that I come across is a simple frontend presentation widget.  Basically the developer is asked to display some sort of data in [...]]]></description>
			<content:encoded><![CDATA[<p>With the latest release of Magento admins now have the ability to create custom “widgets” that can be dropped anywhere on the site to provide additional functionality.  The most common type of widget that I come across is a simple frontend presentation widget.  Basically the developer is asked to display some sort of data in a new way.</p>
<p>Widgets can basically be thought of as easily customizable blocks.  The main difference between standard blocks and widgets is that widgets can be added to CMS pages through the WYSIWYG editor and they can easily accept parameters, also defined through the WYSIWYG.  Thus a non-programmer can add quasi-dynamic content to their CMS pages, hurrah!</p>
<p>You should reference previous articles if you want more details about creating custom Modules and Blocks.</p>
<p>As an example I’m going to build a super simple slideshow widget called “Glider”.  It’s going to be a widget that takes four static block_id(s) as parameters and then displays each static block, in succession, as a slideshow.  If you let your imagination work a little you should be able to see some cool possibilities for such a thing, given that you extend it a little.</p>
<p>I’m using static blocks as the source material for each slide because this would allow a content manager to change out the content of a slide by either editing the static block that contains the content or by editing the block id being passed to the widget.  Either way it’s manageable through the interface.</p>
<p>Also note that the template (presentation layer) is going to be statically defined in this example, but you could easily make that a parameter and create multiple templates for the content manager to choose from!</p>
<p>Finally, I’ve used jQuery to build the actual slideshow.  I’m not going to go into very much detail about the presentation of the slideshow as that’s not really the focus of this article.  Feel free to write in if you want to see the details on how to implement jQuery (or any other script).</p>
<p>First let’s setup the Module:</p>
<p><strong>/app/etc/modules/Spinonesolutions_WidgetGlider.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
 &lt;config&gt;
 &lt;modules&gt;
 &lt;Spinonesolutions_WidgetGlider&gt;
   &lt;active&gt;true&lt;/active&gt;
   &lt;codePool&gt;local&lt;/codePool&gt;
   &lt;depends&gt;
     &lt;Mage_Cms /&gt;
   &lt;/depends&gt;
 &lt;/Spinonesolutions_WidgetGlider&gt;
 &lt;/modules&gt;
 &lt;/config&gt;</pre>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/etc/config.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
 &lt;config&gt;
 &lt;modules&gt;
 &lt;Spinonesolutions_WidgetGlider&gt;
   &lt;version&gt;1.0.0&lt;/version&gt;
 &lt;/Spinonesolutions_WidgetGlider&gt;
 &lt;/modules&gt;
 &lt;global&gt;
 &lt;blocks&gt;
   &lt;spinonesolutions_widgetglider&gt;
     &lt;class&gt;Spinonesolutions_WidgetGlider_Block&lt;/class&gt;
   &lt;/spinonesolutions_widgetglider&gt;
 &lt;/blocks&gt;
 &lt;/global&gt;
 &lt;/config&gt;</pre>
<p>OK!  The next thing we need to do is define our widget’s interface.  To do that we create a <strong>widget.xml</strong> file inside our module’s “etc” folder.</p>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/etc/widget.xml</strong></p>
<pre class="xml" name="code">&lt;?xml version="1.0"?&gt;
&lt;widgets&gt;
&lt;glider type="spinonesolutions_widgetglider/glider"&gt;
   &lt;name&gt;SpinoneSolutions: Glider&lt;/name&gt;
   &lt;description&gt;Displays the given HTML Sections in a Glider Slideshow&lt;/description&gt;
   &lt;parameters&gt;
     &lt;section1&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section1&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section1&gt;
     &lt;section2&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section2&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section2&gt;
     &lt;section3&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section3&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section3&gt;
     &lt;section4&gt;
       &lt;required&gt;0&lt;/required&gt;
       &lt;visible&gt;1&lt;/visible&gt;
       &lt;label&gt;Section4&lt;/label&gt;
       &lt;type&gt;text&lt;/type&gt;
     &lt;/section4&gt;
     &lt;template&gt;
       &lt;visible&gt;0&lt;/visible&gt;
       &lt;value&gt;widgetglider/banner.phtml&lt;/value&gt;
     &lt;/template&gt;
   &lt;/parameters&gt;
&lt;/glider&gt;
&lt;/widgets&gt;</pre>
<p>You can define any number of widgets in here.  We’re only creating one so I’ve only got a single entry, <strong>glider</strong>.</p>
<p>The <strong>type</strong> attribute tells Magento what class to use when instantiating objects.  I’ve set it as <strong>spinonesolutions_widgetglider/glider</strong>.  If you go back and inspect the config.xml and remember your Magento naming conventions you can surmise that this is going to cause Magento to try and instantiate an object of type <strong>Spinonesolutions_WidgetGlider_Block_Glider</strong>.  That class doesn’t exist yet so we should create it.</p>
<p><strong>/app/code/local/Spinonesolutions/WidgetGlider/Block/Glider.php</strong></p>
<pre class="php" name="code">&lt;?php
class Spinonesolutions_WidgetGlider_Block_Glider extends Mage_Core_Block_Template
implements Mage_Widget_Block_Interface {
  const MAXSECTIONS = 4;
  public $sectionArr = array();

  protected function _construct() {
    parent::_construct();
  }

  protected function _toHtml() {
    for ($i=1;$i &lt;= self::MAXSECTIONS;$i++) {
      if ($this-&gt;getData("section$i")) {
        $blockHTML = $this-&gt;getLayout()-&gt;createBlock('cms/block')-&gt;setBlockId($this-&gt;getData("section$i"))-&gt;toHtml();
        $this-&gt;sectionArr[$i] = $blockHTML;
      }
    }
    return parent::_toHtml();
  }
}</pre>
<p>Let’s inspect the class from top to bottom.  The first thing to notice is that in the declaration it implements <strong>Mage_Widget_Block_Interface</strong>.  This is a requirement for Widgets.</p>
<p>Notice my constant <strong>MAXSECTIONS</strong> is set to 4, the same number of section parameters that I defined in widget.xml.  There’s probably some room for improvement here: one could probably figure out the number of parameters dynamically and then remove the constant.  That would make the widget more flexible for future uses.</p>
<p>I call the <strong>_construct</strong> function so that everything gets setup the way it’s supposed to.</p>
<p>Finally the real work gets done in <strong>_toHtml</strong>.  This function will be called automagically by Magento when it goes to render this object to the screen.</p>
<p>What I do is load up each block that gets passed into the widget and I stuff it’s HTML into an array element.  This way the widget can render any block, independently, by referencing a key in the array.</p>
<p>It’s not the classes job to do the rendering, that’s left to the presentation layer.  This class is just gathering everything that the presentation layer needs.</p>
<p>To move on with the tutorial we need to look back at our widget declaration in <strong>widget.xml</strong>.  I’m sure you noticed the last parameter <strong>template</strong> that I haven’t discussed yet.  Notice that the attribute <strong>visible</strong> is set to false.  What this parameter does is define the template that our widget is going to use for presentation.  My value is <strong>widgetglider/banner.phtml</strong> this template doesn’t exist by default so let’s create it.</p>
<p><strong>/app/design/frontend/default/spinonesolutions/template/widgetglider/banner.phtml</strong></p>
<pre class="php" name="code">&lt;style&gt;
.slideshow {
  position:relative;
}

.slideshow .items div {
  float:left;
  opacity:0.0;
  position:absolute;
  z-index:8;
}

.slideshow .items div.active {
  opacity:1.0;
  z-index:10;
}
&lt;/style&gt;

&lt;script&gt;
function slideSwitch() {
  var active = jQuery('.slideshow .items .active');
  // use this to pull the images in the order they appear in the markup
  var next =  jQuery(active).next().length ? jQuery(active).next() : jQuery('.slideshow .items div:first');
  jQuery(next).css({opacity: 0.0})
  .addClass('active')
  .animate({opacity: 1.0}, 1000, function() {
    jQuery(active).removeClass('active');
  });

  jQuery(active).animate({opacity:0.0}, 1000, function(){
  });
}

// execute your scripts when the DOM is ready. this is mostly a good habit
jQuery('document').ready(function() {
  var active = jQuery('.slideshow .items .active');
  if ( active.length == 0 ) {
    active = jQuery('.slideshow .items div:first');
    active.addClass('active').animate({opacity: 1.0}, 1000);
  }

  jQuery(function() {
    setInterval( "slideSwitch()", 5000 );
  });
});
&lt;/script&gt;
&lt;div class="slideshow"&gt;
  &lt;div class="items"&gt;
    &lt;?php foreach($this-&gt;sectionArr as $key =&gt; $section) { ?&gt;
    &lt;div class=""&gt;
      &lt;?php echo $section; ?&gt;
    &lt;/div&gt;
    &lt;?php } ?&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<p>The first part of that path is determined by the theme that you’ve set in Configuration.</p>
<p>Inspecting this file the real takeaway is simply the foreach loop.  All it does it loop over the array that was defined in the Business Layer and output the HTML stored in each element.  The template file does all the presentation.</p>
<p>The reason for doing things this way is that one can easily envision some department manager coming to you and asking for another, different, presentation of the same data for some other location of your website.  Since you’ve done a good job of separating your layers all you have to do is make a new .phtml file, and then change the <strong>template</strong> parameter of your <strong>widget.xml</strong> file and viola, you’ve got a new presentation of your data.</p>
<p>That does it for the code, all we need to do now is build a little demo using the interface.</p>
<p>Load up the admin and navigate to CMS -&gt; Static Blocks.  Create four static blocks and put an image file into each one.  If you hover your mouse over the row you’ll see the block_id.  Make note of these as you’ll need them for when you create the widget.  Mine are: 6,8,9,10.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/static-blocks.png"><img class="aligncenter size-medium wp-image-624" title="static-blocks" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/static-blocks-700x69.png" alt="static-blocks" width="700" height="69" /></a></p>
<p>Go to CMS -&gt; Pages and create a new CMS page to hold the widget.  Alternatively you could add the widget to a preexisting page.  Switch to the Content Tab.  Click the add Widget icon to add your widget.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/add-widget-button.png"><img class="aligncenter size-full wp-image-625" title="add-widget-button" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/add-widget-button.png" alt="add-widget-button" width="97" height="104" /></a></p>
<p>Choose your new widget from the dropdown menu.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-choose.png"><img class="aligncenter size-medium wp-image-626" title="insert-widget-choose" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-choose-700x356.png" alt="insert-widget-choose" width="700" height="356" /></a></p>
<p>Fill in the block_id(s) of your static blocks.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-filledin.png"><img class="aligncenter size-medium wp-image-627" title="insert-widget-filledin" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/insert-widget-filledin-700x360.png" alt="insert-widget-filledin" width="700" height="360" /></a></p>
<p>Hit Insert.</p>
<p>As a learning exercise click the “Show/HideEditor” button.</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/widget-markup.png"><img class="aligncenter size-medium wp-image-628" title="widget-markup" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/widget-markup-700x114.png" alt="widget-markup" width="700" height="114" /></a></p>
<p>Notice what was generated!  It should be pretty similar to what’s in your <strong>widget.xml</strong> file.  As the smart and curious type the you are also realize that you can change these parameters right here.  Thus the widget.xml file serves a template for your widget, which can be customized later to suit your specific needs.</p>
<p>Ok, save your CMS page.  That’s it!</p>
<p><a href="http://www.spinonesolutions.com/wp-content/uploads/2010/10/glider-demo.png"><img class="aligncenter size-medium wp-image-629" title="glider-demo" src="http://www.spinonesolutions.com/wp-content/uploads/2010/10/glider-demo-700x535.png" alt="glider-demo" width="700" height="535" /></a></p>
<p>You can see my <a title="Glider Demo" href="http://magento.spinonesolutions.com/glider-demo" target="_blank">demo here</a>.</p>
<p>As always, questions and comments welcomed!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/10/magento-custom-widget/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Magento Controller Override</title>
		<link>http://www.spinonesolutions.com/2010/03/magento-controller-override/</link>
		<comments>http://www.spinonesolutions.com/2010/03/magento-controller-override/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 16:00:11 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Custom]]></category>
		<category><![CDATA[Override]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=511</guid>
		<description><![CDATA[The Problem: You want to override a Controller&#8217;s action with a custom action. Magento Enterprise v1.6.0.0 The Solution: I ran into some issues trying to override a controller&#8217;s action yesterday. I think it mainly stems from a version change, but at any rate here&#8217;s the &#8220;new&#8221; way to do it. This comes from a helpful [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You want to override a Controller&#8217;s action with a custom action.</p>
<p>Magento Enterprise v1.6.0.0</p>
<h3>The Solution:</h3>
<p>I ran into some issues trying to override a controller&#8217;s action yesterday. I think it mainly stems from a version change, but at any rate here&#8217;s the &#8220;new&#8221; way to do it. This comes from a helpful <a href="http://www.magentocommerce.com/boards/viewthread/37244/">post</a> on the Magento forums.</p>
<p>In this example my custom modules&#8217;s namespace is &#8220;Spinonesolutions&#8221; and I&#8217;m going to override the <strong>createPostAction</strong> in <strong>Mage_Customer_AccountController.</strong></p>
<p>Start by creating a bare bones custom module; if you don&#8217;t know how to do this check out <a title="Magento – Part I : Custom Module" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/">Magento – Part I : Custom Module</a>.</p>
<p>I&#8217;ve only got two files in my custom module; <strong>controllers/AccountController.php</strong> and <strong>etc/config.xml</strong>.</p>
<p>config.xml:</p>
<pre class="php" name="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;config&gt;
&lt;modules&gt;
  &lt;Spinonesolutions_Customer&gt;
    &lt;version&gt;0.0.1&lt;/version&gt;
  &lt;/Spinonesolutions_Customer&gt;
&lt;/modules&gt;
&lt;frontend&gt;
  &lt;routers&gt;
    &lt;!-- This is the frontname to override
    EG: http://mydomainname.com/customer/  --&gt;
    &lt;customer&gt;
      &lt;args&gt;
        &lt;modules&gt;
          &lt;!-- Use the module Spinonesolutions_Customer BEFORE Mage_Customer --&gt;
          &lt;Spinonesolutions_Customer before="Mage_Customer"&gt;Spinonesolutions_Customer&lt;/Spinonesolutions_Customer&gt;
        &lt;/modules&gt;
      &lt;/args&gt;
    &lt;/customer&gt;
  &lt;/routers&gt;
&lt;/frontend&gt;
&lt;/config&gt;</pre>
<p>AccountController.php:</p>
<pre class="php" name="code">&lt;?php
/**
* Override Customer AccountController
*
* Override the createPost action
*
* @category Mage
* @package Mage_Customer
* @author Will Wright
*/

/*Controllers aren't included automatically, so we include it here so that we can extend it*/
include_once("Mage/Customer/controllers/AccountController.php");
class Spinonesolutions_Customer_AccountController extends Mage_Customer_AccountController {
  public function createPostAction() {
    die('here');
  }
}</pre>
<p>That&#8217;s it!  You should now have a working override.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/03/magento-controller-override/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Magento Partial Refund Amount Correction for Authorize.net</title>
		<link>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/</link>
		<comments>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 22:04:48 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Model]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/2009/11/partial-refund-amount-correction-for-authorize-net/</guid>
		<description><![CDATA[The Problem: You&#8217;ve enabled partial refunds in the Authorizenet Model, but it&#8217;s not refunding the proper amounts.  This is due to, in my view, a bug in the core which I&#8217;ll show you how to patch! The Solution: What you need to do is overload the refund method in the Authorizenet model. Create a new [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem:</h3>
<p>You&#8217;ve enabled partial refunds in the Authorizenet Model, but it&#8217;s not refunding the proper amounts.  This is due to, in my view, a bug in the core which I&#8217;ll show you how to patch!</p>
<h3>The Solution:</h3>
<p>What you need to do is overload the <strong>refund</strong> method in the Authorizenet model.</p>
<p>Create a new model that extends the original Authorizenet model.  You&#8217;ll need to follow the general instructions for how to <a title="Magento Custom Module Part I" href="http://www.spinonesolutions.com/2009/09/magento-custom-module-part-i/" target="_blank">create a custom module</a> if you don&#8217;t already know how to do so.</p>
<pre class="php" name="code">
class Spinonesolutions_General_Model_Paygate_Authorizenet extends Mage_Paygate_Model_Authorizenet {
//Override Mage_Paygate_Model_Authorizenet

protected $_canRefund = true;

public function refund(Varien_Object $payment, $amount) {
  $error = false;
  if ($payment-&gt;getRefundTransactionId() &amp;&amp; $amount&gt;0) {
    $payment-&gt;setAnetTransType(self::REQUEST_TYPE_CREDIT);
    $request = $this-&gt;_buildRequest($payment, $amount);
    $request-&gt;setXTransId($payment-&gt;getRefundTransactionId());
    $result = $this-&gt;_postRequest($request);
    if ($result-&gt;getResponseCode()==self::RESPONSE_CODE_APPROVED) {
      $payment-&gt;setStatus(self::STATUS_SUCCESS);
    } else {
      $error = $result-&gt;getResponseReasonText();
    }
  } else {
    $error = Mage::helper('paygate')-&gt;__('Error in refunding the payment');
  }

  if ($error !== false) {
    Mage::throwException($error);
  }

  return $this;
}
}</pre>
<p>Now all we need to do is let Magento know that we&#8217;ve got a custom model.  In config.xml add</p>
<pre class="xml" name="code">
&lt;?xml version="1.0"?&gt;
&lt;config&gt;
  &lt;modules&gt;
    &lt;Spinonesolutions_General&gt;
      &lt;version&gt;0.0.1&lt;/version&gt;
    &lt;/Spinonesolutions_General&gt;
  &lt;/modules&gt;
  &lt;global&gt;
    &lt;models&gt;
      ...
      &lt;paygate&gt;
        &lt;rewrite&gt;
          &lt;authorizenet&gt;Imagistic_General_Model_Paygate_Authorizenet&lt;/authorizenet&gt;
        &lt;/rewrite&gt;
      &lt;/paygate&gt;
      ...
    &lt;/models&gt;
  &lt;/global&gt;
&lt;/config&gt;
</pre>
<p>That should do it!  Questions and comments welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/01/partial-refund-amount-correction-for-authorize-net/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Custom Magento Grid with Ambiguous Column on Filter</title>
		<link>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/</link>
		<comments>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 17:14:58 +0000</pubDate>
		<dc:creator>Will Wright</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.spinonesolutions.com/?p=486</guid>
		<description><![CDATA[The Problem You&#8217;ve built a custom grid and the source collection has an ambiguous column in the where clause when applying a filter. The Solution I recently ran into this problem while I was building a custom grid.  The situation should be familiar to many of you.  I have a custom table storing addresses; for the [...]]]></description>
			<content:encoded><![CDATA[<h3>The Problem</h3>
<p>You&#8217;ve built a custom grid and the source collection has an ambiguous column in the where clause when applying a filter.</p>
<h3>The Solution</h3>
<p>I recently ran into this problem while I was building a custom grid.  The situation should be familiar to many of you.  I have a custom table storing addresses; for the region and country I store a region_id and country_id, respectively.  For display of the grid however I want to do a lookup to show the user the friendly names for both region and country.  To accomplish that I do an inner join on the original collection which yields the full dataset.</p>
<p>However, this also introduces a douplicate column into the collection which was causeing an ambigous column error in my SQL statement whenever I applied a filter (a WHERE clause).  Lets take a look at an example.</p>
<p>My tables:</p>
<p><span style="text-decoration: underline;">retailer</span></p>
<ul>
<li>id</li>
<li>street</li>
<li>city</li>
<li>postcode</li>
<li>country_id</li>
<li>region_id</li>
</ul>
<p><span style="text-decoration: underline;">directory_country_region</span></p>
<ul>
<li>region_id</li>
<li>country_id</li>
<li>code</li>
<li>default_name</li>
</ul>
<p>Now lets take a look at my <strong>_prepareCollection</strong> method.</p>
<pre class="php" name="code">
protected function _prepareCollection() {
  $collection = Mage::getResourceModel('spinonesolutions_storelocator/retailer_collection');
  $collection-&gt;getSelect()
    -&gt;join(array('dcr' =&gt; 'directory_country_region'),'dcr.region_id = main_table.region_id')
    -&gt;reset(Zend_Db_Select::COLUMNS)
    -&gt;columns(array('id','name','street','city','country_id'))
    -&gt;columns(array('default_name'),'dcr');
  $this-&gt;setCollection($collection);
  return parent::_prepareCollection();
}</pre>
<p>This will result in a collection containing all the data that I need for a friendly presentation.  However, if I want to filter by country_id (which I do!) then I&#8217;m going to get an ambiguous column error in my SQL if I simply add &#8220;WHERE country_id = ?&#8221;.  That&#8217;s because country_id is in both tables.</p>
<p>The solution is the &#8220;filter_index&#8221; property.  Here&#8217;s a snippet from <strong>_prepareColumns</strong> which generates the country column and uses filter_index.</p>
<pre class="php" name="code">
$this-&gt;addColumn('country_id', array(
  'header' =&gt; Mage::helper('spinonesolutions_storelocator')-&gt;__('Country'),
  'width' =&gt; '100px',
  'index' =&gt; 'country_id',
  'filter_index' =&gt; 'main_table.country_id',
  'type' =&gt; 'country', ));
</pre>
<p>Now when the SQL statement is generated the ambiguous column error will be fixed since I&#8217;ve provided enough specificity.  Simple!</p>
<p>Questions and comments welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.spinonesolutions.com/2010/01/custom-magento-grid-with-ambiguous-column-on-filter/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

