<?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/"
	>

<channel>
	<title>-= n8v =- &#187; symfony</title>
	<atom:link href="http://n8v.enteuxis.org/tags/symfony/feed/" rel="self" type="application/rss+xml" />
	<link>http://n8v.enteuxis.org</link>
	<description>Just another WordPress weblog</description>
	<pubDate>Mon, 17 Nov 2008 21:31:59 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.8-bleeding-edge</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Adding many-to-many tables to an existing symfony project</title>
		<link>http://n8v.enteuxis.org/2008/10/adding-many-to-many-tables-to-an-existing-symfony-project/</link>
		<comments>http://n8v.enteuxis.org/2008/10/adding-many-to-many-tables-to-an-existing-symfony-project/#comments</comments>
		<pubDate>Fri, 31 Oct 2008 00:31:28 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
		
		<category><![CDATA[Figuring IT Out]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=92</guid>
		<description><![CDATA[ 
This is a symfony 1.0 project, but I think everything applies equally to 1.1, except the command syntax has changed from propel-load-data to propel:load-data
In this case, the application helps nurses collect and analyze data about how they&#8217;re administering intravenous therapies to their patients.  At first they wanted plain text lists of the IV drugs [...]<p><a href="http://sharethis.com/item?&#038;wp=2.8-bleeding-edge&#38;publisher=2d4ffbb0-4e95-4a28-a7ca-90d409134058&#38;title=Adding+many-to-many+tables+to+an+existing+symfony+project&#38;url=http%3A%2F%2Fn8v.enteuxis.org%2F2008%2F10%2Fadding-many-to-many-tables-to-an-existing-symfony-project%2F">ShareThis</a></p>]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>This is a symfony 1.0 project, but I think everything applies equally to 1.1, except the command syntax has changed from <code>propel-load-data</code> to <code>propel:load-data</code></p>
<p>In this case, the application helps nurses collect and analyze data about how they&#8217;re administering intravenous therapies to their patients.  At first they wanted plain text lists of the IV drugs and fluids, but in order to filter based on them, we needed to change them to discreet fields.  In the View, it means changing a couple of fields from plain text to arrays of checkboxes.  In the Model, it means adding separate tables, and a &#8220;through class&#8221; associating the therapy with the new class.</p>
<p><span id="more-92"></span></p>
<h3>Changing the database schema and the generated object model</h3>
<p>The original design had only two classes/tables:  <code>Patients</code>, each having one or more <code>Therapies</code>.  Now, each <code>Therapy</code> can have 0 or more <code>Drugs</code> and <code>Fluids</code>.</p>
<p>First I added additional tables to my <var>schema.yml</var>, using the <a href="http://www.symfony-project.org/book/1_1/08-Inside-the-Model-Layer#Basic Schema Syntax">column naming conventions</a> so symfony will get the table relationships right:</p>
<pre>  drug:
    id:
    name:             varchar(255)
    created_at:
    updated_at:

  fluid:
    id:
    name:             varchar(255)
    created_at:
    updated_at:

  therapy_drug:
    id:
    therapy_id:
    drug_id:

  therapy_fluid:
    id:
    therapy_id:
    fluid_id:</pre>
<p>Propel will generate the table creation SQL:</p>
<pre>./symfony propel-build-sql</pre>
<p>But I don&#8217;t want to obliterate my existing data, so I cut the 4 <code>CREATE TABLE</code> statements for my 4 new tables out of <var>data/sql/lib.model.schema.sql</var> and put it in a file named <var>data/sql/create_drugs_fluids.sql</var> (and added it to Subversion with <code>svn add</code>)</p>
<p>Now I can feed that file to MySQL</p>
<pre>mysql -uroot iv_log &lt; data/sql/create_drugs_fluids.sql</pre>
<p>Next, I wrote a <a href="http://www.symfony-project.org/book/1_1/16-Application-Management-Tools#Populating a Database">fixture file</a> in YAML.</p>
<p>Then I have to clear the cache and rebuild the model in order to populate my new tables from the fixture, but I have all the objects ready to go!</p>
<pre>./symfony cc
./symfony propel-build-model
./symfony propel-load-data frontend</pre>
<h4>Nicer accessors in the Model</h4>
<p>Next I&#8217;ll do some work in the model layer to make things more convenient and logical for accessing the <code>Drug </code>and <code>Fluid </code>objects attached to each <code>Therapy</code>.</p>
<p>Add accessors to the Therapy model that return the array of through-class objects (TherapyDrug and TherapyFluid), for example in <var>lib/model/Therapy.php</var>:</p>
<pre>  public function getDrugs($criteria = null, $con = null)
  {
    return $this-&gt;getTherapyDrugsJoinDrug($criteria, $con);
  }</pre>
<p>(and a similar <code>getFluids </code>method)</p>
<p>Make a list of through-class objects display like a list of the associated thing.  In <var>lib/model/TherapyDrug.php</var>:</p>
<pre>  public function __toString ()
  {
    $s = $this-&gt;getDrug();
      return $s-&gt;__toString();   # i've had problems not doing this explicitly
  }</pre>
<p>(and the same for <var>TherapyFluid.php</var>)</p>
<p>Now make sure the attached objects have a good <code>__toString()</code> method.  In <var>lib/model/Drug.php</var></p>
<pre>/**
 * Method __toString
 *
 *  @return    string   the drug name
 * @package lib.model
*/
  public function __toString ()
  {
    return $this-&gt;getName();
  }</pre>
<h3>Changing the Admin Generator GUI</h3>
<p>Now my database and model are all set, I need to make the new tables/objects available in the GUI.<br />
I am using the Admin Generator for all the parts of the application.</p>
<p>First, I want them to be able to edit the list of drugs and fluids, so I build admin modules:</p>
<pre>./symfony propel-init-admin frontend drug Drug
./symfony propel-init-admin frontend fluid Fluid</pre>
<p>But I don&#8217;t want users to delete these values and leave orphaned rows in the related tables, or delete all related Therapy objects, so I&#8217;ll remove the &#8216;delete&#8217; ability in each new module&#8217;s config/generator.yml, for example, in <var>apps/frontend/modules/drug/config/generator.yml</var>,</p>
<pre>generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Drug
    theme:            default
    list:
      display:
        - =name
      object_actions:
         _edit:          ~
    edit:
      display:
        - name
      actions:
        _save:
          params:  confirm=This will affect all existing log records that use this drug, OK?
        _list:  -</pre>
<p>OK, now to add it to the Therapy object&#8217;s admin module.  I&#8217;m going to need it in three places:</p>
<ol>
<li>The list view</li>
<li>The edit form</li>
<li>The filter list on the list view</li>
</ol>
<h4>List view</h4>
<p>In the list view, I unfortunately can&#8217;t just tell it to display the &#8220;drug&#8221; or &#8220;therapy_drug&#8221; column, because the Admin generator will print the results as &#8220;Array&#8221;.  So I make a <a href="http://www.symfony-project.org/book/1_1/07-Inside-the-View-Layer#Partials">partial</a> to display the list of related objects.  I&#8217;m going to use the same partial for list, edit and filter views using the $type variable <a href="http://www.symfony-project.org/book/1_1/14-Generators#Partial Fields">the admin generator provides</a> to tell them apart.</p>
<p>I define my partial in <var>apps/frontend/modules/therapy/templates/_drugs.php</var></p>
<pre>&lt;!--  begin _drugs partial for type '&lt;?php echo $type ?&gt;' --&gt;</pre>
<pre>&lt;?php switch ($type):  ?&gt;
&lt;?php case 'list': 

echo implode(', ', $therapy-&gt;getDrugs());

?&gt;
&lt;?php break; case 'edit':

   // this is handled by the admin generator

  ?&gt;
&lt;?php break; case 'filter':
   // coming in a minute
 ?&gt;
&lt;?php break; endswitch;  ?&gt;
&lt;!--  end _drugs partial --&gt;</pre>
<div>(and do the same for a <var>_fluids.php</var> partial)</div>
<p>Now I just have to add the partials to the list of fields that display in list view, in</p>
<pre>    list:
      fields:
        # ...
        - _drugs
        - _fluids</pre>
<p>And hooray!  My list of <code>Therapy </code>objects now displays their associated <code>Drug </code>and <code>Fluid </code>objects: </p>
<p><a href="http://n8v.enteuxis.org/wp-content/uploads/2008/10/list-view-works.png"><img class="alignnone size-full wp-image-100" title="list-view-works" src="http://n8v.enteuxis.org/wp-content/uploads/2008/10/list-view-works.png" alt="list-view-works" width="153" height="73" /></a></p>
<p class="MsoPlainText"> </p>
<p> </p>
<h4>Edit view</h4>
<p>The edit view doesn&#8217;t really need the partial at this point, we can get a list of checkboxes in the edit form just by hacking the correct stuff into <var>apps/frontend/modules/therapy/config/generator.yml</var>:</p>
<pre>  edit:
    display:
# ...
          - drug
          - fluid

    fields:
# ...
        drug:
          name:  Drug(s)
          type:  admin_check_list
          params:  through_class=TherapyDrug
        fluid:
          name:  Fluid(s)
          type:  admin_check_list
          params:  through_class=TherapyFluid</pre>
<p>I had to make a little tweak to the <code>.sf_admin_checklist li</code> style in <var>web/css/main.css</var>, but now I have a nice set of working checkboxen!</p>
<p><a href="http://n8v.enteuxis.org/wp-content/uploads/2008/10/edit-view-works.png"><img src="http://n8v.enteuxis.org/wp-content/uploads/2008/10/edit-view-works.png" alt="edit-view-works" title="edit-view-works" width="243" height="183" class="alignnone size-full wp-image-101" /></a></p>
<h4>Filter view</h4>
<p>This will take two stages.  First I put this sort of thing in my <var>_drugs.php</var> and <var>_fluids.php</var> partials:</p>
<pre>&lt;?php break; case 'filter': 

$drugs = DrugPeer::doSelect(new Criteria); // get the list of all the possible drugs
echo select_tag('filters[drug]',
  		  objects_for_select(
				   $drugs, 'getId', 'getName',
				   isset($filters['drug']) ?
				     $filters['drug'] : '',
				   'include_blank=true')
		);

 ?&gt;
</pre>
<p>and tell the Admin Generator to use the partials, back in <var>generator.yml</var>:</p>
<pre>
    list:
      # ...
      filters:
        # ...
        - _drugs
        - _fluids
</pre>
<p>Now I have a nice widget in my filters box, but it doesn&#8217;t do anything quite yet:</p>
<p><a href="http://n8v.enteuxis.org/wp-content/uploads/2008/10/filter-view-works.png"><img src="http://n8v.enteuxis.org/wp-content/uploads/2008/10/filter-view-works.png" alt="filter-view-works" title="filter-view-works" width="258" height="141" class="alignnone size-full wp-image-102" /></a></p>
<p>To get it working I&#8217;ll need to help out the filter action, by extending the addFiltersCriteria action generated by the admin generator.  I will edit my copy in <var>apps/frontend/modules/therapy/actions/actions.class.php</var>:</p>
<pre>  protected function addFiltersCriteria($c)
  {

    if (isset($this->filters['drug']) &#038;&#038; $this->filters['drug'] != '') {
      $c->addJoin( TherapyPeer::ID, TherapyDrugPeer::THERAPY_ID, Criteria::LEFT_JOIN);
      $c->add(TherapyDrugPeer::DRUG_ID, $this->filters['drug']);
    }

    if (isset($this->filters['fluid']) &#038;&#038; $this->filters['fluid'] != '') {
      $c->addJoin( TherapyPeer::ID, TherapyFluidPeer::THERAPY_ID, Criteria::LEFT_JOIN);
      $c->add(TherapyFluidPeer::FLUID_ID, $this->filters['fluid']);
    }

    return parent::addFiltersCriteria($c);
  }</pre>
<p>Now the action will add additional constraining filter criteria before displaying the list of Therapy objects, if the filters have been set.  That will let the user search for only records with a particular combination of values, for example.</p>
<p>Whew, that got a little bit involved but I&#8217;m sure it will be easier next time. </p>
<p>The big breakthrough for me learning how to work with the admin generator was when I realized that it generates all its files in the cache directory, so you can look in the cache at how it&#8217;s doing everything, and override as necessary with partials and actions when you run past what you can do with <var>generator.yml</var>.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2008/10/adding-many-to-many-tables-to-an-existing-symfony-project/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Adding Subversion keywords to an entire Symfony project</title>
		<link>http://n8v.enteuxis.org/2008/10/adding-subversion-keywords-to-an-entire-symfony-project/</link>
		<comments>http://n8v.enteuxis.org/2008/10/adding-subversion-keywords-to-an-entire-symfony-project/#comments</comments>
		<pubDate>Tue, 07 Oct 2008 19:07:14 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
		
		<category><![CDATA[Figuring IT Out]]></category>

		<category><![CDATA[subversion]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=90</guid>
		<description><![CDATA[For some reason, even though I&#8217;ve set default properties in my .subversion/config, it doesn&#8217;t always apply to new files, so I end up doing this once in a while:
svn propset svn:keywords 'Id Rev URL HeadUrl' \
`find apps/ config/ doc/ lib/ web data/ test/ \
-name '*.php' -or -name '*.yml' -or -name '*.css' -or -name '*.sql'`
This tells [...]<p><a href="http://sharethis.com/item?&#038;wp=2.8-bleeding-edge&#38;publisher=2d4ffbb0-4e95-4a28-a7ca-90d409134058&#38;title=Adding+Subversion+keywords+to+an+entire+Symfony+project&#38;url=http%3A%2F%2Fn8v.enteuxis.org%2F2008%2F10%2Fadding-subversion-keywords-to-an-entire-symfony-project%2F">ShareThis</a></p>]]></description>
			<content:encoded><![CDATA[<p>For some reason, even though I&#8217;ve set default properties in my <var>.subversion/config</var>, it doesn&#8217;t always apply to new files, so I end up doing this once in a while:</p>
<pre>svn propset svn:keywords 'Id Rev URL HeadUrl' \
`find apps/ config/ doc/ lib/ web data/ test/ \
-name '*.php' -or -name '*.yml' -or -name '*.css' -or -name '*.sql'`</pre>
<p>This tells Subversion to go into those types of files and update <a href="http://svnbook.red-bean.com/en/1.4/svn.advanced.props.special.keywords.html">the <code>$Id$</code> and other keyword tags</a>.</p>
<p>(Note, I&#8217;ve been fooled before by not noticing the keywords are CASE-SENSITIVE.  If you set them to &#8216;id rev url headURL&#8217; they will NOT work!)</p>
<p>It works with <a href="http://cygwin.com">Cygwin</a>, if you&#8217;re stuck in Windowsland like I am for local development.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2008/10/adding-subversion-keywords-to-an-entire-symfony-project/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Upgrading sfGuardPlugin for symfony 1.1</title>
		<link>http://n8v.enteuxis.org/2008/08/upgrading-sfguardplugin-for-symfony-11/</link>
		<comments>http://n8v.enteuxis.org/2008/08/upgrading-sfguardplugin-for-symfony-11/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 21:27:20 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
		
		<category><![CDATA[Figuring IT Out]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=44</guid>
		<description><![CDATA[Last week I upgraded my first symfony 1.0 project to symfony 1.1 following the
UPGRADE file that comes with symfony 1.1
The first part of the upgrade went pretty smoothly, but my project broke due to the sfGuardPlugin.  There weren&#8217;t any details about plugins in the UPGRADE doc, and removing and reinstalling it didn&#8217;t work for [...]<p><a href="http://sharethis.com/item?&#038;wp=2.8-bleeding-edge&#38;publisher=2d4ffbb0-4e95-4a28-a7ca-90d409134058&#38;title=Upgrading+sfGuardPlugin+for+symfony+1.1&#38;url=http%3A%2F%2Fn8v.enteuxis.org%2F2008%2F08%2Fupgrading-sfguardplugin-for-symfony-11%2F">ShareThis</a></p>]]></description>
			<content:encoded><![CDATA[<p>Last week I upgraded my first symfony 1.0 project to <a href="http://www.symfony-project.org/blog/2008/06/30/the-wait-is-over-symfony-1-1-released">symfony 1.1</a> following the<br />
<a href="http://trac.symfony-project.com/browser/branches/1.1/UPGRADE">UPGRADE</a> file that comes with symfony 1.1</p>
<p>The first part of the upgrade went pretty smoothly, but my project broke due to the sfGuardPlugin.  There weren&#8217;t any details about plugins in the UPGRADE doc, and removing and reinstalling it didn&#8217;t work for me.</p>
<p>However, this week, with <a href="http://www.symfony-project.org/forum/index.php/m/58542/#msg_num_6">the help of some friendly symfony forum users</a>, this procedure finally worked for me:</p>
<p><code><br />
svn rm plugins/sfGuardPlugin<br />
svn ci plugins/sfGuardPlugin -m 'removed old version of sfGuardPlugin'<br />
rm -rf plugins/sfGuardPlugin plugins/.channels plugins/.depdb plugins/.depdblock plugins/.filemap plugins/.lock plugins/.registry/<br />
rm -rf cache/.pear<br />
./symfony plugin:install sfGuardPlugin<br />
svn add plugins/sfGuardPlugin/<br />
</code></p>
<p>my successful plugin installation looked like this:<br />
<code><br />
$  <kbd>./symfony plugin:install sfGuardPlugin</kbd><br />
&gt;&gt; plugin    installing plugin &#8220;sfGuardPlugin&#8221;<br />
&gt;&gt; sfPearFrontendPlugin Attempting to discover channel &#8220;pear.symfony-project.com&#8221;&#8230;<br />
&gt;&gt; sfPearFrontendPlugin downloading channel.xml &#8230;<br />
&gt;&gt; sfPearFrontendPlugin Starting to download channel.xml (663 bytes)<br />
&gt;&gt; sfPearFrontendPlugin .<br />
&gt;&gt; sfPearFrontendPlugin &#8230;done: 663 bytes<br />
&gt;&gt; sfPearFrontendPlugin Auto-discovered channel &#8220;pear.symfony-project.com&#8221;, alias<br />
&gt;&gt; sfPearFrontendPlugin &#8220;symfony&#8221;, adding to registry<br />
&gt;&gt; sfPearFrontendPlugin Attempting to discover channel<br />
&gt;&gt; sfPearFrontendPlugin &#8220;plugins.symfony-project.org&#8221;&#8230;<br />
&gt;&gt; sfPearFrontendPlugin downloading channel.xml &#8230;<br />
&gt;&gt; sfPearFrontendPlugin Starting to download channel.xml (639 bytes)<br />
&gt;&gt; sfPearFrontendPlugin &#8230;done: 639 bytes<br />
&gt;&gt; sfPearFrontendPlugin Auto-discovered channel &#8220;plugins.symfony-project.org&#8221;, alias<br />
&gt;&gt; sfPearFrontendPlugin &#8220;symfony-plugins&#8221;, adding to registry<br />
&gt;&gt; sfPearFrontendPlugin downloading sfGuardPlugin-2.2.0.tgz &#8230;<br />
&gt;&gt; sfPearFrontendPlugin Starting to download sfGuardPlugin-2.2.0.tgz (18,589 bytes)<br />
&gt;&gt; sfPearFrontendPlugin &#8230;done: 18,589 bytes<br />
&gt;&gt; sfPearFrontendPlugin Failed to download symfony/symfony (version &gt;= 1.1.0, version<br />
&gt;&gt; sfPearFrontendPlugin &lt;= 1.2.0, excluded versions: 1.2.0), latest release is version<br />
&gt;&gt; sfPearFrontendPlugin 1.1.1, stability &#8220;stable&#8221;, use<br />
&gt;&gt; sfPearFrontendPlugin &#8220;channel://pear.symfony-project.com/symfony-1.1.1&#8243; to install<br />
&gt;&gt; sfSymfonyPluginManager Installation successful for plugin &#8220;sfGuardPlugin&#8221;<br />
</code></p>
<p>Then I did the first couple of steps from the install again to get it working:</p>
<p><code>$ symfony propel:build-model<br />
$ symfony propel:build-sql<br />
$ symfony cc</code></p>
<p>But grrr&#8230; my customized authentication and signin forms are hosing it up.  Time to learn more about the new release I guess.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2008/08/upgrading-sfguardplugin-for-symfony-11/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The intranets!  Let them in!  Let them play!</title>
		<link>http://n8v.enteuxis.org/2008/08/ldap-authn-authz-for-symfony/</link>
		<comments>http://n8v.enteuxis.org/2008/08/ldap-authn-authz-for-symfony/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 18:49:04 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
		
		<category><![CDATA[Giving back]]></category>

		<category><![CDATA[AD]]></category>

		<category><![CDATA[intranet]]></category>

		<category><![CDATA[LDAP]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=32</guid>
		<description><![CDATA[I just released bhLDAPAuthPlugin to the world with permission from my employer.  I&#8217;ve been using symfony (&#8221;PHP on Rails&#8221;) for about a year at work for a few intranet projects, and over and over I have needed to use our enterprise-wide Microsoft Active Directory® for user authentication and authorization. The plugin might work with non-Microsoft [...]<p><a href="http://sharethis.com/item?&#038;wp=2.8-bleeding-edge&#38;publisher=2d4ffbb0-4e95-4a28-a7ca-90d409134058&#38;title=The+intranets%21++Let+them+in%21++Let+them+play%21&#38;url=http%3A%2F%2Fn8v.enteuxis.org%2F2008%2F08%2Fldap-authn-authz-for-symfony%2F">ShareThis</a></p>]]></description>
			<content:encoded><![CDATA[<p>I just released <a href="http://www.symfony-project.org/plugins/bhLDAPAuthPlugin">bhLDAPAuthPlugin</a> to the world with permission from my employer.  I&#8217;ve been using <a href="http://www.symfony-project.org/">symfony</a> (&#8221;PHP on Rails&#8221;) for about a year at work for a few intranet projects, and over and over I have needed to use our enterprise-wide Microsoft Active Directory® for user authentication and authorization. The plugin might work with non-Microsoft LDAP servers too, but I don&#8217;t have any of them to play with.</p>
<p>Maybe this will help other developers cook up Intranet apps that rock using symfony.</p>
<p>I have been able to rapidly develop some things that users really like with symfony, so I appreciate this chance to give back to the project.  Also, I&#8217;m the only one in my organization doing this sort of thing, so I hope I&#8217;ll be able to get some good feedback and contributions from others.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2008/08/ldap-authn-authz-for-symfony/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
