<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Levihackwith.com</title>
	
	<link>http://www.levihackwith.com</link>
	<description>The Life of Levi Hackwith</description>
	<lastBuildDate>Sun, 13 May 2012 12:27:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/levihackwith" /><feedburner:info uri="levihackwith" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>This is An Invocation</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/qFQMRJMDRCE/</link>
		<comments>http://www.levihackwith.com/this-is-an-invocation/#comments</comments>
		<pubDate>Sat, 12 May 2012 23:04:35 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=138</guid>
		<description><![CDATA[Sometimes I sit back and wonder what the hell I&#8217;m doing with my career. As a web professional, I&#8217;m surrounded by people who ooze creativity, whose talents and ideas are readily packaged and dispersed for the enjoyment and consumption of millions around the world. It&#8217;s in these moments that I find myself doubting what I [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes I sit back and wonder what the hell I&#8217;m doing with my career. As a web professional, I&#8217;m surrounded by people who ooze creativity, whose talents and ideas are readily packaged and dispersed for the enjoyment and consumption of millions around the world. It&#8217;s in these moments that I find myself doubting what I know, overwhelmed by what I don&#8217;t, and horribly envious of those who appear to have it all figured out. Sometimes I feel like I don&#8217;t belong. Sometimes I feel like I should stay where I&#8217;m at in my career in an attempt to hide where I&#8217;m not.<span id="more-138"></span></p>
<p>As I reflect on these feelings, I realize that I just need to get off my ass and create, produce. I&#8217;ve got a head full of ideas that I need to get out into the public view, not so they can be lauded and cheered, but so they can be judged and measured. Some of these ideas will have already been executed by others in a manner better than I could have ever dreamed. Other ideas will fall flat, unable to resonate with anyone but myself. Most ideas will fail due to poor execution or general sucky-ness and be scorned by those unlucky enough to stumble upon them. However, despite the risk or rejection or failure, I&#8217;ve decided that I will no longer sit on my ideas, artificially perfecting them in my brain like some kind of mental purgatory, that phase where they&#8217;re ready for the world forever <em>just</em> out of reach. My ideas, as soon as they hit my head, will go here on this website to be viewed by as many people as possible. Will this site still be about web development and design? Sure, but not because I desire some kind of weird programmer fame and glory &#8211; I don&#8217;t think that&#8217;s the right motivation for anything, really. Instead, this site is going to be about web development because that&#8217;s what I happen to enjoy doing with most of my time. If that changes, well, you&#8217;ll learn about it here first.</p>
<p>So with all this in mind, here&#8217;s my idea for &#8220;The Web Developer&#8217;s Invocation&#8221;:</p>
<blockquote><p>
May I not get consumed by typography and web fonts. May I not obsess over pixel-perfect layouts or CSS selectors. May I not get caught in arguments about language or syntax. Let me instead be consumed with the desire to make this Internet a better place; to bring creative, exciting people together to create stuff and do things that are awesome.
</p></blockquote>
<p>I thought it was neat. I may change it later. If you have suggestions, please comment. </p>
<p>And with that, <a title="Let's start this shit up" href="http://www.youtube.com/watch?feature=player_embedded&amp;v=RYlCVwxoL_g">let&#8217;s start this shit up.</a></p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/qFQMRJMDRCE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/this-is-an-invocation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/this-is-an-invocation/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Uncaught TypeError: Cannot call method ‘substring’ of undefined ext-all-debug line 4384</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/2b-yE12X-Rc/</link>
		<comments>http://www.levihackwith.com/extjs-4-uncaught-typeerror-cannot-call-method-substring-of-undefined-ext-all-debug-line-4384/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 06:00:13 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Lessons Learned]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=130</guid>
		<description><![CDATA[When working with ExtJS 4, you'll often run into ambiguous error message like this one:

Uncaught TypeError: Cannot call method 'substring' of undefined

ext-all-debug.js line 4384

I recently ran into this while coding up an Ext application for another blog post, and I thought I'd share with you its root cause and solution.]]></description>
			<content:encoded><![CDATA[<p>When working with ExtJS 4, you&#8217;ll often run into ambiguous error message like this one:</p>
<blockquote><p>Uncaught TypeError: Cannot call method &#8216;substring&#8217; of undefined</p></blockquote>
<p><cite> ext-all-debug.js line 4384</cite></p>
<p>I recently ran into this while coding up an Ext application for another blog post, and I thought I&#8217;d share with you its root cause and solution.</p>
<p><span id="more-130"></span></p>
<p>If you head straight to the line number in question, you&#8217;ll find yourself somewhere in the middle of the <code>parseNamespace</code> method of Ext&#8217;s ClassManager object and you&#8217;ll notice that the parameter that the method expects (<code>namespace</code>) is undefined, causing the method to throw an error. However if you look a little deeper in the callstack, you&#8217;ll notice that the <code>instantiateByAlias</code> method was called just before <code>parseNamespace</code>:.</p>
<pre class="brush: jscript; title: ; notranslate">
instantiateByAlias: function() {
    var alias = arguments[0],
        args = arraySlice.call(arguments),
        className = this.getNameByAlias(alias);

    if (!className) {
        className = this.maps.aliasToName[alias];

        Ext.syncRequire(className);
    }

    args[0] = className;

    return this.instantiate.apply(this, args);
}
</pre>
<p>If you place a breakpoint in this method and run the application again, you&#8217;ll be able to watch it load each Ext class (as well as your application&#8217;s custom components) by its xtype alias. Eventually, it attempt to load one of your application&#8217;s classes and then crash.</p>
<p>The reason for this crash is because you&#8217;ve most likely misspelled the alias of that component while referencing it in another component. Take a look at my grid code:</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.define('App.view.person.Grid', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.persongrid',
    title: 'People',
    columns: [{
        header: 'ID',
        dataIndex: 'id'
    }, {
        header: 'First Name',
        dataIndex: 'first_name'
    }, {
        header: 'Last Name',
        dataIndex: 'last_name'
    }, {
        header: 'Address',
        dataIndex: 'address'
    }, {
        header: 'City',
        dataIndex: 'city'
    }, {
        header: 'State',
        dataIndex: 'state'
    }, {
        header: 'Zip Code',
        dataIndex: 'zip_code'
    }]
});
</pre>
<p>Now take a look at my viewport code:</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.define('App.view.Viewport', {
    extend: 'Ext.container.Viewport',
    config: {
        items: [{
            xtype: 'peoplegrid',
            store: 'People'
        }]
    }
});
</pre>
<p>See how I referenced my Person grid view by the alias <code>peoplegrid</code> in the viewport file but I declared the alias to be <code>persongrid</code> in the grid file? That&#8217;s what&#8217;s causing the JavaScript error. So, the moral of the story is: If you get obscure errors about strings being undefined in ExtJS 4, <em>always</em> check deeper in the callstack (not just the line-number in question) and <em>always</em> double-check your xtype aliases across your application.</p>
<p>Hope this helps.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/2b-yE12X-Rc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-uncaught-typeerror-cannot-call-method-substring-of-undefined-ext-all-debug-line-4384/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-uncaught-typeerror-cannot-call-method-substring-of-undefined-ext-all-debug-line-4384/</feedburner:origLink></item>
		<item>
		<title>Order Your Methods to Add Clarity to Your Code</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/N8t5rKn9j7Q/</link>
		<comments>http://www.levihackwith.com/order-your-methods-to-add-clarity-to-your-code/#comments</comments>
		<pubDate>Mon, 30 Jan 2012 06:00:39 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[Clean Code]]></category>
		<category><![CDATA[Code Formatting]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Robert Martin]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=126</guid>
		<description><![CDATA[In general we want function call dependencies to point in the downward direction. That is, a function that is called should be below a function that does the calling.2This creates a nice flow down the source code module from high level to low level.]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve been reading <em><a title="View Clean Code (KIndle Edition) On Amazon.com " href="http://www.amazon.com/Clean-Code-Handbook-Craftsmanship-ebook/dp/B001GSTOAM/ref=tmm_kin_title_0?ie=UTF8&amp;m=AG56TWVU5XWC2" target="_blank">Clean Code</a></em> by Robert C Martin and come across this wonderful piece of programming advice from Chapter 5:</p>
<blockquote cite="Martin, Robert C. (2011-11-11). Robert C. Martin Clean Code Collection, The (Kindle Locations 2580-2585). Pearson Education (USA). Kindle Edition."><p>In general we want function call dependencies to point in the downward direction. That is, a function that is called should be below a function that does the calling.<sup>2</sup>This creates a nice flow down the source code module from high level to low level.</p>
<p>As in newspaper articles, we expect the most important concepts to come first, and we expect them to be expressed with the least amount of polluting detail. We expect the low-level details to come last. This allows us to skim source files, getting the gist from the first few functions, without having to immerse ourselves in the details.</p></blockquote>
<p><span id="more-126"></span><br />
When I first read this, I was just stunned. During my career I&#8217;ve encountered (and written) classes that were very difficult to read and follow despite their methods being well-written and documented. It wasn&#8217;t until I&#8217;d discovered this piece of coding advice, that  I understood why.</p>
<p>To illustrate the point Mr. Martin is trying to make, let&#8217;s take a look at an example class I put together:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?
class SalesReport {

    private $startDate = '';
    private $endDate = '';
    private $salesQuarter = 0;
    private $salesTeamMembers = array();

    public function setEndDate($date) {
        $this-&gt;endDate = $date;
    }

    public function __construct() {

    }

    public function setStartDate($date) {
        $this-&gt;startDate = $date;
    }

    public function setSalesTeamMembers($teamMemberIds) {
        if(is_array($teamMemberIds)) {
            $this-&gt;salesTeamMembers = $teamMemberIds;
        } else {
            throw new Exception('SalesReport::setSalesTeamMembers only accepts an array of team member ids');
        }
    }

    public function generateReportQueryLimitClause() {
        // Generate Limit clause
    }

    public function generate() {
        $whereClause = $this-&gt;generateReportQueryWhereClause();
        $orderByClause = $this-&gt;generateReportQueryOrderByClause();
        $limitClause = $this-&gt;generateReportQueryLimitClause();
        $query = &quot;
            SELECT
                /* Field Listing */
            FROM
                sales
            $whereClause
            $orderByClause
            $limitClause
        &quot;;
        // execute query
        return TRUE;
    }

    public function generateReportQueryWhereClause() {
        // Generate WHERE clause based on report selection criteria
    }

    public function generateReportQueryOrderByClause() {
        // Generate ORDER BY clause
    }

    public function load() {
        // Load report results from temporary table
    }

    public function setSalesQuarter($salesQuarter) {
        if(is_int($salesQuarter)) {
            $this-&gt;salesQuarter = $salesQuarter;
        } else {
            throw new Exception('Sales Quarter must be an integer');
        }
    }

}
?&gt;
</pre>
<p>Take a glance at the above class. Do you notice how your eyes have to keep jumping around the class in order to follow what&#8217;s going on? By having the methods randomly scattered throughout the code, you really have to focus in on (and possibly get lost in) the details of the code.  Now let&#8217;s rearrange the methods of the class to more closely match the order in which things are called and referenced:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?
class SalesReport {

    private $startDate = '';
    private $endDate = '';
    private $salesQuarter = 0;
    private $salesTeamMembers = array();

    public function __construct() {

    }

    public function setEndDate($date) {
        $this-&gt;endDate = $date;
    }

    public function setStartDate($date) {
        $this-&gt;startDate = $date;
    }

    public function setSalesQuarter($salesQuarter) {
        if(is_int($salesQuarter)) {
            $this-&gt;salesQuarter = $salesQuarter;
        } else {
            throw new Exception('Sales Quarter must be an integer');
        }
    }

    public function setSalesTeamMembers($teamMemberIds) {
        if(is_array($teamMemberIds)) {
            $this-&gt;salesTeamMembers = $teamMemberIds;
        } else {
            throw new Exception('SalesReport::setSalesTeamMembers only accepts an array of team member ids');
        }
    }

    public function generate() {
        $whereClause = $this-&gt;generateReportQueryWhereClause();
        $orderByClause = $this-&gt;generateReportQueryOrderByClause();
        $limitClause = $this-&gt;generateReportQueryLimitClause();
        $query = &quot;
            SELECT
                /* Field Listing */
            FROM
                sales
            $whereClause
            $orderByClause
            $limitClause
        &quot;;
        // execute query
        return TRUE;
    }

    public function generateReportQueryWhereClause() {
        // Generate WHERE clause based on report selection criteria
    }

    public function generateReportQueryOrderByClause() {
        // Generate ORDER BY clause
    }

    public function generateReportQueryLimitClause() {
        // Generate Limit clause
    }

    public function load() {
        // Load report results from temporary table
    }
}
?&gt;
</pre>
<p>See the difference? Notice how the code naturally flows from one method to the next, allowing you to quickly ascertain what the class is doing and when it&#8217;s doing it. By ordering the methods so the calling method (caller) is declared before the method being called (callee), you drastically increase your code&#8217;s readability.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/N8t5rKn9j7Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/order-your-methods-to-add-clarity-to-your-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/order-your-methods-to-add-clarity-to-your-code/</feedburner:origLink></item>
		<item>
		<title>New GitHub Account and a Request for Help</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/PF60QNyW2SM/</link>
		<comments>http://www.levihackwith.com/new-github-account-and-a-request-for-help/#comments</comments>
		<pubDate>Wed, 12 Oct 2011 03:09:30 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=122</guid>
		<description><![CDATA[Recently, I&#8217;ve been getting a lot of comments on my blog post ExtJS 4: Combo Boxes, loadRecord() and Remote Stores that have offered some really great feedback including a lot of suggestions for changes that should be made. Unfortunately, I haven&#8217;t had the time to integrate any of the suggested fixes. At the same time, I [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been getting a lot of comments on my blog post <a title="ExtJS 4: Combo Boxes, loadRecord() and Remote Stores" href="http://www.levihackwith.com/extjs-4-combo-boxes-loadrecord-and-remote-stores/">ExtJS 4: Combo Boxes, loadRecord() and Remote Stores</a> that have offered some really great feedback including a lot of suggestions for changes that should be made. Unfortunately, I haven&#8217;t had the time to integrate any of the suggested fixes. At the same time, I don&#8217;t like having code that doesn&#8217;t work quite right and help the community.</p>
<p>To alleviate this problem, I&#8217;ve create a <a title="OpnSrce's Github " href="https://github.com/opnsrce" target="_blank">GitHub Account</a> and created a repository just for the <a title="Code Snippets Repository" href="https://github.com/opnsrce/Code-Snippets" target="_blank">code snippets I put on this site</a>. I encourage you to take a look at what I&#8217;ve got in there (more will be added soon) and see if you can make any improvements. Feel free to fork, comment and commit to your heart&#8217;s content. I&#8217;d really appreciate it.</p>
<p>Thanks again for all of your comments and support. I look forward to seeing what you can do!</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/PF60QNyW2SM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/new-github-account-and-a-request-for-help/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/new-github-account-and-a-request-for-help/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Parsing Filters From the FilterFeature Using PHP</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/wjkHAsy_dQE/</link>
		<comments>http://www.levihackwith.com/extjs-4-parsing-filters-from-the-filterfeature-using-php/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 08:07:24 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[Filter]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=112</guid>
		<description><![CDATA[I wrote this method a few weeks ago and though I&#8217;d share it. It parses ExtJS filters sent in by the FilterFeature. You can view examples of using the FilterFeature in ExtJS 4 on the ExtJS 4 examples page for grid filtering. Update: The source code for this snippet is available here.]]></description>
			<content:encoded><![CDATA[<p>I wrote this method a few weeks ago and though I&#8217;d share it. It parses ExtJS filters sent in by the FilterFeature.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?
function parseExtJSFilters() {
    if(!isset($_GET['filter') { // No filter passed in
        return FALSE;
    }
    $filters = json_decode($_GET['filter']); // Decode the filter
    if($filters == NULL) { // If we couldn't decode the filter
        return FALSE;
    }
    $whereClauses = array(); // Stores whereClauses
    foreach($filters as $filter) {
        switch($filter-&gt;type) {
            case 'boolean':
                $filter-&gt;value = ($filter-&gt;value === TRUE) ? '1' : '0'; // Convert value for DB
                $whereClauses[] = &quot;$filter-&gt;field = $filter-&gt;value&quot; ;
                break;
            case 'date':
                $filter-&gt;value = &quot;'$filter-&gt;value'&quot;; // Enclose data in quotes
            case 'numeric':
                switch($filter-&gt;comparison) {
                    case 'lt': // Less Than
                        $whereClauses[] = &quot;$filter-&gt;field &lt; $filter-&gt;value&quot;;
                        break;
                    case 'gt': // Greather Than
                        $whereClauses[] = &quot;$filter-&gt;field &gt; $filter-&gt;value&quot;;
                        break;
                    case 'eq': // Equal To
                        $whereClauses[] = &quot;$filter-&gt;field = $filter-&gt;value&quot;;
                        break;
                }
                break;
            case 'list':
                $listItems = array();
                foreach($filter-&gt;value as $value) {
                    $listItems[] = &quot;'$value'&quot;;
                }
                $whereClauses[] = &quot;$filter-&gt;field IN(&quot; . implode(',', $listItems) . ')';
                break;
            case 'string':
            default: // Assume string
                $whereClauses[] = &quot;(
                    $filter-&gt;field LIKE '{$filter-&gt;value}%' OR
                    $filter-&gt;field LIKE '%{$filter-&gt;value}' OR
                    $filter-&gt;field LIKE '%{$filter-&gt;value}%' OR
                    $filter-&gt;field = '{$filter-&gt;value}'
                )&quot;;
                break;
        }
    }
    if(count($whereClauses) &gt; 0) {
        return implode(' AND ', $whereClauses);
    }
    return FALSE;
}
?&gt;&lt;?
function parseExtJSFilters() {
    if(!isset($_GET['filter') { // No filter passed in
        return FALSE;
    }
    $filters = json_decode($_GET['filter']); // Decode the filter
    if($filters == NULL) { // If we couldn't decode the filter
        return FALSE;
    }
    $whereClauses = array(); // Stores whereClauses
    foreach($filters as $filter) {
        switch($filter-&gt;type) {
            case 'boolean':
                $filter-&gt;value = ($filter-&gt;value === TRUE) ? '1' : '0'; // Convert value for DB
                $whereClauses[] = &quot;$filter-&gt;field = $filter-&gt;value&quot; ;
                break;
            case 'date':
                $filter-&gt;value = &quot;'$filter-&gt;value'&quot;; // Enclose data in quotes
            case 'numeric':
                switch($filter-&gt;comparison) {
                    case 'lt': // Less Than
                        $whereClauses[] = &quot;$filter-&gt;field &lt; $filter-&gt;value&quot;;
                        break;
                    case 'gt': // Greather Than
                        $whereClauses[] = &quot;$filter-&gt;field &gt; $filter-&gt;value&quot;;
                        break;
                    case 'eq': // Equal To
                        $whereClauses[] = &quot;$filter-&gt;field = $filter-&gt;value&quot;;
                        break;
                }
                break;
            case 'list':
                $listItems = array();
                foreach($filter-&gt;value as $value) {
                    $listItems[] = &quot;'$value'&quot;;
                }
                $whereClauses[] = &quot;$filter-&gt;field IN(&quot; . implode(',', $listItems) . ')';
                break;
            case 'string':
            default: // Assume string
                $whereClauses[] = &quot;(
                    $filter-&gt;field LIKE '{$filter-&gt;value}%' OR
                    $filter-&gt;field LIKE '%{$filter-&gt;value}' OR
                    $filter-&gt;field LIKE '%{$filter-&gt;value}%' OR
                    $filter-&gt;field = '{$filter-&gt;value}'
                )&quot;;
                break;
        }
    }
    if(count($whereClauses) &gt; 0) {
        return implode(' AND ', $whereClauses);
    }
    return FALSE;
}
?&gt;
</pre>
<p>
You can view examples of using the <a href="http://dev.sencha.com/deploy/ext-4.0.2a/examples/grid-filtering/grid-filter-local.html" target="_blank">FilterFeature in ExtJS 4 on the ExtJS 4 examples page for grid filtering.</a>
</p>
<p>
<strong>Update: </strong>The source code for this snippet is available <a href="https://github.com/opnsrce/Code-Snippets/commit/96847c4b5177fc49bacba6aa1716b88accdb2082#diff-2">here</a>.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/wjkHAsy_dQE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-parsing-filters-from-the-filterfeature-using-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-parsing-filters-from-the-filterfeature-using-php/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Passing Filters Between a Grid and a Chart Store</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/zYLOEhgCOfM/</link>
		<comments>http://www.levihackwith.com/extjs-4-passing-filters-between-a-grid-and-a-chart-store/#comments</comments>
		<pubDate>Sun, 02 Oct 2011 21:16:42 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[Charting]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[filtering]]></category>
		<category><![CDATA[stores]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=107</guid>
		<description><![CDATA[In preparation for another round of Envato screencasts, I&#8217;ve been messing around with the new Charting API that comes with ExtJS 4. For this project, I wanted to show how you can filter a grid full of data and have it change the data in the pie chart. Unfortunately, I soon discovered that pie charts [...]]]></description>
			<content:encoded><![CDATA[<p>In preparation for another round of Envato screencasts, I&#8217;ve been messing around with the new Charting API that comes with ExtJS 4. For this project, I wanted to show how you can filter a grid full of data and have it change the data in the pie chart. Unfortunately, I soon discovered that pie charts (or rather, charts in general) and data grids take two different types of data. <span id="more-107"></span>For example: here&#8217;s the JSON response for the store that runs my pie chart:</p>
<pre class="brush: jscript; title: ; notranslate">
[
    {
        &quot;favorite_color&quot;: &quot;blue&quot;,
        &quot;total&quot;: &quot;48&quot;,
        &quot;percentage&quot;: &quot;12&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;green&quot;,
        &quot;total&quot;: &quot;53&quot;,
        &quot;percentage&quot;: &quot;13&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;orange&quot;,
        &quot;total&quot;: &quot;56&quot;,
        &quot;percentage&quot;: &quot;14&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;pink&quot;,
        &quot;total&quot;: &quot;59&quot;,
        &quot;percentage&quot;: &quot;15&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;red&quot;,
        &quot;total&quot;: &quot;38&quot;,
        &quot;percentage&quot;: &quot;10&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;violet&quot;,
        &quot;total&quot;: &quot;45&quot;,
        &quot;percentage&quot;: &quot;11&quot;
    },
    {
        &quot;favorite_color&quot;: &quot;yellow&quot;,
        &quot;total&quot;: &quot;101&quot;,
        &quot;percentage&quot;: &quot;25&quot;
    }
]
</pre>
<p>
For a pie chart, your store needs to have two main things: a field that the pie chart&#8217;s labeling system will use (e.g., &#8216;favorite_color&#8217;) and a field that the pie chart&#8217;s series will use (e.g., &#8216;total&#8217;). As you can see from the feature image, the pie chart uses the <code>favorite_color</code> and <code>total</code> fields to display the data in the correct proportions. Now let&#8217;s look at a single record from the JSON response for the data grid:
</p>
<pre class="brush: jscript; title: ; notranslate">
    {
        &quot;id&quot;: &quot;50&quot;,
        &quot;first_name&quot;: &quot;Wynne&quot;,
        &quot;last_name&quot;: &quot;Aguilar&quot;,
        &quot;age&quot;: &quot;94&quot;,
        &quot;gender&quot;: &quot;2&quot;,
        &quot;hair_color&quot;: &quot;Other&quot;,
        &quot;eye_color&quot;: &quot;Hazel&quot;,
        &quot;state&quot;: &quot;ND&quot;,
        &quot;favorite_color&quot;: &quot;yellow&quot;,
        &quot;car_model&quot;: &quot;Toyota&quot;,
        &quot;housing_type&quot;: &quot;Mobile Home&quot;,
        &quot;marriage_status&quot;: &quot;Single&quot;,
        &quot;has_pets&quot;: &quot;1&quot;,
        &quot;num_children&quot;: &quot;10&quot;
    }
</pre>
<p>
As you can see from the drastic difference between the two data stores, if we tried to power the grid and the pie chart from the same store, neither would render correctly; the pie chart wouldn&#8217;t have a field to calculate it&#8217;s segment sizes with and the grid wouldn&#8217;t have any of the fields it&#8217;s expecting through the column model. Long story short, there&#8217;s no way to tie the grid&#8217;s data to the pie chart (or vice versa) without causing serious issues.
</p>
<p>
To get around this limitation, we need to simultaneously filter both stores at the same time. Here&#8217;s the controller for both the grid and the pie chart:
</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.define('App.controller.People', {
    extend: 'Ext.app.Controller',
    models: [
        'Person',
    ],
    stores: [
        'people.People',
        'people.FavoriteColorCounts'
    ],
    views:[
        'person.Grid',
        'chart.FavoriteColorPieChart'
    ],
    refs: [{
        ref: 'favoriteColorPieChart',
        selector: 'favoritecolorpiechart'
    }, {
        ref: 'personGrid',
        selector: 'persongrid'
    }],
    init: function() {
        this.getPeoplePeopleStore().on(
            'load',
            function(store, records, successful, operation, options) {
                var filters;
                var gridFilterFeature = this.getPersonGrid().filters;
                    filters = gridFilterFeature.buildQuery(gridFilterFeature.getFilterData());
                this.getPeopleFavoriteColorCountsStore().load({
                   params: {
                       filter: filters
                   }
                });
            },
            this
        )
        this.callParent(arguments)
    }
});
</pre>
<p>
There&#8217;s a lot going on there, but we really need to only focus on the <code>init</code> method:
</p>
<pre class="brush: jscript; title: ; notranslate">
...
    init: function() {
        this.getPeoplePeopleStore().on(
            'load',
            function(store, records, successful, operation, options) {
                var filters;
                var gridFilterFeature = this.getPersonGrid().filters;
                    filters = gridFilterFeature.buildQuery(gridFilterFeature.getFilterData());
                this.getPeopleFavoriteColorCountsStore().load({
                   params: {
                       filter: filters
                   }
                });
            },
            this
        )
        this.callParent(arguments)
    }
</pre>
<p>
Let&#8217;s break it down:
</p>
<pre class="brush: jscript; title: ; notranslate">
...
        this.getPeoplePeopleStore().on(
            'load',
            function(store, records, successful, operation, options) {
...
</pre>
<p> Here, we&#8217;re adding a listener to the <code>load</code> event of the <code>people.People</code> store.</p>
<pre class="brush: jscript; title: ; notranslate">
...
          var filters;
          var gridFilterFeature = this.getPersonGrid().filters;
          filters = gridFilterFeature.buildQuery(gridFilterFeature.getFilterData());
          this.getPeopleFavoriteColorCountsStore().load({
              params: {
                  filter: filters
              }
...
</pre>
<p>
Here, we&#8217;re grabbing the filters from the grid we want to use on the pie chart&#8217;s store, rebuilding them into a JSON string using <code>buildQuery</code> and then reloading the pie chart&#8217;s store while passing in the filters.
</p>
<p>
Well, I hope that helps someone out because God knows I wasted fours of my life figuring it out.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/zYLOEhgCOfM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-passing-filters-between-a-grid-and-a-chart-store/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-passing-filters-between-a-grid-and-a-chart-store/</feedburner:origLink></item>
		<item>
		<title>Envato Extras and a New Portfolio Item</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/qv_an7t2ppA/</link>
		<comments>http://www.levihackwith.com/envato-extras-and-a-new-portfolio-item/#comments</comments>
		<pubDate>Sun, 14 Aug 2011 19:29:58 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Envato]]></category>
		<category><![CDATA[Sencha Touch]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=101</guid>
		<description><![CDATA[Recently, Envato announced a new website: Envato Extras. The purpose of this site is to showcase applications, tools and utilities that people have built using the Envato API. A while back, I created a simple mobile app using Sencha Touch that used the Envato API to grab popular items from the Audio Jungle website and [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, Envato announced a new website: <a href="http://extras.envato.com" target="_blank">Envato Extras</a>. The purpose of this site is to showcase applications, tools and utilities that people have built using the Envato API. A while back, I created a simple mobile app using Sencha Touch that used the Envato API to grab popular items from the Audio Jungle website and display them in a mobile friendly list. You can <a href="http://extras.envato.com/web-apps/audio-jungle-most-popular-items-app/" target="_blank">check out the application</a> on the Envato Extras website or you can head over to my portfolio and view the item there.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/qv_an7t2ppA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/envato-extras-and-a-new-portfolio-item/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/envato-extras-and-a-new-portfolio-item/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Combo Boxes, loadRecord() and Remote Stores</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/kuugDK8A2ls/</link>
		<comments>http://www.levihackwith.com/extjs-4-combo-boxes-loadrecord-and-remote-stores/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 05:00:38 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[combo box]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[override]]></category>
		<category><![CDATA[stores]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=75</guid>
		<description><![CDATA[A while back I ran into an interesting issue regarding loading records from the database into a form that contained combo boxes driven by remote stores. The problem was, when the record got loaded into the form, the stores for the combo boxes hadn&#8217;t loaded, so all the combo boxes said &#8220;select one&#8221; instead of [...]]]></description>
			<content:encoded><![CDATA[<p>A while back I ran into an interesting issue regarding loading records from the database into a form that contained combo boxes driven by remote stores. The problem was, when the record got loaded into the form, the stores for the combo boxes hadn&#8217;t loaded, so all the combo boxes said &#8220;select one&#8221; instead of the option that was chosen when the form got submitted. After doing some digging, I came up with a way around this issue:<span id="more-75"></span></p>
<h2>The Override Code</h2>
<pre class="brush: jscript; title: ; notranslate">
Ext.form.field.ComboBox.override( {
    setValue: function(v) {
        v = (v &amp;amp;&amp;amp; v.toString) ? v.toString() : v;
        if(!this.store.isLoaded &amp;amp;&amp;amp; this.queryMode == 'remote') {
            this.store.addListener('load', function() {
                this.store.isLoaded = true;
                this.setValue(v);
            }, this);
           this.store.load();
        } else {
            this.callOverridden(arguments);
        }
    }
});
</pre>
<p>Here, we override the setValue method of the ComboBox component and do the following:</p>
<ol>
<li>Make sure the store is not yet loaded (a custom property I added) and that it is tied to a remote store</li>
<li>Add a listener to the &#8216;load&#8217; event. When the store is loaded, set isLoaded equal to true and call setValue again.</li>
<li>Load the store</li>
<li>If the store is already loaded or the store is local, call the original overridden setValue method</li>
</ol>
<p>Just drop this into whatever JS file you keep your other overrides in and you&#8217;ll be good to go. Happy coding!</p>
<p>
<strong>Update: </strong>The source code for this snippet is available <a href="https://github.com/opnsrce/Code-Snippets/commit/96847c4b5177fc49bacba6aa1716b88accdb2082#diff-0">here</a>.</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/kuugDK8A2ls" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-combo-boxes-loadrecord-and-remote-stores/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-combo-boxes-loadrecord-and-remote-stores/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Using Listeners objects in Controllers (this.control)</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/r955LnSK-cY/</link>
		<comments>http://www.levihackwith.com/extjs-4-using-listeners-objects-in-controllers-this-control/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 02:46:24 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[Listener]]></category>
		<category><![CDATA[MVC]]></category>

		<guid isPermaLink="false">http://www.levihackwith.com/?p=74</guid>
		<description><![CDATA[When setting up a controller in ExtJS 4, you might do something like this: What this code is saying is &#8220;Find every textfield inside of the form in the current view (usually the viewport) and, whenever the value changes, fire the textFieldChange method&#8221;. Now, this is fine and all, but what if your textFieldChange method [...]]]></description>
			<content:encoded><![CDATA[<p>When setting up a controller in ExtJS 4, you might do something like this:</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.define('app.controller.myController', {
    init: function() {
        this.control({
            'form &amp;gt; textfield': {
                change: this.textFieldChange
            }
        })
    },
    textFieldChange: function(textField, newValue, oldValue, options) {
      alert('The text box went from' + oldValue + ' to ' + newValue);
    }
});
</pre>
<p>What this code is saying is &#8220;Find every textfield inside of the form in the current view (usually the viewport) and, whenever the value changes, fire the textFieldChange method&#8221;. Now, this is fine and all, but what if your textFieldChange method sent a request to the server? That would mean that, for every character you typed, a new request would be created and sent to the server causing a lot of unnecessary overhead.<span id="more-74"></span></p>
<p>The best solution would be to use the &#8220;buffer&#8221; property of the event <a href="http://docs.sencha.com/ext-js/4-0/#/api/Ext.form.Panel-method-addListener">listener object</a> to delay the request until we&#8217;re finished typing. Here&#8217;s how you go about declaring additional properties of an event listener from inside the controller:</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.define('app.controller.myController', {
    init: function() {
        this.control({
            'form &amp;gt; textfield': {
                change: {
                    fn: this.textFieldChange,
                    buffer: 500 // Delay the request by half a second
                 }
            }
        })
    },
    textFieldChange: function(textField, newValue, oldValue, options) {
      alert('The text box went from' + oldValue + ' to ' + newValue);
    }
});
</pre>
<p>Hope somebody out there finds this as helpful as I did. Happy coding!</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/r955LnSK-cY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-using-listeners-objects-in-controllers-this-control/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-using-listeners-objects-in-controllers-this-control/</feedburner:origLink></item>
		<item>
		<title>ExtJS 4: Proxy Calling ‘Create’ Instead of ‘Update’ When Saving Record</title>
		<link>http://feedproxy.google.com/~r/levihackwith/~3/QSXuIIgAzL4/</link>
		<comments>http://www.levihackwith.com/extjs-4-proxy-calling-create-instead-of-update-when-saving-record/#comments</comments>
		<pubDate>Sun, 26 Jun 2011 05:00:41 +0000</pubDate>
		<dc:creator>Levi Hackwith</dc:creator>
				<category><![CDATA[Programming / Web Development]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[Lessons Learned]]></category>

		<guid isPermaLink="false">http://levihackwith.com/?p=70</guid>
		<description><![CDATA[Recently, while working with a model and proxy in ExtJS 4, I ran into the issue where the model&#8217;s proxy would call the &#8216;create&#8217; action instead of &#8216;update&#8217; when saving changes to an existing record. Here&#8217;s the sample model and store we&#8217;ll be using to duplicate the problem: Now let&#8217;s try saving our changes and [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, while working with a model and proxy in ExtJS 4, I ran into the issue where the model&#8217;s proxy would call the &#8216;create&#8217; action instead of &#8216;update&#8217; when saving changes to an existing record. <span id="more-70"></span> Here&#8217;s the sample model and store we&#8217;ll be using to duplicate the problem:</p>
<pre class="brush: jscript; title: ; notranslate">
Ext.Loader.setConfig({ // Set up auto-loading
    enabled: true,
    paths: {
        Ext: 'extjs/src'
    }
});
Ext.define('User', { // The store
    alias: 'widget.userModel',
    extend: 'Ext.data.Model',
    idProperty: 'id',
    fields: [{
        name: 'id',
        type: 'int'
    }, {
        name: 'name',
        type: 'string'
    }, {
        name: 'dob',
        type: 'date',
        dateFormat: 'Y-m-d'
    }],
    proxy: {
        type: 'ajax',
        api: {
            create: 'myBackend.php?action=create', // Called when saving new records
            read: 'data/users.json', // Called when reading existing records
            update: 'myBackend.php?action=update', // Called when updating existing records
            destroy: 'myBackend.php?action=destroy' // Called when deleting existing records
        },
        reader: {
            type: 'json', // We expect the server to give us a JSON string as a response
            root: 'users'
        }
    }
})

Ext.define('Users', {
    extend: 'Ext.data.Store',
    alias: 'widget.userStore',
    model: 'User',
    autoLoad: false,
    autoSync: true
});&lt;/pre&gt;
This is a pretty straightforward example. We have a 'User' model with the following fields: id, name and dob (date of birth) and a store that is tied to that model. Let's load up one of those user objects from the database and try to change the title:
&lt;pre escaped=&quot;true&quot; lang=&quot;javascript&quot; line=&quot;1&quot;&gt;Ext.onReady(function() {
    Ext.widget('userModel').self.load(1, {
        success: function(record, operation) {
            record.data.name = 'Joe Smith';
        }
    })
})
</pre>
<p>Now let&#8217;s try saving our changes and take a peek at the AJAX request sent to the server (via Chrome&#8217;s JavaScript tools console):</p>
<p><strong>Console Output:</strong></p>
<pre class="brush: jscript; title: ; notranslate">
record.save();
url: http://www.dev.levihackwith.com/dnd_dev/myBackend.php?action=create&amp;amp;_dc=1309112727215
Query String Parameters:
action:create
...
1
As you can a see, our proxy attempted to create the record via the model proxy's 'create' api command instead of update it using the 'update' command. Why is this? Well, let's take a closer look at the record that was returned to us when we called the model's load method:

&lt;a href=&quot;http://www.levihackwith.com/wp-content/uploads/2011/06/ScreenClip.png&quot;&gt;&lt;img class=&quot;size-full wp-image-72&quot; title=&quot;Loaded User Model&quot; src=&quot;http://www.levihackwith.com/wp-content/uploads/2011/06/ScreenClip.png&quot; alt=&quot;User model returned when save() was called&quot; width=&quot;513&quot; height=&quot;204&quot; /&gt;&lt;/a&gt;

See the model's &quot;phantom&quot; property? That's been set to true. Let's learn a little more about this property via the API documentation (emphasis mine):
&lt;blockquote&gt;Phantom: Boolean
True when the record does not yet exist in the server-side database (see setDirty). &lt;strong&gt;Any record which has a real database pk [primary key] set as its id property is NOT a phantom&lt;/strong&gt; -- it's real.&lt;/blockquote&gt;
Now, what does that mean, exactly? Well, when you are setting up a model, one of the properties you can set is the idProperty property. This specifies which field in the model serves as the unique identifier for that record when it's sent and received from the server. Now let's take another look at the response from the server:

1
{
    'success': true,
    'users':[{
        'id': '',
        'name': 'John Smith',
        'dob': '1980-06-12'
    }]
}</pre>
<p><!-- Server response code here --></p>
<p>See how the ID field is blank? Because it&#8217;s blank, Ext assumes that it&#8217;s not been saved to the database yet and sets the Phantom property to true. Once we adjust our backend code to set the value of the field that acts as the idProperty (in this case, &#8220;id&#8221;), Ext recognizes the record as coming from the server and sets Phantom to false:</p>
<p>So, next time your proxy starts misbehaving, double check your server responses and model configuration and make sure you&#8217;re returning a fully-populated object. Happy coding!</p>
<img src="http://feeds.feedburner.com/~r/levihackwith/~4/QSXuIIgAzL4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.levihackwith.com/extjs-4-proxy-calling-create-instead-of-update-when-saving-record/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		<feedburner:origLink>http://www.levihackwith.com/extjs-4-proxy-calling-create-instead-of-update-when-saving-record/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.590 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-05-13 07:57:46 -->

