<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Recoursive &#187; symfony</title>
	<atom:link href="http://recoursive.com/blog/archives/category/symfony/feed" rel="self" type="application/rss+xml" />
	<link>http://recoursive.com/blog</link>
	<description>Technology, Stuff</description>
	<lastBuildDate>Mon, 28 Sep 2009 15:32:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>sfManagedCachePlugin released</title>
		<link>http://recoursive.com/blog/archives/183</link>
		<comments>http://recoursive.com/blog/archives/183#comments</comments>
		<pubDate>Wed, 17 Jun 2009 13:50:10 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[sfManagedCachePlugin]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=183</guid>
		<description><![CDATA[The first alpha release is up on symfony-project.org now and can be installed through the command line as well.
]]></description>
			<content:encoded><![CDATA[<p>The first alpha release is up on <a href="http://www.symfony-project.org/">symfony-project.org</a> now and can be installed through the command line as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/183/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfManagedCachePlugin</title>
		<link>http://recoursive.com/blog/archives/161</link>
		<comments>http://recoursive.com/blog/archives/161#comments</comments>
		<pubDate>Tue, 19 May 2009 16:56:12 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[recoursive]]></category>
		<category><![CDATA[sfManagedCachePlugin]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=161</guid>
		<description><![CDATA[The rough plugin for Symfony is done, albeit not published yet. Usage is very similar to the sfFunctionCache class, and it comes with the appropriate tasks to refresh/clear cached items.
Usage example:


$sfManagedCache = new sfManagedFunctionCache(
  new sfFileCache(array(
    'cache_dir' =&#62; sfConfig::get('sf_external_cache_dir').'/sfManagedCache',
    'lifetime' =&#62; 86400))
);

$xml = $sfManagedCache-&#62;call(
  array('Webserice', 'call''),
  [...]]]></description>
			<content:encoded><![CDATA[<p>The rough plugin for Symfony is done, albeit not published yet. Usage is very similar to the sfFunctionCache class, and it comes with the appropriate tasks to refresh/clear cached items.</p>
<p>Usage example:</p>
<blockquote>
<pre>
$sfManagedCache = new sfManagedFunctionCache(
  new sfFileCache(array(
    'cache_dir' =&gt; sfConfig::get('sf_external_cache_dir').'/sfManagedCache',
    'lifetime' =&gt; 86400))
);

$xml = $sfManagedCache-&gt;call(
  array('Webserice', 'call''),
  array($parameter1, $parameter2),
  1800
);
</pre>
</blockquote>
<p>The tasks are used like this and should be set up as cron jobs:</p>
<blockquote>
<pre>
./symfony managed_cache:refresh --application=webservice --env=prod
./symfony managed_cache:refresh --env=prod
</pre>
</blockquote>
<p>The first call is for a specific application while the second one is for application-agnostic cache items (not for all items!).</p>
<p>This is not a fire-and-forget plugin. It requires planning and maintenance. Since the cached items are designed to never expire, carelessness can easily lead to problems. I will cleanup the plugin some more, write documentation and then release it.</p>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/161/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cachtrocities</title>
		<link>http://recoursive.com/blog/archives/156</link>
		<comments>http://recoursive.com/blog/archives/156#comments</comments>
		<pubDate>Mon, 27 Apr 2009 14:58:18 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[sfManagedCachePlugin]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=156</guid>
		<description><![CDATA[This week, I&#039;ve had to incorparate a vendor&#039;s webservice into the rendering of an existing website. It was going to replace the programatic generation of URLs for a list of files that used to be hosted internally. In the process I had to deal with X things:
1) The data was raw and needed to be [...]]]></description>
			<content:encoded><![CDATA[<p>This week, I&#039;ve had to incorparate a vendor&#039;s webservice into the rendering of an existing website. It was going to replace the programatic generation of URLs for a list of files that used to be hosted internally. In the process I had to deal with X things:</p>
<p>1) The data was raw and needed to be reprocessed before we could use it. That meant parsing the XML, running it through the processor and then writing it out again. Too much effort to do on every request, so again data would have to be cached.</p>
<p>2) More importantly, the webservice performance was atrocious. Request times for a 4 item rss feed hovered around 5 seconds. A completely rendered page could require several calls to this service. Whether these long request times were due to problems on our end, their end or somewhere in between was unimportant for the moment. The results would have to be cached to be useful.</p>
<p>Naturally, I could have left the caching to the application that used the webservice, ie. parse the information provided and store the results in memcache. The problem with that approach is that memcache is a very simple cache, and paired with the long request times for the webservice you&#039;re bound to run into problems. No matter how scalable your application and infrastructure is, if a reasonably common request is taking 5, 10, 15 seconds to complete, you&#039;re going to see a thread pileup sooner or later, which is what will happen when the items in memcache expire. And don&#039;t even get me started on the degraded user experience.</p>
<p>The proper solution for this is a managed cache.Â  One important concept is prefetch, ie. refresh the cached data before it expires, so it doesn&#039;t matter how long it takes to create it. WP-Supercache has this feature and Varnish recently introduced this feature as well along with grace. Grace is the other concept, which allows you to continue serving up stale or expired data if the data source becomes unavailable. In most cases, serving up old data is better than no data at all.</p>
<p>Symfony doesn&#039;t have any plugins or classes or other facilities to deal with these kinds of things as of right now, so I decided to just deploy Varnish for the purpose of caching the modified webservice data. No development time and very little effort to deploy and working perfectly. Unfortunately, I have to abandon that setup because of &#034;complexity concerns&#034;. So in the next couple of weeks, I&#039;ll probably write a managed cache plugin for symfony.</p>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/156/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to operate Symfony in a virtual folder</title>
		<link>http://recoursive.com/blog/archives/136</link>
		<comments>http://recoursive.com/blog/archives/136#comments</comments>
		<pubDate>Thu, 19 Feb 2009 17:41:18 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=136</guid>
		<description><![CDATA[Problem:
I needed to run symfony in a virtual subfolder under an existing site, so that the asset URLs generate by helpers still originate from the root folder while URLs generated from routes contain the virtual subfolder. For example:
I have a site xyz.com that is run on some legacy platform that uses the same sort of [...]]]></description>
			<content:encoded><![CDATA[<h2>Problem:</h2>
<p>I needed to run symfony in a virtual subfolder under an existing site, so that the asset URLs generate by helpers still originate from the root folder while URLs generated from routes contain the virtual subfolder. For example:</p>
<p>I have a site xyz.com that is run on some legacy platform that uses the same sort of layout for assets as symfony (stylesheets in /css, etc.). All the traffic for xyz.com goes through a load-balancer that splits off requests which URL starts with the prefix /symfonyApp and sends them to the server(s) running the symfony app. Symfony needs to generate asset URLs that look like /images/logo.gif while generating action URLs looking like /symfonyApp/signup/index.</p>
<h2>Analysis:</h2>
<p>The reason I was able to make this work at all is that the helper functions and the routing classes use different ways to insert the prefix folder name. Helpers get something called &#034;RelativeUrlRoot&#034; from the request object. This value can be set in factories.yml. Otherwise, it&#039;s calculated on demand by taking whatever is in front of the script file name in the SCRIPT_NAME environment variable.</p>
<p>Routes, on the other hand, store the prefix internally, though it&#039;s initialized to &#034;RelativeUrlRoot + ScriptName&#034;, unless you override it in factories.yml.</p>
<h2>Solution:</h2>
<p>One solution would be to set the desired prefix values in factories.yml. But that requires duplicating the desired environment, which would be a pain to replicate. Instead, I opted to modify the values in the script file prior to dispatching the request. This way seems to work smoothly.</p>
<blockquote><p>&lt;?php</p>
<p>$tmp = dirname(__FILE__);<br />
ini_set(&#039;error_log&#039;, $tmp . &#039;/../../log/frontend_virtual_prod-error.log&#039;);</p>
<p>require_once($tmp.&#039;/../../config/ProjectConfiguration.class.php&#039;);</p>
<p>$configuration = ProjectConfiguration::getApplicationConfiguration(&#039;frontend&#039;, &#039;prod&#039;, false);<br />
$context = sfContext::createInstance($configuration);</p>
<p>// set separate prefixes for assets and links<br />
$context-&gt;getRequest()-&gt;setRelativeUrlRoot(&#034;);<br />
$routing = $context-&gt;getRouting();<br />
$routingOptions = $routing-&gt;getOptions();<br />
$routingOptions['context']['prefix'] = &#039;/symfonyApp&#039;;<br />
$routing-&gt;initialize($context-&gt;getEventDispatcher(), $routing-&gt;getCache(), $routingOptions);</p>
<p>$context-&gt;dispatch();</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/136/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony 1.2 released</title>
		<link>http://recoursive.com/blog/archives/67</link>
		<comments>http://recoursive.com/blog/archives/67#comments</comments>
		<pubDate>Sat, 06 Dec 2008 07:00:16 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=67</guid>
		<description><![CDATA[The new symfony release sort of snuck by under my radar. Thus, it so happened that upgrading my current project to the new version fell on a friday (afternoon). The upgrade guide made everything sound easy enough. Unfortunately, some things related to the Doctrine plugin had been changed without deprecating (as far as I know [...]]]></description>
			<content:encoded><![CDATA[<p>The new symfony release sort of snuck by under my radar. Thus, it so happened that upgrading my current project to the new version fell on a friday (afternoon). The upgrade guide made everything sound easy enough. Unfortunately, some things related to the Doctrine plugin had been changed without deprecating (as far as I know at least) them first. That, plus a <a href="http://trac.symfony-project.org/ticket/5194" target="_blank">bug</a>, made the upgrade task take a lot longer than I had planned.</p>
<p>So, I can&#039;t really say much yet, but some things have certainly gotten easier and more elegant. As long as the performance stays the same, I probably won&#039;t complain. No, I&#039;ll probably find something regardless.</p>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/67/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Well, one size doesn&#039;t fit all</title>
		<link>http://recoursive.com/blog/archives/63</link>
		<comments>http://recoursive.com/blog/archives/63#comments</comments>
		<pubDate>Fri, 05 Dec 2008 06:10:49 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=63</guid>
		<description><![CDATA[I came across a curious bug today when after deploying a revision of one of web apps I&#039;ve been working on. The automatic test suite had run its course, no errors. However, when I repeated one of the processes covered by a test manually, I ended up with a fatal error.
The reason the test worked [...]]]></description>
			<content:encoded><![CDATA[<p>I came across a curious bug today when after deploying a revision of one of web apps I&#039;ve been working on. The automatic test suite had run its course, no errors. However, when I repeated one of the processes covered by a test manually, I ended up with a fatal error.</p>
<p>The reason the test worked fine while the real process didn&#039;t is a not entirely unimportant weakness in the test framework. The individual requests simulated by functional tests are not isolated from one another like regular requests would be. They all happen inside the same request context, so there is no teardown at the end and no cleanup. There are certain things in PHP that you can&#039;t undo unless you finish a request. One of those things is registering functions.</p>
<p>So what happened was that I included a helper (collection of functions) only in the template of the first request in the process. That was no problem in the test run because the functions stayed defined throughout, whereas in the real world, they wouldn&#039;t.</p>
<p>I&#039;m trying to figure out what would be the best way to address this problem. The most thorough way, isolating every request into its own CLI session, would be impractical. Although it would address more than this very specific problem. The less general but easier to implement way would be to write a parser that checks whether every function used in the templates is defined or included in the template it&#039;s used in.</p>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/63/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Another bug report</title>
		<link>http://recoursive.com/blog/archives/48</link>
		<comments>http://recoursive.com/blog/archives/48#comments</comments>
		<pubDate>Fri, 24 Oct 2008 13:44:40 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[bug_report]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=48</guid>
		<description><![CDATA[Ticket is here.
When using a custom 404 module/action, calling sfController::forward() or sfController::redirect() or any other part of symfony that results in an sfStopException being thrown, this exception will not be caught and thus result in a fatal error. The same is true for all other exceptions as well, but I&#039;m highlighting sfStopExceptions because they are [...]]]></description>
			<content:encoded><![CDATA[<p>Ticket is <a href="http://trac.symfony-project.org/ticket/4741" target="_blank">here</a>.</p>
<blockquote><p>When using a custom 404 module/action, calling sfController::forward() or sfController::redirect() or any other part of symfony that results in an sfStopException being thrown, this exception will not be caught and thus result in a fatal error. The same is true for all other exceptions as well, but I&#039;m highlighting sfStopExceptions because they are part of symfony&#039;s normal operation and it can be reasonably expected they be caught.</p>
<p>Analysis:</p>
<p>The forward to the 404 action happens inside the printStackTrace() method of the sfError404Exception that is throw and immediately caught in sfFrontWebController::dispatch(). There are no try-catch blocks around either the forward() call nor the printStackTrace call to catch exceptions that are throw as part of symfony&#039;s normal operation, or any exceptions for that matter.</p>
<p>Stack trace:</p>
<p>PHP Fatal error:  Uncaught exception &#039;sfStopException&#039; in /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php:294<br />
Stack trace:<br />
#0 /var/www/promotions/current/apps/frontend/modules/error/actions/actions.class.php(19): sfAction-&gt;redirect(&#039;http://&#8230;&#039;, 404)<br />
#1 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(462): errorActions-&gt;executeError404(Object(sfWebRequest))<br />
#2 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1109): sfActions-&gt;execute(Object(sfWebRequest))<br />
#3 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1104): sfExecutionFilter-&gt;executeAction(Object(errorActions))<br />
#4 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1093): sfExecutionFilter-&gt;handleAction(Object(sfFilterChain), Object(errorActions))<br />
#5 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1189): sfExecutionFilter-&gt;execute(Object(sfFilterChain))<br />
#6 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1051): sfFilterChain-&gt;execute()<br />
#7 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1189): sfCommonFilter-&gt;execute(Object(sfFilterChain))<br />
#8 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1152): sfFilterChain-&gt;execute()<br />
#9 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(1189): sfRenderingFilter-&gt;execute(Object(sfFilterChain))<br />
#10 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(734): sfFilterChain-&gt;execute()<br />
#11 /var/www/promotions/current/lib/symfony/exception/sfError404Exception.class.php(49): sfController-&gt;forward(&#039;error&#039;, &#039;error404&#039;)<br />
#12 /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php(2530): sfError404Exception-&gt;printStackTrace()<br />
#13 /var/www/promotions/current/lib/symfony/util/sfContext.class.php(164): sfFrontWebController-&gt;dispatch()<br />
#14 /var/www/promotions/current/web/index.php(9): sfContext-&gt;dispatch()<br />
#15 {main}<br />
thrown in /var/www/promotions/current/cache/frontend/prod/config/config_core_compile.yml.php on line 294</p>
<p>Possible solutions:</p>
<p>One way to solve this problem would be to move the forward out of the printStackTrace() method since that strikes me as a weird place to put it in the first place. The other solution would be to place another try-catch block around either the forward or the printStackTrace() call to ensure that normal symfony behavior can occur without causing a fatal error.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/48/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Proper bug reports</title>
		<link>http://recoursive.com/blog/archives/42</link>
		<comments>http://recoursive.com/blog/archives/42#comments</comments>
		<pubDate>Fri, 17 Oct 2008 15:54:26 +0000</pubDate>
		<dc:creator>rkunde</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[bug_report]]></category>

		<guid isPermaLink="false">http://recoursive.com/blog/?p=42</guid>
		<description><![CDATA[If you are a programmer, it doesn&#039;t hurt to do some research before submitting a bug report. Not only will it help getting the bug fixed as quickly as possible. But it will also give you an understanding of how the product you are using works. That applies to open source products only, of course.
I [...]]]></description>
			<content:encoded><![CDATA[<p>If you are a programmer, it doesn&#039;t hurt to do some research before submitting a bug report. Not only will it help getting the bug fixed as quickly as possible. But it will also give you an understanding of how the product you are using works. That applies to open source products only, of course.</p>
<p>I found an annoying rather impeding bug in symfony the other day, and submitted the follwing <a href="http://trac.symfony-project.org/ticket/4696" target="_blank">ticket</a>:</p>
<blockquote><p>Symfony&#039;s clear cache task will fail when trying to clear config cache files created by another user (ie. web server) when there are config files that are newer than the cached versions.</p>
<p style="padding-left: 30px;">./symfony cc</p>
<p style="padding-left: 30px;">&gt;&gt; cache   Clearing cache type &#034;all&#034; for &#034;frontend&#034; app and &#034;prod&#034; env</p>
<p style="padding-left: 30px;">Failed to write cache file &#034;/var/www/promotions/current/cache/frontend/prod/config/config_settings.yml.php&#034; generated from configuration file &#034;config/settings.yml&#034;.</p>
<p>Analysis:</p>
<p>While cache folders are created with full permissions (777, or umask 000) the cache files are created with default permissions (644, or umask 022).</p>
<p>When the clear cache task executes, it iterates through all cached applications and environments and loads the configuration for each before doing the actual cleaning.</p>
<p>Because it loads the application configuration with debug mode turned on, sfConfigCache will check if any of the config files are newer than the cached version and reprocess each such file it finds.</p>
<p>Since the task runs under a user different from the owner of the config cache files, writing the new config cache file fails.</p>
<p>Stack trace:</p>
<p class="wiki" style="padding-left: 30px;">at /var/www/promotions/current/lib/symfony/config/sfConfigCache.class.php:344<br />
sfConfigCache-&gt;writeCacheFile at /var/www/promotions/current/lib/symfony/config/sfConfigCache.class.php:107<br />
sfConfigCache-&gt;callHandler at /var/www/promotions/current/lib/symfony/config/sfConfigCache.class.php:194<br />
sfConfigCache-&gt;checkConfig at /var/www/promotions/current/lib/symfony/config/sfApplicationConfiguration.class.php:113<br />
sfApplicationConfiguration-&gt;initConfiguration at /var/www/promotions/current/lib/symfony/config/sfApplicationConfiguration.class.php:49<br />
sfApplicationConfiguration-&gt;__construct at /var/www/promotions/current/lib/symfony/config/sfProjectConfiguration.class.php:342<br />
sfProjectConfiguration::getApplicationConfiguration at /var/www/promotions/current/lib/symfony/task/cache/sfCacheClearTask.class.php:104<br />
sfCacheClearTask-&gt;execute at /var/www/promotions/current/lib/symfony/task/sfBaseTask.class.php:77<br />
sfBaseTask-&gt;doRun at /var/www/promotions/current/lib/symfony/task/sfTask.class.php:75<br />
sfTask-&gt;runFromCLI at /var/www/promotions/current/lib/symfony/command/sfSymfonyCommandApplication.class.php:72<br />
sfSymfonyCommandApplication-&gt;run at /var/www/promotions/current/lib/symfony/command/cli.php:20<br />
include at /var/www/promotions/current/symfony:15</p>
<p>Proposed solutions:</p>
<p>Create the config cache files with full write permissions. Since the cache folders already have full write permissions and the sticky bit doesn&#039;t get set, everyone can delete cache files and then create another file with the same name. Therefore, it shouldn&#039;t make a difference from a security standpoint.</p>
<p>Alternatively, unlink the existing file before writing the new one.</p>
<p>Here&#039;s how to reproduce the problem:</p>
<ol>
<li>clear cache manually: rm -rf cache/*</li>
<li>make a request through your browser to any application</li>
<li>change the mod time on any config file that is required to build the application configuration for that application: touch apps/frontend/config/settings.yml</li>
</ol>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://recoursive.com/blog/archives/42/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
