<?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>dead fish &#187; Work</title>
	<atom:link href="http://www.thomaskeller.biz/blog/category/work/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.thomaskeller.biz/blog</link>
	<description>only dead fish swim with the stream</description>
	<lastBuildDate>Wed, 28 Jul 2010 11:13:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Symfony development</title>
		<link>http://www.thomaskeller.biz/blog/2010/02/25/symfony-development/</link>
		<comments>http://www.thomaskeller.biz/blog/2010/02/25/symfony-development/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 11:14:49 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=562</guid>
		<description><![CDATA[Last week the second incarnation of Symfony Live came to an end and I just had the time to check a couple of shared slides from the event. Definitely interesting stuff going on there, especially the preview release of Symfony 2.0 whose code is available on GitHub since a couple of weeks and which makes [...]]]></description>
			<content:encoded><![CDATA[<p>Last week the second incarnation of Symfony Live came to an end and I just had the time to check <a href="http://www.symfony-project.org/blog/2010/02/17/symfony-live-day-1">a couple of shared slides</a> from the event.</p>

<p>Definitely interesting stuff going on there, especially the preview release of <a href="http://www.slideshare.net/fabpot/symfony-20-revealed">Symfony 2.0</a> whose code is available on <a href="http://github.com/symfony/symfony">GitHub</a> since a couple of weeks and which makes major changes to the &#8220;good old way&#8221; one used to write symfony applications (actions are now &#8220;controllers&#8221; and extensions &#8220;bundles&#8221; and well, a dozen of other things changed as well of course&#8230; you can read everything in detail <a href="http://symfony-reloaded.org/learn">here</a>).</p>

<p>Also, <a href="http://www.slideshare.net/jwage/doctrine-2-not-the-same-old-php-orm">Doctrine 2.0</a> seems to be the first PHP ORM which decouples the modelling approach from the actual database abstraction layer, skips the need for base classes and enables the model definition via annotations. Also, they seem to fight against the overly complex magic from Doctrine 1.x (one of my top complaints on Doctrine in comparison to, f.e. Propel) &#8211; maybe I&#8217;ll revisit Doctrine again when the next version gets stable.</p>

<p>The guys at Sensio labs do really have a fast development pace and I get more and more the impression that the Symfony ecosystem is the major competitor for the Zend framework. Community-wise I think Symfony is already much bigger than any other PHP framework.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2010/02/25/symfony-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Never trust doctrine:data-dump&#8230;</title>
		<link>http://www.thomaskeller.biz/blog/2010/01/29/never-trust-doctrinedata-dump/</link>
		<comments>http://www.thomaskeller.biz/blog/2010/01/29/never-trust-doctrinedata-dump/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 16:52:33 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=537</guid>
		<description><![CDATA[&#8230;and especially not if you get the impression that the dump will afterwards be readable by the doctrine:data-load command of symfony. It was a costly lesson today when I tried to reimport a dump of a couple of Sympal tables. One of them, the one which models the menu items, has a nested set behaviour, [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230;and especially not if you get the impression that the dump will afterwards be readable by the <code>doctrine:data-load</code> command of <a href="http://www.symfony-project.org">symfony</a>.</p>

<p>It was a costly lesson today when I tried to reimport a dump of a couple of <a href="http://www.sympalphp.org">Sympal</a> tables. One of them, the one which models the menu items, has a nested set behaviour, and apparently this one cannot be restored properly by <a href="http://www.doctrine-project.org">doctrine</a>:</p>

<p><pre>[Doctrine_Record_UnknownPropertyException]<br />
  Unknown record property / related component "children" 
  on "sfSympalMenuItem"</pre></p>

<p>Apparently this particular issue popped up a couple of times in the past for other people as well (<a href="http://www.google.com/search?q=doctrine+data-load+%22nested+set%22">Google for it</a>) and while the help of <code>doctrine:data-dump</code> still (Doctrine 1.2) blatantly states</p>

<p><pre> The doctrine:data-dump task dumps database data:</pre></p>

<p>./symfony doctrine:data-dump</p>

<p>The task dumps the database data in data/fixtures/%target%.</p>

<p>The dump file is in the YML format and can be reimported
 by using the doctrine:data-load task.</p>

<p>./symfony doctrine:data-load
</p>

<p><small>(with the emphasis of &#8220;can be reimported&#8221;)</small></p>

<p>the author of Doctrine, Jonathan Wage, told me today on Sympal&#8217;s IRC (shortened):</p>

<blockquote>
&lt;jonwage> we don&#8217;t want people to think you can dump and then restore
&lt;jonwage> that is not what the data fixtures are for
&lt;jonwage> b/c dumping and then loading will never work
&lt;jonwage> an ORM modifies data on the way and and the way out
&lt;me> I mean the least thing doctrine could do there is that if it detects the nested set behaviour it should error out clearly on dump
&lt;jonwage> so you can&#8217;t dump the data through an ORM and then try and reload it
&lt;jonwage> i.e. hashed passwords
&lt;me> if dumping is &#8220;never&#8221; going to work &#8211; why do you support dumping into yaml at all?!
&lt;jonwage> if we do that then we would have to throw errors in sooooooo many other cases too
&lt;jonwage> because it is at least a little bit of a convenience
&lt;me> its like a half-baked feature then
&lt;jonwage> we dump the raw data
&lt;jonwage> and you can tweak it
&lt;jonwage> thats my point though, it will ALWAYS be a half baked feature thats why we document it that way
&lt;jonwage> it can NEVER work 100% the way you want it to
&lt;jonwage> so if we fix that one thing, a million other things will be reported that we cannot fix
&lt;jonwage> bc an ORM is not a backup and restore tool
&lt;jonwage> it is impossible
</blockquote>

<p>Now I know that as well. My only problem was that I struggled &#8220;what is wrong with my fixtures&#8221; the whole time and never dared to ask &#8220;what is wrong with doctrine&#8221;&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2010/01/29/never-trust-doctrinedata-dump/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tip: Logging with Symfony &gt;= 1.2</title>
		<link>http://www.thomaskeller.biz/blog/2010/01/25/tip-logging-with-symfony-1-2/</link>
		<comments>http://www.thomaskeller.biz/blog/2010/01/25/tip-logging-with-symfony-1-2/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 15:00:31 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=529</guid>
		<description><![CDATA[Imagine you have a business method in your model which needs to be accessed by two environments: once from a symfony task and once from the web. So far so good, now what if this business method should be able to log contents somewhere visibly, in case of the command line task to console and [...]]]></description>
			<content:encoded><![CDATA[<p>Imagine you have a business method in your model which needs to be accessed by two environments: once from a symfony task and once from the web. So far so good, now what if this business method should be able to log contents somewhere visibly, in case of the command line task to console and to a file and in case of the web application to the default logging mechanisms used there?</p>

<p>Getting the logger in web context is easy, all you have to do is</p>

<div class="geshi no php"><ol><li class="li1"><div class="de1"><span class="re1">$logger</span> <span class="sy0">=</span> sfContext<span class="sy0">::</span><span class="me2">getInstance</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getLogger</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li></ol></div>

<p>but its a little harder to do for the command line task.</p>

<p>By default no symfony context is created for a command line task and even if it is created, the above call returns an instance of <code>sfNoLogger</code>. Logging in command applications happens through the <code>sfTask::logSection()</code> method, which basically throws an event at the created dispatcher in <code>SYMFONYDIR/lib/command/cli.php</code>. There you can also see that an instance of <code>sfCommandLogger</code> is created, but there is no way to get your fingers at this instance, because its purely local.</p>

<p>So what can we do? Parametricizing the business method with the <code>sfTask</code> instance and using the <code>logSection()</code> is obviously no solution, because this would break in web context where no such sfTask instance exists&#8230;</p>

<p>My solution was a bit more straight forward &#8211; I simply decided to not use the task-supplied logging schema at all, but created my own logger like this:</p>

<div class="geshi no php"><ol><li class="li1"><div class="de1"><span class="re1">$dispatcher</span> <span class="sy0">=</span> <span class="kw2">new</span> sfEventDispatcher<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="re1">$logger</span> <span class="sy0">=</span> <span class="kw2">new</span> sfAggregateLogger<span class="br0">&#40;</span><span class="re1">$dispatcher</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="re1">$logger</span><span class="sy0">-&gt;</span><span class="me1">addLogger</span><span class="br0">&#40;</span><span class="kw2">new</span> sfCommandLogger<span class="br0">&#40;</span><span class="re1">$dispatcher</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co1">// optionally add another file logger</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re1">$logToFile</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="re1">$logger</span><span class="sy0">-&gt;</span><span class="me1">addLogger</span><span class="br0">&#40;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">new</span> sfFileLogger<span class="br0">&#40;</span><span class="re1">$this</span><span class="sy0">-&gt;</span><span class="me1">dispatcher</span><span class="sy0">,</span> <span class="sy0">&#8230;</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li></ol></div>

<p>Hope this helps somebody.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2010/01/25/tip-logging-with-symfony-1-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Doctrine Horror</title>
		<link>http://www.thomaskeller.biz/blog/2010/01/15/doctrine-horror/</link>
		<comments>http://www.thomaskeller.biz/blog/2010/01/15/doctrine-horror/#comments</comments>
		<pubDate>Fri, 15 Jan 2010 13:47:30 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=523</guid>
		<description><![CDATA[My latest Symfony project uses Doctrine as ORM, which is considered to be a lot better than Propel by many people&#8230; Well, not by me. Doctrine seems to have a couple of very good concepts, amongst them built-in validators, a powerful query language, and last but not least, an easy schema language. (Though to be [...]]]></description>
			<content:encoded><![CDATA[<p>My latest <a href="http://www.symfony-project.com">Symfony</a> project uses <a href="http://www.doctrine-project.org">Doctrine</a> as ORM, which is considered to be a lot better than <a href="http://propel.phpdb.org">Propel</a> by many people&#8230;</p>

<p>Well, not by me. Doctrine seems to have a couple of very good concepts, amongst them built-in validators, a powerful query language, and last but not least, an easy schema language. (Though to be fair, Propel will gain most of these useful things in the future as well or already has, f.e. with its <code>PropelQuery</code> feature.)</p>

<p>But Doctrine also fails in many areas; the massive use of overloads everywhere makes it very hard to debug and even worse, it tries to outsmart you (the developer) in many areas, which makes it even more hard to debug stuff which Doctrine doesn&#8217;t get right.</p>

<p>A simple example &#8211; consider this schema:</p>

<div class="geshi no yaml"><ol><li class="li1"><div class="de1">Foo:
</div></li>
<li class="li1"><div class="de1">&nbsp; columns:
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;id: { type: integer(5), primary: true, autoincrement: true }
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;name: { type: string }
</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">Bar:
</div></li>
<li class="li1"><div class="de1">&nbsp; columns:
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;id: { type: integer(5), primary: true, autoincrement: true }
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;name: { type: string }
</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">FooBarBaz:
</div></li>
<li class="li1"><div class="de1">&nbsp; columns:
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;foo_id: { type: integer(5), primary: true }
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;bar_id: { type: integer(5), primary: true }
</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp;name: { type: string }</div></li></ol></div>

<p>(I&#8217;ll skip the relation setup here, Doctrine should find them all with an additional <code>detect_relations: true</code>)</p>

<p>So what do you expect you see when you call this?</p>

<div class="geshi no php"><ol><li class="li1"><div class="de1"><span class="re1">$obj</span> <span class="sy0">=</span> <span class="kw2">new</span> FooBarBaz<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="kw3">print_r</span><span class="br0">&#40;</span><span class="re1">$obj</span><span class="sy0">-&gt;</span><span class="me1">toArray</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li></ol></div>

<p>Well, I expected to get an empty object, with a <code>NULL</code>ed <code>foo_id</code> and <code>bar_id</code>, but I didn&#8217;t! For me <code>foo_id</code> was filled with a 1. Wait, where does this come from?</p>

<p>After I digged deep enough in Doctrine_Record, I saw that this was automatically assigned in the constructor, coming from a statically incremented <code>$_index</code> variable. I could revert this by using my own constructor and call <code>assignIdentifier()</code> like this:</p>

<div class="geshi no php"><ol><li class="li1"><div class="de1"><span class="kw2">class</span> FooBarBaz <span class="kw2">extends</span> BaseFooBarBaz </div></li>
<li class="li1"><div class="de1"><span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="br0">&#41;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp;<span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; parent<span class="sy0">::</span>__construct<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; <span class="re1">$this</span><span class="sy0">-&gt;</span><span class="me1">assignIdentifier</span><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp;<span class="br0">&#125;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li></ol></div>

<p>but now this object could no longer be added to a <code>Doctrine_Collection</code> (which is a bummer, because if you want to extend object lists with &#8220;default&#8221; empty objects, you most likely stumble upon a Doctrine_Collection, which is the default data structure returned for every SQL query).</p>

<p>So you might ask &#8220;Why the hell does all this impose a problem for you?&#8221;</p>

<p>Well, if you work with the <code>FooForm</code> created by the doctrine plugin for you in Symfony and you want to add <code>FooBarBazForm</code> via <code>sfForm::embedFormForEach</code> a couple of times (similar to the use case <a href="http://blog.barros.ws/2009/01/01/using-embedformforeach-in-symfony-part-ii/">described here</a>), you suddenly have the problem that your embedded form for the appended new <code>FooBarBaz</code> object &#8220;magically&#8221; gets a foo_id of a wrong (maybe not existing) <code>Foo</code> object and you wonder where the heck this comes from&#8230;</p>

<p>I have my lesson learned for the last one and a half days. I promise I&#8217;ll never <em>ever</em> create a table in Doctrine with a multi-key primary key again and I&#8217;m returing back to Propel for my next project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2010/01/15/doctrine-horror/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quick Tip: NetworkManager and /etc/resolv.conf</title>
		<link>http://www.thomaskeller.biz/blog/2009/11/06/quick-tip-networkmanager-and-etcresolv-conf/</link>
		<comments>http://www.thomaskeller.biz/blog/2009/11/06/quick-tip-networkmanager-and-etcresolv-conf/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 09:31:08 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=457</guid>
		<description><![CDATA[If you have trouble with NetworkManager overwriting your search and domain configuration after every startup and you&#8217;re using DHCP, add the following line to your /etc/dhclient.conf: append domain-name " company.local other.company.local"; So whenever your DHCP server doesn&#8217;t provide these information (the one in my company does not), it&#8217;ll add this domain company.local search company.local other.company.local [...]]]></description>
			<content:encoded><![CDATA[<p>If you have trouble with NetworkManager overwriting your <code>search</code> and <code>domain</code> configuration after every startup and you&#8217;re using DHCP, add the following line to your <code>/etc/dhclient.conf</code>:</p>

<p><pre>append domain-name " company.local other.company.local";</pre></p>

<p>So whenever your DHCP server doesn&#8217;t provide these information (the one in my company does not), it&#8217;ll add this</p>

<p><pre>
domain company.local
search company.local other.company.local
</pre></p>

<p>to your <code>/etc/resolv.conf</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2009/11/06/quick-tip-networkmanager-and-etcresolv-conf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fixing MySQL / PDO error 2014</title>
		<link>http://www.thomaskeller.biz/blog/2009/09/09/fixing-mysql-pdo-error-2014/</link>
		<comments>http://www.thomaskeller.biz/blog/2009/09/09/fixing-mysql-pdo-error-2014/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 10:51:09 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=423</guid>
		<description><![CDATA[The following error on my current project at work really gave me lots of headaches today: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. So, [...]]]></description>
			<content:encoded><![CDATA[<p>The following error on my current project at work really gave me lots of headaches today:</p>

<p><pre>SQLSTATE[HY000]: General error: 2014 Cannot execute queries
while other unbuffered queries are active. Consider using 
PDOStatement::fetchAll().
Alternatively, if your code is only ever going to run against
mysql, you may enable query buffering by setting the
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.</pre></p>

<p>So, yes, I already have <code>PDO::MYSQL_ATTR_USE_BUFFERED_QUERY</code> set to <code>TRUE</code>, so why is PDO still complaining? And especially why it is complaining now, because the same code which triggered the error today ran without problems for the past 9 months?</p>

<p>After struggling a lot I found the cause: I missed to close a statement which was reused in a loop!</p>

<p>So take care that you always call <code>PDOStatement->closeCursor()</code> in use cases like this:</p>

<p><pre>$stmt = $con->prepare("SELECT * FROM doodle WHERE id = ?");</pre></p>

<p>foreach (range(1,10) as $id)
{
   $stmt->execute(array($id));
   $row = $stmt->fetch();
   <b>$stmt->closeCursor();</b>
}</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2009/09/09/fixing-mysql-pdo-error-2014/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Useful Gotcha #27</title>
		<link>http://www.thomaskeller.biz/blog/2009/04/09/useful-gotcha-27/</link>
		<comments>http://www.thomaskeller.biz/blog/2009/04/09/useful-gotcha-27/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 07:57:03 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Debian/Ubuntu Administration]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=344</guid>
		<description><![CDATA[If you get this error ssl_error_rx_record_too_long when browsing an SSL-secured virtual host and wonder what the heck is going on (hey, it worked the day before), ensure that you&#8217;ve noticed that your admins have changed the IP address of the machine and that you have to adapt the IP-based VHost configuration accordingly&#8230; not that this [...]]]></description>
			<content:encoded><![CDATA[<p>If you get this error <code>ssl_error_rx_record_too_long</code> when browsing an SSL-secured virtual host and wonder what the heck is going on (hey, it worked the day before), ensure that you&#8217;ve noticed that your admins have changed the IP address of the machine and that you have to adapt the IP-based VHost configuration accordingly&#8230; not that this SSL error wouldn&#8217;t have said that in first place!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2009/04/09/useful-gotcha-27/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Change svn:externals quickly</title>
		<link>http://www.thomaskeller.biz/blog/2009/01/05/change-svnexternals-quickly/</link>
		<comments>http://www.thomaskeller.biz/blog/2009/01/05/change-svnexternals-quickly/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 17:34:25 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=308</guid>
		<description><![CDATA[If you&#8217;ve worked with external repository definitions and branches before, you probably know the problem: If you create a new branch off an existing one or merge one branch into another, subversion is not smart enough to update svn:externals definitions which point to the same repository, but rather keep them pointing to the old (wrong) [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve worked with external repository definitions and branches before, you probably know the problem: If you create a new branch off an existing one or merge one branch into another, subversion is not smart enough to update <code>svn:externals</code> definitions which point to the same repository, but rather keep them pointing to the old (wrong) branch. (I read <a href="http://svnbook.red-bean.com/nightly/en/svn.advanced.externals.html">they fixed that</a> with SVN 1.5 by supporting relative URLs, but still, a couple of people might not be able to upgrade and I want to keep rather explicit with external naming anyways.)</p>

<p>Anyways, today at work I was so sick of the problem that I decided should hack something together. Here is the result:
<pre>#!/bin/bash
export LANG=C
if [ $# -ne 2 ]
then
    echo "Usage:" $(basename $0) "&lt;old&gt; &lt;new&gt;"
    exit 1
fi</pre></p>

<p>old=$1
new=$2
repo_root=<code>svn info | grep "Repository Root" | cut -f3 -d" "</code>;</p>

<p>if [ -n "$(svn info $repo_root/$new 2&gt;&amp;1 | grep "Not a valid URL")" ]
then
    echo "$repo_root/$new is not a valid URL"
    exit 1
fi</p>

<p>for ext in  $(svn st | grep -e "^X" | cut -c 8- | xargs -L1 dirname | uniq)
do
    externals=$(svn propget svn:externals $ext)
    if [[ "$externals" == <em>$repo_root/$old</em> ]]
    then
        externals=${externals//$repo_root\/$old/$repo_root\/$new}
        svn propset svn:externals "$externals" $ext
    fi
done
Save this into a file, make it executable and you&#8217;re good to go! The script is smart enough to check if the target URL (based on the repositories&#8217;s root and the given <code>&lt;new&gt;</code> path) actually exists and also only changes those external definitions which actually match the repository root.</p>

<p>Fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2009/01/05/change-svnexternals-quickly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Global AJAX responders in Prototype</title>
		<link>http://www.thomaskeller.biz/blog/2008/10/30/global-ajax-responders-in-prototype/</link>
		<comments>http://www.thomaskeller.biz/blog/2008/10/30/global-ajax-responders-in-prototype/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 13:49:11 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=259</guid>
		<description><![CDATA[I encountered a small, but ugly problem in our Symfony-driven project today: Unauthenticated AJAX requests, which f.e. may happen when the session timed out on the server, but the user hasn&#8217;t reloaded the page in the meantime, are also forwarded to the globally defined login module / action. This of course leaves the HTML page, [...]]]></description>
			<content:encoded><![CDATA[<p>I encountered a small, but ugly problem in our Symfony-driven project today: Unauthenticated AJAX requests, which f.e. may happen when the session timed out on the server, but the user hasn&#8217;t reloaded the page in the meantime, are also forwarded to the globally defined login module / action. This of course leaves the HTML page, which is constructed upon single HTML components, in a total mess. Ouch!</p>

<p>So yeah, rendering the complete login mask HTML as partial to the client is stupid, but also relatively easy to fix:</p>

<p><pre>
public function executeLogin($request)
{
    if ($request->isXmlHttpRequest())
    {
        // renderJSON is a custom function which json_encode's
        // the argument and sets an X-JSON header on response
        return $this->renderJSON(array("error" =>
                                    "Your session expired"));
    }
    ...
}
</pre></p>

<p>This was of course only half of the fix. I still had to handle this (and other) special JSON response on the browser&#8217;s side:</p>

<p><pre>
new Ajax.Request("mymodule/myaction", {
     onSuccess: function(response, json) {
         if (json.error)
         {
             // display the error
             alert(json.error);
             return;
         }
         // the actual callback functionality
     }
}
</pre></p>

<p>Uh, anyone screams <a href="http://en.wikipedia.org/wiki/Spaghetti_code">&#8220;spaghetti code&#8221;</a>? Yeah, you&#8217;re right. I quickly headed for a more general implementation, also since we can&#8217;t do that for a couple of symfony-specific prototype helpers anyways, like <code>update_element_function</code>, whose Javascript code gets generated by Symfony dynamically. So how can this be generalized?</p>

<h4>Ajax.Responders to the rescue</h4>

<p>Actually, prototype already contains some kind of &#8220;global hook-in&#8221; functionality for all Ajax requests triggered by the library: <a href="http://www.prototypejs.org/api/ajax/responders"http://www.prototypejs.org/api/ajax/responders">Ajax.Responders</a>.</p>

<p>While this seemed to support all common callbacks (among them onCreate, onSuccess, onFailure and onComplete), some testing showed though that f.e. the <code>onComplete</code> callback was always called <em>after</em> the specific AJAX request&#8217;s <code>onComplete</code> callback, so this was pretty useless for me. After all, I also wanted to <em>prevent</em> that the specific callback gets executed when I encountered an error&#8230;</p>

<p>After diving through prototype&#8217;s code for some hours I found a solution. Particularily helpful here is that prototype signals every created Ajax request to the <code>onCreate</code> handler and gives the request and response object handling this request as arguments to it. Time to overwrite prototype&#8217;s responder code! Here is it:</p>

<p><pre>
Ajax.Responders.register({
    onCreate: function(request) {
        var oldRespondToReadyState = request.respondToReadyState;
        request.respondToReadyState = function(readyState) {
            var state = Ajax.Request.Events[readyState];
            var response = new Ajax.Response(this);
            var json = response.headerJSON;</pre></p>

<pre><code>        if (state == 'Complete' &amp;&amp; json &amp;&amp; json.error)
        {
            alert(json.error);
            return;
        }
        oldRespondToReadyState.call(response.request, 
                                       readyState);
    }
}
</code></pre>

<p>});
</p>

<p>Another particularily useful piece of knowledge I gathered today to let this work is how <code>Function.prototype.call</code> and <code>Function.prototype.apply</code> work (both are available since Javascript 1.3).
Basically they allow the execution of a function in scope of the object given as first parameter (there is a nice introduction <a href="http://odetocode.com/Blogs/scott/archive/2007/07/04/11067.aspx">available here</a>).</p>

<p>If you&#8217;ve ever wanted to &#8220;send an event to some object to make its listener fire&#8221; because the listener&#8217;s code depended on the fact that the <code>this</code> reference points to the object the event was fired upon, you should now have a viable alternative:</p>

<p><pre>
Event.observe(myObj, 'click', myHandler);
// is call-wise equivalent to
myHandler.call(myObj);
</pre></p>

<p>No need to create custom mouse events and throw them around any longer&#8230; <img src='http://www.thomaskeller.biz/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2008/10/30/global-ajax-responders-in-prototype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New server setup</title>
		<link>http://www.thomaskeller.biz/blog/2008/09/19/new-server-setup/</link>
		<comments>http://www.thomaskeller.biz/blog/2008/09/19/new-server-setup/#comments</comments>
		<pubDate>Thu, 18 Sep 2008 22:37:13 +0000</pubDate>
		<dc:creator>Thomas Keller</dc:creator>
				<category><![CDATA[Debian/Ubuntu Administration]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.thomaskeller.biz/blog/?p=207</guid>
		<description><![CDATA[I finally got sick of my SuSE 9.3 V-Server when a good friend of mine pointed me to this really fancy and sexy IMAP web frontend called RoundCube last week. Written entirely in PHP 5 there was no real chance that I could get this easily working on my oldish PHP 4.3 installation without recompiling [...]]]></description>
			<content:encoded><![CDATA[<p>I finally got sick of my SuSE 9.3 V-Server when a good friend of mine pointed me to this really fancy and sexy IMAP web frontend called <a href="http://roundcube.net">RoundCube</a> last week. Written entirely in PHP 5 there was no real chance that I could get this easily working on my oldish PHP 4.3 installation without recompiling everything. I wanted to upgrade to some Ubuntu LTS server in short to middleterm anyways because I got sick of Plesk as well, and while I had these upgrade thoughts now for a while, the price tag for a temporary setup to make a clean transition was just too high: It would have cost me at least 65 Euro to get a throw-away V-Server for about three months &#8211; whereas two weeks would have been enough.</p>

<p>So, being a little kid with these things sometimes in terms of being not able to wait for stuff to happen, I did this one thing what one really should not do at all: Touching a running system.</p>

<p>I backed up all important stuff to a special directory inside the virtual machine and told the automatic installer procedure to start installing Ubuntu 8.04 LTS. After approximately two hours my working setup was gone. No emailing, no webserver, nothing.</p>

<p>So I started with a clean ubuntu server instance from scratch yesterday evening and it took me the whole last night to get some things working. While the mail setup is still a beast (need to read myself into exim and try out <a href="http://www.exim-new-users.co.uk/">a couple</a> <a href="http://www.tty1.net/virtual_domains_en.html">of tutorials</a>), I&#8217;m already quite proud of my Apache / FastCGI PHP setup. I copied a lot of ideas from the www setup at work where we have implemented separated, secured V-Host users, suexec-protected php wrappers and more.
Tonight I added another little puzzle piece into the mix: SFTP/SCP access for individual users to their virtual hosts.</p>

<p>Again, the <a href="http://ubuntuforums.org/">Ubuntu community</a> was very helpful &#8211; I found a <a href="http://ubuntuforums.org/showthread.php?t=128206">HOWTO</a> for getting an sftp server up and running in a jailed environment. There was actually very little I had to change so it fitted my use case &#8211; instead of using /home/chroot as jail, I put the jail into /var/www/vhostjail and all websites / vhosts which should get file transfer access below that directory. The biggest plus with this setup &#8211; beside the security point (people can only sftp or scp to the jail and cannot break anything on the rest of the system) &#8211; is now that the user who uploads files and the webuser who executes the request (i.e. the Apache user) is one and the same. No need to make files world-readable or even -writable when setting up a web application which has to read or write data. No need to change the owner or the access of uploaded files because the webuser could otherwise not read, write or execute them.</p>

<p>Wow. I like that setup.</p>

<p>Now, if only exim would so easy to understand and master&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.thomaskeller.biz/blog/2008/09/19/new-server-setup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
