<?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>Colin Mollenhour&#039;s Technical Blog &#187; php</title>
	<atom:link href="http://colin.mollenhour.com/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://colin.mollenhour.com</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Thu, 13 Oct 2011 21:08:06 +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>Benchmarking Zend_Cache backends for Magento</title>
		<link>http://colin.mollenhour.com/2011/10/03/benchmarking-zend_cache-backends-for-magento/</link>
		<comments>http://colin.mollenhour.com/2011/10/03/benchmarking-zend_cache-backends-for-magento/#comments</comments>
		<pubDate>Mon, 03 Oct 2011 20:37:59 +0000</pubDate>
		<dc:creator>colin</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://colin.mollenhour.com/?p=144</guid>
		<description><![CDATA[The Zend_Cache module from the Zend Framework is a nice piece of work. It has a slew of programmer-friendly frontends and a respectable set of backends with a well-designed interface. I love the a-la-carte approach, but I am only really interested in the Zend_Cache_Core frontend and the backends that support tagging since that is what is required by Magento. This begs the question, which backend should you use? While I have my own opinion on that matter (ahem, Redis. -post coming soon-ish), I wanted a reliable way to test Zend_Cache backend performances so I wrote a benchmark! This benchmark was both forked from and inspired by the benchmark found in <a href="http://magebase.com/magento-tutorials/improving-the-file-cache-backend/">Vinai Kopp's Symlink Cache</a>. It uses Magento's core/cache model rather than Zend_Cache_Core directly so a Magento (or <a href="https://github.com/colinmollenhour/magento-lite">Magento-lite</a>) installation and bash are the only requirements.

The purpose of this post is not to provide a bunch of cache backend benchmarks, but rather to simply introduce my benchmark code in the hopes that others conduct their own tests and hopefully publish their findings.]]></description>
			<content:encoded><![CDATA[<p>The Zend_Cache module from the Zend Framework is a nice piece of work. It has a slew of programmer-friendly frontends and a respectable set of backends with a well-designed interface. I love the a-la-carte approach, but I am only really interested in the Zend_Cache_Core frontend and the backends that support tagging since that is what is required by Magento. This begs the question, which backend should you use? While I have my own opinion on that matter (ahem, Redis. -post coming soon-ish), I wanted a reliable way to test Zend_Cache backend performances so I wrote a benchmark! This benchmark was both forked from and inspired by the benchmark found in <a href="http://magebase.com/magento-tutorials/improving-the-file-cache-backend/">Vinai Kopp&#8217;s Symlink Cache</a>. It uses Magento&#8217;s core/cache model rather than Zend_Cache_Core directly so a Magento (or <a href="https://github.com/colinmollenhour/magento-lite">Magento-lite</a>) installation and bash are the only requirements.</p>
<p>The purpose of this post is not to provide a bunch of cache backend benchmarks, but rather to simply introduce my benchmark code in the hopes that others conduct their own tests and hopefully publish their findings. A link to this post is appreciated. Also, if there are any criticisms of the benchmark I&#8217;d love to see a pull request. :)</p>
<p><span id="more-144"></span></p>
<p>The benchmark suite is fully-featured:</p>
<ul>
<li>Repeatable tests. Dataset is written to static files so the <strong>exact</strong> same test can be repeated, even with entirely different backends.</li>
<li>Test datasets can easily be zipped up and copied to different environments or shared for others to use.</li>
<li>Can relatively easily test multiple pre-generated datasets to compare different scenarios on the same hardware.</li>
<li>Uses true multi-process benchmarking, each process with a different set of random operations.</li>
<li>Flexible dataset generation via options to init command. Cache record data size, number of tags, expiration, popularity and volatility are all randomized.</li>
</ul>
<p><br/><br />
Currently the benchmarks are run via the command line so testing the APC backend or any others that only work via a cgi or apache module environment will not work. This could be remedied easily enough with the use of CuRL and some php copy/paste if you had the desire to test on your actual web server.</p>
<p>Here is an example run using the Redis backend using my dev environment, a Lubuntu VirtualBox guest:</p>
<pre>
Cache Backend: Zend_Cache_Backend_Redis
Loading 'default' test data...
Loaded 10000 cache records in 29.1080 seconds. Data size is 5008.9K
Analyzing current cache contents...
Counted 10023 cache IDs and 2005 cache tags in 0.2062 seconds
Benchmarking getIdsMatchingTags...
Average: 0.00036 seconds (36.82 ids per tag)
Benchmarking 4 concurrent clients, each with 100000 operations...
4 concurrent clients completed in 62 seconds

         |   reads|  writes|  cleans
------------------------------------
Client  1| 1811.83|  184.66|    6.81
Client  2| 1799.84|  165.29|    6.91
Client  3| 1818.90|  165.17|    6.79
Client  0| 1790.91|  153.56|    7.40
------------------------------------
ops/sec  | 7221.48|  668.68|   27.91
</pre>
<p>The important numbers to look at are the summed ops/sec. Given the three variables: dataset, hardware and backend, it is easy to change just one of these without affecting the others so this benchmark can be used to test any one of the three variables reliably. The three metrics observed are reads, writes and cleans. The first two are pretty self-explanatory. The third is a clean operation on a single tag using <code>Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG</code> which is the only mode Magento ever uses other than <code>Zend_Cache::CLEANING_MODE_ALL</code> for manual cache refreshes. Individual read/write operations are very fast so given the large number of operations in a test I did not feel the need to examine min, max, average, or standard deviations.</p>
<p>The test uses (hopefully) sane defaults for dataset generation parameters, but there is plenty of flexibility. I advise you to examine your production environment (number of cache keys, number of cache tags, number of concurrent clients) to tweak the test to more closely match your own environment. Here is the output of the <code>--help</code> cli parameter:</p>
<pre>
$ php shell/cache-benchmark.php --help
This script will either initialize a new benchmark dataset or run a benchmark.

Usage:  php -f shell/cache-benchmark.php [command] [options]

Commands:
  init [options]        Initialize a new dataset.
  load --name &lt;string&gt;  Load an existing dataset.
  clean                 Flush the cache backend.
  tags                  Benchmark getIdsMatchingTags method.
  ops [options]         Execute a pre-generated set of operations on the existing cache.

'init' options:
  --name &lt;string&gt;       A unique name for this dataset (default to "default")
  --keys &lt;num&gt;          Number of cache keys (default to 10000)
  --tags &lt;num&gt;          Number of cache tags (default to 2000)
  --min-tags &lt;num&gt;      The min number of tags to use for each record (default 0)
  --max-tags &lt;num&gt;      The max number of tags to use for each record (default 15)
  --min-rec-size &lt;num&gt;  The smallest size for a record (default 1)
  --max-rec-size &lt;num&gt;  The largest size for a record (default 1024)
  --clients &lt;num&gt;       The number of clients for multi-threaded testing (defaults to 4)
  --seed &lt;num&gt;          The random number generator seed (default random)

'ops' options:
  --name &lt;string&gt;       The dataset to use (from the --name option from init command)
  --client &lt;num&gt;        Client number (0-n where n is --clients option from init command)
  -q|--quiet            Be less verbose.
</pre>
<p>To handle multi-process benchmarking the test is actually launched from a shell script which backgrounds each client and sums the results using awk so unless you are doing single-process benchmarks you never need to invoke the &#8216;ops&#8217; command yourself.</p>
<h2>Give me the code already!</h2>
<p>The code is hosted at <a href="https://github.com/colinmollenhour/magento-cache-benchmark">github.com/colinmollenhour/magento-cache-benchmark</a>. If you use modman you can install it like so:</p>
<pre>
modman cachebench clone git://github.com/colinmollenhour/magento-cache-benchmark.git
</pre>
<p>Or, you may also <a href="https://github.com/colinmollenhour/magento-cache-benchmark/zipball/v1.0">download it directly</a> and just extract cache-benchmark.php to the &#8220;shell&#8221; folder in your Magento installation.</p>
<h2>Run a test!</h2>
<p>Assuming you&#8217;ve cloned/downloaded the code already, here is how you run your first test:</p>
<pre>
php shell/cache-benchmark.php init
bash var/cachebench/default/run.sh
</pre>
<p>Could it get any easier?</p>
<p>PS. I included a &#8220;Null&#8221; backend which is just a black hole for the purpose of getting a general idea of your PHP overhead.</p>
]]></content:encoded>
			<wfw:commentRss>http://colin.mollenhour.com/2011/10/03/benchmarking-zend_cache-backends-for-magento/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Adding Minimal Price To Any Product Collection in Magento</title>
		<link>http://colin.mollenhour.com/2009/06/04/adding-minimal-price-to-any-product-collection-in-magento/</link>
		<comments>http://colin.mollenhour.com/2009/06/04/adding-minimal-price-to-any-product-collection-in-magento/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 07:05:08 +0000</pubDate>
		<dc:creator>colin</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://colin.mollenhour.com/?p=65</guid>
		<description><![CDATA[There are many &#8220;Bestseller&#8220;, &#8220;Most Viewed&#8221;, and other front-page modules available for Magento. Those that use the Reports module to maintain good performance have the slight drawback that they do not inherit the catalog/product_collection resource model and it&#8217;s handy addMinimalPrices() function. This function adds the fields necessary for the getPriceHtml($product, TRUE) function to work, which [...]]]></description>
			<content:encoded><![CDATA[<p>There are many &#8220;<a href="http://inchoo.net/ecommerce/magento/bestseller-products-in-magento/">Bestseller</a>&#8220;, &#8220;Most Viewed&#8221;, and other front-page modules available for Magento. Those that use the Reports module to maintain good performance have the slight drawback that they do not inherit the <code>catalog/product_collection</code> resource model and it&#8217;s handy <code>addMinimalPrices()</code> function. This function adds the fields necessary for the <code>getPriceHtml($product, TRUE)</code> function to work, which prints out the &#8220;As low as&#8221; text for products that have tiered pricing. This is a must-have feature if you use tiered pricing, so here is how you can make <code>getPriceHTML($product, TRUE)</code> work with any collection of products:
</p>
<pre class="brush: php;">
$productIds = array_keys($_products-&gt;getItems());
$minimalPriceModel = Mage::getResourceModel('catalogindex/price');
$minimalPriceModel-&gt;setStoreId(Mage::app()-&gt;getStore()-&gt;getId());
$minimalPriceModel-&gt;setCustomerGroupId(
  Mage::getSingleton('customer/session')-&gt;getCustomerGroupId());
$minimalPrices = $minimalPriceModel-&gt;getMinimalPrices($productIds);
foreach ($minimalPrices as $row) {
  $item = $_products-&gt;getItemById($row['entity_id']);
  if ($item) {
    $item-&gt;setData('minimal_price', $row['value']);
    $item-&gt;setData('minimal_tax_class_id', $row['tax_class_id']);
  }
}
</pre>
<p>There you have it!</p>
]]></content:encoded>
			<wfw:commentRss>http://colin.mollenhour.com/2009/06/04/adding-minimal-price-to-any-product-collection-in-magento/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Hiding &#8220;Out of Stock&#8221; Items in Magento</title>
		<link>http://colin.mollenhour.com/2009/06/02/hiding-out-of-stock-items-in-magento/</link>
		<comments>http://colin.mollenhour.com/2009/06/02/hiding-out-of-stock-items-in-magento/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 23:48:57 +0000</pubDate>
		<dc:creator>colin</dc:creator>
				<category><![CDATA[Magento]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://colin.mollenhour.com/?p=56</guid>
		<description><![CDATA[Updated 7/14/09 This module has been replaced with one that correctly updates the layered navigation counts. See the new version here. Updated 7/3/09 The in-stock-only module now works properly when multiple websites are in use. Updated 6/26/09 The in-stock-only module now works with configurable products. &#160; Magento has several criteria for determining if an item [...]]]></description>
			<content:encoded><![CDATA[<h3>Updated 7/14/09</h3>
<p>This module has been replaced with one that correctly updates the layered navigation counts. See the <a href="http://colin.mollenhour.com/2009/07/hiding-out-of-stock-items-in-layered-navigation/">new version here</a>.</p>
<h3>Updated 7/3/09</h3>
<p>The in-stock-only module now works properly when multiple websites are in use.</p>
<h3>Updated 6/26/09</h3>
<p>The in-stock-only module now works with configurable products.</p>
<p>&nbsp;</p>
<p>Magento has several criteria for determining if an item should be visible in the store, but one of these is not whether or not the item is <b>in stock</b>. Magento can manage your stock and will set your stock status to &#8220;Out of Stock&#8221; for you, but what if you want these out of stock items to be hidden from the store.. automatically?  Also, in my case I do not want to &#8220;disable&#8221; the item because the inventory management system will then ignore it. Turns out this was much more difficult to figure out than I expected it to be but the end solution was quite simple.</p>
<p><span id="more-56"></span></p>
<p>To hide all out of stock items from Magento&#8217;s storefront we are going to create a local module and call it &#8220;Lucky_InStockOnly&#8221;. This will be a very simple module, so get ready to copy and paste.</p>
<p>Every module needs a config file. Ours is very basic, here it is:</p>
<p><code>app/code/local/Lucky/InStockOnly/etc/config.xml</code></p>
<pre class="brush: xml;">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config&gt;

&lt;global&gt;
  &lt;models&gt;
    &lt;lucky_instockonly&gt;
      &lt;class&gt;Lucky_InStockOnly_Model&lt;/class&gt;
    &lt;/lucky_instockonly&gt;
  &lt;/models&gt;
&lt;/global&gt;

&lt;frontend&gt;
  &lt;events&gt;
    &lt;catalog_block_product_list_collection&gt;
      &lt;observers&gt;
        &lt;lucky_instockonly_list&gt;
          &lt;type&gt;singleton&lt;/type&gt;
          &lt;class&gt;lucky_instockonly/observer&lt;/class&gt;
          &lt;method&gt;addInStockOnlyFilter&lt;/method&gt;
        &lt;/lucky_instockonly_list&gt;
      &lt;/observers&gt;
    &lt;/catalog_block_product_list_collection&gt;
  &lt;/events&gt;
&lt;/frontend&gt;

&lt;/config&gt;</pre>
<p>As you can see, we declare an event for the frontend that observes the &#8220;catalog_block_product_list_collection&#8221; event which is dispatched in <code>Mage_Catalog_Block_Product_List</code> in the <code>_beforeToHtml()</code> method. This _beforeToHtml method is called before the corresponding template code is loaded, and the next line after the dispatchEvent loads the collection at which point it is too late to add any further filters, so we&#8217;re just in time.</p>
<p>Next, we add the observer code:</p>
<p><code>app/code/local/Lucky/InStockOnly/Model/Observer.php</code></p>
<pre class="brush: php;">
&lt;?php

class Lucky_InStockOnly_Model_Observer {

  /**
   * Observes the catalog_block_product_list_collection event
   */
  public function addInStockOnlyFilter($observer){
    $observer-&gt;getEvent()-&gt;getCollection()
      -&gt;joinField('stock_status','cataloginventory/stock_status','stock_status',
        'product_id=entity_id', array(
          'stock_status' =&gt; Mage_CatalogInventory_Model_Stock_Status::STATUS_IN_STOCK,
          'website_id' =&gt; Mage::app()-&gt;getWebsite()-&gt;getWebsiteId(),
        ))
    ;
  }
}
</pre>
<p>That&#8217;s it! That&#8217;s it? Like all things Magento, easy for a veteran, not so easy for anyone else; hence, this blog post. All that is left is to enable our module and we&#8217;re off!</p>
<p><code>app/etc/modules/Lucky_InStockOnly.xml</code></p>
<pre class="brush: xml;">
&lt;config&gt;
  &lt;modules&gt;
    &lt;Lucky_InStockOnly&gt;
      &lt;active&gt;true&lt;/active&gt;
      &lt;codePool&gt;local&lt;/codePool&gt;
    &lt;/Lucky_InStockOnly&gt;
  &lt;/modules&gt;
&lt;/config&gt;
</pre>
<p>Last thing, you need to refresh your configuration cache so Magento will notice the new module. In the admin backend you can do that under System > Cache Management.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://colin.mollenhour.com/2009/06/02/hiding-out-of-stock-items-in-magento/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Implementing Zend Framework&#8217;s &#8220;Conventional Modular&#8221; Directory Structure in Kohana</title>
		<link>http://colin.mollenhour.com/2009/04/19/implementing-zend-frameworks-conventional-modular-directory-structure-in-kohana/</link>
		<comments>http://colin.mollenhour.com/2009/04/19/implementing-zend-frameworks-conventional-modular-directory-structure-in-kohana/#comments</comments>
		<pubDate>Sun, 19 Apr 2009 18:09:30 +0000</pubDate>
		<dc:creator>colin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[kohana]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://colin.mollenhour.com/?p=39</guid>
		<description><![CDATA[There is a little conflict in terms here because &#8220;modules&#8221; are not the same to Kohana as they are to Zend Framework and Yii Framework, which both have support for modular directory structures. In Kohana, modules are like plugins to the framework which can change or add functionality to the core to be made use [...]]]></description>
			<content:encoded><![CDATA[<p>There is a little conflict in terms here because &#8220;modules&#8221; are not the same to Kohana as they are to Zend Framework and Yii Framework, which both have support for modular directory structures. In Kohana, modules are like plugins to the framework which can change or add functionality to the core to be made use of in the application. The <a href="http://framework.zend.com/manual/en/zend.controller.modular.html">&#8220;Conventional Modular&#8221; Directory Structure</a> in Zend Framework is a configuration option, and modules are more like sub-applications; essentially just a neat way to organize various components of an application.
</p>
<p><span id="more-39"></span></p>
<p>While modules in Kohana can (and often do) have their own controllers and views, they sit below the application layer in terms of cascading priority, whereas the modules in Zend Framework sit above the main application layer. That is, if a module is specified in the route, classes will be searched for first in the module directory, and then in the default directory. I really like this directory structure and want to apply it to Kohana. Because of the naming conflict, I am calling these sub-application directories <i>components</i> instead of modules. Here is an example of what I am shooting for:
</p>
<pre>
/application
   /cache
   /config
   /controllers
      /template.php (Template_Controller)
      /welcome.php  (Welcome_Controller)
   /libraries
   /models
   <b>/components</b>
      /admin
         /controllers
            /welcome.php (Welcome_Controller)
            /users.php (Users_Controller)
            /posts.php (Posts_Controller)
         /views
            /template.php (overrides /application/views/template.php)
      /blog
         /controllers
            /posts.php (Posts_Controller)
         /views
            /posts.php (from within blog component: new View('posts'))
      /rest
         ...
      /mobile
         ...
      ...
/modules (Traditional Kohana Modules)
   /auth
   /curl
   ...
/system (Kohana Core)
</pre>
<p>
I use the router to determine the current component, implemented inside my branch of the router3 module. The default value can be set for &#8216;component&#8217; in a route, or the component can be discovered from the uri, or it can fall back to the default component, which by default is the application itself. The default component can also be given a name such as &#8216;default&#8217; in the config file. To avoid conflicts I have an array in my config file to define the components that are enabled and the router will only attempt to match those components via a regex built into the route.
</p>
<p>
Hacking the find_file system is not particularly easy, especially when you enable caching because the component is chosen on-the-fly so the results for (&#8216;controller&#8217;,'welcome&#8217;) will be different from one request to the next. In order to support cascading of all resources in the component directories, the core would have to be hacked. However, I have successfully implemented this as a module which only supports &#8220;controllers&#8221; and &#8220;views&#8221; in the component&#8217;s directory. Caching of find_file paths is not broken, and components that are not active for the current request are not in the cascading order at all which I believe to be preferable. Any controllers and views that should be shared among all components in the application can go in the application directories, all others can be separated into component directories.
</p>
<p>
So what does this accomplish? This let&#8217;s you easily keep components of your application organized in different directories. I currently do not include the component name in the controller class like Zend does, so your controller class and file names and view paths can be kept short. E.g., for the typical blog example:
</p>
<pre>
/application
/controllers
   /welcome.php (Welcome_Controller for blog frontend)
/views
   /template.php (template for blog frontend)
   /posts.php (render frontend view of blog posts)
/components
   /admin (URLs starting with admin will use this component)
      /controllers
         /welcome.php (Welcome_Controller for admin backend)
      /views
         /template.php (template for admin backend)
         /posts.php (render admin view of blog posts)
</pre>
<p>
Aside from the more compartmentalized directory structure, the template name does not have to be changed for the component&#8217;s template to be used, it just works! Also, when instantiating a view, there is no need to specify sub-directories.
</p>
<pre>
// New:
$this->template->content = new View('posts');
// Old:
public $template = 'admin/template';
$this->template->content = new View('admin/posts');
</pre>
<p>
From a code-management standpoint, this could also have some benefits. For example, do you want to revert the admin component back to an older revision but leave all other components alone? Since the admin components files are all contained under one directory, rather than mixed in with every other component this is a simple task.
</p>
<p><i><b>Update:</b></i></p>
<p>The powers that be cannot be convinced that such a directory structure is worthwhile<del datetime="2009-04-21T06:42:06+00:00">, or that <a href="http://dev.kohanaphp.com/ticket/1271">the Kohana class does not have to be &#8220;final&#8221;</a> so I&#8217;ve unfortunately decided to give up and fork Kohana and track it&#8217;s progress.. So much for, as the <a href="http://kohanaphp.com">Kohana homepage</a> puts it, &#8220;Loosely coupled architecture&#8221; and &#8220;Extremely easy to extend&#8221;&#8230;</del>  If anyone is interested in a patch that seamlessly adds this feature, let me know!
</p>
<p><i><b>Update 2 (4/21/09):</b></i></p>
<p>It turns out that the Kohana devs have agreed to make Kohana no longer &#8220;final&#8221; for 2.4, and in fact have moved the Bootstrap.php file into the application directory as well; Icing on the cake! See <a href="http://dev.kohanaphp.com/changeset/4231">r4231</a></p>
]]></content:encoded>
			<wfw:commentRss>http://colin.mollenhour.com/2009/04/19/implementing-zend-frameworks-conventional-modular-directory-structure-in-kohana/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

