<?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>-= n8v =- &#187; PHP</title>
	<atom:link href="http://n8v.enteuxis.org/tags/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://n8v.enteuxis.org</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 27 Sep 2011 00:52:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2-beta2-18055</generator>
		<item>
		<title>PHPUnit for XAMPP on Windows with Cygwin</title>
		<link>http://n8v.enteuxis.org/2011/09/phpunit-for-xampp-on-windows-with-cygwin/</link>
		<comments>http://n8v.enteuxis.org/2011/09/phpunit-for-xampp-on-windows-with-cygwin/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 23:30:41 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[Cygwin]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[xampp]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=510</guid>
		<description><![CDATA[Steps to get PHPUnit to run on my XAMPP setup with Cygwin, so I can write and run Symfony2 unit tests. 1. Upgrade PEAR Download http://pear.php.net/go-pear.phar to C:\xampp\php\go-pear.phar Run this in cmd.exe (cygwin prompts hosed somehow), taking all defaults c:\xampp\php&#62;go-pear.bat Yay. c:\xampp\php&#62;pear version PEAR Version: 1.9.4 PHP Version: 5.3.5 Zend Engine Version: 2.3.0 Running on: [...]]]></description>
			<content:encoded><![CDATA[<p>Steps to get PHPUnit to run on my XAMPP setup with Cygwin, so I can write and run Symfony2 unit tests.</p>

<h3>1. Upgrade PEAR</h3>

<ol>
<li><p>Download <code>http://pear.php.net/go-pear.phar</code>  to <var>C:\xampp\php\go-pear.phar</var></p></li>
<li><p>Run this <strong>in <var>cmd.exe</var></strong> (cygwin prompts hosed somehow), taking all defaults</p></li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="dos">c:\xampp\php<span class="sy0">&gt;</span>go-pear.bat</pre></div></div>


<ol>
<li>Yay.</li>
</ol>


<div class="wp_syntax"><div class="code"><pre class="dos">c:\xampp\php<span class="sy0">&gt;</span>pear version
PEAR Version: 1.9.4
PHP Version: 5.3.5
Zend Engine Version: 2.3.0
Running on: Windows NT FAI1046162 6.1 build 7600 <span class="sy0">(</span>Unknow Windows version Enterpr
ise Edition<span class="sy0">)</span> i586</pre></div></div>


<h3>2. Install/upgrade PHPUnit</h3>

<p>Now we can use the cygwin shell.  Not sure <a href="http://forum.kohanaframework.org/discussion/7346/installing-phpunit-on-windows-xampp/p1">all these channels are needed</a>, I did this out of order.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw3">cd</span> <span class="sy0">/</span>cygdrive<span class="sy0">/</span>c<span class="sy0">/</span>xampp<span class="sy0">/</span>php
pear update-channels
pear channel-discover components.ez.no
pear channel-discover pear.symfony-project.com
pear channel-discover pear.phpunit.de
&nbsp;
pear <span class="kw2">install</span> <span class="re5">--alldeps</span> phpunit<span class="sy0">/</span>PHPUnit</pre></div></div>


<h3>3. Use it</h3>

<p>XAMPP and/or PHPUnit come with a wrapper called <var>phpunit.bat</var>, which has now been upgraded, but you may need to set your <var>PHPBIN</var> environment var. Also I already have <var>c:\xampp\php</var> in my <var>$PATH</var>.</p>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw3">export</span> <span class="re2">PHPBIN</span>=c:<span class="sy0">/</span>xampp<span class="sy0">/</span>php<span class="sy0">/</span>php.exe
&nbsp;
<span class="kw3">cd</span> <span class="sy0">/</span>path<span class="sy0">/</span>to<span class="sy0">/</span>mysf2project
phpunit.bat <span class="re5">-c</span> app</pre></div></div>


<p>Now PHPUnit works. Make tests and make them work!</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2011/09/phpunit-for-xampp-on-windows-with-cygwin/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sorting, deleting from a PropelObjectCollection</title>
		<link>http://n8v.enteuxis.org/2011/06/sorting-deleting-propel-object-collectio/</link>
		<comments>http://n8v.enteuxis.org/2011/06/sorting-deleting-propel-object-collectio/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 06:23:13 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[orm]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[propel]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[symfony1.4]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=503</guid>
		<description><![CDATA[Propel 1.6 (and Propel 1.5 before it) is pretty sweet (thank you François!). I had some confusion with my model&#8217;s array of related objects though, thinking it was a regular PHP array. Actually it&#8217;s a Collection, specifically a PropelObjectCollection, which implements PHP 5&#8242;s ArrayObject interface. You can do a lot of cool things with them. [...]]]></description>
			<content:encoded><![CDATA[<p>Propel 1.6 (and Propel 1.5 before it) is pretty sweet (thank you François!). I had some confusion with my model&#8217;s array of related objects though, thinking it was a regular PHP array. Actually it&#8217;s a <em>Collection</em>, specifically a PropelObjectCollection, which implements <a href="http://www.php.net/manual/en/class.arrayobject.php">PHP 5&#8242;s ArrayObject interface</a>. <a href="http://propel.posterous.com/propel-gets-collections">You can do a lot of cool things with them.</a></p>

<h2>Sorting</h2>

<p>Not immediately obvious, however, was how to sort them. This did the trick for my case (I have a Sequence field manually re-calculable through a <a href="http://jqueryui.com/demos/sortable/">jQueryUI sortable widget</a>. Also note the cool <a href="http://php.net/manual/en/functions.anonymous.php">inline anonymous function syntax</a> available since PHP 5.3. Incidentally, I&#8217;m not sure the terms <em>lambda</em> or <em>closure</em> are helpful because they&#8217;re not <em>quite</em> like Lisp lambdas or JavaScript closures.</p>


<div class="wp_syntax"><div class="code"><pre class="php"><span class="co1">// Re-sort them by Sequence, numerically</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">collSegments</span><span class="sy0">-&gt;</span><span class="me1">uasort</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">,</span> <span class="re0">$b</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">getSequence</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-</span> <span class="re0">$b</span><span class="sy0">-&gt;</span><span class="me1">getSequence</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



<div class="wp_syntax"><div class="code"><pre class="php"><span class="co1">// Re-sort them as strings, case-insensitively.</span>
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">collSegments</span><span class="sy0">-&gt;</span><span class="me1">uasort</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">,</span> <span class="re0">$b</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/strnatcasecmp"><span class="kw3">strnatcasecmp</span></a><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span>__toString<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$b</span><span class="sy0">-&gt;</span>__toString<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>


<h2>Deleting</h2>

<p>Thanks to the <a href="http://www.propelorm.org/docs/api/1.6/runtime/propel-runtime-collection/PropelArrayCollection.html">PropelArrayCollection API Documentation</a></p>


<div class="wp_syntax"><div class="code"><pre class="php">  <span class="coMULTI">/*
   * Remove the provided Segment object.
   *
   * @param Segment $s
   * @return Segment $s that was deleted.
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> deleteSegment<span class="br0">&#40;</span>Segment <span class="re0">$s</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="re0">$s</span><span class="sy0">-&gt;</span><span class="me1">delete</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$key</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">collSegments</span><span class="sy0">-&gt;</span><span class="me1">search</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$ret</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">collSegments</span><span class="sy0">-&gt;</span><span class="me1">remove</span><span class="br0">&#40;</span><span class="re0">$key</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="kw1">return</span> <span class="re0">$s</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div>


<p>So elsewhere,</p>


<div class="wp_syntax"><div class="code"><pre class="php">	      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">deleteSegment</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2011/06/sorting-deleting-propel-object-collectio/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Adding WordPress-like tags to a Symfony 1.4 admin generator form</title>
		<link>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/</link>
		<comments>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/#comments</comments>
		<pubDate>Sat, 15 May 2010 01:15:46 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=325</guid>
		<description><![CDATA[Update 2010-08-06: It looks like the sfDoctrineActAsTaggablePlugin team has incorporated much of this into the version they released today. I&#8217;ll post more when I get a chance to try it out. This week I used the sfDoctrineActAsTaggablePlugin to add tag behavior to a Symfony project. My goal was to have a user interface similar to [...]]]></description>
			<content:encoded><![CDATA[<p><ins datetime="2010-08-06T23:57:46+00:00">Update 2010-08-06:  It looks like the sfDoctrineActAsTaggablePlugin team has incorporated much of this into the version they released today.  I&#8217;ll post more when I get a chance to try it out.</ins></p>

<p>This week I used the <a href="http://www.symfony-project.org/plugins/sfDoctrineActAsTaggablePlugin">sfDoctrineActAsTaggablePlugin</a> to add tag behavior to a Symfony project.  My goal was to have a user interface similar to WordPress&#8217;s, which I like a lot:</p>

<p><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/wordpress_tag_ui.png" alt="Tag user interface in WordPress" title="wordpress_tag_ui" width="290" height="174" class="aligncenter size-full wp-image-330" /></p>

<p>Another goal was to use <a href="http://jqueryui.com/">JQuery UI</a> with the nice visual theme I built with their <a href="http://jqueryui.com/themeroller/">Theme Roller tool</a> (which I had already installed and added to my symfony project).</p>

<p>The documentation was a little bit sparse and I&#8217;ll probably end up doing this again, so here are relevant instructions so Future Me and others may also benefit:
<span id="more-325"></span></p>

<h2>Set up</h2>

<ol>
    <li>get/install/checkout sfDoctrineActAsTaggablePlugin.  I use this line in the `svn:externals` property on <var>plugins/</var>:
  
<pre>sfDoctrineActAsTaggablePlugin/ http://svn.symfony-project.com/plugins/sfDoctrineActAsTaggablePlugin/tags/RELEASE_1_0_0</pre>
</li>

    <li>enable the plugin in <var>config/ProjectConfiguration.class.php</var>.


<div class="wp_syntax"><div class="code"><pre class="php">    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">enablePlugins</span><span class="br0">&#40;</span>
                         <span class="st_h">'sfDoctrinePlugin'</span><span class="sy0">,</span> 
                         <span class="sy0">...</span>
			 <span class="st_h">'sfDoctrineActAsTaggablePlugin'</span>
			 <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>

    <li>Add the Taggable behavior to your model(s) in <var>config/doctrine/schema.yml</var>


<div class="wp_syntax"><div class="code"><pre class="yaml">    actAs:            { Timestampable: ~ , Taggable: ~ }</pre></div></div>




         (<strong>not</strong> <code>templates: [Taggable]</code> as the README says)

</li>
    <li>Rebuild your model and forms and everything.  My favorite way is to dump the old data to fixtures, then rebuild everything.


<div class="wp_syntax"><div class="code"><pre class="bash">.<span class="sy0">/</span>symfony <span class="re5">--color</span> doctrine:data-dump
.<span class="sy0">/</span>symfony <span class="re5">--color</span> doctrine:build <span class="re5">--all</span> <span class="re5">--and-load</span> <span class="re5">--no-confirmation</span></pre></div></div>




</li>

</ol>

<p>At this point you should have new database tables <code>tag</code> and <code>tagging</code>, and the proper model relations and everything.</p>

<h2>Form fields for tags</h2>

<div id="attachment_352" class="wp-caption aligncenter" style="width: 490px"><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_ui.png" alt="" title="my_tags_ui" width="480" height="150" class="size-full wp-image-352" /><p class="wp-caption-text">UI for entering tags, displaying existing tags (with remove buttons)</p></div>

<p>I&#8217;m going to have</p>

<ol>
<li>a single text input field for adding tags, </li>
<li>a link to display a tag cloud (see below) if the user wants to pick tags by clicking instead of typing</li>
<li>a styled list of existing tags with delete icons</li>
<li>a hidden field for storing tags to be removed after clicking on the delete icons.</li>
</ol>

<p>The delete icons will trigger a Javascript function which populates the hidden field and hides the tag.  Changes won&#8217;t be saved until the user submits the form, so we&#8217;ll also provide a little reminder.</p>

<img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_removed.png" alt="" title="my_tags_removed" width="461" height="86" class="size-full wp-image-354" />

<ol>
    <li>add the tag field(s) to the <code>configure()</code> method of your form, in <var>lib/form/doctrine/<samp>Model</samp>Form.class.php</var>.


<div class="wp_syntax"><div class="code"><pre class="php">    <span class="co1">// this text appears in gray until the user focuses on the field</span>
    <span class="re0">$default</span> <span class="sy0">=</span> <span class="st_h">'Add tags with commas'</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="st_h">'new_tags'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfWidgetFormInput
      <span class="br0">&#40;</span>
       <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'label'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'Add Tags'</span><span class="sy0">,</span> <span class="st_h">'default'</span>   <span class="sy0">=&gt;</span>  <span class="re0">$default</span><span class="br0">&#41;</span><span class="sy0">,</span>
       <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
             <span class="st_h">'onclick'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;if (this.value=='<span class="es4">$default</span>') { 
                                this.value = ''; this.style.color='black'; }&quot;</span><span class="sy0">,</span> 
             <span class="st_h">'size'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'32'</span><span class="sy0">,</span>
	     <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="st_h">'new_tags'</span><span class="sy0">,</span> 
             <span class="co1">// don't let the browser autocomplete.  We'll add typeahead, below</span>
	     <span class="st_h">'autocomplete'</span> <span class="sy0">=&gt;</span> <span class="st0">&quot;off&quot;</span><span class="sy0">,</span>      
	     <span class="st_h">'style'</span> <span class="sy0">=&gt;</span> <span class="st_h">'color:#aaa'</span>
	     <span class="br0">&#41;</span>
       <span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="co1">// allow the field to remain blank</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setValidator</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="sy0">,</span> <span class="kw2">new</span> sfValidatorString<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'required'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// this hidden field will be populated with JavaScript.</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="st_h">'remove_tags'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfWidgetFormInputHidden<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setValidator</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="sy0">,</span> <span class="kw2">new</span> sfValidatorString<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'required'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>
    <li>Add a partial with the admin generator.  In <var>apps/frontend/modules/<samp>mymodule</samp>/config/generator.yml</var>:


<div class="wp_syntax"><div class="code"><pre class="yaml">      form:
        display:
          # add another section after the other fields...
          Tags: [_tags]</pre></div></div>




</li>
    <li>edit the partial, <var>apps/frontend/modules/<samp>mymodule</samp>/templates/_tags.php</var>


<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span> use_helper<span class="br0">&#40;</span><span class="st_h">'JavascriptBase'</span><span class="sy0">,</span> <span class="st_h">'Tags'</span><span class="br0">&#41;</span>  <span class="sy1">?&gt;</span>
<span class="kw2">&lt;?php</span>  
&nbsp;
<span class="co1">// much of this I copied and adapted from a cached admin generator template.</span>
<span class="re0">$name</span> <span class="sy0">=</span> <span class="st_h">'new_tags'</span><span class="sy0">;</span> <span class="re0">$label</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span> <span class="re0">$help</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span> 
<span class="re0">$class</span> <span class="sy0">=</span> <span class="st_h">'sf_admin_form_row sf_admin_text sf_admin_form_field_tags'</span><span class="sy0">;</span>
&nbsp;
 <span class="sy1">?&gt;</span>
&nbsp;
  &lt;div class=&quot;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$class</span> <span class="sy1">?&gt;</span><span class="kw2">&lt;?php</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">hasError</span><span class="br0">&#40;</span><span class="br0">&#41;</span> and <span class="kw1">print</span> <span class="st_h">' errors'</span> <span class="sy1">?&gt;</span>&quot;&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderError</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
    &lt;div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderLabel</span><span class="br0">&#40;</span><span class="re0">$label</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
      &lt;div class=&quot;content&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">render</span><span class="br0">&#40;</span><span class="re0">$attributes</span> instanceof sfOutputEscaper ? <span class="re0">$attributes</span><span class="sy0">-&gt;</span><span class="me1">getRawValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="re0">$attributes</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="co1">// tag cloud will go here, see below ?&gt;</span>
&nbsp;
&nbsp;
<span class="sy0">&lt;/</span>div<span class="sy0">&gt;</span>
&nbsp;
      <span class="kw2">&lt;?php</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$help</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
        &lt;div class=&quot;help&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> __<span class="br0">&#40;</span><span class="re0">$help</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'messages'</span><span class="br0">&#41;</span> <span class="sy1">?&gt;</span>&lt;/div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$help</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="br0">&#91;</span><span class="re0">$name</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">renderHelp</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">:</span> <span class="sy1">?&gt;</span>
        &lt;div class=&quot;help&quot;&gt;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$help</span> <span class="sy1">?&gt;</span>&lt;/div&gt;
      <span class="kw2">&lt;?php</span> <span class="kw1">endif</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
    &lt;/div&gt;
  &lt;/div&gt;
&nbsp;
<span class="kw2">&lt;?php</span> <span class="co1">// list of current tags, with remove buttons ?&gt;</span>
<span class="sy0">&lt;</span>div <span class="kw2">class</span><span class="sy0">=</span><span class="st0">&quot;sf_admin_form_row sf_admin_text sf_admin_form_field_tags&quot;</span><span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>div<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>label<span class="sy0">&gt;</span>Current tags<span class="sy0">&lt;/</span>label<span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>div <span class="kw2">class</span><span class="sy0">=</span><span class="st0">&quot;content&quot;</span><span class="sy0">&gt;</span>
<span class="sy0">&lt;</span>div <span class="kw2">class</span><span class="sy0">=</span><span class="st0">&quot;taglist&quot;</span><span class="sy0">&gt;</span>   
   <span class="kw2">&lt;?php</span> <span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getTags</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$t</span><span class="br0">&#41;</span><span class="sy0">:</span>   <span class="sy1">?&gt;</span>
    &lt;span&gt;&lt;nobr&gt;<span class="kw2">&lt;?php</span> 
&nbsp;
<span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span><span class="st0">&quot;Remove '<span class="es4">$t</span>'&quot;</span><span class="sy0">,</span> 
           <span class="st0">&quot;remove_tag(&quot;</span><span class="sy0">.</span><a href="http://www.php.net/json_encode"><span class="kw3">json_encode</span></a><span class="br0">&#40;</span><span class="re0">$t</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st0">&quot;, this.parentElement)&quot;</span><span class="sy0">,</span> 
           <span class="st0">&quot;class=removetag&quot;</span><span class="br0">&#41;</span>
&nbsp;
  <span class="sy1">?&gt;</span>&amp;nbsp;<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> <span class="re0">$t</span>  <span class="sy1">?&gt;</span>&lt;/nobr&gt;&lt;/span&gt;
    <span class="kw2">&lt;?php</span> <span class="kw1">endforeach</span><span class="sy0">;</span>  <span class="sy1">?&gt;</span>
&lt;/div&gt;
&lt;span id=&quot;remove_tag_help&quot; style=&quot;display:none;&quot;&gt;Tag(s) removed. Remember to save the complaint.&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&nbsp;
&lt;/div&gt;</pre></div></div>



</li>

    <li>Add a Javascript function to support the &#8220;remove tag&#8221; buttons.


<div class="wp_syntax"><div class="code"><pre class="javascript">$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="co1">// add fancy jQuery UI button styles.  See additional in &quot;CSS&quot; below</span>
	    $<span class="br0">&#40;</span><span class="st0">&quot;.taglist a&quot;</span><span class="br0">&#41;</span>.<span class="me1">button</span><span class="br0">&#40;</span><span class="br0">&#123;</span>icons<span class="sy0">:</span><span class="br0">&#123;</span>primary<span class="sy0">:</span><span class="st0">'ui-icon-trash'</span><span class="br0">&#125;</span><span class="sy0">,</span> text<span class="sy0">:</span> <span class="kw2">false</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw2">function</span> remove_tag <span class="br0">&#40;</span>tag<span class="sy0">,</span> element<span class="br0">&#41;</span> <span class="br0">&#123;</span>
  remove_field <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st0">&quot;#complaint_remove_tags&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="kw1">if</span> <span class="br0">&#40;</span> remove_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">length</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    remove_field.<span class="me1">val</span><span class="br0">&#40;</span> remove_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>  <span class="sy0">+</span> <span class="st0">&quot;,&quot;</span> <span class="sy0">+</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="br0">&#123;</span>
    remove_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  $<span class="br0">&#40;</span>element<span class="br0">&#41;</span>.<span class="me1">hide</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  $<span class="br0">&#40;</span><span class="st0">&quot;#remove_tag_help&quot;</span><span class="br0">&#41;</span>.<span class="me1">show</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>




</li>
    <li>edit the `processForm` action to process the `new_tags` and `remove_tags` fields.    I started by copying the `processForm` method from <var>cache/frontend/dev/modules/auto<samp>Mymodel</samp>/actions/actions.class.php</var> into <var>apps/frontend/modules/<samp>mymodule</samp>/actions/actions.class.php</var>, then added code after validation:


<div class="wp_syntax"><div class="code"><pre class="php">  <span class="kw2">protected</span> <span class="kw2">function</span> processForm<span class="br0">&#40;</span>sfWebRequest <span class="re0">$request</span><span class="sy0">,</span> sfForm <span class="re0">$form</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">bind</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">getFiles</span><span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getName</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">isValid</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$notice</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isNew</span><span class="br0">&#40;</span><span class="br0">&#41;</span> ? <span class="st_h">'The item was created successfully.'</span> <span class="sy0">:</span> <span class="st_h">'The item was updated successfully.'</span><span class="sy0">;</span>
&nbsp;
      <span class="co1">// NEW: deal with tags</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	<span class="kw1">foreach</span> <span class="br0">&#40;</span><a href="http://www.php.net/preg_split"><span class="kw3">preg_split</span></a><span class="br0">&#40;</span><span class="st_h">'/\s*,\s*/'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'remove_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$tag</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	  <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">removeTag</span><span class="br0">&#40;</span><span class="re0">$tag</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
      <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
	<span class="kw1">foreach</span> <span class="br0">&#40;</span><a href="http://www.php.net/preg_split"><span class="kw3">preg_split</span></a><span class="br0">&#40;</span><span class="st_h">'/\s*,\s*/'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getValue</span><span class="br0">&#40;</span><span class="st_h">'new_tags'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$tag</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
          <span class="co1">// sorry, it would be better to not hard-code this string</span>
	  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'Add tags with commas'</span><span class="br0">&#41;</span> <span class="kw1">continue</span><span class="sy0">;</span>
	  <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">addTag</span><span class="br0">&#40;</span><span class="re0">$tag</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
&nbsp;
      try <span class="br0">&#123;</span>
        <span class="re0">$complaint</span> <span class="sy0">=</span> <span class="re0">$form</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="co1">// and the remainder is just pasted from the generated actions file</span></pre></div></div>




</li>
</ol>

<p>Yay!  Now I can add, display, and remove tags.   Now for the fancy parts.</p>

<h2>Typeahead tag autocompletion</h2>

<p><img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_typeahead.png" alt="" title="my_tags_typeahead" width="480" height="150" class="aligncenter size-full wp-image-360" /></p>

<p>As detailed in the README, sfDoctrineActAsTaggablePlugin has typeahead support. I tried it, but I didn&#8217;t feel like the user interaction was quite smooth enough, and I wanted to use the excellent, beautiful, and user-expectation-meeting <a href="http://jqueryui.com/demos/autocomplete/">jQuery UI Autocomplete widget</a>.</p>

<p>I ended up using the action provided by sfDoctrineActAsTaggablePlugin, but modified the view to return JSON instead of an HTML &lt;ul&gt;, and I used the <a href="http://jqueryui.com/demos/autocomplete/multiple-remote.html">multiple, remote demo</a> code from <a href="http://jqueryui.com/demos/autocomplete/#multiple-remote">the jQuery UI Autocomplete documentation</a>.</p>

<ol>
    <li>override the <code>completeSuccess</code> view for the <code>taggableComplete/complete</code> action


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">mkdir</span> <span class="re5">-p</span> apps<span class="sy0">/</span>frontend<span class="sy0">/</span>modules<span class="sy0">/</span>taggableComplete<span class="sy0">/</span>templates
<span class="kw2">touch</span> apps<span class="sy0">/</span>frontend<span class="sy0">/</span>modules<span class="sy0">/</span>taggableComplete<span class="sy0">/</span>templates<span class="sy0">/</span>completeSuccess.php</pre></div></div>




And here is my new template:


<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="co1">// we're rewriting the view for the taggable plugin to output JSON instead of HTML</span>
<span class="co1">// see http://wiki.jqueryui.com/Autocomplete</span>
&nbsp;
<span class="re0">$tags_simple</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">foreach</span> <span class="br0">&#40;</span> <span class="re0">$tagSuggestions</span> <span class="kw1">as</span> <span class="re0">$suggestion</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="re0">$tags_simple</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span>  <span class="re0">$suggestion</span><span class="br0">&#91;</span><span class="st_h">'suggested'</span><span class="br0">&#93;</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw1">echo</span> <a href="http://www.php.net/json_encode"><span class="kw3">json_encode</span></a><span class="br0">&#40;</span><span class="re0">$tags_simple</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>




You can test your autocomplete action with a URL like <code>http://myserver/myproject/taggableComplete/complete/current/<samp>p</samp></code>.

In my case (because I have some data in my <code>tag</code> table) it returns this JSON-formatted array:


<div class="wp_syntax"><div class="code"><pre class="javascript"><span class="br0">&#91;</span><span class="st0">&quot;PHP&quot;</span><span class="sy0">,</span><span class="st0">&quot;plugins&quot;</span><span class="br0">&#93;</span></pre></div></div>



</li>

    <li>Add jQuery UI javascript.  I used a <code>&lt;script&gt;</code> section in my <var>_tags.php</var> partial, but you could also use an external javascript file (but mind the line of PHP code using the <code>url_for()</code> helper).


<div class="wp_syntax"><div class="code"><pre class="javascript">	$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
<span class="co1">// for debug info, uncomment these lines and add a &lt;div id=&quot;autocomplete_log&quot;&gt;</span>
<span class="co1">// 		function log(message) {</span>
<span class="co1">// 			$(&quot;&lt;div/&gt;&quot;).text(message).prependTo(&quot;#autocomplete_log&quot;);</span>
<span class="co1">// 			$(&quot;#autocomplete_log&quot;).attr(&quot;scrollTop&quot;, 0);</span>
<span class="co1">// 		}</span>
		<span class="kw2">function</span> split<span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</span>
			<span class="kw1">return</span> val.<span class="me1">split</span><span class="br0">&#40;</span><span class="co2">/\s*,\s*/</span><span class="br0">&#41;</span><span class="sy0">;</span>
		<span class="br0">&#125;</span>
		<span class="kw2">function</span> extractLast<span class="br0">&#40;</span>term<span class="br0">&#41;</span> <span class="br0">&#123;</span>
		        last <span class="sy0">=</span> split<span class="br0">&#40;</span>term<span class="br0">&#41;</span>.<span class="me1">pop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="co1">// 			log ( &quot;extracted last = &quot;+last );</span>
			<span class="kw1">return</span> last<span class="sy0">;</span>
		<span class="br0">&#125;</span>
&nbsp;
&nbsp;
		$<span class="br0">&#40;</span><span class="st0">&quot;#new_tags&quot;</span><span class="br0">&#41;</span>.<span class="me1">autocomplete</span><span class="br0">&#40;</span><span class="br0">&#123;</span>
&nbsp;
			source<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>request<span class="sy0">,</span> response<span class="br0">&#41;</span> <span class="br0">&#123;</span>
		      $.<span class="me1">getJSON</span><span class="br0">&#40;</span><span class="sy0">&lt;?</span>php echo json_encode<span class="br0">&#40;</span>url_for<span class="br0">&#40;</span><span class="st0">&quot;taggableComplete/complete&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">?&gt;,</span> <span class="br0">&#123;</span>
					current<span class="sy0">:</span> extractLast<span class="br0">&#40;</span>request.<span class="me1">term</span><span class="br0">&#41;</span>
				<span class="br0">&#125;</span><span class="sy0">,</span> response<span class="br0">&#41;</span><span class="sy0">;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
			search<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="co1">// custom minLength</span>
				<span class="kw2">var</span> term <span class="sy0">=</span> extractLast<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">if</span> <span class="br0">&#40;</span>term.<span class="me1">length</span> <span class="sy0">&lt;</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
					<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
				<span class="br0">&#125;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
		        <span class="kw3">focus</span><span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="co1">// prevent value inserted on focus</span>
				<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
			<span class="br0">&#125;</span><span class="sy0">,</span>
			select<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>event<span class="sy0">,</span> ui<span class="br0">&#41;</span> <span class="br0">&#123;</span>
				<span class="kw2">var</span> terms <span class="sy0">=</span> split<span class="br0">&#40;</span> <span class="kw1">this</span>.<span class="me1">value</span> <span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// remove the current input</span>
				terms.<span class="me1">pop</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// add the selected item</span>
				terms.<span class="me1">push</span><span class="br0">&#40;</span> ui.<span class="kw1">item</span>.<span class="me1">value</span> <span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="co1">// add placeholder to get the comma-and-space at the end</span>
				terms.<span class="me1">push</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">this</span>.<span class="me1">value</span> <span class="sy0">=</span> terms.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">&quot;, &quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
				<span class="kw1">return</span> <span class="kw2">false</span><span class="sy0">;</span>
			<span class="br0">&#125;</span>
&nbsp;
		<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
	<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>



</li>
</ol>

<h2>tag cloud</h2>

<img src="http://n8v.enteuxis.org/wp-content/uploads/2010/05/my_tags_pick_from_cloud.png" alt="" title="my_tags_pick_from_cloud" width="468" height="76" class="size-full wp-image-362" />

<p>I like how WordPress has an option for picking tags from a tag cloud too.  The sfDoctrineActAsTaggablePlugin made this nice and easy.</p>

<ol>
    <li>Here&#8217;s the code for the view (in the <var>_tags.php</var> partial)


<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span> <span class="kw1">echo</span> link_to_function<span class="br0">&#40;</span><span class="st0">&quot;Choose from the most used tags &amp;gt;&amp;gt;&quot;</span><span class="sy0">,</span> <span class="st_h">'$(&quot;#add_tag_from_cloud&quot;).show(); $(this).hide()'</span> <span class="br0">&#41;</span> <span class="sy1">?&gt;</span>
&nbsp;
&lt;div id=&quot;add_tag_from_cloud&quot; class=&quot;tag_cloud popular&quot; style=&quot;display:none&quot;&gt;
&lt;h3&gt;Popular tags&lt;/h3&gt;
<span class="kw2">&lt;?php</span> 
<span class="co1">// gets the popular tags</span>
<span class="re0">$tags</span> <span class="sy0">=</span> PluginTagTable<span class="sy0">::</span><span class="me2">getPopulars</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="co1">// Display the tags cloud, using link_to_function() instead of link_to()</span>
<span class="co1">// The %s in the second arg will be substituted with the tag text.</span>
<span class="kw1">echo</span> tag_cloud<span class="br0">&#40;</span><span class="re0">$tags</span><span class="sy0">,</span> <span class="st_h">'add_tag(&quot;%s&quot;)'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
				<span class="st_h">'link_function'</span>   <span class="sy0">=&gt;</span>  <span class="st_h">'link_to_function'</span><span class="sy0">,</span>  
				<span class="st_h">'link_options'</span>   <span class="sy0">=&gt;</span>  <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'class=addtag'</span><span class="br0">&#41;</span>
					     <span class="br0">&#41;</span>
	       <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="sy1">?&gt;</span>
&lt;/div&gt;</pre></div></div>



</li>
    <li>And here&#8217;s the javascript to handle those links.


<div class="wp_syntax"><div class="code"><pre class="javascript"><span class="kw2">function</span> add_tag <span class="br0">&#40;</span>tag<span class="br0">&#41;</span> <span class="br0">&#123;</span>
  add_field <span class="sy0">=</span> $<span class="br0">&#40;</span><span class="st0">&quot;#new_tags&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="kw1">if</span> <span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">==</span> <span class="st0">&quot;Add tags with commas&quot;</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
    add_field.<span class="me1">css</span><span class="br0">&#40;</span><span class="st0">&quot;color&quot;</span><span class="sy0">,</span> <span class="st0">&quot;black&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">length</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> add_field.<span class="me1">val</span><span class="br0">&#40;</span><span class="br0">&#41;</span>  <span class="sy0">+</span> <span class="st0">&quot;, &quot;</span> <span class="sy0">+</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="kw1">else</span> <span class="br0">&#123;</span>
    add_field.<span class="me1">val</span><span class="br0">&#40;</span> tag <span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
  $<span class="br0">&#40;</span>element<span class="br0">&#41;</span>.<span class="me1">hide</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>



</li>
</ol>

<h2>CSS</h2>

<p>I made lots of incremental changes to my CSS but here are all of the sections relevant to the tag stuff I&#8217;ve shown here, I think.</p>


<div class="wp_syntax"><div class="code"><pre class="css">&nbsp;
<span class="re1">.taglist</span> <span class="re1">.removetag</span> <span class="br0">&#123;</span>
   <span class="kw1">vertical-align</span><span class="sy0">:</span> <span class="kw2">middle</span><span class="sy0">;</span>
   <span class="kw1">width</span><span class="sy0">:</span> <span class="re3">18px</span><span class="sy0">;</span>
   <span class="kw1">height</span><span class="sy0">:</span> <span class="re3">18px</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re1">.taglist</span> span <span class="br0">&#123;</span>
   <span class="kw1">margin-right</span><span class="sy0">:</span> <span class="re3">1.4em</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re1">.tag_cloud</span> li <span class="br0">&#123;</span>
   <span class="kw1">display</span><span class="sy0">:</span> <span class="kw2">inline</span><span class="sy0">;</span>
   <span class="kw1">list-style</span><span class="sy0">:</span> <span class="kw2">none</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">#sf_admin_container</span> <span class="re1">.tag_cloud</span> li a <span class="br0">&#123;</span>
   <span class="kw1">background</span><span class="sy0">:</span> <span class="kw2">transparent</span><span class="sy0">;</span>
   <span class="kw1">padding-left</span><span class="sy0">:</span> <span class="re3">0px</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>


<p>And I had this in my <var>apps/frontend/templates/layout.php</var> to apply JQuery UI button styling to all my form buttons and hyperlinks with the &#8220;button&#8221; CSS class:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript"><span class="sy0">&lt;</span>script type<span class="sy0">=</span><span class="st0">&quot;text/javascript&quot;</span><span class="sy0">&gt;</span>
<span class="co1">// use JQueryUI buttons</span>
      $<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       $<span class="br0">&#40;</span><span class="st0">&quot;input:submit,  button, a.button&quot;</span><span class="br0">&#41;</span>.<span class="me1">button</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="sy0">&lt;/</span>script<span class="sy0">&gt;</span></pre></div></div>


<p>Yay! I&#8217;m pretty happy with it so far.  I hacked at it for a couple days though and have been cloudy with fighting a cold, so if I&#8217;ve missed anything let me know.  I think this is enough to get me there more quickly the next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2010/05/adding-wordpress-like-tags-to-a-symfony-1-4-admin-generator-form/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Getting PHP&#8217;s GD module to work with IIS</title>
		<link>http://n8v.enteuxis.org/2008/11/getting-phps-gd-module-to-work-with-iis/</link>
		<comments>http://n8v.enteuxis.org/2008/11/getting-phps-gd-module-to-work-with-iis/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 21:26:38 +0000</pubDate>
		<dc:creator>nathan</dc:creator>
				<category><![CDATA[Figuring IT Out]]></category>
		<category><![CDATA[GD]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[JPEG]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://n8v.enteuxis.org/?p=106</guid>
		<description><![CDATA[Grrr, this cost me about 10 hours, and was hard to research, so I&#8217;m documenting it here for The Good Of Everyone: Problem I work with PHP on a bunch of different web servers. In this case I needed to resize photos (JPEGs) from Microsoft SQL Server (MSSQL) blobs on a Windows web server running [...]]]></description>
			<content:encoded><![CDATA[<p>Grrr, this cost me about 10 hours, and was hard to research, so I&#8217;m documenting it here for The Good Of Everyone:</p>

<h3>Problem</h3>

<p>I work with PHP on a bunch of different web servers.  In this case I needed to resize photos (JPEGs) from Microsoft SQL Server (MSSQL) blobs on a Windows web server running IIS.  I got stuff working on my local Windows development machine (under Apache, <a href="http://www.apachefriends.org/en/xampp.html">XAMPP </a>rocks BTW), but when I moved to the production server:</p>

<ul>
    <li>the script would silently fail with a 500 error whenever I called a GD function, specifically <code><a href="http://us2.php.net/manual/en/function.imagecreatefromstring.php">imagecreatefromstring()</a></code></li>
    <li>The most common IIS and GD error appears to be when PHP can&#8217;t find the GD DLL at all, which produces a nice message like 


<blockquote>Fatal error: Call to undefined function: imagecreatefromstring() in c:\inetpub\wwwroot\test2.php on line 7
PHP Warning: Unable to load dynamic library &#8216;c:\php\ext\php_gd2.dll&#8217; &#8211; The specified procedure could not be found. in Unknown on line 0 
</blockquote>

This was NOT my problem.  My script kept failing silently, with no output after I called the first GD function.</li>
    <li>IIS has no real error log like Apache.  When my script silently failed, nothing was logged in the Application Event log, PHP&#8217;s <var>error.log</var> or the pathetic <var>c:\WINDOWS\system32\LogFiles\HTTPERR\httperr*.log</var>.
<a href="http://blog.monstuff.com/archives/000179.html">Googling hard</a>, I found I <em>might</em> have luck looking for <a href="http://technet.microsoft.com/en-us/library/cc756146.aspx">&#8220;Worker Process Recycling Events&#8221;</a>, which is apparently Microsoft&#8217;s IIS term for that confusing word &#8220;error&#8221;, but I didn&#8217;t go far down that path.
</li>
    <li>Running my script from the command line using PHP didn&#8217;t produce any visible error either</li>

</ul>

<p>IIS sucks.  Apache&#8217;s error log is <strong>way</strong> better.</p>

<h3>Solutions</h3>

<p>I had to do both these things:</p>

<ul>
    <li><a href="http://www.vbulletin.com/forum/archive/index.php/t-111622.html">Copy the php_gd2.dll to C:\WINDOWS\system32</a>.  Ridiculous, but I have had to do it before with other PHP modules to have them really work.  After I did that, the script would work for <em>small</em> JPEG images.</li>
    <li>Increase the memory_limit in php.ini from 16MB to 32MB, so any whole high-res JPEG from the database will fit uncompressed in PHP&#8217;s memory</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://n8v.enteuxis.org/2008/11/getting-phps-gd-module-to-work-with-iis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</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 [...]]]></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
<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>


<div class="wp_syntax"><div class="code"><pre class="bash"><span class="kw2">svn</span> <span class="kw2">rm</span> plugins<span class="sy0">/</span>sfGuardPlugin
<span class="kw2">svn</span> ci plugins<span class="sy0">/</span>sfGuardPlugin <span class="re5">-m</span> <span class="st_h">'removed old version of sfGuardPlugin'</span>
<span class="kw2">rm</span> <span class="re5">-rf</span> plugins<span class="sy0">/</span>sfGuardPlugin plugins<span class="sy0">/</span>.channels plugins<span class="sy0">/</span>.depdb plugins<span class="sy0">/</span>.depdblock plugins<span class="sy0">/</span>.filemap plugins<span class="sy0">/</span>.lock plugins<span class="sy0">/</span>.registry<span class="sy0">/</span>
<span class="kw2">rm</span> <span class="re5">-rf</span> cache<span class="sy0">/</span>.pear
.<span class="sy0">/</span>symfony plugin:<span class="kw2">install</span> sfGuardPlugin
<span class="kw2">svn</span> add plugins<span class="sy0">/</span>sfGuardPlugin<span class="sy0">/</span></pre></div></div>


<p>my successful plugin installation looked like this:
<pre>
$  <kbd>./symfony plugin:install sfGuardPlugin</kbd>
&gt;&gt; plugin    installing plugin "sfGuardPlugin"
&gt;&gt; sfPearFrontendPlugin Attempting to discover channel "pear.symfony-project.com"...
&gt;&gt; sfPearFrontendPlugin downloading channel.xml ...
&gt;&gt; sfPearFrontendPlugin Starting to download channel.xml (663 bytes)
&gt;&gt; sfPearFrontendPlugin .
&gt;&gt; sfPearFrontendPlugin ...done: 663 bytes
&gt;&gt; sfPearFrontendPlugin Auto-discovered channel "pear.symfony-project.com", alias
&gt;&gt; sfPearFrontendPlugin "symfony", adding to registry
&gt;&gt; sfPearFrontendPlugin Attempting to discover channel
&gt;&gt; sfPearFrontendPlugin "plugins.symfony-project.org"...
&gt;&gt; sfPearFrontendPlugin downloading channel.xml ...
&gt;&gt; sfPearFrontendPlugin Starting to download channel.xml (639 bytes)
&gt;&gt; sfPearFrontendPlugin ...done: 639 bytes
&gt;&gt; sfPearFrontendPlugin Auto-discovered channel "plugins.symfony-project.org", alias
&gt;&gt; sfPearFrontendPlugin "symfony-plugins", adding to registry
&gt;&gt; sfPearFrontendPlugin downloading sfGuardPlugin-2.2.0.tgz ...
&gt;&gt; sfPearFrontendPlugin Starting to download sfGuardPlugin-2.2.0.tgz (18,589 bytes)
&gt;&gt; sfPearFrontendPlugin ...done: 18,589 bytes
&gt;&gt; sfPearFrontendPlugin Failed to download symfony/symfony (version &gt;= 1.1.0, version
&gt;&gt; sfPearFrontendPlugin &lt;= 1.2.0, excluded versions: 1.2.0), latest release is version
&gt;&gt; sfPearFrontendPlugin 1.1.1, stability "stable", use
&gt;&gt; sfPearFrontendPlugin "channel://pear.symfony-project.com/symfony-1.1.1" to install
&gt;&gt; sfSymfonyPluginManager Installation successful for plugin "sfGuardPlugin"
</pre></p>

<p>Then I did the first couple of steps from the install again to get it working:</p>


<div class="wp_syntax"><div class="code"><pre class="bash">$ symfony propel:build-model
$ symfony propel:build-sql
$ symfony <span class="kw2">cc</span></pre></div></div>


<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>
		<slash:comments>1</slash:comments>
		</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 (&#8220;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 [...]]]></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> (&#8220;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>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

