<?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>Joe's Amazing Technicolor Weblog &#187; PHP</title>
	<atom:link href="http://slagwerks.com/blog/index.php/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://slagwerks.com/blog</link>
	<description></description>
	<lastBuildDate>Fri, 23 Jul 2010 22:31:13 +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>Custom flickr sidebar via wget, cron &amp; PHP</title>
		<link>http://slagwerks.com/blog/index.php/2009/07/29/custom-flickr-sidebar-via-wget-cron-php/</link>
		<comments>http://slagwerks.com/blog/index.php/2009/07/29/custom-flickr-sidebar-via-wget-cron-php/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 15:33:15 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flickr]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/?p=305</guid>
		<description><![CDATA[The new site launched with a sidebar that shows two random photos from our flickr account, using their javascript widget. This was a great way to get things going, but now we&#8217;ve developed slightly more involved needs and I&#8217;ve had to come up with a custom&#160;solution. Getting the list of&#160;photos You need a flickr API [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://thefoodproject.org/">The new site</a> launched with a sidebar that shows two random photos from our flickr account, using their javascript widget. This was a great way to get things going, but now we&#8217;ve developed slightly more involved needs and I&#8217;ve had to come up with a custom&nbsp;solution.</p>
<h3>Getting the list of&nbsp;photos</h3>
<p>You need a flickr <span class="caps">API</span> key, which is quick <span class="amp">&amp;</span> easy to get. Then wget <span class="amp">&amp;</span> cron to get &#8216;em: <code>wget --quiet 'http://api.flickr.com/services/rest/?method=flickr.photos.search&amp;api_key=YOUR_API_KEY&amp;user_id=YOUR_USER_ID&amp;tags=website&amp;per_page=500' -O&nbsp;photos.xml</code></p>
<p>Note that this includes a <em>tags</em> argument. The thing that pushed me to switch the workflow was the desire to be able to upload photos to our flickr account that don&#8217;t necessarily fit into the sidebar format, such as panoramics. To handle this, everything that belongs on the website gets the tag <em>website</em>, and we only fetch those ones. We&#8217;ve also talked about just getting landscape oriented photos, but haven&#8217;t implemented&nbsp;that.</p>
<p>I&#8217;m running this daily, which is plenty often to update the available photo list. I believe this gets the newest 500, which seems more than adequate, particularly since we don&#8217;t have close to 500 photos&nbsp;yet.</p>
<h3>Parsing the list <span class="amp">&amp;</span> generating the&nbsp;<span class="caps">HTML</span></h3>
<p><span class="caps">PHP5</span>&#8217;s SimpleXML is pretty nice&thinsp;&#8212;&thinsp;here&#8217;s what we&#8217;re doing:<br />
<code> </code></p>
<pre>try {
  $xml = new SimpleXMLElement(file_get_contents('photos.xml'));
    $number_of_photos = count($xml-&gt;photos-&gt;photo);
    $displayed_photos = array();
    array_push(
      $displayed_photos,
      $xml-&gt;photos-&gt;photo[rand(0, $number_of_photos - 1)]);
    array_push(
      $displayed_photos,
      $xml-&gt;photos-&gt;photo[rand(0, $number_of_photos - 1)]);
    foreach ($displayed_photos as $photo) { ?&gt;
  &lt;div&gt;
&lt;?php
      print "&lt;a href=\"http://www.flickr.com/photos/8562013@N07/" .
        $photo['id'] . "\"&gt;&lt;img src=\"http://farm" . $photo['farm'] .
        ".static.flickr.com/" . $photo['server'] . "/" . $photo['id'] . "_" .
        $photo['secret'] .  "_m.jpg\" alt=\"" . $photo['title'] . "\" /&gt;&lt;/a&gt;";
?&gt;
  &lt;/div&gt;
&lt;?php
 }
} catch (Exception $e) {
  error_log("flickr badge had some troubles: " .
    $e-&gt;getMessage());
}</pre>
<p>This snippet takes my laptop less than 1/20th of a second to run from the command line, which suits me fine. The actual code sits in&nbsp;<code>page.tpl.php</code>.</p>
<p><a href="http://www.flickr.com/services/api/">Flickr&#8217;s <span class="caps">API</span> docs</a>, in particular the <span class="caps">API</span> Explorer, were awful handy in figuring this all&nbsp;out.</p>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2009/07/29/custom-flickr-sidebar-via-wget-cron-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Joe&#8217;s hacky approach to getting arbitrary behavior out of Drupal</title>
		<link>http://slagwerks.com/blog/index.php/2009/07/28/joes-hacky-approach-to-getting-arbitrary-behavior-out-of-drupal/</link>
		<comments>http://slagwerks.com/blog/index.php/2009/07/28/joes-hacky-approach-to-getting-arbitrary-behavior-out-of-drupal/#comments</comments>
		<pubDate>Tue, 28 Jul 2009 20:42:39 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/?p=257</guid>
		<description><![CDATA[Wherein I disqualify myself for work as a &#8220;drupal&#160;developer&#8221; Self indulgent history&#160;part Way back in 1999 when I started out writing web apps, Embperl seemed like the logical tool to use&#8201;&#8212;&#8201;so I&#8217;m used to having direct access to every step in the request-to-response process. In years since, I&#8217;ve progressed through a bunch of different tools [...]]]></description>
			<content:encoded><![CDATA[<p><em>Wherein I disqualify myself for work as a &#8220;drupal&nbsp;developer&#8221;</em></p>
<h3>Self indulgent history&nbsp;part</h3>
<p>Way back in 1999 when I started out writing web apps, <a href="http://perl.apache.org/embperl/">Embperl</a> seemed like the logical tool to use&thinsp;&#8212;&thinsp;so I&#8217;m used to having direct access to every step in the request-to-response process. In years since, I&#8217;ve progressed through a bunch of different tools and approaches, which have included writing a few rudimentary content management systems and using a bunch of prexisting&nbsp;ones.</p>
<p>Over the last few years I&#8217;ve become a big fan of ruby on rails, so if a site does much of anything (simple, recent example: The Food Project&#8217;s online <a href="http://apply.thefoodproject.org">summer program application</a>), that&#8217;d be my starting&nbsp;point.</p>
<h3>so, why use&nbsp;Drupal?</h3>
<p>Even so, when a site is basically about some content that&#8217;s written and edited on an ongoing basis by other folks, Drupal starts looking like a reasonable tool. It&#8217;s pretty easy to get it to generate semantic output with reasonable URLs, and the editor-facing <span class="caps">UI</span> does a fair job of offerring a large degree of control and customizability without being overwhelmingly&nbsp;complex.</p>
<p>Despite having done some <a href="http://jamaicaplaingazette.com/node/2568">custom work</a> <a href="http://womenslunchplace.org/biographical-sketch-sharon-reilly">on a few</a> live Drupal sites, I still get confused about the best way to do some of the arbitrary web interaction tasks that were so straightforward back in the Embperl days. There are a billion modules in the Drupal ecosystem, but I often find that it takes more time to figure out if there is an appropriate one for my task <span class="amp">&amp;</span> if it works with the current version of Drupal than it would to code up a solution on my own. Also, while I&#8217;ve made several attempts to solve programming tasks in what I understand to be the Drupal way, wrapping my head around all the relevant APIs (which can totally change every 6-12 months, with each Drupal release) similarly tends to take more time than bypassing Drupal&#8217;s functionality <span class="amp">&amp;</span> handling things in Plain Old&nbsp;<span class="caps">PHP</span>.</p>
<p>Here&#8217;s a common approach I&#8217;ll take, then. I have no interest in extensive coding through a web browser (i.e. <a href="http://drupal.org/handbook/customization/php-snippets">putting a bunch of <span class="caps">PHP</span> in a node or block</a>), so I&#8217;ll set up a Drupal module to hold my application&#8217;s arbitrary php functions. Then I&#8217;ll create a page at the desired <span class="caps">URL</span> and enter a line of <span class="caps">PHP</span> to route the <span class="caps">GET</span> and/or <span class="caps">POST</span> to my code, as&nbsp;appropriate.</p>
<h3>Example</h3>
<p>I&#8217;m working on an email list signup that needs to communicate with a FileMaker database. An <span class="caps">HTML</span> form POSTs to http://thefoodproject.org/mailing_list_signup, which is just a Drupal page using the <span class="caps">PHP</span> input filter (which you now need to turn on via admin settings) containing <code>&lt;?php tfp_process_list_signup($_POST); </code> The code for that function lives in sites/all/modules/tfp/tfp.module, and does the normal PHP things to pull information out of the POST <span class="amp">&amp;</span> hand that info off to the FileMaker database. Here&#8217;s a bit of&nbsp;it:</p>
<p><code>
<pre>function tfp_process_list_signup($_POST) {
  $reply = '';
  $sent_plausible_address = FALSE;
  if ($_POST['email']) {
    $supplied_email = $_POST['email'];
    if (preg_match(PLAUSIBLE_EMAIL, $supplied_email)) {
      $sent_plausible_address = TRUE;
      $reply = "Thanks! We'll add your to our mailing list.";
    } else {
      $reply = "'$supplied_email' doesn't look like an email address to me. ";
    }
    //. . .
  }
  return $reply;
}</pre>
<p></code></p>
<p>On the upside, this is quick <span class="amp">&amp;</span> easy. The downside with this approach vs. writing a module the Drupal way is that I&#8217;m losing out on Drupal&#8217;s <a href="http://api.drupal.org/api/file/developer/topics/forms_api.html">form <span class="caps">API</span></a> and its associated validation, antispoofing, etc. services. On the upside, last time I checked the linked documentation for the form <span class="caps">API</span>, it&nbsp;said</p>
<blockquote><p><strong>Warning - this page has only been partially updated for the Drupal 6.x <span class="caps">API</span><br />
</strong>Until it has been fully updated, reference this page as well:  <a href="http://drupal.org/node/144132">Drupal 5.x to 6.x FormAPI&nbsp;changes</a></p></blockquote>
<p>so I&#8217;m quite happy to not have to wade through all of that!<span id="more-257"></span></p>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2009/07/28/joes-hacky-approach-to-getting-arbitrary-behavior-out-of-drupal/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FileMaker error 100</title>
		<link>http://slagwerks.com/blog/index.php/2008/11/21/filemaker-error-100/</link>
		<comments>http://slagwerks.com/blog/index.php/2008/11/21/filemaker-error-100/#comments</comments>
		<pubDate>Fri, 21 Nov 2008 11:29:54 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tech Stuff]]></category>
		<category><![CDATA[FileMaker]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/?p=208</guid>
		<description><![CDATA[or, Why To Use Dedicated Layouts When Connecting To FileMaker Via&#160;PHP I&#8217;d read that it&#8217;s a good practice to always use a dedicated layout for any PHP scripts you have that are talking to a FileMaker database. While I&#8217;d seen reasons of efficiency and reliability, today I learned another reason that&#8217;s true: it can eliminate [...]]]></description>
			<content:encoded><![CDATA[<p><em>or, Why To Use Dedicated Layouts When Connecting To FileMaker Via&nbsp;<span class="caps">PHP</span></em></p>
<p>I&#8217;d read that it&#8217;s a good practice to always use a dedicated layout for any <span class="caps">PHP</span> scripts you have that are talking to a FileMaker database. While I&#8217;d seen reasons of efficiency and reliability, today I learned another reason that&#8217;s true: it can eliminate otherwise hard-to-debug&nbsp;problems.</p>
<p>At first when working on my current FileMaker &lt;-&gt; <span class="caps">PHP</span> project, I was attempting to reuse an existing layout that had all the info I needed. While my permissions seemed to be fine for the data file and layout I was attempting to access, actually running the script kept resulting in &#8220;Error 100: File is missing&#8221; coming back at me as soon as I added any criteria to my search. FileMaker doesn&#8217;t bother putting anything useful in its server logs, either, so it wouldn&#8217;t have been much fun picking through the layout <span class="amp">&amp;</span> figuring what linkage(s) were to&nbsp;blame.</p>
<p>However, by simply creating a dedicated layout, everything started working as planned. A practice I&#8217;ll be following in the&nbsp;future.</p>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2008/11/21/filemaker-error-100/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sending email from FileMaker via PHP, revisited</title>
		<link>http://slagwerks.com/blog/index.php/2008/10/22/sending-email-from-filemaker-via-php-revisited/</link>
		<comments>http://slagwerks.com/blog/index.php/2008/10/22/sending-email-from-filemaker-via-php-revisited/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 15:57:01 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tech Stuff]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[FileMaker]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/?p=118</guid>
		<description><![CDATA[We last looked at this a few months ago, but have been revisiting it to come up with something a little more robust.&#160;Notes: there&#8217;s a good overview of using PHP with FM at the sixfriedrice&#160;blog. the API for FileMaker&#8217;s PHP interface is available at&#160;http://YOURSERVER.URL:16000/docs/PHP%20API%20Documentation/index.html I&#8217;d missed this last time around, but accounts &#38; permissions are [...]]]></description>
			<content:encoded><![CDATA[<p>We last looked at this <a href="http://slagwerks.com/blog/index.php/2008/06/12/sending-server-side-emails-from-filemaker-via-php/  ">a few months ago</a>, but have been revisiting it to come up with something a little more robust.&nbsp;Notes:</p>
<ul>
<li>there&#8217;s a good overview of using <span class="caps">PHP</span> with <span class="caps">FM</span> <a href="http://sixfriedrice.com/wp/up-to-speed-with-the-filemaker-php-api/">at the sixfriedrice&nbsp;blog</a>.</li>
<li>the <span class="caps">API</span> for FileMaker&#8217;s <span class="caps">PHP</span> interface is available at&nbsp;http://<span class="caps">YOURSERVER</span>.<span class="caps">URL</span>:16000/docs/<span class="caps">PHP</span>%<span class="caps">20API</span>%20Documentation/index.html</li>
<li>I&#8217;d missed this last time around, but accounts <span class="amp">&amp;</span> permissions are a little funky. <em>fmphp</em> needs to be added to the Extended Privileges of the database you&#8217;re trying to get to, and must have the same privilege set as the account you&#8217;re connecting&nbsp;as.</li>
<li>The solution we settled on is a <span class="caps">CLI</span> <span class="caps">PHP</span> script running hourly, checking for mail to send. Launchd would be the logical way to do the scheduling, but always drives me nuts. Fortunately the server in question has cron set up (so much&nbsp;simpler!)</li>
</ul>
<p>The code we&#8217;re more or less&nbsp;using:</p>
<pre><code>
#!/usr/bin/php
&lt;?php
set_include_path(get_include_path() . PATH_SEPARATOR .
  '/Library/FileMaker Server/Web Publishing/publishing-engine/php/lib/php/');
require_once('FileMaker.php');

echo "PHP email-sending-script, running at " .
  date('m/d/Y H:i') . "\n";
$layout = 'Outgoing_Email';
$fm = new FileMaker('Layout Name');
$fm-&gt;setProperty('username', 'your filemaker username');
$fm-&gt;setProperty('password', 'your filemaker password');

$findCmd =&amp; $fm-&gt;newFindCommand($layout);
$findCmd-&gt;addFindCriterion('Sent_Flag', '&lt; 1');
$result = $findCmd-&gt;execute();
if (FileMaker::isError($result)) {
  if ($result-&gt;code == 401) {
    exit("No emails to send.\n");
  } else {
    exit("trouble: " . $result-&gt;message . "(" . $result-&gt;code . ")");
  }
}

$records = $result-&gt;getRecords();
foreach($records as $record) {
  echo "To: " . $record-&gt;getField('Recipient') . "\n";
  echo "Subject: " . $record-&gt;getField('Subject') . "\n";
  $headers = array(
    "From: filemaker@example.com",
    "MIME-Version: 1.0",
    "Content-type: text/html"
    );

  /*
   FM helpfully encodes &lt; and &gt;...
   */
  $body = preg_replace('/&amp;lt;/', '&lt; ', $record-&gt;getField('Body'));
  $body = preg_replace('/&amp;gt;/', '&gt;', $body);
  $rc = mail($record-&gt;getField('Recipient'),
       $record-&gt;getField('Subject'),
       $body,
       implode("\r\n", $headers)
      );
  if ($rc) {
    $update = $fm-&gt;newEditCommand($layout, $record-&gt;getRecordId());
    $update-&gt;setField('Sent_Date', date('m/d/Y'));
    $update-&gt;setField('Sent_Time', date('H:i'));
    $update-&gt;setField('Sent_Flag', '1');
    $result = $update-&gt;execute();
    if (FileMaker::isError($result)) {
      exit("trouble updating the database after sending email: " .
        $result-&gt;message . "(" . $result-&gt;code . ")");
    }
    echo "Mailed!\n";
  } else {
    exit("Mail didn't work.\n");
  }
}

</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2008/10/22/sending-email-from-filemaker-via-php-revisited/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sending server-side emails from FileMaker via PHP</title>
		<link>http://slagwerks.com/blog/index.php/2008/06/12/sending-server-side-emails-from-filemaker-via-php/</link>
		<comments>http://slagwerks.com/blog/index.php/2008/06/12/sending-server-side-emails-from-filemaker-via-php/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 23:15:54 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[FileMaker]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/?p=57</guid>
		<description><![CDATA[Some context&#8201;&#8212;&#8201;my new gig features a big &#8216;ol FileMaker installation, which has a number of automated maintenance routines. Some of those routines send emails, through a convoluted process involving FileMaker calling a GUI MUA (e.g. Mail.app). There are a number of practical problems with this, such as the requirement of another computer running, always logged [...]]]></description>
			<content:encoded><![CDATA[<p>Some context&thinsp;&#8212;&thinsp;my new gig features a big &#8216;ol <a href="http://en.wikipedia.org/wiki/FileMaker">FileMaker</a> installation, which has a number of automated maintenance routines. Some of those routines send emails, through a convoluted process involving FileMaker calling a <span class="caps">GUI</span> <span class="caps">MUA</span> (e.g. Mail.app). There are a number of practical problems with this, such as the requirement of another computer running, always logged into an account capable of sending the&nbsp;emails.</p>
<p>We&#8217;d done a bit of research about strictly server-side alternatives, and found surprisingly little. The best resource was <a href="http://www.grahamsprague.com/server_side_email/server_side_email.html">Graham Sprague&#8217;s page about sending emails via FileMaker&#8217;s <span class="caps">XSLT</span> Web Publishing tool</a>. We gave that approach a try, but didn&#8217;t get any results, or anything useful from FileMaker&#8217;s logs to explain why things weren&#8217;t working. I&#8217;m not sure what FileMaker version Graham&#8217;s example was written for, perhaps something&#8217;s changed with version&nbsp;9?</p>
<p>Rather than dive into FileMaker&#8217;s proprietary <span class="caps">XSLT</span> system to debug things, it occurred to me that this might be a job for FileMaker&#8217;s <span class="caps">PHP</span> <span class="caps">API</span>. Sure enough, after about 15 minutes of consulting the <span class="caps">API</span> Doc, we were sending emails based on the contents of a FileMaker&nbsp;record. </p>
<p>We&#8217;re still working on ironing out the details, but here&#8217;s the rough proof of concept <span class="caps">PHP</span> file. It works with the example email database from Graham&#8217;s <span class="caps">XSLT</span> sample, with the php permission added to the database. Plenty of missing features such as cc <span class="amp">&amp;</span> bcc fields, actually checking for the &#8216;send&#8217; flag, checking for errors, any kind of authorization or authentication, etc. In other words, you probably don&#8217;t want to be running this on a publicly accessible webserver, but at least it presents the basic idea in a simple&nbsp;form.</p>
<pre><code>
&lt;?php
require_once('FileMaker.php');
$fm = new FileMaker();
$fm->setProperty('username', 'send_email');
$fm->setProperty('password', 'whatever_the_password_is');
$fm->setProperty('database', 'Email');

$findCmd =&#038; $fm->newFindAllCommand('Utility_Email');
$result = $findCmd->execute();
$records = $result->getRecords();
foreach($records as $record) {
  $headers = array("From: " . $record->getField('from'));

  mail($record->getField('to'),
       $record->getField('subject'),
       $record->getField('message'),
       implode("\r\n", $headers)
      );
}
echo "Emails sent";
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2008/06/12/sending-server-side-emails-from-filemaker-via-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>puttering around with Symfony</title>
		<link>http://slagwerks.com/blog/index.php/2008/01/23/puttering-around-with-symfony/</link>
		<comments>http://slagwerks.com/blog/index.php/2008/01/23/puttering-around-with-symfony/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 01:25:04 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/index.php/2008/01/23/puttering-around-with-symfony/</guid>
		<description><![CDATA[On advice from Nate, I&#8217;m taking Symfony for a spin (using the stable version 1, not the under-development 1.1), reimplementing the aforementioned contact management application. Here&#8217;s what I&#8217;m&#160;noticing: Somewhat like Rails, there&#8217;s DB-independent schema definition! Big win here. Among other things, this lets you develop in SQLite and deploy in MySQL, which is a nice [...]]]></description>
			<content:encoded><![CDATA[<p>On <a href="http://slagwerks.com/blog/index.php/2007/12/14/first-thoughts-on-cakephp-from-a-rails-perspective/#comment-4035">advice from Nate</a>, I&#8217;m taking <a href="http://www.symfony-project.org/">Symfony</a> for a spin (using the stable version 1, not the under-development 1.1), reimplementing the aforementioned contact management application. Here&#8217;s what I&#8217;m&nbsp;noticing:</p>
<ul>
<li>Somewhat like Rails, there&#8217;s <span class="caps">DB</span>-independent schema definition! Big win here. Among other things, this lets you develop in SQLite and deploy in MySQL, which is a nice pattern. Rails&#8217; awesome migrations aren&#8217;t here, so it&#8217;s not as useful and flexible a system, but it&#8217;s better than nothing for getting up <span class="amp">&amp;</span>&nbsp;running.</li>
<li>One big difference from Rails that&#8217;s clear right away: rather than building code dynamically based on the <span class="caps">DB</span> schema, thousands of lines of getters / setters / etc. are generated by the symfony command line tool. Makes sense for <span class="caps">PHP</span>, but it&#8217;s a clunkier development&nbsp;experience.</li>
<li>There&#8217;s <a href="http://www.symfony-project.org/book/1_0/15-Unit-and-Functional-Testing">testing</a> built in! It&#8217;s a bit of a <span class="caps">PITA</span> to do things like create a test database, and all the pieces for testing your models aren&#8217;t there right away, but still better than CakePHP. The aforementioned missing piece is available as <a href="http://trac.symfony-project.com/wiki/sfModelTestPlugin">a plugin</a>. There doesn&#8217;t seem to be a straightforward way to get the <code>propel-insert-sql</code> task to run on alternate environments, so one must create the db on their own. I&#8217;m using SQLite, which is great, but my local environment somehow ended up with PHP having SQLite 2.8 while my command line is version 3 (macports at fault? what a step backwards from Ubuntu&#8230;). One <code>port install sqlite2</code> later, and you can do <code>sqlite data/test.db &lt;&nbsp;data/sql/lib.model.schema.sql</code></li>
<li>No console, which makes the tests even more essential, so it does seem to be worth the pain of getting them&nbsp;working.</li>
</ul>
<p>Side note&thinsp;&#8212;&thinsp;already, on the basis of the previous post, I&#8217;m seeing a surprising amount of traffic from searches on CakePHP, Symfony, and <span class="caps">REST</span>. Clearly I&#8217;m not the only one looking for this kind of&nbsp;thing.</p>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2008/01/23/puttering-around-with-symfony/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>First thoughts on CakePHP from a Rails perspective</title>
		<link>http://slagwerks.com/blog/index.php/2007/12/14/first-thoughts-on-cakephp-from-a-rails-perspective/</link>
		<comments>http://slagwerks.com/blog/index.php/2007/12/14/first-thoughts-on-cakephp-from-a-rails-perspective/#comments</comments>
		<pubDate>Fri, 14 Dec 2007 22:31:03 +0000</pubDate>
		<dc:creator>joe</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://slagwerks.com/blog/index.php/2007/12/14/first-thoughts-on-cakephp-from-a-rails-perspective/</guid>
		<description><![CDATA[I have a new project coming up that seems like a great fit for Ruby on Rails, particularly the RESTful interfaces that have gone in over the last year. However, the typical questions about using Rails apply here: I&#8217;m not sure how well the project&#8217;s hosting environment will support Rails, and collaborators aren&#8217;t as familiar [...]]]></description>
			<content:encoded><![CDATA[<p>I have a new project coming up that seems like a great fit for Ruby on Rails, particularly the <a href="http://ryandaigle.com/articles/2006/08/01/whats-new-in-edge-rails-simply-restful-support-and-how-to-use-it">RESTful interfaces</a> that have gone in over the last year. However, the typical questions about using Rails apply here: I&#8217;m not sure how well the project&#8217;s hosting environment will support Rails, and collaborators aren&#8217;t as familiar with it. Thus,  it seemed like it might be worth another look at options on the <span class="caps">PHP</span> side of things. I keep hearing that <a href="cakephp.org/">CakePHP</a> is Rails-inspired and has many of the same advantages, so today I&#8217;ve taken the stable version (1.1.8.5850) for a spin, letting <a href="http://manual.cakephp.org/appendix/blog_tutorial">the Cake manual&#8217;s blog tutorial</a> get me started. Here&#8217;s what I&#8217;ve noticed about CakePHP development as practiced in the tutorial&thinsp;&#8212;&thinsp;maybe there&#8217;s better ways to do things <span class="amp">&amp;</span> the tutorial just isn&#8217;t mentioning&nbsp;them?</p>
<ul>
<li>No <a href="http://api.rubyonrails.org/classes/ActiveRecord/Migration.html">migrations</a>; you have to generate the <span class="caps">DDL</span> on your own, both initially and for any subsequent modifications. Also, no model or controller generators. It&#8217;s definitely nicer to just do  <code>script/generate scaffold post title:string body:text; rake db:migrate</code>  and be off to the races&thinsp;&#8212;&thinsp;from Rails 1.2 on, those races include the whole REST business. To be fair, there is a one off reference to &#8216;bake&#8217; scripts in the CakePHP manual, but no pointers on what those are, or where they live, and the website isn&#8217;t much&nbsp;clearer.</li>
<li>No <span class="caps">TDD</span>. Woah. That&#8217;s, like, half the advantage of Rails&thinsp;&#8212;&thinsp;automated testing is right there in your face, and is firmly entrenched in the&nbsp;community.</li>
<li><span class="caps">PHP</span> code is not quite as elegant as Ruby. For example, generating a link to delete a post looks like this: <code>$html-&gt;link('Delete', "/posts/delete/{$post['Post'][id']}", null, 'Are you sure?' )</code>. Can you spot the syntax error? Probably you can, but it took me a good few minutes. The Rails equivalent would be<br />
<code>link_to "Delete", { :action =&gt; "delete", :id =&gt; @post.id }, :confirm =&gt; "Are you sure?", :method =&gt;&nbsp;:delete</code></li>
<li>A lack of the experiences baked into Rails. For example, after the Google Web Accelerator fiasco, it became common practice to make all links to destructive actions happen via <span class="caps">POST</span>, which can be done via <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M000900">link_to</a>&#8217;s :method parameter. Compare to the <span class="caps">GET</span>-powered delete link above, straight from the Cake&nbsp;tutorial.</li>
<li>I miss my <a href="http://www.vim.org/scripts/script.php?script_id=1567">vim <span class="amp">&amp;</span> rails integration</a>, which makes creating and navigating the various files a breeze. (Glad I went to the trouble of making that a link, as it got me re-reading the plugin&#8217;s about page, and I saw the parts about partial extraction and migration inversion, neither of which I&#8217;d noticed&nbsp;before)</li>
</ul>
<p>On the upside, using CakePHP sure beats writing a <span class="caps">CRUD</span>-heavy <span class="caps">PHP</span> application from scratch. One of my current projects, a completely custom contact management application, would be in much better shape if it were using CakePHP instead of the project-specific <span class="caps">ORM</span> I cobbled together&thinsp;&#8212;&thinsp;I&#8217;m going to have to give conversion of that project to CakePHP some serious&nbsp;thought.</p>
<p>But is CakePHP a <a href="http://en.wikipedia.org/wiki/Domain-specific_programming_language"><span class="caps">DSL</span></a> for the web in the sense that Rails is? Not&nbsp;yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://slagwerks.com/blog/index.php/2007/12/14/first-thoughts-on-cakephp-from-a-rails-perspective/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
