<?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/"
	>

<channel>
	<title>Easytech blog</title>
	<atom:link href="http://blog.easytech.com.ar/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.easytech.com.ar</link>
	<description>Technological Solutions</description>
	<pubDate>Sat, 03 Jul 2010 07:36:36 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7-bleeding</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>A PHP Shell</title>
		<link>http://blog.easytech.com.ar/2010/07/02/a-php-shell/</link>
		<comments>http://blog.easytech.com.ar/2010/07/02/a-php-shell/#comments</comments>
		<pubDate>Fri, 02 Jul 2010 22:34:37 +0000</pubDate>
		<dc:creator>miquel</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming and Scripting]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=515</guid>
		<description><![CDATA[
We do a lot of development in PHP here at Easytech. Many times you need to test a bit of PHP code. If you played around with python you surely used the python shell. Fortunately the people at Facebook have created a similar shell for PHP (ironically written in python!). You can find it here: [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.easytech.com.ar/wp-content/uploads/20080426-perfect-halved-nautilus-shell.jpg" rel="thumbnail"><img class="size-full wp-image-525   alignleft" style="margin: 0 15px 0 0;" title="A Nautilus shell" src="http://blog.easytech.com.ar/wp-content/uploads/20080426-perfect-halved-nautilus-shell.jpg" alt="A Nautilus shell" width="128" height="108" /></a></p>
<p>We do a lot of development in PHP here at Easytech. Many times you need to test a bit of PHP code. If you played around with python you surely used the python shell. Fortunately the people at Facebook have created a similar shell for PHP (ironically written in python!). You can find it here: http://www.phpsh.org/. From there you can access the GIT repository or download a tgz or zip file.</p>
<p>Currently I couldn&#8217;t find a DEB package for Ubuntu. If you want to install it just follow the following steps (you need python installed)</p>
<div class="dean_ch" style="white-space: wrap;">$ cd ~/Devel/PHP (o donde lo quieran tirar)<br />
$ wget http://github.com/facebook/phpsh/tarball/master<br />
$ tar zxvf facebook-phpsh-*<br />
$ cd facebook-phpsh-*<br />
$ sudo python setup.py install</div>
<p>thats it! To test some PHP weirdness&#8230;</p>
<div class="dean_ch" style="white-space: wrap;">$ phpsh<br />
Starting php<br />
type &#8216;h&#8217; or &#8216;help&#8217; to see instructions &amp;amp; features<br />
php&gt; var_dump( 1 == &#8216;1&#8242; )<br />
bool(true)<br />
&nbsp;<br />
php&gt;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2010/07/02/a-php-shell/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Exploding and imploding&#8230;</title>
		<link>http://blog.easytech.com.ar/2010/04/24/exploding-and-imploding/</link>
		<comments>http://blog.easytech.com.ar/2010/04/24/exploding-and-imploding/#comments</comments>
		<pubDate>Sat, 24 Apr 2010 04:42:05 +0000</pubDate>
		<dc:creator>miquel</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming and Scripting]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=496</guid>
		<description><![CDATA[Very often when I review other peoples PHP code I come across an old problem: generating a list of comma separated values from a list of things. This happens often when you want to, say, write an SQL query with a WHERE field IN (a,b,c,&#8230;,x) and you have an array with a, b, etc.
Another example [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.easytech.com.ar/wp-content/uploads/php_src.png" rel="thumbnail"><img class="size-full wp-image-506 alignright" title="PHP source icon" src="http://blog.easytech.com.ar/wp-content/uploads/php_src.png" alt="" width="128" height="128" /></a>Very often when I review other peoples PHP code I come across an old problem: generating a list of comma separated values from a list of things. This happens often when you want to, say, write an SQL query with a <em>WHERE field IN (a,b,c,&#8230;,x)</em> and you have an array with a, b, etc.</p>
<p>Another example is when you want to create an include path by concatenating a list of directories with the <em>PATH_SEPARATOR</em>. Yet another example is when you want to build a path concatenating them with the <em>DIRECTORY_SEPARATOR</em>.</p>
<p>The usual code to accomplish looks something like this:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; &nbsp;<span class="co1">// loop through list an generate string</span><br />
&nbsp; &nbsp; <span class="re0">$line</span> = <span class="st0">&#8221;</span>;<br />
&nbsp; &nbsp; <span class="kw1">foreach</span><span class="br0">&#40;</span> <span class="re0">$list</span> <span class="kw1">as</span> <span class="re0">$el</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$line</span> .= <span class="re0">$el</span> . <span class="st0">&#8216;,&#8217;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="re0">$line</span> = <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span> <span class="re0">$line</span>, <span class="nu0">0</span>, <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">&#40;</span> <span class="re0">$line</span> <span class="br0">&#41;</span> - <span class="nu0">1</span> <span class="br0">&#41;</span>;<br />
<span class="kw2">?&gt;</span><br />
&nbsp;</div>
<p><span id="more-496"></span></p>
<p>There is really nothing wrong with this code snippet. The last line is kind of &#8216;ugly&#8217;: while you are looping over the array and are concatenating a string with &#8216;,&#8217; you don&#8217;t know which is the last element in the list. This means that when the loop is done you have an extra &#8216;,&#8217; character. The solution: use substring to remove the final &#8216;,&#8217;. Another alternative is:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; &#8230;<br />
&nbsp; &nbsp; <span class="re0">$line</span> = <a href="http://www.php.net/preg_replace"><span class="kw3">preg_replace</span></a><span class="br0">&#40;</span> <span class="st0">&#8216;/,$/&#8217;</span>, <span class="st0">&#8221;</span>, <span class="re0">$line</span> <span class="br0">&#41;</span>;<br />
<span class="kw2">?&gt;</span><br />
&nbsp;</div>
<p>This way we use a regular expression to replace the last &#8216;,&#8217; with a blank. A bit nicer than the <em>substr()</em> example. Both ways are ok but PHP has a really nice function called <em>implode()</em>. What <em>implode()</em> does is it takes a list or array and joins it with whatever character/s you want. So, the code we just wrote can be replaced with the much cleaner:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; &#8230;<br />
&nbsp; &nbsp; <span class="re0">$line</span> = <a href="http://www.php.net/implode"><span class="kw3">implode</span></a><span class="br0">&#40;</span> <span class="st0">&#8216;,&#8217;</span>, <span class="re0">$list</span> <span class="br0">&#41;</span>;<br />
<span class="kw2">?&gt;</span><br />
&nbsp;</div>
<p>With <em>implode()</em> you don&#8217;t need to do weird stuff to remove the last &#8216;,&#8217; or whatever char/chars you used to concatenate the string. Another advantage is that the code is much faster since <em>implode()</em> is implemented in C code.</p>
<p>The <em>implode()</em> function has another useful and related function: <em>explode()</em>. This function takes a delim delimiter and a subject string and returns an array of strings which is obtained by splitting the subject using the delimiter. I&#8217;m quite sure you&#8217;ve used <em>explode()</em>. It&#8217;s used when you want to, for example take a comma separated list and parse it to obtain the fields. Of course if you want to parse a CSV file you should use another PHP function: <em>fgetcsv()</em>; but that is for another post&#8230;</p>
<p>So, the moral of this post should be: before embarking on doing weird things first take a look at the PHP library of functions. Chances are that someone has come across the same problem and have solved it and included it as a PHP function or library. The advantage is that these functions not only execute faster since they are straight C code but also have been tested by thousands of programmers and, in most cases, are known to work. This is often the case when you have to do operations on dates. For example: calculate what day of the month is next Friday, etc. This functions are quite tricky to write because there are a lot of border cases: leap years, change of month / year, etc. If you write<br />
them your are quite likely to forget about some border case. You should always use library functions and particularly PHP library functions which have been extensively tested and used for years.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2010/04/24/exploding-and-imploding/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Creating a page with tabs in Drupal</title>
		<link>http://blog.easytech.com.ar/2010/01/18/creating-a-page-with-tabs-in-drupal/</link>
		<comments>http://blog.easytech.com.ar/2010/01/18/creating-a-page-with-tabs-in-drupal/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 20:44:08 +0000</pubDate>
		<dc:creator>miquel</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=478</guid>
		<description><![CDATA[If you are developing a module for Drupal you might need to use tabs to simplify a bit a screen which has too much functionality. Typically a settings page that might need too many options to comfortably fit on a single screen. Since I had to search and experiment a bit to find out how [...]]]></description>
			<content:encoded><![CDATA[<p>If you are developing a module for Drupal you might need to use tabs to simplify a bit a screen which has too much functionality. Typically a settings page that might need too many options to comfortably fit on a single screen. Since I had to search and experiment a bit to find out how to do it I decided to write a short post with my findings. In this article I assume you have a basic understanding on writing Drupal modules.</p>
<div style="width: 700px; clear: both; float: left;"><a href="http://blog.easytech.com.ar/wp-content/uploads/post01.png" rel="thumbnail"><img class="alignnone size-full wp-image-485" title="Resulting page in Drupal" src="http://blog.easytech.com.ar/wp-content/uploads/post01.png" alt="" width="663" height="370" /></a></div>
<p><span id="more-478"></span></p>
<p>Basically you define what content goes in what tab in your modules <em>hook_menu()</em> function defining menu items which are called <strong>MENU_LOCAL_TASK</strong>. Suppose I want a page which has two tabs: Company and Mail as seen on the screen shot. This is the corresponding <em>hook_menu()</em> code:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="coMULTI">/**<br />
&nbsp;* Implementation of hook_menu()<br />
&nbsp;*/</span><br />
<span class="kw2">function</span> my_module_menu<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; <span class="re0">$items</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="co1">// definition for main page</span><br />
&nbsp; <span class="re0">$items</span><span class="br0">&#91;</span><span class="st0">&#8217;settings&#8217;</span><span class="br0">&#93;</span> =<br />
&nbsp; &nbsp; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;title&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Settings&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;description&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Settings for Ticket System&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;page callback&#8217;</span> =&gt; <span class="st0">&#8216;my_module_settings_root&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;access callback&#8217;</span> =&gt; <span class="kw2">true</span>,<br />
&nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
&nbsp; <span class="co1">// definition for default tab.</span><br />
&nbsp; <span class="re0">$items</span><span class="br0">&#91;</span><span class="st0">&#8217;settings/company&#8217;</span><span class="br0">&#93;</span> =<br />
&nbsp; &nbsp; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;title&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Company&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;description&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Settings for Ticket System&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;type&#8217;</span> =&gt; MENU_DEFAULT_LOCAL_TASK,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;weight&#8217;</span> =&gt; <span class="nu0">0</span>,<br />
&nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
&nbsp; <span class="co1">// definition for additional tab.</span><br />
&nbsp; <span class="re0">$items</span><span class="br0">&#91;</span><span class="st0">&#8217;settings/mail&#8217;</span><span class="br0">&#93;</span> =<br />
&nbsp; &nbsp; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;title&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Mail&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;description&#8217;</span> =&gt; t<span class="br0">&#40;</span><span class="st0">&#8216;Settings for Ticket System&#8217;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;access callback&#8217;</span> =&gt; <span class="kw2">true</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;page callback&#8217;</span> =&gt; <span class="st0">&#8216;my_module_settings_mail&#8217;</span>,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;type&#8217;</span> =&gt; MENU_LOCAL_TASK,<br />
&nbsp; &nbsp; &nbsp; <span class="st0">&#8216;weight&#8217;</span> =&gt; <span class="nu0">2</span>,<br />
&nbsp; &nbsp; <span class="br0">&#41;</span>;</p>
<p>&nbsp; <span class="kw1">return</span> <span class="re0">$items</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">function</span> my_module_settings_root<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">return</span> <span class="st0">&#8216;page root&#8217;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">function</span> my_module_settings_mail<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">return</span> <span class="st0">&#8216;page mail&#8217;</span>;<br />
<span class="br0">&#125;</span></div>
<p>Here are the main highlights of how this works:</p>
<ul>
<li>The first item should be a standard menu item and its route should be shared with the other tabs. In this case, the route is &#8217;settings&#8217;.</li>
<li>Each additional tab should be of type <strong>MENU_LOCAL_TASK</strong>.</li>
<li>You need at least two tabs. If you only have one child route then you will not see a tab.</li>
<li>If you add more than one <strong>MENU_LOCAL_TASK</strong>, you must single out one as required by setting its type to <strong>MENU_DEFAULT_LOCAL_TASK</strong>. The default local task doesn&#8217;t need a &#8216;page callback&#8217; since it is handled by the root item.</li>
<li>Additional tabs should be of type <strong>MENU_LOCAL_TASK</strong> and should have a page callback function assigned to them.</li>
<li>The &#8216;title&#8217; of the standard item appears a the top of the tab bar. The title of the <strong>MENU_LOCAL_TASK</strong> and <strong>MENU_DEFAULT_LOCAL_TASK</strong> are used as the titles on the individual tabs.</li>
<li>You can change the order of the tabs by adding a &#8216;weight&#8217; item to each menu<br />
item.</li>
<li>You need to specify an &#8216;access callback&#8217; item and have permissions to view the corresponding tab.</li>
</ul>
<p>Finally, remember that each time you change an item in <em>hook_menu()</em> you need to flush your cache so that the items are re-read. This can be achived by going to admin-&gt;settings-&gt;performance and hitting clear cache or by using drush and doing &#8216;drush cache clear&#8217;.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2010/01/18/creating-a-page-with-tabs-in-drupal/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal Tip - How to determine what module handles a given path</title>
		<link>http://blog.easytech.com.ar/2009/11/18/drupal-tip-how-to-determine-what-module-handles-a-given-path/</link>
		<comments>http://blog.easytech.com.ar/2009/11/18/drupal-tip-how-to-determine-what-module-handles-a-given-path/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 18:48:18 +0000</pubDate>
		<dc:creator>miquel</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<category><![CDATA[Modules]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=460</guid>
		<description><![CDATA[Drupal has a sophisticated module system that allows developers to extend the CMSs functionality very easily. Each module &#8220;hooks&#8221; into Drupal by implementing hook functions. On way to use this feature is to hook different URLs to module functions. Essentially the developer in his module declares an array of url paths and what function should [...]]]></description>
			<content:encoded><![CDATA[<p>Drupal has a sophisticated module system that allows developers to extend the CMSs functionality very easily. Each module &#8220;hooks&#8221; into Drupal by implementing hook functions. On way to use this feature is to hook different URLs to module functions. Essentially the developer in his module declares an array of url paths and what function should be called when that path is requested. This small post will show you how you can determine which module handles a specific URL. This can be quite useful for debugging and/or browsing other peoples source code to learn how to do something.</p>
<p>Every module in Drupal that hooks to a URL path needs to implement the <strong>hook_menu</strong> function. This hook basically tells Drupal what paths will be handled by this module. This information is read when the module is enabled and stored in a database table. In Drupal 6 this information is cached so if you modify the array returned by the <strong>hook_menu</strong> function you need to clear the cache. To determine what module is handling what path you simply need to query the <strong>menu_router</strong> table. A simple query to do this is:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">SELECT</span><br />
&nbsp; path<br />
&nbsp; , file<br />
&nbsp; , page_callback<br />
&nbsp; , type<br />
&nbsp; , title<br />
<span class="kw1">FROM</span><br />
&nbsp; menu_router m<br />
<span class="kw1">ORDER</span> <span class="kw1">BY</span><br />
&nbsp; path</div>
<p>This table has more information that might be useful: <strong>access_callback</strong> and <strong>access_arguments</strong> store information related to what access function is called to determine who has access to that path, <strong>page_arguments</strong> stores information related to what arguments to pass to the callback function. This is specially relevant when the page_callback function is <strong>drupal_get_form</strong> in which case Drupal will render a form and this field stores the name of the form to render.</p>
<p>An example usage might be:</p>
<pre>$ drush sql cli
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1859
Server version: 5.0.77 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql&gt; SELECT path, file, page_callback FROM menu_router ORDER BY path;

+-----------------------------------+---------------------------------+------------------------------+
| path                              | file                            | page_callback                |
+-----------------------------------+---------------------------------+------------------------------+
| admin                             | modules/system/system.admin.inc | system_main_admin_page       |
| admin/build                       | modules/system/system.admin.inc | system_admin_menu_block_page |
| admin/build/block                 | modules/block/block.admin.inc   | block_admin_display          |
| admin/build/block/add             | modules/block/block.admin.inc   | drupal_get_form              |
| admin/build/block/configure       | modules/block/block.admin.inc   | drupal_get_form              |
| admin/build/block/delete          | modules/block/block.admin.inc   | drupal_get_form              |
| admin/build/block/list            | modules/block/block.admin.inc   | block_admin_display          |
| admin/build/block/list/bluemarine | modules/block/block.admin.inc   | block_admin_display          |
| admin/build/block/list/chameleon  | modules/block/block.admin.inc   | block_admin_display          |
| admin/build/block/list/donline    | modules/block/block.admin.inc   | block_admin_display          |
  .....

mysql&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/11/18/drupal-tip-how-to-determine-what-module-handles-a-given-path/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using Zend_Reflection to generate API docs</title>
		<link>http://blog.easytech.com.ar/2009/08/08/using-zend_reflection-to-generate-api-docs/</link>
		<comments>http://blog.easytech.com.ar/2009/08/08/using-zend_reflection-to-generate-api-docs/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 05:24:26 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=439</guid>
		<description><![CDATA[Today I needed to generate source code documentation for a webservice APIs we are in coding. One of the guys in the office suggested I take a look at Zend_Reflection. It turns out its quite simple to write PHP code to parse source files and extract the documentation from them. I took a little time [...]]]></description>
			<content:encoded><![CDATA[<p>Today I needed to generate source code documentation for a webservice APIs we are in coding. One of the guys in the office suggested I take a look at <a href="http://framework.zend.com/manual/en/zend.reflection.html">Zend_Reflection</a>. It turns out its quite simple to write PHP code to parse source files and extract the documentation from them. I took a little time to write this sample program. </p>
<p>This program is quite simple: it has a single class called <strong>TestClass</strong> with one method: <strong>addIntegers()</strong>. Below this class I wrote a little code which parses the file and then outputs the information. You can use this and a templating system to generate doc. I used it to write the documentation so that we can easily add it to our Wiki.</p>
<p>The script I wrote parses the documentation style used in Zend Framework. Here&#8217;s a sample class:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span></p>
<p><span class="coMULTI">/**<br />
&nbsp;* This is a sample test class.<br />
&nbsp;*<br />
&nbsp;* This class has only one method: addIntegers() which adds<br />
&nbsp;* two integers. Its a sample class for our test.<br />
&nbsp;*<br />
&nbsp;*/</span><br />
<span class="kw2">class</span> TestClass<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="coMULTI">/**<br />
&nbsp; &nbsp; &nbsp;* This method adds two integers.<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* This method adds the two given integers and returns <br />
&nbsp; &nbsp; &nbsp;* its sum. If only one integer is given it sums zero.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param int $number1 &nbsp;The first integer<br />
&nbsp; &nbsp; &nbsp;* @param int $number2 &nbsp;The second integer<br />
&nbsp; &nbsp; &nbsp;* @return int The sum of $number1 and $number2.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> addIntegers<span class="br0">&#40;</span> <span class="re0">$number1</span>, <span class="re0">$number2</span> = <span class="nu0">0</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">return</span> <span class="re0">$number1</span> + <span class="re0">$number2</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p>&nbsp;</p></div>
<p>Read the rest of the post to see how to easily parse this code&#8230;<br />
<span id="more-439"></span></p>
<p>Below is the complete sample code. Fire up your text editor, copy-and-paste this code into it, save it as <em>test_zend_reflection.php</em> and run it. Hope this helps!</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span></p>
<p><span class="co1">// setup Zend auto loader</span><br />
<span class="kw1">require_once</span> <span class="st0">&#8216;Zend/Loader/Autoloader.php&#8217;</span>;<br />
<span class="re0">$autoloader</span> = Zend_Loader_Autoloader::<span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="coMULTI">/**<br />
&nbsp;* This is a sample test class.<br />
&nbsp;*<br />
&nbsp;* This class has only one method: addIntegers() which adds<br />
&nbsp;* two integers. Its a sample class for our test.<br />
&nbsp;*<br />
&nbsp;*/</span><br />
<span class="kw2">class</span> TestClass<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="coMULTI">/**<br />
&nbsp; &nbsp; &nbsp;* This method adds two integers.<br />
&nbsp; &nbsp; &nbsp;* <br />
&nbsp; &nbsp; &nbsp;* This method adds the two given integers and returns <br />
&nbsp; &nbsp; &nbsp;* its sum. If only one integer is given it sums zero.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param int $number1 &nbsp;The first integer<br />
&nbsp; &nbsp; &nbsp;* @param int $number2 &nbsp;The second integer<br />
&nbsp; &nbsp; &nbsp;* @return int The sum of $number1 and $number2.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> addIntegers<span class="br0">&#40;</span><span class="re0">$number1</span>, <span class="re0">$number2</span> = <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">return</span> <span class="re0">$number1</span> + <span class="re0">$number2</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="co1">// use this file</span><br />
<span class="re0">$file</span> = <span class="kw2">__FILE__</span>;</p>
<p><span class="co1">// Zend Reflection require that you load the file. If you are loading</span><br />
<span class="co1">// another file then you need the following line:</span><br />
<span class="co1">// require_once( $file );</span><br />
<span class="re0">$zr</span> = <span class="kw2">new</span> Zend_Reflection_File<span class="br0">&#40;</span> <span class="re0">$file</span> <span class="br0">&#41;</span>;</p>
<p><span class="co1">// Get all classes defined in this file and parse each one</span><br />
<span class="re0">$classDoc</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">foreach</span><span class="br0">&#40;</span> <span class="re0">$zr</span>-&gt;<span class="me1">getClasses</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$class</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="re0">$classDoc</span><span class="br0">&#91;</span><span class="br0">&#93;</span> = parseClass<span class="br0">&#40;</span> <span class="re0">$zr</span>, <span class="re0">$class</span> <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<a href="http://www.php.net/print_r"><span class="kw3">print_r</span></a><span class="br0">&#40;</span> <span class="re0">$classDoc</span> <span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// parses a Zend_Reflection_Class object</span><br />
<span class="kw2">function</span> parseClass<span class="br0">&#40;</span> <span class="re0">$zr</span>, <span class="re0">$class</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>&nbsp; &nbsp; </p>
<p>&nbsp; &nbsp; <span class="co1">// read class docs</span><br />
&nbsp; &nbsp; <span class="re0">$docBlock</span> &nbsp; &nbsp; &nbsp; = <span class="re0">$class</span>-&gt;<span class="me1">getDocblock</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$fileName</span> &nbsp; &nbsp; &nbsp; = <span class="re0">$zr</span>-&gt;<span class="me1">getFileName</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$classShortComment</span> &nbsp;= <span class="re0">$docBlock</span>-&gt;<span class="me1">getShortDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$classLongComment</span> &nbsp; = <span class="re0">$docBlock</span>-&gt;<span class="me1">getLongDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">// load class info</span><br />
&nbsp; &nbsp; <span class="re0">$classDoc</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;fileName&#8217;</span>&nbsp; &nbsp; &nbsp; =&gt; <span class="re0">$fileName</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;className&#8217;</span>&nbsp;&nbsp; &nbsp; =&gt; <span class="re0">$class</span>-&gt;<span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8217;shortComment&#8217;</span>&nbsp; =&gt; <span class="re0">$classShortComment</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;longComment&#8217;</span>&nbsp; &nbsp;=&gt; <span class="re0">$classLongComment</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">// Read methods</span><br />
&nbsp; &nbsp; <span class="re0">$methods</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$class</span>-&gt;<span class="me1">getMethods</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$methodObj</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$methods</span><span class="br0">&#91;</span><span class="br0">&#93;</span> = parseMethod<span class="br0">&#40;</span> <span class="re0">$methodObj</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="re0">$classDoc</span><span class="br0">&#91;</span><span class="st0">&#8216;methods&#8217;</span><span class="br0">&#93;</span> = <span class="re0">$methods</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$classDoc</span>;<br />
<span class="br0">&#125;</span>&nbsp; &nbsp;</p>
<p><span class="co1">// parses a Zend_Reflection_Method object</span><br />
<span class="kw2">function</span> parseMethod<span class="br0">&#40;</span> <span class="re0">$methodObj</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; <span class="re0">$return</span> = <span class="st0">&#8216;void&#8217;</span>;</p>
<p>&nbsp; &nbsp; <span class="re0">$docBlock</span> &nbsp;= <span class="re0">$methodObj</span>-&gt;<span class="me1">getDocblock</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$shortDesc</span> = <span class="re0">$docBlock</span>-&gt;<span class="me1">getShortDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$longDesc</span> &nbsp;= <span class="re0">$docBlock</span>-&gt;<span class="me1">getLongDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">// read method tags</span><br />
&nbsp; &nbsp; <span class="re0">$tags</span> = <span class="re0">$docBlock</span>-&gt;<span class="me1">getTags</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">// parse them</span><br />
&nbsp; &nbsp; <span class="re0">$paramDoc</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="kw1">foreach</span><span class="br0">&#40;</span> <span class="re0">$tags</span> <span class="kw1">as</span> <span class="re0">$tag</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$tag</span>-&gt;<span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span> == <span class="st0">&#8216;return&#8217;</span> <span class="br0">&#41;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$return</span> &nbsp; &nbsp; = <span class="re0">$tag</span>-&gt;<span class="me1">getType</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$returnDesc</span> = <span class="re0">$tag</span>-&gt;<span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$tag</span>-&gt;<span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span> == <span class="st0">&#8216;param&#8217;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$paramDoc</span><span class="br0">&#91;</span><span class="br0">&#93;</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;name&#8217;</span> =&gt; <span class="re0">$tag</span>-&gt;<span class="me1">getVariableName</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;type&#8217;</span> =&gt; <span class="re0">$tag</span>-&gt;<span class="me1">getType</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;desc&#8217;</span> =&gt; <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span> <span class="re0">$tag</span>-&gt;<span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="re0">$method</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8216;name&#8217;</span> <span class="br0">&#93;</span> &nbsp; &nbsp; &nbsp; = <span class="re0">$methodObj</span>-&gt;<span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8217;shortDesc&#8217;</span> <span class="br0">&#93;</span>&nbsp; = <span class="re0">$shortDesc</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8216;longDesc&#8217;</span> <span class="br0">&#93;</span>&nbsp; &nbsp;= <span class="re0">$longDesc</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8216;returnType&#8217;</span><span class="br0">&#93;</span> &nbsp;= <span class="re0">$return</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8216;returnDesc&#8217;</span><span class="br0">&#93;</span> &nbsp;= <span class="re0">$returnDesc</span>;<br />
&nbsp; &nbsp; <span class="re0">$method</span><span class="br0">&#91;</span> <span class="st0">&#8216;params&#8217;</span> <span class="br0">&#93;</span> &nbsp; &nbsp; = <span class="re0">$paramDoc</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$method</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>If you run our PHP code you get:</p>
<div class="dean_ch" style="white-space: wrap;">
$ php test_zend_reflection.php</p>
<p>Array<br />
(<br />
&nbsp; [fileName] =&gt; /var/www/html/soa/doc/test_zend_reflection.php<br />
&nbsp; [className] =&gt; TestClass<br />
&nbsp; [shortComment] =&gt; This is a sample test class.<br />
&nbsp; [longComment] =&gt; This class has only one method: addIntegers() which adds<br />
two integers. Its a sample class for our test.<br />
&nbsp; [methods] =&gt; Array<br />
&nbsp; &nbsp; (<br />
&nbsp; &nbsp; &nbsp; [0] =&gt; Array<br />
&nbsp; &nbsp; &nbsp; &nbsp; (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [name] =&gt; addIntegers<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [shortDesc] =&gt; This method adds two integers.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [longDesc] =&gt; This method adds the two given integers and returns <br />
its sum. If only one integer is given it sums zero.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [returnType] =&gt; int<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [returnDesc] =&gt; The sum of $number1 and $number2.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [params] =&gt; Array<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [0] =&gt; Array<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [name] =&gt; $number1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [type] =&gt; int<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [desc] =&gt; The first integer<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [1] =&gt; Array<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [name] =&gt; $number2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [type] =&gt; int<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [desc] =&gt; The second integer<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )<br />
&nbsp; &nbsp; &nbsp; &nbsp; )<br />
&nbsp; &nbsp; )<br />
)<br />
&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/08/08/using-zend_reflection-to-generate-api-docs/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Initializing only one module per request in Zend_Framework.</title>
		<link>http://blog.easytech.com.ar/2009/08/04/initializing-only-one-module-per-request-in-zend_framework/</link>
		<comments>http://blog.easytech.com.ar/2009/08/04/initializing-only-one-module-per-request-in-zend_framework/#comments</comments>
		<pubDate>Tue, 04 Aug 2009 15:46:57 +0000</pubDate>
		<dc:creator>adji</dc:creator>
		
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=421</guid>
		<description><![CDATA[Zend Framework recently introduced the concept of modules so that your applications become more manegable. The application on startup will load the resources defined in the main application.ini file. To configure each module there is a resource called modules that calls the bootstraping code for each module on every request. If you want to load [...]]]></description>
			<content:encoded><![CDATA[<p>Zend Framework recently introduced the concept of modules so that your applications become more manegable. The application on startup will load the resources defined in the main application.ini file. To configure each module there is a resource called modules that calls the bootstraping code for each module on every request. If you want to load resources on a per module basis you need to write a bootstrap for each module. This can also generate clashes if two modules try to load the same resource. Additionally this process can have a negative impact on your applications performance.</p>
<p>In this blog I propose a different strategy: I created a controller action plugin that will load resources dynamically using the main bootstraping code. The idea is that after the routes are parsed and before the action is executed this code will load the module&#8217;s config file and call the bootstrap again so that it will load the resources defined in this config. </p>
<p>This method has several advantages: only the resources for the module that is being called are loaded. Becuase only one config file is read there is no possiblity of clashes.</p>
<p>Here&#8217;s the code:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw2">&lt;?php</span></p>
<p><span class="coMULTI">/**<br />
&nbsp;* Bootstraps the module used in the current request<br />
&nbsp;* It merges the options from main application.ini with the options from a<br />
&nbsp;* module specific application.ini.<br />
&nbsp;* I&#8217;m using the fact that a resources are loaded only once, so a resource<br />
&nbsp;* declared in main application.ini is initialized there. If you wish to use some resource<br />
&nbsp;* in every module use the key default (see bellow).<br />
&nbsp;*<br />
&nbsp;* The keys default and disable in the main application.ini have a special meaning.<br />
&nbsp;* default: It is merged initally so a key default.resources.xxx is added as resource.xxx<br />
&nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;so it load the resource xxx as a default for all modules<br />
&nbsp;* disable: It is used to disable keys after merging so a key disable.resources.xxx disables<br />
&nbsp;* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this resource in all modules.<br />
&nbsp;*/</span><br />
<span class="kw2">class</span> Easytech_Controller_Plugin_ModuleBootstrap <span class="kw2">extends</span> Zend_Controller_Plugin_Abstract<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; const MODULE_APPLICATION_INI = <span class="st0">&quot;configs/application.ini&quot;</span>;</p>
<p>&nbsp; &nbsp; protected <span class="re0">$_bootstrap</span>;</p>
<p>&nbsp; &nbsp; protected <span class="re0">$_autoloader</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> dispatchLoopStartup<span class="br0">&#40;</span> Zend_Controller_Request_Abstract <span class="re0">$request</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$moduleName</span> = <span class="re0">$request</span>-&gt;<span class="me1">getModuleName</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/empty"><span class="kw3">empty</span></a><span class="br0">&#40;</span> <span class="re0">$moduleName</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$moduleName</span> = <span class="st0">&#8216;default&#8217;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$front</span> = Zend_Controller_Front::<span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$moduleDir</span> = <span class="re0">$front</span>-&gt;<span class="me1">getModuleDirectory</span><span class="br0">&#40;</span> <span class="re0">$moduleName</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/empty"><span class="kw3">empty</span></a><span class="br0">&#40;</span> <span class="re0">$moduleDir</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$moduleDir</span> = APPLICATION_PATH;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Para ser usado en los ini.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/define"><span class="kw3">define</span></a><span class="br0">&#40;</span><span class="st0">&#8216;MODULE_PATH&#8217;</span>, <span class="re0">$moduleDir</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/define"><span class="kw3">define</span></a><span class="br0">&#40;</span><span class="st0">&#8216;MODULE_NAME&#8217;</span>, <span class="re0">$moduleName</span> <span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Create a autoloader for this module</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$autoloader</span> = <span class="kw2">new</span> Zend_Application_Module_Autoloader<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;namespace&#8217;</span> =&gt; <span class="re0">$moduleName</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#8216;basePath&#8217;</span> &nbsp;=&gt; <span class="re0">$moduleDir</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;_bootstrap = <span class="re0">$front</span>-&gt;<span class="me1">getParam</span><span class="br0">&#40;</span><span class="st0">&#8216;bootstrap&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$globalOptions</span> = <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">getOptions</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Default options from main application.ini</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$globalOptions</span><span class="br0">&#91;</span><span class="st0">&#8216;default&#8217;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> = <span class="re0">$globalOptions</span><span class="br0">&#91;</span><span class="st0">&#8216;default&#8217;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$globalOptions</span><span class="br0">&#91;</span> <span class="re0">$moduleName</span> <span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> = <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">mergeOptions</span><span class="br0">&#40;</span><span class="re0">$options</span>, <span class="re0">$globalOptions</span><span class="br0">&#91;</span> <span class="re0">$moduleName</span> <span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$applicationFile</span> = <span class="re0">$moduleDir</span> . DIRECTORY_SEPARATOR . self::<span class="me2">MODULE_APPLICATION_INI</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$globalOptions</span><span class="br0">&#91;</span> <span class="st0">&#8216;application_file&#8217;</span> <span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$applicationFile</span> &nbsp;= <span class="re0">$moduleDir</span> . DIRECTORY_SEPARATOR . <span class="re0">$globalOptions</span><span class="br0">&#91;</span> <span class="st0">&#8216;application_file&#8217;</span> <span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> = <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">mergeOptions</span><span class="br0">&#40;</span> <span class="re0">$options</span>, <span class="re0">$this</span>-&gt;_loadConfig<span class="br0">&#40;</span> <span class="re0">$applicationFile</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$globalOptions</span><span class="br0">&#91;</span><span class="st0">&#8216;disable&#8217;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$options</span> = <span class="re0">$this</span>-&gt;<span class="me1">unsetOptions</span><span class="br0">&#40;</span><span class="re0">$options</span>, <span class="re0">$globalOptions</span><span class="br0">&#91;</span><span class="st0">&#8216;disable&#8217;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">setOptions</span><span class="br0">&#40;</span> <span class="re0">$options</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">bootstrap</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="coMULTI">/**<br />
&nbsp; &nbsp; &nbsp;* Unset options recursively.<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param &nbsp;array $array1<br />
&nbsp; &nbsp; &nbsp;* @param &nbsp;mixed $array2<br />
&nbsp; &nbsp; &nbsp;* @return array<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> unsetOptions<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="re0">$array1</span>, <span class="re0">$array2</span> = <span class="kw2">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span><span class="re0">$array2</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$array2</span> <span class="kw1">as</span> <span class="re0">$key</span> =&gt; <span class="re0">$val</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> ! <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$array1</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">continue</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span> <span class="re0">$array2</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$array1</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">unsetOptions</span><span class="br0">&#40;</span> <span class="re0">$array1</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span>, <span class="re0">$array2</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span> <span class="re0">$array1</span><span class="br0">&#91;</span> <span class="re0">$key</span> <span class="br0">&#93;</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$array1</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="coMULTI">/**<br />
&nbsp; &nbsp; &nbsp;* Based heavily on Zend_Application-&gt;_loadConfig<br />
&nbsp; &nbsp; &nbsp;* Load configuration file of options<br />
&nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp;* @param &nbsp;string $file<br />
&nbsp; &nbsp; &nbsp;* @throws Zend_Application_Exception When invalid configuration file is provided<br />
&nbsp; &nbsp; &nbsp;* @return array<br />
&nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; protected <span class="kw2">function</span> _loadConfig<span class="br0">&#40;</span><span class="re0">$file</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>! Zend_Loader::<span class="me2">isReadable</span><span class="br0">&#40;</span><span class="re0">$file</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$environment</span> = <span class="re0">$this</span>-&gt;_bootstrap-&gt;<span class="me1">getApplication</span><span class="br0">&#40;</span><span class="br0">&#41;</span>-&gt;<span class="me1">getEnvironment</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$suffix</span> &nbsp; &nbsp; &nbsp;= <a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">&#40;</span><a href="http://www.php.net/pathinfo"><span class="kw3">pathinfo</span></a><span class="br0">&#40;</span><span class="re0">$file</span>, PATHINFO_EXTENSION<span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span><span class="re0">$suffix</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;ini&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$config</span> = <span class="kw2">new</span> Zend_Config_Ini<span class="br0">&#40;</span><span class="re0">$file</span>, <span class="re0">$environment</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;xml&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$config</span> = <span class="kw2">new</span> Zend_Config_Xml<span class="br0">&#40;</span><span class="re0">$file</span>, <span class="re0">$environment</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;php&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">&#8216;inc&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$config</span> = <span class="kw1">include</span> <span class="re0">$file</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw <span class="kw2">new</span> Zend_Application_Exception<span class="br0">&#40;</span><span class="st0">&#8216;Invalid configuration file provided; PHP file does not return array value&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$config</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">default</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw <span class="kw2">new</span> Zend_Application_Exception<span class="br0">&#40;</span><span class="st0">&#8216;Invalid configuration file provided; unknown config type&#8217;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$config</span>-&gt;<span class="me1">toArray</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/08/04/initializing-only-one-module-per-request-in-zend_framework/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Filtering table data by user in PostgreSQL</title>
		<link>http://blog.easytech.com.ar/2009/02/19/filtering-table-data-by-user-in-postgresql/</link>
		<comments>http://blog.easytech.com.ar/2009/02/19/filtering-table-data-by-user-in-postgresql/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 02:18:54 +0000</pubDate>
		<dc:creator>miquel</dc:creator>
		
		<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=402</guid>
		<description><![CDATA[When developing multi-organization web applications it is of utmost importance that data from one organization is not visible to the other. There are several software aproaches for this. Usually this can be solved by having an organization ID and whenever a query is made a &#8216;where&#8217; clause is added to filter by organization. Although this [...]]]></description>
			<content:encoded><![CDATA[<p>When developing multi-organization web applications it is of utmost importance that data from one organization is not visible to the other. There are several software aproaches for this. Usually this can be solved by having an organization ID and whenever a query is made a &#8216;where&#8217; clause is added to filter by organization. Although this approach works fine it is up to developers to always filter by org_id but its certainly error prone.</p>
<p>To solve this problem there are other approaches. One is that each organization gets a copy of the database and a single database user to log to this database. When the user logs in the application uses the URL to determine the organization (say: <em>http://<strong>organization</strong>.domain.com/login</em>). With the organization name extracted from the URL, the aplication determines which database instance, database user and password to use for the application to use. This obviously solves the problem since, by definition, there is no way data from the two organizations can mix: they live in different databases alltogether.</p>
<p><span id="more-402"></span></p>
<p>The problem with the above approach is that, if you have a large number of organizations that means you have a large number of databases. In the case of thousands of organizations (don&#8217;t think corporations, think small business owners which use your webapp daily) then there might be performance issues in the database since regular databases are not designed to have thousands of small databases. At least the ones I know of.</p>
<p>Chatting about this problem with the nice folks over at the <strong>#postgres</strong> IRC channel on the FreeNode servers they pointed me to two different approaches. One was to use PL/pgSQL code to isolate all access to the data. You have PL/pgSQL code which takes a user as a parameter and uses it to filter or insert the data into tables which have an org_id column.</p>
<p>A second approach which seemed more interesting to me was to create a schema for each organization and encode the organization_id in the schema name. Then you can create an updatable view which uses the schema name to filter the data by organiation_id.</p>
<p>The last approach appealed to me more because I wanted the database to take care of the filtering. The problem with it is that you have to create a schema for each new user. Another setback the guys at #postgres pointed out was that connection spooling is not possible (I don&#8217;t know enough postgres to understand why).</p>
<p>In this article I will point out a slighly different approach our team at Easytech came up with inspired by this last method. The idea is that when the applications logs into the database it sets the organization ID as a kind of &#8217;session parameter&#8217; . All data is accesible through updatable views and this views filter the data using de org_id. When data is updated in the table the org_id is pulled from the &#8217;session&#8217; and inserted in the original table so that it can be marked as beloging to that organization.</p>
<p>The trick here is to create a run-time paramater. To do this you need to modify your <strong>postgres.conf</strong> file and add a parameter. For example:</p>
<div class="dean_ch" style="white-space: wrap;">
&nbsp;# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
&nbsp;# &nbsp;Organization ID <br />
&nbsp;# &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>&nbsp;custom_variable_classes = &#8216;org&#8217; &nbsp;# list of custom variable class names<br />
&nbsp;org.id = &#8216;private&#8217; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # set initial value<br />
&nbsp;</div>
<p>After re-starting the server you can now connect to the server with psql and set the value of <strong>org.id</strong> with:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">SET</span> SESSION org.id <span class="kw1">TO</span> <span class="st0">&#8216;apple&#8217;</span>;</div>
<p>Lets see how we can use this to create views which display different data to different application users:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2"># su - postgres</span><br />
$ psql<br />
Welcome <span class="kw1">TO</span> psql <span class="nu0">7.3</span><span class="nu0">.4</span>, the PostgreSQL interactive terminal.</p>
<p>Type: &nbsp;\copyright <span class="kw1">FOR</span> distribution terms<br />
&nbsp; &nbsp; &nbsp; &nbsp;\h <span class="kw1">FOR</span> help <span class="kw1">WITH</span> SQL commands<br />
&nbsp; &nbsp; &nbsp; &nbsp;\? <span class="kw1">FOR</span> help <span class="kw1">ON</span> internal slash commands<br />
&nbsp; &nbsp; &nbsp; &nbsp;\g <span class="kw1">OR</span> terminate <span class="kw1">WITH</span> semicolon <span class="kw1">TO</span> execute query<br />
&nbsp; &nbsp; &nbsp; &nbsp;\q <span class="kw1">TO</span> quit</p>
<p>postgres=<span class="co2"># select &nbsp;version();</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;version<br />
<span class="co1">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</span><br />
&nbsp;PostgreSQL <span class="nu0">8.2</span><span class="nu0">.5</span> <span class="kw1">ON</span> i686-pc-linux-gnu, compiled <span class="kw1">BY</span> GCC gcc <span class="br0">&#40;</span>GCC<span class="br0">&#41;</span> <span class="nu0">3.3</span><span class="nu0">.2</span> <span class="nu0">20031022</span> <span class="br0">&#40;</span>Red Hat Linux <span class="nu0">3.3</span><span class="nu0">.2</span><span class="nu0">-1</span><span class="br0">&#41;</span></p>
<p>postgres=<span class="co2"># &nbsp;create database corp;</span><br />
<span class="kw1">CREATE</span> <span class="kw1">DATABASE</span></p>
<p>postgres=<span class="co2"># \connect corp</span><br />
You are now connected <span class="kw1">TO</span> <span class="kw1">DATABASE</span> corp.</p>
<p>corp=<span class="co2"># create table secret_projects ( org_id varchar, project_name varchar);</span><br />
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span></p>
<p>corp=<span class="co2"># insert into secret_projects values (&#8217;apple&#8217;, &#8216;iPhone&#8217;);</span><br />
corp=<span class="co2"># insert into secret_projects values (&#8217;apple&#8217;, &#8216;iMac&#8217;);</span><br />
corp=<span class="co2"># insert into secret_projects values (&#8217;microsoft&#8217;, &#8216;Zune&#8217;);</span><br />
&#8230;</p>
<p>corp=<span class="co2"># create view secret_projects_v as</span><br />
<span class="kw1">SELECT</span> *<br />
<span class="kw1">FROM</span> secret_projects<br />
<span class="kw1">WHERE</span> org_id = <span class="br0">&#40;</span> <span class="kw1">SELECT</span> current_setting<span class="br0">&#40;</span><span class="st0">&#8216;org.id&#8217;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>;<br />
<span class="kw1">CREATE</span> <span class="kw1">VIEW</span></p>
<p>corp=<span class="co2"># set session org.id to &#8216;apple&#8217;;</span><br />
<span class="kw1">SET</span></p>
<p>corp=<span class="co2"># select * from secret_projects_v;</span><br />
&nbsp;org_id | project_name<br />
<span class="co1">&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;</span><br />
&nbsp;apple &nbsp;| iPhone<br />
&nbsp;apple &nbsp;| iMac<br />
<span class="br0">&#40;</span><span class="nu0">2</span> rows<span class="br0">&#41;</span></p>
<p>corp=<span class="co2"># set session org.id to &#8216;microsoft&#8217;;</span><br />
<span class="kw1">SET</span></p>
<p>corp=<span class="co2"># select * from secret_projects_v;</span><br />
&nbsp; org_id &nbsp; | project_name<br />
<span class="co1">&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8211;</span><br />
&nbsp;microsoft | Zune<br />
<span class="br0">&#40;</span><span class="nu0">1</span> row<span class="br0">&#41;</span></div>
<p>As you can see with this approach each application user can see different data from the same table. When a user logs into the application we pull the organization from the URL and use it to setup the session parameter. Once the session paramater is set, all views of sensitive data filter by org_id. Of course if you select from the original tables then you will see all data. It is important that the development team only use this filtered views to access the data.</p>
<p>We still have to investigate how this technique might work in a real application. Another issue to study is how to perform joins with several views and how it performs. We will report how this technique turns out in another posting.</pre>
</pre>
</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/02/19/filtering-table-data-by-user-in-postgresql/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Using csv data with oracle</title>
		<link>http://blog.easytech.com.ar/2009/01/13/using-csv-data-with-oracle/</link>
		<comments>http://blog.easytech.com.ar/2009/01/13/using-csv-data-with-oracle/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 20:54:35 +0000</pubDate>
		<dc:creator>lucas</dc:creator>
		
		<category><![CDATA[Database]]></category>

		<category><![CDATA[Oracle]]></category>

		<category><![CDATA[csv]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=340</guid>
		<description><![CDATA[
Sometimes I need to use data from a csv (comma separated values) in an oracle procedure. The best way to do that is inserting the data into a db table using sqlloader  and then reading it from the PL/SQL.
In this post I will show you how to use sql loader to load a csv [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.easytech.com.ar/wp-content/uploads/oracle_logo.gif" rel="thumbnail"><img class="size-full wp-image-342 alignleft" title="oracle_logo" src="http://blog.easytech.com.ar/wp-content/uploads/oracle_logo.gif" alt="" width="94" height="94" /></a><br />
Sometimes I need to use data from a csv (comma separated values) in an oracle procedure. The best way to do that is inserting the data into a db table using sqlloader  and then reading it from the PL/SQL.</p>
<p>In this post I will show you how to use sql loader to load a csv file exported from excel into an oracle table.</p>
<p>Suppose that you got a XLS spreadsheet with contact data: first name, last name, security number, phone number.</p>
<p>First, create a table where the file will be loaded:</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> people_from_csv<br />
&nbsp; &nbsp;<span class="br0">&#40;</span>first_name varchar2<span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;,last_name varchar2<span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;,security_number number<br />
&nbsp; &nbsp;,phone_number varchar2<span class="br0">&#40;</span><span class="nu0">50</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#41;</span>;</div>
<p>In my xls (people.xls) I have the following info:</p>
<table border="1" cellspacing="0" frame="box" rules="groups">
<colgroup><col width="86"></col></colgroup>
<colgroup><col width="86"></col></colgroup>
<colgroup><col width="86"></col></colgroup>
<colgroup><col width="86"></col></colgroup>
<tbody>
<tr>
<td width="86" height="14" align="left" bgcolor="#e6e6ff"><span style="font-size: xx-small;">First Name</span></td>
<td width="86" align="left" bgcolor="#e6e6ff"><span style="font-size: xx-small;">Last Name</span></td>
<td width="86" align="left" bgcolor="#e6e6ff"><span style="font-size: xx-small;">Secutiry Number</span></td>
<td style="text-align: center;" width="86" bgcolor="#e6e6ff"><span style="font-size: xx-small;">Phone Number</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John </span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000001</span></td>
<td align="right"><span style="font-size: xx-small;">11111123456</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 01</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000002</span></td>
<td align="right"><span style="font-size: xx-small;">11111123457</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 02</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000003</span></td>
<td align="right"><span style="font-size: xx-small;">11111123458</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 03</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000004</span></td>
<td align="right"><span style="font-size: xx-small;">11111123459</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 04</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000005</span></td>
<td align="right"><span style="font-size: xx-small;">11111123460</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 05</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000006</span></td>
<td align="right"><span style="font-size: xx-small;">11111123461</span></td>
</tr>
</tbody>
<tbody>
<tr>
<td height="13" align="left"><span style="font-size: xx-small;">John 06</span></td>
<td align="left"><span style="font-size: xx-small;">Doe</span></td>
<td align="right"><span style="font-size: xx-small;">00000007</span></td>
<td align="right"><span style="font-size: xx-small;">11111123462</span></td>
</tr>
</tbody>
</table>
<p>Save the data as a comma delimited file.</p>
<p><a href="http://blog.easytech.com.ar/wp-content/uploads/screenshot-2.png" rel="thumbnail"><img class="size-full wp-image-348 alignright" title="screenshot-2" src="http://blog.easytech.com.ar/wp-content/uploads/screenshot-2.png" alt="" width="128" height="104" /></a>File -&gt; Save As<br />
Change File name to people_csv<br />
Select ‘Text CSV ’ in the File type drop down box.</p>
<p>If you open the people_csv.csv file in a text editor (vi in my case), you will see it in a comma separated format.  Two commas will denote fields without a value, these will be loaded as nulls into the Oracle table.</p>
<p><strong>CSV file</strong>:</p>
<div class="dean_ch" style="white-space: wrap;">First Name,Last Name,Secutiry Number,Phone Number<br />
John ,Doe,00000001,11111123456<br />
John 01,Doe,00000002,11111123457<br />
John 02,Doe,00000003,11111123458<br />
John 03,Doe,00000004,11111123459<br />
John 04,Doe,00000005,11111123460<br />
John 05,Doe,00000006,11111123461<br />
John 06,Doe,00000007,11111123462</div>
<p>Create the following sql loader control file (people_ctrl.txt)</p>
<div class="dean_ch" style="white-space: wrap;"><span class="kw1">LOAD</span> <span class="kw1">DATA</span><br />
<span class="kw1">INFILE</span> <span class="st0">&#8216;people_csv.csv&#8217;</span><br />
<span class="kw1">INTO</span> <span class="kw1">TABLE</span> people_from_csv<br />
<span class="kw1">FIELDS</span> TERMINATED <span class="kw1">BY</span> <span class="st0">&#8216;,&#8217;</span><br />
<span class="br0">&#40;</span> first_name, last_name , security_number, phone_number<span class="br0">&#41;</span></div>
<p>at last  run the sql loader to put the info into the db table.</p>
<div class="dean_ch" style="white-space: wrap;">$ sqlldr usr/<span class="kw3">pwd</span> <span class="re2">control=</span>people_ctrl.txt <span class="re2">log=</span>csvlog</p>
<p>SQL*Loader: Release <span class="nu0">9.2</span><span class="nu0">.0</span><span class="nu0">.8</span><span class="nu0">.0</span> - Production on Tue Jan <span class="nu0">13</span> <span class="nu0">17</span>:<span class="nu0">26</span>:<span class="nu0">53</span> <span class="nu0">2009</span></p>
<p>Copyright <span class="br0">&#40;</span>c<span class="br0">&#41;</span> <span class="nu0">1982</span>, <span class="nu0">2002</span>, Oracle Corporation. &nbsp;All rights reserved.</p>
<p>Commit point reached - logical record count <span class="nu0">7</span></div>
<p>Now I can use the data from sql with a simple query:</p>
<div class="dean_ch" style="white-space: wrap;">SQL&gt; <span class="kw1">SELECT</span> phone_number <span class="kw1">FROM</span> people_from_csv;</p>
<p>PHONE_NUMBER<br />
<span class="co1">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</span><br />
<span class="nu0">11111123456</span><br />
<span class="nu0">11111123457</span><br />
<span class="nu0">11111123458</span><br />
<span class="nu0">11111123459</span><br />
<span class="nu0">11111123460</span><br />
<span class="nu0">11111123461</span><br />
<span class="nu0">11111123462</span></p>
<p><span class="nu0">7</span> rows selected.</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/01/13/using-csv-data-with-oracle/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Haciendo POSTs con CURL</title>
		<link>http://blog.easytech.com.ar/2009/01/12/haciendo-posts-con-curl/</link>
		<comments>http://blog.easytech.com.ar/2009/01/12/haciendo-posts-con-curl/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 18:15:09 +0000</pubDate>
		<dc:creator>Leandro</dc:creator>
		
		<category><![CDATA[Programming and Scripting]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=271</guid>
		<description><![CDATA[curl es un programa que nos permite transferir datos (o archivos) desde o hasta un servidor, a través de distintos protocolos (entre ellos HTTP, FTP, SCP, etc).

hackers usando curl para testear un SQL injection
Lo interesante (y lo más usado entre los code-monkeys de Easytech) es su uso para emular POSTs a ciertas URLs, sin tener [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://curl.haxx.se/">curl</a> es un programa que nos permite transferir datos (o archivos) desde o hasta un servidor, a través de distintos protocolos (entre ellos HTTP, FTP, SCP, etc).</p>
<p><a href="http://blog.easytech.com.ar/wp-content/uploads/hackers04.jpg" rel="thumbnail"><img class="alignnone size-full wp-image-119" src="http://blog.easytech.com.ar/wp-content/uploads/hackers04.jpg" alt="hackers usando curl para testear un SQL injection." width="280" height="89" /></a><br />
<br/><br/><br/><br/><br/><em>hackers usando curl para testear un SQL injection</em></p>
<p>Lo interesante (y lo más usado entre los <em>code-monkeys</em> de Easytech) es su uso para emular POSTs a ciertas URLs, sin tener que pasar por la página en el browser.</p>
<p>si no lo tienen, pueden bajarlo del link anterior, aunque tiene fama de estar en todos los repos de las distros conocidas.</p>
<p>En mi caso particular, curl me fue muy útil para hacer un POST a una de las webapps que desarrollamos, y poder chequear el XML que devolvía, sin complicaciones ni pasar por un web-browser.</p>
<p><img class="size-full wp-image-266" src="http://blog.easytech.com.ar/wp-content/uploads/viewerpl.jpeg" alt="un PM de Easytech le enseña a un junior a probar sus Forms con curl." width="400" height="280" /><br />
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><em>un PM de Easytech le enseña a un junior a probar sus Forms con curl.</em></p>
<p>empecemos por lo más básico, emular un formulario. esto lo hacemos con <span style="#008000;">curl -F</span>, o <span style="#008000;">curl -d</span> (dependiendo del content-type que querramos usar). La sintáxis sería algo como:</p>
<div class="dean_ch" style="white-space: wrap;">curl -d &quot;nombre_campo1=valor_campo1&amp;amp;nombre_campo2=valor_campo2&amp;amp;nombre_campoN=valor_campoN&quot; url_a_donde_hacemos_el_post.com</div>
<p>Otro uso interesante es el de hacer upload de files, emulando un  de un form html. La sintáxis:</p>
<div class="dean_ch" style="white-space: wrap;">curl -F &quot;nombre_del_input=@path_al_file_a_subir&quot; url_a_donde_hacemos_el_post.com</div>
<p>o&#8230;</p>
<div class="dean_ch" style="white-space: wrap;">curl -F &quot;nombre_del_input=@path_al_file_a_subir;filename=nombre_del_file&quot; url_a_donde_hacemos_el_post.com</div>
<p>&#8230; si queremos un nombre específico para el file.</p>
<p>Nótese que la arroba delante del path del file es obligatoria.</p>
<p>Claro que, lo que yo quería, era ver qué me devolvía la aplicación (en este caso es un upload de un file a un servidor que devolvía un XML con datos). Para hacer esto tenemos varias formas, u opciones, para pasarle al comando curl, como ser &#8211;verbose, &#8211;trace, o &#8211;trace-ascii. Cada una muestra distintas cosas, dependiendo lo que necesitemos. En mi caso, el servidor devolvía el XML con un simple fpassthru, para lo que trace-ascii venía perfecto.</p>
<p>La sintáxis, entonces, sería así:</p>
<div class="dean_ch" style="white-space: wrap;">curl &#8211;trace-ascii -F &quot;nombre_del_input=@path_al_file_a_subir;filename=nombre_del_file&quot; url_a_donde_hacemos_el_post.com</div>
<p>la aplicación recibió el file a uploadear como si de un form se tratase, y al devolver el XML, curl lo mostró por stdout. Ideal para debuggear desde la terminal en un servidor remoto o sin tener que pasar por la aplicación web.</p>
<p>Dicen por ahí que también es muy útil para testear vulnerabilidades en algunos sitios con poca validación de formularios, pero eso es demasiado oscuro para mí.</p>
<p><img class="size-full wp-image-264" src="http://blog.easytech.com.ar/wp-content/uploads/hackers2.gif" alt="hacker sexy tipea un script con 2 joysticks." width="350" height="216" /><br />
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><em>hacker sexy tipea un script con 2 joysticks.</em></p>
<p>Para ver más ejemplos, consulten <a href="http://curl.haxx.se/docs/httpscripting.html">acá</a> o en el man de curl, por supuesto.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2009/01/12/haciendo-posts-con-curl/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Día de Campo</title>
		<link>http://blog.easytech.com.ar/2008/12/12/dia-de-camp/</link>
		<comments>http://blog.easytech.com.ar/2008/12/12/dia-de-camp/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 00:19:23 +0000</pubDate>
		<dc:creator>Leandro</dc:creator>
		
		<category><![CDATA[Misc]]></category>

		<guid isPermaLink="false">http://blog.easytech.com.ar/?p=252</guid>
		<description><![CDATA[Como es costumbre, todos los veranos Easytech organiza un &#8220;día de campo&#8221; bien merecido por los developers que tanto sufrimos durante el año (no podemos vivir manejando helicópteros de juguete todo el día).
Para distendernos, fuimos obligados a hacer deporte (terrestre Y ACUÁTICO). Además, no consultamos nuestros mails en todo el día (Bueno, en realidad sí, [...]]]></description>
			<content:encoded><![CDATA[<p>Como es costumbre, todos los veranos Easytech organiza un &#8220;día de campo&#8221; bien merecido por los developers que tanto sufrimos durante el año (no podemos vivir manejando helicópteros de juguete todo el día).</p>
<p>Para distendernos, fuimos obligados a hacer deporte (terrestre Y ACUÁTICO). Además, no consultamos nuestros mails en todo el día (Bueno, en realidad sí, había Wi-Fi).</p>
<p>En agradecimiento por ese exquisito matambrito a la pizza (y por organizar el evento un día laboral), compartimos las fotos que documentan el hecho:</p>

<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0400_new3/' title='img_0400_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0400_new3.jpg" width="112" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0402_new3/' title='img_0402_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0402_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0404_new3/' title='img_0404_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0404_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0408_new3/' title='img_0408_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0408_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0409_new3/' title='img_0409_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0409_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0412_new3/' title='img_0412_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0412_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>
<a href='http://blog.easytech.com.ar/2008/12/12/dia-de-camp/img_0413_new3/' title='img_0413_new3'><img src="http://blog.easytech.com.ar/wp-content/uploads/img_0413_new3.jpg" width="150" height="112" class="attachment-thumbnail" alt="" /></a>

]]></content:encoded>
			<wfw:commentRss>http://blog.easytech.com.ar/2008/12/12/dia-de-camp/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
