<?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>Uncarved &#187; Symfony</title>
	<atom:link href="http://uncarved.prometheas.com/tag/symfony/feed" rel="self" type="application/rss+xml" />
	<link>http://uncarved.prometheas.com</link>
	<description>An ongoing tension of potential, or how i learned to stop worrying and embrace the iterations.</description>
	<lastBuildDate>Mon, 08 Aug 2011 05:14:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Designing the sfRESTClientPlugin: Sketching a Client API for RESTful Interactions</title>
		<link>http://uncarved.prometheas.com/2009/06/sketching-a-client-api-for-restful-interactions.html</link>
		<comments>http://uncarved.prometheas.com/2009/06/sketching-a-client-api-for-restful-interactions.html#comments</comments>
		<pubDate>Mon, 01 Jun 2009 05:41:25 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Public Brainstorm]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[proposal]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[sfRESTClientPlugin]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=373</guid>
		<description><![CDATA[I&#8217;ve lately been exploring the value proposition of RESTful APIs to organizations whose technological infrastructures are built upon a collection of legacy software components, customized to communicate with each other by highly tailored middleware software stacks. That exploration will not unfold in this post, however. It could easily be an entire book unto itself. Rather, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve lately been exploring the value proposition of RESTful APIs to organizations whose technological infrastructures are built upon a collection of legacy software components, customized to communicate with each other by highly tailored middleware software stacks.</p>

<p>That exploration will not unfold in this post, however. It could easily be an entire book unto itself.</p>

<p>Rather, I would like to focus specifically on ideas I&#8217;ve had about what a high level object oriented API for interacting with RESTful services might look like, and funnel those thoughts into the design and implementation of a plugin I&#8217;m developing for the <a href="http://www.symfony-project.org">Symfony framework</a>, called <a href="http://www.symfony-project.org/plugins/sfRESTClientPlugin">sfRESTClientPlugin</a>.</p>

<h3>Audience and Scope</h3>

<p>This post assumes at least casual familiarity with Web development. I will explore some general principles of the RESTful interaction paradigm, but only to the extent to which they inform the design direction of the plugin&#8217;s API.</p>

<p>Although all the code samples will be in PHP, it is my hope that the exercise will yield material valuable to people working with other software stacks.</p>

<p><span id="more-373"></span></p>

<h3>The Fundamentals</h3>

<p>Wikipedia offers a great <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">article</a> describing REST that is worth reading, if you would like a quick brush-up or introduction to the concept. I would describe REST as an &#8220;organic&#8221; extension to the model around which the World Wide Web itself was designed, as it wholly embraces a model composed of resources (text, images, videos, etc) that can be accessed using specific URLs.</p>

<p>I&#8217;ll be using the following assertion from the article as the springboard for my API design considerations (emphasis added to highlight the principal entities):</p>

<blockquote>
  <p>An important concept in REST is the existence of resources (sources of specific information), each of which is referenced with a global identifier (e.g., a URI in HTTP). In order to manipulate these resources, components of the network (user agents and origin servers) communicate via a standardized interface (e.g., HTTP) and exchange representations of these resources (the actual documents conveying the information).</p>
</blockquote>

<p>The API will therefore designed around the following discreet entities:</p>

<ul>
<li>Service</li>
<li>Resource</li>
<li>Client (or &#8220;user agent&#8221;)</li>
<li>Request</li>
<li>Response</li>
</ul>

<p>Another design goal for the plugin is that it offers the integration mechanisms that developers familiar with Symfony (and other high-quality MVC frameworks) will find familiar, such as named routes, YAML project configuration, <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> design, and an environment-aware configuration cascade.</p>

<h3>A Sneak Peak</h3>

<p>At a certain point, examples speak more clearly than theories and principles. For the remainder of this post, I will talk about a sample REST service, which represents a &#8220;traditional&#8221; library — a collection of books.</p>

<p>The primary entities with which your site&#8217;s business logic will be dealing with are the <em>services</em> themselves, each which offer one or more <em>resources</em>. Each service is defined by a collection of properties that declare information such as its host name, the types of resources available from the service, authentication credentials, and perhaps smaller details like a port number, root URI, etc.</p>

<p>A sample configuration might look like this:</p>

<pre><code>  [#!yaml]
  # config/rest_services.yml
  services:
    service_1:
      scheme  : https
      host    : exampleservice.com
      root_uri: /api

      resources:

        book:
          list: /books.xml
          item: /books/:id.xml

        author:
          list: /authors.xml
          item: /authors/:id.xml
</code></pre>

<p>The RESTful service in our example is located at <code>https://exampleservice.com/api</code> and offers two resource entities: <code>book</code> and <code>author</code>. These configuration values will be used to populate the properties of a <code>sfRESTOriginService</code> instance that represents the service.</p>

<p>Note that this configuration is defined under the key <code>service_1</code>. Here&#8217;s what some code that interacts with this service might look like:</p>

<pre><code>  [#!php]
  $svc = sfRESTOriginService::getInstance( 'service_1' );

  // GET https://exampleservice.com/api/articles/34.xml
  $response = $svc-&gt;get( '@book?id=34' );

  // make sure we have a valid response
  if ( $response-&gt;isError() )
  {
    if ( $response-&gt;isStatusCode( sfRESTClient::STATUS_UNAUTHORIZED ) )
    {
      throw new Exception( 'Access to resource is unauthorized!' );
    }
    else
    {
      throw new Exception( 'An error occurred attempting to access the resource!' );
    }
  }

  // load the XML into a locally defined entity and manipulate it
  $book = new MyLocalBook();
  $book-&gt;loadFromXML( $response-&gt;getResponseXML() );
  $book-&gt;setTitle( 'A New Title' );

  // PUT https://exampleservice.com/api/articles/34.xml
  $svc-&gt;put( '@book?id=34', array(
    'data' =&gt; $book-&gt;serializeXml()
  ));
</code></pre>

<p>As the sample suggests, each service will be represented by a single instance.</p>

<p>Each service naturally supports the four <a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods">HTTP methods</a> used by REST: <code>GET</code>, <code>POST</code>, <code>PUT</code>, and <code>DELETE</code>, so requests of these method types are issued by invoking the corresponding class methods of a <code>sfRESTOriginService</code> instance.</p>

<p>The <code>GET</code> method requires only a URI, indicating the desired resource.</p>

<p>Each request to the service produces a response object, which offers access to the resource data in question. The response object also provides access to response information such as HTTP headers, the resource URL, the request method used for the query that created it, and the <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">HTTP status code</a>.</p>

<p>Each method must be performed against a particular URI, which must be specified, and the <code>PUT</code> and <code>POST</code> methods also require a data payload.</p>

<h3>Parting Thoughts</h3>

<p>This post is simply a starting point; a sketch. I will follow up shortly with another post outlining deeper use cases, such as using the <code>POST</code> method to create new resources, and dealing with resources of different data types, such as JSON, plain text, or even media files.</p>

<p>In the meantime, I welcome any thoughts or questions regarding this initial direction.</p>

<p>One particular matter I&#8217;m not so hot on from the examples above is the way in which resources are defined in the service configuration. I wonder if there isn&#8217;t some better way to express the resource configuration, and manage to still deliver the &#8220;named route&#8221;-like approach to specifying resource URIs shown in the sample code above.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/06/sketching-a-client-api-for-restful-interactions.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony Components &#8211; Standalone Libraries for PHP</title>
		<link>http://uncarved.prometheas.com/2009/05/symfony-components.html</link>
		<comments>http://uncarved.prometheas.com/2009/05/symfony-components.html#comments</comments>
		<pubDate>Sun, 24 May 2009 14:42:21 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Check it out]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>
		<category><![CDATA[Symfony components]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=352</guid>
		<description><![CDATA[The Symfony project has recently launched the Symfony Components sub-project and website. Its goal is to produce a collection of standalone libraries for PHP. Although these libraries were initially born for use in the Symfony MVC framework, the talented developers involved in the project have designed them to avoid any interdependencies with any of the [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://symfony-project.org/">Symfony project</a> has recently launched the Symfony Components sub-project and <a href="http://components.symfony-project.org/">website</a>. Its goal is to produce a collection of standalone libraries for PHP.</p>

<p>Although these libraries were initially born for use in the Symfony MVC framework, the talented developers involved in the project have designed them to avoid any interdependencies with any of the other parts of the overall framework. This effort has resulted in components that may be used individually in any other PHP project without requiring the use of any of the rest of the Symfony framework.</p>

<p>The initial round of components include:</p>

<ul>
<li><em>YAML</em>, a parser that translates data between YAML and native PHP arrays;</li>
<li><em>Event Dispatcher</em>, which provides a generic event dispatching framework; and</li>
<li><em>Templating</em>, which provides parameterized and scope-isolated templating functionality.</li>
</ul>

<p>I&#8217;ll be keeping a keen eye on this project.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/05/symfony-components.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfPropelLazyHydrationIteratorPlugin — Lazy Hydration, Made Concise</title>
		<link>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html</link>
		<comments>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html#comments</comments>
		<pubDate>Wed, 13 May 2009 05:49:06 +0000</pubDate>
		<dc:creator>John</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[announcement]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[laziness]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Propel]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://uncarved.prometheas.com/?p=310</guid>
		<description><![CDATA[sfPropelLazyHydrationIteratorPlugin lets you utilize Propel 1.2's "lazy hydration" technique of iterating a database query without dealing with its lower level Creole APIs.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been working on <a href="http://www.symfony-project.org/">Symfony</a> / <a href="http://propel.phpdb.org/">Propel</a> projects that deal with particularly large data sets. In such cases, Propel&#8217;s documentation recommends a &#8220;lazy hydration&#8221; approach.</p>

<p>This &#8220;lazy hydration&#8221; of Propel&#8217;s looks like this:</p>

<pre><code>  [#!php]
  // query all the author entities as a Creole ResultSet
  $rs = AuthorPeer::doSelectRS( new Criteria() );

  while( $rs-&gt;next() )
  {
    $author = new Author();
    $author-&gt;hydrate( $rs );
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>The code above does the following:</p>

<ol>
<li>it queries the database for all records in the <code>author</code> table, and loads it into a <a href="http://creole.phpdb.org/">Creole</a> <code>ResultSet</code> object.</li>
<li>enters a loop, iterating over each result (ie, table row) in the <code>ResultSet</code>, and with each of its records, it:

<ol>
<li>creates a new, empty Author object</li>
<li>hydrates the empty object with the data in the <code>ResultSet</code>&#8216;s current row</li>
<li>writes the author&#8217;s last and first name to the output buffer</li>
</ol></li>
</ol>

<p>In this way, only one <code>Author</code> instance is in use at any given time. Each iteration discards the previous instance and creates a new one.</p>

<p>But I hate it — it&#8217;s ugly and unwieldy.</p>

<p>This overt use of the <code>ResultSet</code> object is an awkward practice when using an ORM. The primary design goal of ORMs is to allow the developer to work at a higher level of abstraction than SQL queries and database result sets.</p>

<p>So what <em>should</em> it look like? <span id="more-310"></span></p>

<p>Assuming you&#8217;re <em>not</em> worried the query&#8217;s results might chew up all system&#8217;s RAM, the Propel API lets you get the job done like this:</p>

<pre><code>  [#!php]
  foreach( AuthorPeer::doSelect( new Criteria() ) as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>For starters, this is a more concise block of code.</p>

<p>Secondly, this block of code focuses more directly on classes that are directly relevant to your application&#8217;s business logic.</p>

<p>Unfortunately, for all the theoretical loveliness it espouses, it consumes considerably more RAM since the data from each record of <code>author</code> table is loaded into unique instances of <code>Author</code> objects, which are all dumped into an array.</p>

<p>If the database only has ten authors, you won&#8217;t have any problems finding the RAM to instantiate all ten <code>Author</code> objects.</p>

<p>If you have <em>tens of thousands</em> of <code>author</code> records, on the other hand, it might be challenging enough to allocate enough RAM to store the entirety of the raw data generated by the database query, let alone to load that data into tens of thousands of <code>Author</code> object instances.</p>

<p>Propel&#8217;s &#8220;lazy hydration&#8221; approach sacrifices a little concision in return for some resource efficiency.</p>

<p>But I was writing <em>many dozens</em> of blocks of code like this, and seeing what is essentially the same lines of code dutifully repeated all over the place started to wear on me. I was even nesting these iterations, winding up with variable scopes that simultaneously contained variables named <code>$authors_rs</code>, <code>$books_rs</code>, and <code>$whatever_else_rs</code>.</p>

<p>I got fed up, so I decided to fix it.</p>

<p>I had started thinking about some other Symfony classes that managed to abstract Propel API quirks, and found inspiration in the <code>sfPropelPager</code> class. I decided to encapsulate all that into the sfPropelLazyHydrationIterator class, which implements PHP&#8217;s <code>Iterator</code> interface to provide the best of both worlds.</p>

<p>Let&#8217;s start simply:</p>

<pre><code>  [#!php 1]
  // create a sfPropelLazyHydrationIterator
  $authors = new sfPropelLazyHydrationIterator('Author', new Criteria());

  foreach( $authors as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>The constructor requires two arguments: the name of the Propel model class, and a Criteria object. Internally, the object queries the database to retrieve a <code>ResultSet</code>. Using this object in a <code>foreach()</code> loop iterates through the database results using the same lazy hydration technique we looked at earlier.</p>

<p>Let&#8217;s take a look at a slightly more complex scenario, which uses a Propel 1.2 <code>Connection</code> for an in-transaction query:</p>

<pre><code>  [#!php 1]
  // let's add a transaction to the mix
  $con = Propel::getConnection();
  $con-&gt;begin();

  try
  {
    // do some stuff to author records within the transaction...

    $authors = new sfPropelLazyHydrationIterator( 'Author', new Criteria(), $con );
    foreach( $authors as $author )
    {
      echo sprintf('%s, %s', $author-&gt;getFirstName(), $author-&gt;getLastName());
      $author-&gt;setLastAccessedOn( 'now' );
      $author-&gt;save( $con );
    }

    $con-&gt;commit();
  }
  catch (SqlException $sqle)
  {
    $con-&gt;rollback();
  }
</code></pre>

<p>But how does this all happen? Let&#8217;s look at an abbreviated version of this class:</p>

<pre><code>  [#!php 1]
  class sfPropelLazyHydrationIterator
  implements Iterator
  {
    private $modelClassName;
    private $resultSet;

    /**
     * Contstructor.
     *
     * @param string $model_class_name
     * @param Criteria $c
     * @param Connection $con
     * @param string $peer_name
     */
    public function __construct( $model_class_name, $c, $con=null, $peer_name=null )
    {
      $this-&gt;modelClassName = $model_class_name;
      $this-&gt;modelPeerName  = empty($peer_name) ? $this-&gt;modelClassName.'Peer' : $peer_name;
      $this-&gt;resultSet      = call_user_func(array($this-&gt;modelPeerName, 'doSelectRS'), $c);
    }

    /**
     * Implements Iterator::current()
     */
    public function current()
    {
      if (false !== $this-&gt;resultSet-&gt;getIterator()-&gt;current())
      {
        return $this-&gt;createAndHydrateCurrent();
      }

      return false;
    }

    /**
     * Implements Iterator::next()
     */
    public function next()
    {
      if (false !== $this-&gt;resultSet-&gt;getIterator()-&gt;next())
      {
        return $this-&gt;createAndHydrateCurrent();
      }

      return false;
    }

    // ... other Iterator methods

    /**
     * Returns a hydrated instance of the appropriate model class, using
     * the row data at the ResultSet's current pointer position.
     *
     * @return mixed
     */
    protected function createAndHydrateCurrent()
    {
      $object = new $this-&gt;modelClassName();
      $object-&gt;hydrate( $this-&gt;resultSet );
      return $object;
    }

  }
</code></pre>

<p>The real work happens in the constructor and <code>createAndHydrate()</code> method. The latter is called by the <code>Iterator</code> interface implementations of the <code>next()</code> and <code>current()</code> methods (included in the code excerpt above).</p>

<p>This class is available in its entirety as part of the <a href="http://www.symfony-project.org/plugins/sfPropelLazyHydrationIteratorPlugin">sfPropelLazyHydrationIteratorPlugin</a>, which I have already published to the Symfony plugins site. The plugin is not, at the time of this writing, available as a PEAR package, but I intend to sort that out in the coming days.</p>

<p><strong>Please note</strong>: the sfPropelLazyHydrationIterator presently only works with Propel 1.2.</p>

<h3>Getting <em>Really</em> Lazy</h3>

<p>And finally, let&#8217;s surrender fully to the laziness within — let&#8217;s look at super concision. We&#8217;ll add a new method to the <code>AuthorPeer</code> class:</p>

<pre><code>  [#!php 1]
  class AuthorPeer extends BaseAuthorPeer
  {

    /**
     * Returns a sfPropelLazyHydrationIterator to allow iteration over retrieved
     * database results, utilizing "lazy hydration".
     *
     * @param Criteria $c
     * @param Connection $con
     * @return sfPropelLazyHydrationIterator
     */
    public static function doSelectLazy( $c, $con=null )
    {
      return new sfPropelLazyHydrationIterator('Author', $c, $con);
    }

    // ... other peer methods ...
  }
</code></pre>

<p>Now, we can iterator over all <code>author</code> records like so:</p>

<pre><code>  [#!php 1]
  foreach( AuthorPeer::doSelectLazy(new Criteria()) as $author )
  {
    echo "{$author-&gt;getLastName()}, {$author-&gt;getFirstName()}";
  }
</code></pre>

<p>Whoever said you couldn&#8217;t have your cake <em>and</em> eat it obviously wasn&#8217;t terribly determined to be as lazy as possible.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://uncarved.prometheas.com/2009/05/lazy-hydration-made-concise.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

