<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Codelicious</title>
	
	<link>http://www.codelicious.nl</link>
	<description>Personal weblog of Aron Rotteveel</description>
	<lastBuildDate>Tue, 02 Aug 2011 07:53:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/codelicious/jgBH" /><feedburner:info uri="codelicious/jgbh" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Using Zend Framework’s router to setup ACL role-based controllers</title>
		<link>http://feedproxy.google.com/~r/codelicious/jgBH/~3/--H4tVgLwlI/</link>
		<comments>http://www.codelicious.nl/zend-frameworks-router-setup-acl-rolebased-controllers/#comments</comments>
		<pubDate>Wed, 20 Oct 2010 14:09:13 +0000</pubDate>
		<dc:creator>Aron</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://www.codelicious.nl/?p=168</guid>
		<description><![CDATA[Since I started using Zend Framework about 2.5 years ago, I have developed several applications in it, some of them using Zend_Acl. Even though these applications work just fine, I have yet to discover an easy way to implement Zend_Acl in a uniform way and plugging it into my own framework so that I can [...]]]></description>
			<content:encoded><![CDATA[<p>Since I started using Zend Framework about 2.5 years ago, I have developed several applications in it, some of them using Zend_Acl.</p>
<p>Even though these applications work just fine, I have yet to discover an easy way to implement <a href="http://framework.zend.com/manual/en/zend.acl.html">Zend_Acl</a> in a uniform way and plugging it into my own framework so that I can easily set it up on future projects.</p>
<p>I am currently working on a application involving three user roles with very distinct features to them. I have first tried using Zend_Acl to handle all of these permissions correctly, but have found it to be quite a pain. Most of my controllers end up containing three times the number of actions they would normally contain, or, even worse, I would have to implement several switches in one single action to facilitate the different features required by each of the user roles.</p>
<p>To make my life a bit easier, I have fiddled around with <a href="http://framework.zend.com/manual/en/zend.controller.router.html">Zend_Controller_Router_Route</a> and have come up with a way to use one uniform URI scheme that points to different controllers, based on the user role. This is done without priorly setup routes, which saves me quite a lot of work.</p>
<p>All is done by extend Zend_Controller_Router_Route_Module and querying the ACL in the match() and assemble() methods.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php 

class App_Controller_Router_Route_Rolebasedcontroller extends Zend_Controller_Router_Route_Module
{
	/**
	 * Roles that should be rewritten automatically
	 *
	 * @var array
	 */
	protected $_rewriteRoles = array('employee', 'executive');

	/**
	 * Exceptions that should not be rewritten
	 *
	 * @var array
	 */
	protected $_exceptions = array(
	   array(
	       'module' =&gt; 'auth',
	       'controller' =&gt; 'index'
	   ),
	   array(
	       'module' =&gt; 'core',
	       'controller' =&gt; 'profile'
	   )
	);

    /**
     * Matches a user submitted path. Assigns and returns an array of variables
     * on a successful match.
     *
     * If a request object is registered, it uses its setModuleName(),
     * setControllerName(), and setActionName() accessors to set those values.
     * Always returns the values as an array.
     *
     * @param string $path Path used to match against this routing map
     * @return array An array of assigned values or a false on a mismatch
     */
	public function match($path, $partial = false)
	{
		$result = parent::match($path, $partial);

		$role = Plano_Acl::getInstance()-&gt;getCurrentRole();

		if (null !== $role &amp;&amp; in_array($role, $this-&gt;_rewriteRoles))
		{
            if (!$this-&gt;hasException($result['module'], $result['controller'], $result['action']))
            {
				if (isset($result[$this-&gt;_controllerKey]))
				{
					$result[$this-&gt;_controllerKey] = ucfirst($role) . '-' . ucfirst($result[$this-&gt;_controllerKey]);
				}
            }
		}

		return $result;
	}

    /**
     * Assembles user submitted parameters forming a URL path defined by this route
     * Removes fole prefixes when required
     *
     * @param array $data An array of variable and value pairs used as parameters
     * @param bool $reset Weither to reset the current params
     * @return string Route path with user submitted parameters
     */
    public function assemble($data = array(), $reset = false, $encode = true, $partial = false)
    {
        if (!$this-&gt;_keysSet) {
            $this-&gt;_setRequestKeys();
        }

        $params = (!$reset) ? $this-&gt;_values : array();

        foreach ($data as $key =&gt; $value) {
            if ($value !== null) {
                $params[$key] = $value;
            } elseif (isset($params[$key])) {
                unset($params[$key]);
            }
        }

        $params += $this-&gt;_defaults;

        $url = '';

        if ($this-&gt;_moduleValid || array_key_exists($this-&gt;_moduleKey, $data)) {
            if ($params[$this-&gt;_moduleKey] != $this-&gt;_defaults[$this-&gt;_moduleKey]) {
                $module = $params[$this-&gt;_moduleKey];
            }
        }
        unset($params[$this-&gt;_moduleKey]);

        $controller = $params[$this-&gt;_controllerKey];

        // remove role prefix from url when required
        $role = Plano_Acl::getInstance()-&gt;getCurrentRole();

        if (null !== $role &amp;&amp; in_array($role, $this-&gt;_rewriteRoles))
        {
        	if (strtolower(substr($params[$this-&gt;_controllerKey], 0, strlen($role))) == strtolower($role))
        	{
        		// Controller is in the form Role-Controller, so we should use strlen()+1 to extract the controller part
        		$controller = lcfirst(substr($params[$this-&gt;_controllerKey], strlen($role) + 1));
        	}
        }

        unset($params[$this-&gt;_controllerKey]);

        $action = $params[$this-&gt;_actionKey];
        unset($params[$this-&gt;_actionKey]);

        foreach ($params as $key =&gt; $value) {
            $key = ($encode) ? urlencode($key) : $key;
            if (is_array($value)) {
                foreach ($value as $arrayValue) {
                    $arrayValue = ($encode) ? urlencode($arrayValue) : $arrayValue;
                    $url .= '/' . $key;
                    $url .= '/' . $arrayValue;
                }
            } else {
                if ($encode) $value = urlencode($value);
                $url .= '/' . $key;
                $url .= '/' . $value;
            }
        }

        if (!empty($url) || $action !== $this-&gt;_defaults[$this-&gt;_actionKey]) {
            if ($encode) $action = urlencode($action);
            $url = '/' . $action . $url;
        }

        if (!empty($url) || $controller !== $this-&gt;_defaults[$this-&gt;_controllerKey]) {
            if ($encode) $controller = urlencode($controller);
            $url = '/' . $controller . $url;
        }

        if (isset($module)) {
            if ($encode) $module = urlencode($module);
            $url = '/' . $module . $url;
        }

        return ltrim($url, self::URI_DELIMITER);
    }	

    /**
     * Check wether the specified request is excempted
     *
     * @param string $module
     * @param controller $controller
     * @param action $action
     * @return boolean
     */
    protected function hasException($module = null, $controller = null, $action = null)
    {
    	$e = false;

    	foreach ($this-&gt;_exceptions as $exception)
    	{
    		if (null !== $module)
    		{
    			$e = (isset($exception['module']) &amp;&amp; $exception['module'] == $module);
	            if (true === $e &amp;&amp; null !== $controller)
	            {
	                $e = (isset($exception['controller']) &amp;&amp; $exception['controller'] == $controller);

		            if (true === $e &amp;&amp; null !== $action)
		            {
		                if (isset($exception['action']))
		                {
		                    $e = ($exception['action'] == $action);
		                }
		            }
	            }
	            if (true === $e) break;
    		}
    	}

    	return $e;
    }
}
</pre>
<img src="http://feeds.feedburner.com/~r/codelicious/jgBH/~4/--H4tVgLwlI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.codelicious.nl/zend-frameworks-router-setup-acl-rolebased-controllers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.codelicious.nl/zend-frameworks-router-setup-acl-rolebased-controllers/</feedburner:origLink></item>
		<item>
		<title>Using Zend_CodeGenerator to generate a Data Mapper</title>
		<link>http://feedproxy.google.com/~r/codelicious/jgBH/~3/kVZWaCYrd70/</link>
		<comments>http://www.codelicious.nl/using-zendcodegenerator-to-generate-data-mapper/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 16:09:28 +0000</pubDate>
		<dc:creator>Aron</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://www.codelicious.nl/?p=24</guid>
		<description><![CDATA[I have always liked the Data Mapper pattern example ZF Quickstart&#8217;s model creation section but have never actually used it in one of my applications. The main reason is that I am lazy. Which, in this case, is a good thing. Applying the data mapper pattern to even a very simple database table would require [...]]]></description>
			<content:encoded><![CDATA[<p>I have always liked the Data Mapper pattern example <a href="http://framework.zend.com/manual/en/learning.quickstart.create-model.html">ZF Quickstart&#8217;s model creation section</a> but have never actually used it in one of my applications.</p>
<p>The main reason is that I am lazy. Which, in this case, is a <a href="http://www.codinghorror.com/blog/2005/08/how-to-be-lazy-dumb-and-successful.html">good thing</a>. Applying the data mapper pattern to even a very simple database table would require sufficient amount of programming. Assuming every column should have at least a getter and a setter method, and it&#8217;s property defined in the model, this would take up 1 object property and 2 methods per column. Even with a relatively simple database table with, let&#8217;s say 6 columns, this would require me to write 6 properties and 12 methods. Asuming my application has 20 tables, this would mean I&#8217;d have to write 120 properties ans 240 methods.</p>
<p>The worst thing is that these getters and setters don&#8217;t do anything special. It&#8217;s simply setting the property and returning the model, or getting the property. Doing this over and over is quite tedious and simply a waste of time.</p>
<p>So, being lazy and all, I have decided to make this job a bit easier by extending the Zend_Db_Table class with functionality that allows me to write the Mapper and Model for me. This was also a good moment to examine the capabilities of <a href="http://framework.zend.com/manual/en/zend.codegenerator.html">Zend_CodeGenerator</a>.</p>
<p>The code is at this time still a work in progress and not so generic that it can be copied straid into your application, but should it reach that point, I will make it available for download here. For now, I hope a short roundup of how I did can inspire you to do something similiar.</p>
<p><strong>Extending Zend_Db_Table:</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

abstract class Plano_Db_Table_Abstract extends Zend_Db_Table
{
	/**
	 * Generate model by examining the DB structure (if not done already)
	 *
	 * @return void
	 */
	public function setupMapperPattern()
	{
		$this-&gt;_createModel()
			-&gt;_createMapper();
	}

	/**
	 * Create model file
	 *
	 * @return Plano_Db_Table_Abstract
	 */
	private function _createModel()
	{
   		$reflectionClass = new ReflectionClass(get_class($this));
   		if ($reflectionClass-&gt;isAbstract()) return false;

		$fields = $this-&gt;info(Zend_Db_Table::METADATA);

		$class = new Zend_CodeGenerator_Php_Class();
		$docblock = new Zend_CodeGenerator_Php_Docblock(array(
			'shortDescription' =&gt; 'Automatically generated data model',
			'longDescription' =&gt; 'This class has been automatically generated based on the dbTable &quot;' . $this-&gt;info(Zend_Db_Table::NAME) . '&quot; @ ' . strftime('%d-%m-%Y %H:%M')
		));

		$modelClassName = preg_replace('/_DbTable/', '', get_class($this));

		$class-&gt;setName($modelClassName)
			-&gt;setDocblock($docblock)
			-&gt;setExtendedClass('Plano_Model_Abstract');

		$filter = new Zend_Filter_Word_UnderscoreToCamelCase();

		foreach ($fields as $key =&gt; $meta)
		{
			$propertyName = $filter-&gt;filter($key);
			$class
				// Property
				-&gt;setProperty(array(
					'name' =&gt; lcfirst($propertyName),
					'visibility' =&gt; 'protected',
					'defaultValue' =&gt; (isset($meta['DEFAULT']) &amp;&amp; $meta['DEFAULT'] != '') ? $meta['DEFAULT'] : new Zend_CodeGenerator_Php_Property_DefaultValue(&quot;null&quot;),
					'docblock' =&gt; array(
						'shortDescription' =&gt; 'Automatically generated from db'
					)
				))
				// Setter method
				-&gt;setMethod(array(
					'name' =&gt; 'set' . ucfirst($propertyName),
					'parameters' =&gt; array(
						array('name' =&gt; 'value')
					),
					'body' =&gt; '$this-&gt;' . lcfirst($propertyName) . ' = $value;' . &quot;\n&quot; . 'return $this;',
					'docblock' =&gt; new Zend_CodeGenerator_Php_Docblock(array(
						'shortDescription' =&gt; 'Set the ' . lcfirst($propertyName) . ' property',
						'tags' =&gt; array(
							new Zend_CodeGenerator_Php_Docblock_Tag_Param(array(
								'paramName' =&gt; 'value',
								'datatype' =&gt; 'string'
							)),
							new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
								'datatype' =&gt; $modelClassName
							))
						)
					))
				))
				// Getter method
				-&gt;setMethod(array(
					'name' =&gt; 'get' . ucfirst($propertyName),
					'body' =&gt; 'return $this-&gt;' . lcfirst($propertyName) . ';',
					'docblock' =&gt; new Zend_CodeGenerator_Php_Docblock(array(
						'shortDescription' =&gt; 'Get the ' . lcfirst($propertyName) . ' property',
						'tags' =&gt; array(
							new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
								'datatype' =&gt; 'string'
							))
						)
					))
				));
    	}

    	$class-&gt;setProperty(array(
    		'name' =&gt; 'installed',
    		'visibility' =&gt; 'public',
    		'docblock' =&gt; 'Installed flag. Remove to regenerate.',
			'defaultValue' =&gt; 1
    	));

    	$front = Zend_Controller_Front::getInstance();
    	$exploded = explode('_', $modelClassName);
    	unset($exploded[0]); // module prefix
    	unset($exploded[1]); // model prefix
    	$model = implode('_', $exploded);
    	$path = $front-&gt;getModuleDirectory() . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $model) . '.php';

    	$file = new Zend_CodeGenerator_Php_File(array(
    		'classes' =&gt; array($class)
    	));
    	file_put_contents($path, $file-&gt;generate());

	    return $this;
	}

	/**
	 * Create model file
	 *
	 * @return Plano_Db_Table_Abstract
	 */
	private function _createMapper()
	{
   		$reflectionClass = new ReflectionClass(get_class($this));
   		if ($reflectionClass-&gt;isAbstract()) return false;

		$fields = $this-&gt;info(Zend_Db_Table::METADATA);

		$class = new Zend_CodeGenerator_Php_Class();
		$docblock = new Zend_CodeGenerator_Php_Docblock(array(
			'shortDescription' =&gt; 'Automatically generated data mapper',
			'longDescription' =&gt; 'This class has been automatically generated based on the dbTable &quot;' . $this-&gt;info(Zend_Db_Table::NAME) . '&quot; @ ' . strftime('%d-%m-%Y %H:%M')
		));

		$modelClassName = preg_replace('/_DbTable/', '', get_class($this) . '_Mapper');

		$class-&gt;setName($modelClassName)
			-&gt;setDocblock($docblock)
			-&gt;setExtendedClass('Plano_Model_Mapper_Db');

		$filter = new Zend_Filter_Word_UnderscoreToCamelCase();

		$class-&gt;setProperty(array(
			'name' =&gt; '_dbTable',
			'defaultValue' =&gt; get_class($this),
			'visibility' =&gt; 'protected',
			'docblock' =&gt; array(
				'shortDescription' =&gt; 'Db Table'
			)
		));

		if (array_key_exists('deleted', $fields))
		{
			$class-&gt;setProperty(array(
				'name' =&gt; '_deletedColumn',
				'defaultValue' =&gt; 'deleted',
				'visibility' =&gt; 'protected',
				'docblock' =&gt; array(
					'shortDescription' =&gt; 'Deleted column'
				)
			));
		}

    	$front = Zend_Controller_Front::getInstance();
    	$exploded = explode('_', $modelClassName);
    	unset($exploded[0]); // module prefix
    	unset($exploded[1]); // model prefix
    	$model = implode('_', $exploded);

    	$dir = $front-&gt;getModuleDirectory() . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR . $exploded[2];

    	if (!is_dir($dir))
    	{
    		mkdir($dir, 0755, true);
    	}

    	$path = $dir . DIRECTORY_SEPARATOR . $exploded[3] . '.php';

    	$file = new Zend_CodeGenerator_Php_File(array(
    		'classes' =&gt; array($class)
    	));
    	file_put_contents($path, $file-&gt;generate());

	    return $this;
	}
}
</pre>
<p><strong>What this code does:</strong></p>
<ul>
<li>First of all, it assumes you put the a DbTable class somewhere inside modules/yourmodule/models/DbTable/Class.php and you have the table name defined</li>
<li><span style="color: #000000;">When extending from this base class you can call setupMapperPattern() which then creates the the model &#8216;Table.php&#8217; and the mapper in &#8216;Table/Mapper.php&#8217;</span></li>
</ul>
<p><strong><em>Disclaimer:</em></strong> this code is not intended to be copy pasted into your own application and will not work by default. The code could use some (thorough) cleaning up, is not as elegant as it could be and contains some hacky solutions, This post  is merely intended as an example of a practical usage of <a href="http://framework.zend.com/manual/en/zend.codegenerator.html">Zend_CodeGenerator</a>.</p>
<img src="http://feeds.feedburner.com/~r/codelicious/jgBH/~4/kVZWaCYrd70" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.codelicious.nl/using-zendcodegenerator-to-generate-data-mapper/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.codelicious.nl/using-zendcodegenerator-to-generate-data-mapper/</feedburner:origLink></item>
		<item>
		<title>PHP Suhosin truncating POST variables</title>
		<link>http://feedproxy.google.com/~r/codelicious/jgBH/~3/ys_N4LImzd4/</link>
		<comments>http://www.codelicious.nl/phpsuhosin-truncating-post-variables/#comments</comments>
		<pubDate>Fri, 14 May 2010 14:29:36 +0000</pubDate>
		<dc:creator>Aron</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[suhosin]]></category>

		<guid isPermaLink="false">http://www.codelicious.nl/?p=7</guid>
		<description><![CDATA[I recently spent an afternoon trying to figure out why my POST-data was being truncated on our production server. I was sending a pretty large POST from a large form (approx. 1200 input fields) but for some reason it was being truncated. After quite a while I found the culprit: Setting these two two a [...]]]></description>
			<content:encoded><![CDATA[<p>I recently spent an afternoon trying to figure out why my POST-data was being truncated on our production server.</p>
<p>I was sending a pretty large POST from a large form (approx. 1200 input fields) but for some reason it was being truncated. After quite a while I found the <a href="http://www.hardened-php.net/suhosin/configuration.html#suhosin.post.max_vars">culprit</a>:</p>
<pre class="brush: plain; title: ; notranslate">
suhosin.post.max_vars = 200
suhosin.request.max_vars = 200
</pre>
<p>Setting these two two a higher number solved the problem for me. Hopefully this saves you from spending the same time debugging this problem as I did.</p>
<img src="http://feeds.feedburner.com/~r/codelicious/jgBH/~4/ys_N4LImzd4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.codelicious.nl/phpsuhosin-truncating-post-variables/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.codelicious.nl/phpsuhosin-truncating-post-variables/</feedburner:origLink></item>
	</channel>
</rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching using disk: basic

Served from: www.codelicious.nl @ 2012-01-10 16:19:42 -->

