<?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>Richard Miller</title>
	<atom:link href="http://richardmiller.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://richardmiller.co.uk</link>
	<description>has apparently been blogging for just over a year now</description>
	<lastBuildDate>Tue, 08 May 2012 14:17:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>ShefPHP Symfony2 Bootcamp Part 3</title>
		<link>http://richardmiller.co.uk/2012/05/08/shefphp-symfony2-bootcamp-part-3/</link>
		<comments>http://richardmiller.co.uk/2012/05/08/shefphp-symfony2-bootcamp-part-3/#comments</comments>
		<pubDate>Tue, 08 May 2012 14:17:49 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://richardmiller.co.uk/?p=990</guid>
		<description><![CDATA[Tomorrow is the third part of the ShefPHP Symfony2 bootcamp. As well as last month&#8217;s requirements, this month you need to install elasticsearch. For the purposes of the session, it can just be downloaded and run, there is no need to worry about making it into a service (you will you need Java as well [...]]]></description>
			<content:encoded><![CDATA[<p>Tomorrow is the third part of the <a href="https://twitter.com/#!/ShefPHP">ShefPHP</a> <a href="http://symfony.com">Symfony2</a> bootcamp. As well as last month&#8217;s requirements, this month you need to install <a href="http://www.elasticsearch.org/">elasticsearch</a>. For the purposes of the session, it can just be <a href="http://www.elasticsearch.org/download/">downloaded</a> and run, there is no need to worry about making it into a service (you will you need Java as well to run it). You will also need to have curl support enabled in PHP.</p>
<p>Please also <a href="/wp-content/uploads/2012/05/ShefPHPThree.tar.gz">download the start point</a>, as with last month this is different from last month&#8217;s end point so please will all attendees download this. Thanks, see you on Wednesday evening.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2012/05/08/shefphp-symfony2-bootcamp-part-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ShefPHP Symfony2 Bootcamp Part 2</title>
		<link>http://richardmiller.co.uk/2012/04/25/shefphp-symfony2-bootcamp-part-2/</link>
		<comments>http://richardmiller.co.uk/2012/04/25/shefphp-symfony2-bootcamp-part-2/#comments</comments>
		<pubDate>Wed, 25 Apr 2012 09:04:03 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://richardmiller.co.uk/?p=984</guid>
		<description><![CDATA[Tonight is the second part of the ShefPHP Symfony2 bootcamp. There is a bit of preparation for attendees. Please could you have mongodb installed, along with the pecl extension. You also need to have the gd or ImageMagick extension installed. I have put together a starting point for the application, please could you download this [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight is the second part of the <a href="https://twitter.com/#!/ShefPHP">ShefPHP</a> <a href="http://symfony.com">Symfony2</a> bootcamp. There is a bit of preparation for attendees. Please could you have <a href="http://www.mongodb.org/">mongodb</a> installed, along with the <a href="http://pecl.php.net/package/mongo">pecl extension</a>. You also need to have the <a href="http://php.net/manual/en/book.image.php">gd</a> or <a href="http://www.php.net/manual/en/book.imagick.php">ImageMagick</a> extension installed. </p>
<p>I have put together a <a href="/wp-content/uploads/2012/04/ShefPHPStart.tar.gz">starting point</a> for the application, please could you download this in advance. This is not the same as the end point of session one, so please can you do this even if you <strong>did</strong> attend the first part.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2012/04/25/shefphp-symfony2-bootcamp-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Manipulating Service Parameters and Definitions</title>
		<link>http://richardmiller.co.uk/2012/02/22/symfony2-manipulating-service-parameters-and-definitions/</link>
		<comments>http://richardmiller.co.uk/2012/02/22/symfony2-manipulating-service-parameters-and-definitions/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 09:56:17 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dependency injection]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=906</guid>
		<description><![CDATA[In my previous post I looked at Symfony2 Service Container Compiler Passes, in this post I will look at how to manipulate service container parameters and definitions from within a compiler pass. So the important method of the compiler pass which gets called when the container is being built is the process method which looks [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous post I looked at <a href="/2012/02/15/symfony2-service-container-compiler-passes/">Symfony2 Service Container Compiler Passes</a>, in this post I will look at how to manipulate service container parameters and definitions from within a compiler pass.</p>
<p>So the important method of the compiler pass which gets called when the container is being built is the <code>process</code> method which looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">public</span> <span class="kw2">function</span> process<span class="br0">&#40;</span>ContainerBuilder <span class="re0">$container</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="co1">//--</span>
<span class="br0">&#125;</span></pre></div></div>

<p>In this method we can work with the passed in container which has been set up with parameters and service definitions from the various configuration files.</p>
<h2>Getting and Setting Container Parameters</h2>
<p>Working with container parameters is straight forward using the container&#8217;s accessor methods for parameters. You can check if a parameter has been defined in the container with</p>

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

<p>You can retrieve parameters set in the container with:</p>

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

<p>and set a parameter in the container with:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">setParameter</span><span class="br0">&#40;</span><span class="re0">$name</span><span class="sy0">,</span> <span class="re0">$value</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<h2>Getting and Setting Service Definitions</h2>
<p>There are also some helpful methods of the passed in container builder for working with the service definitions.</p>
<p>To find out if there is a definition for a service id:</p>

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

<p>This is useful if you only want to do something if a particular definition exists. In my previous post I looked at an example from the AsseticBundle where a parameter was required only if a particular service has defined so <code>hasDefinition()</code> was used to check for the service definition before checking if the parameter was set. Here it is again:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">class</span> CheckCssEmbedFilterPass implements CompilerPassInterface
<span class="br0">&#123;</span>
    <span class="kw2">public</span> <span class="kw2">function</span> process<span class="br0">&#40;</span>ContainerBuilder <span class="re0">$container</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">hasDefinition</span><span class="br0">&#40;</span><span class="st_h">'assetic.filter.cssembed'</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span>
            <span class="sy0">!</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">getParameterBag</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">resolveValue</span><span class="br0">&#40;</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'assetic.filter.cssembed.jar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="kw1">throw</span> <span class="kw2">new</span> \RuntimeException<span class="br0">&#40;</span><span class="st_h">'The &quot;assetic.filters.cssembed&quot; configuration requires a &quot;jar&quot; value.'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>You can retrieve a definition with</p>

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

<p>or</p>

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

<p>which unlike <code>getDefinition()</code> also resolves aliases so if the <code>$serviceId</code> argument is an alias you will get the underlying definition.</p>
<p>The service definitions themselves are objects so if you retrieve a definition with these methods and make changes to it these will be reflected in the container. If, however, you are creating a new definition then you can add it to the container using:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">setDefinition</span><span class="br0">&#40;</span><span class="re0">$id</span><span class="sy0">,</span> <span class="re0">$definition</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<h2>Working with a definition</h2>
<h3>Creating a new definition</h3>
<p>If you need to create a new definition rather than manipulate one retrieved from then container then the definition class is <code>Symfony\Component\DependencyInjection\Definition</code>.</p>
<h3>Class</h3>
<p>First up is the class of a definition, this is the class of the object returned when the service is requested from the container.</p>
<p>You may want to change the class used by a definition, if for example there is functionality which can only be used if a service from another bundle exists then you may have a class which make use of that other service and one that does not. The one that does not could be used for the service and then the one with the extra functionality swapped in using a compiler pass if the other service is available.</p>
<p>To find out what class is set for a definition:</p>

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

<p>and to set a different class:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$definition</span><span class="sy0">-&gt;</span><span class="me1">setClass</span><span class="br0">&#40;</span><span class="re0">$class</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">//Fully qualified class name as string</span></pre></div></div>

<h3>Constructor Arguments</h3>
<p>To get an array of the constructor arguments for a definition you can use</p>

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

<p>or to get a single argument by its position</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$definition</span><span class="sy0">-&gt;</span><span class="me1">getArgument</span><span class="br0">&#40;</span><span class="re0">$index</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">//e.g. $definition-&gt;getArguments(0) for the first argument</span></pre></div></div>

<p>You can add a new argument to the end of the arguments array using</p>

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

<p>The argument can be a string, an array, a service parameter by using <code>'%paramater_name%'</code> or a service id by using</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">use</span> Symfony\Component\DependencyInjection\Reference<span class="sy0">;</span>
&nbsp;
<span class="co1">//--</span>
&nbsp;
<span class="re0">$definition</span><span class="sy0">-&gt;</span><span class="me1">addArgument</span><span class="br0">&#40;</span><span class="kw2">new</span> Reference<span class="br0">&#40;</span><span class="st_h">'service_id'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>In a similar way you can replace an already set argument by index using:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$definition</span><span class="sy0">-&gt;</span><span class="me1">replaceArgument</span><span class="br0">&#40;</span><span class="re0">$index</span><span class="sy0">,</span> <span class="re0">$argument</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>You can also replace all the arguments (or set some if there are none) with an array of arguments</p>

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

<h3>Method Calls</h3>
<p>If the service you are working with uses setter injection then you can manipulate any method calls in the definitions as well.</p>
<p>You can get an array of all the method calls with:</p>

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

<p>Add a method call with:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="re0">$definition</span><span class="sy0">-&gt;</span><span class="me1">addMethodCall</span><span class="br0">&#40;</span><span class="re0">$method</span><span class="sy0">,</span> <span class="re0">$arguments</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>

<p>Where <code>$method</code> is the method name and $arguments is an array of the arguments to call the method with. The arguments can be strings, arrays, parameters or service ids as with the constructor arguments.</p>
<p>You can also replace any existing method calls with an array of new ones with:</p>

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

<h2>Wrapping Up</h2>
<p>The methods available then are the same ones that can be used to configure the container in the first place and which are shown in the Symfony2 documentation along with the XML and YAML ways you may be more familiar with. You would usually want to use config files rather than directly creating the definitions when setting the container up. In compiler passes you need to use these methods for making changes to the service definitions. </p>
<p>I have only looked at the more common methods of the definition object here, you can see some more available methods, by looking at the relevant docs e.g. <a href="http://symfony.com/doc/2.0/cookbook/service_container/factories.html">How to Use a Factory to Create Services</a> and looking at the PHP tab in the examples. Bear in mind the place of compiler passes in the process of building the service container though, for example, if you add a tag to a definition in a compiler pass, but the pass that looks for those tags has already run, then it will have no effect.</p>
<p>If there is one thing to take away from this post, it is that if you dislike writing YAML or XML configs for services then just be glad you can and you do not have to write all the definitions this way <img src='http://richardmiller.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2012/02/22/symfony2-manipulating-service-parameters-and-definitions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: Service Container Compiler Passes</title>
		<link>http://richardmiller.co.uk/2012/02/15/symfony2-service-container-compiler-passes/</link>
		<comments>http://richardmiller.co.uk/2012/02/15/symfony2-service-container-compiler-passes/#comments</comments>
		<pubDate>Wed, 15 Feb 2012 10:48:05 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dependency injection]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=701</guid>
		<description><![CDATA[In this post I am going to look at compiler passes. This is not something that you will often need to worry about when making an app with Symfony2. They do come in useful for some needs though and in particular for releasable bundles. What are Compiler Passes The lifecycle of Symfony2 service container is [...]]]></description>
			<content:encoded><![CDATA[<p>In this post I am going to look at compiler passes. This is not something that you will often need to worry about when making an app with Symfony2. They do come in useful for some needs though and in particular for releasable bundles.</p>
<h2>What are Compiler Passes</h2>
<p>The lifecycle of Symfony2 service container is roughly along these lines. The configuration is loaded from the various bundles configurations and the app level config files are processed by the Extension classes in each bundle. Various compiler passes are then run against this configuration before it is all cached to file. This cached configuration is then used on subsequent requests. To read more about the loading of config files by a bundle&#8217;s extension class and processing the configuration see my posts <a href="/2011/04/15/symfony2-controller-as-service/">Symfony2: Controller as Service</a> and <a href="/2011/06/01/symfony2-writing-a-dependency-injection-extension-configuration/">Symfony2: Writing a Dependency Injection Extension Configuration</a>.</p>
<p>The compilation of the configuration is itself done first using a compiler pass. Further compiler passes are then used for various tasks to optimise the configuration before it is cached. For example, private services and abstract services are removed, and aliases are resolved. </p>
<p>Many of these compiler passes are part of the Dependency Injection component but individual bundles can register their own compiler passes. A common use is to inject tagged services into that bundle&#8217;s services. This functionality allows for services to be defined outside of a bundles config but still be used by that bundle. The bundle is not aware of these services in its own static config and a fresh container is passed to the Extension class meaning it does not have access to any other services, so compiler passes which are executed after all the configuration has been loaded are neccessary to inject tagged services. By using a compiler pass you know that all the other service config files have been already been processed.</p>
<h2>Creating a Compiler Pass</h2>
<p>To create a compiler pass it needs to implements the <code>Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface</code> interface.</p>
<p>It is standard practice to put the compiler passes in the DependencyInjection/Compiler folder of a bundle. They are not automatically registered though, to add the pass to the container, override the build method of the bundle definition class:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">namespace</span> LimeThinking\ExampleBundle<span class="sy0">;</span>
&nbsp;
<span class="kw2">use</span> LimeThinking\ExampleBundle\DependencyInjection\Compiler\ExamplePass<span class="sy0">;</span>
<span class="kw2">use</span> Symfony\Component\DependencyInjection\ContainerBuilder<span class="sy0">;</span>
<span class="kw2">use</span> Symfony\Component\HttpKernel\Bundle\Bundle<span class="sy0">;</span>
&nbsp;
<span class="kw2">class</span> ExampleBundle <span class="kw2">extends</span> Bundle
<span class="br0">&#123;</span>
    <span class="kw2">public</span> <span class="kw2">function</span> build<span class="br0">&#40;</span>ContainerBuilder <span class="re0">$container</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">addCompilerPass</span><span class="br0">&#40;</span><span class="kw2">new</span> ExamplePass<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<h2>Uses for Compiler Passes</h2>
<p>You can implement tags for your own services to allow other people to create services to be injected into your bundle. This of course only make sense for shared bundles which are released for other people to use. For bundles only used in a single application you have full control over its config and can just inject the services in there. There is <a href="http://symfony.com/doc/current/cookbook/service_container/tags.html">a cookbook article</a> in the Symfony docs on writing a compiler pass that makes use of tags.</p>
<p>Basically the compiler gives you an opportunity to manipulate the service definitions that have been compiled. Hence this being not something needed in everyday use. In most cases the service definitions in the config can be changed.</p>
<p>There are other uses such as providing more complicated checks on the configuration than is possible during configuration processing. For example, the configuration builder does not provide a way of checking that a value is required only when a certain service is present. The following example from AsseticBundle shows checking if a parameter has been set in the container if a particular service has been defined:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">class</span> CheckCssEmbedFilterPass implements CompilerPassInterface
<span class="br0">&#123;</span>
    <span class="kw2">public</span> <span class="kw2">function</span> process<span class="br0">&#40;</span>ContainerBuilder <span class="re0">$container</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">hasDefinition</span><span class="br0">&#40;</span><span class="st_h">'assetic.filter.cssembed'</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span>
            <span class="sy0">!</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">getParameterBag</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">resolveValue</span><span class="br0">&#40;</span><span class="re0">$container</span><span class="sy0">-&gt;</span><span class="me1">getParameter</span><span class="br0">&#40;</span><span class="st_h">'assetic.filter.cssembed.jar'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            <span class="kw1">throw</span> <span class="kw2">new</span> \RuntimeException<span class="br0">&#40;</span><span class="st_h">'The &quot;assetic.filters.cssembed&quot; configuration requires a &quot;jar&quot; value.'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>In my next post on this topic I will look at how to manipulate service container definitions from within a compiler pass.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2012/02/15/symfony2-service-container-compiler-passes/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Symfony2: elasticsearch autocomplete  queries</title>
		<link>http://richardmiller.co.uk/2012/01/10/symfony2-elasticsearch-autocomplete-queries/</link>
		<comments>http://richardmiller.co.uk/2012/01/10/symfony2-elasticsearch-autocomplete-queries/#comments</comments>
		<pubDate>Tue, 10 Jan 2012 09:20:20 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[elastica]]></category>
		<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[foqelasticabundle]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=797</guid>
		<description><![CDATA[This is the fifth in a series of posts about using elasticsearch with Symfony2: Symfony2: Integrating elasticsearch]]></description>
			<content:encoded><![CDATA[<p>This is the fifth in a series of posts about using <a href="http://www.elasticsearch.org/">elasticsearch</a> with <a href="http://symfony.com">Symfony2</a>:</p>
<ol>
<li><a href="/2011/11/11/symfony2-integrating-elasticsearch/">Symfony2: Integrating elasticsearch</a</li>
<li><a href="/2011/11/18/symfony2-improving-elasticsearch-results/">Symfony2: improving elasticsearch results</a</li>
<li><a href="/2011/11/23/symfony2-elasticsearch-analyzers/">Symfony2: elasticsearch custom analyzers</a></li>
<li><a href="/2011/12/19/symfony2-elasticsearch-custom-repositories/">Symfony2: elasticsearch custom repositories</a></li>
<li>Symfony2: elasticsearch autocomplete queries</li>
</ol>
<p>In this post I will take a quick a look at how we can create another query for the indexed site entities to provide results for an autocomplete field. I am not going to look at the actual implementation of the autocomplete box or even the formatting of the response since that will depend on the autocomplete implementation.</p>
<p>At the moment the sort of results we are retrieving from the search index will not be suitable for use with autocomplete. For a start, whilst we have used stemming we will not get results when searching for the first part of a word in the name. For example, if we have added a site with <code>Lime Thinking</code> as the name then it will not be returned for a search for <code>L</code>, <code>Li</code>, <code>Lim</code> etc as we will need for autocomplete.</p>
<p>Fortunately this is very easy to remedy with elasticsearch by making our query a <code>text_phrase_prefix</code> query. We can also simplify the query if we assume we are only searching on the name field. So let&#8217;s make another method in the custom repository for our new query and add the type to the query object:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">namespace</span> LimeThinking\ExampleBundle\SearchRepository<span class="sy0">;</span>
&nbsp;
<span class="kw2">use</span> FOQ\ElasticaBundle\Repository<span class="sy0">;</span>
&nbsp;
<span class="kw2">class</span> SiteRepository <span class="kw2">extends</span> Repository
<span class="br0">&#123;</span>
&nbsp;
    <span class="co1">//--</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> findByPartialName<span class="br0">&#40;</span><span class="re0">$searchTerm</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'type'</span><span class="sy0">,</span> <span class="st_h">'phrase_prefix'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
<span class="br0">&#125;</span></pre></div></div>

<p>This will now return the Lime Thinking site for searches for <code>L</code>, <code>Li</code>, <code>Lim</code> etc as we needed. </p>
<p>It is worth being aware of how this query is processed so that the results make sense. If we search for multiple words then this phrase is not split up but searched for whole. So a search for <code>lime thi</code> will return the <code>Lime Thinking</code> site but a search for <code>lim thi</code> will not find it. The search phrase does not need to match the start of the name though, so a search for <code>thi</code> will return the <code>Lime Thinking</code> entity.</p>
<p>Additionally if we were also to index a site with the name <code>Lime Pickle</code> then we would get both sites for <code>lim</code> but only <code>Lime Thinking</code> on a search for <code>lime thin</code> which differs from the search from previous posts where both would be found for a search for <code>lime thin</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2012/01/10/symfony2-elasticsearch-autocomplete-queries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: elasticsearch custom repositories</title>
		<link>http://richardmiller.co.uk/2011/12/19/symfony2-elasticsearch-custom-repositories/</link>
		<comments>http://richardmiller.co.uk/2011/12/19/symfony2-elasticsearch-custom-repositories/#comments</comments>
		<pubDate>Mon, 19 Dec 2011 09:12:33 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[elastica]]></category>
		<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[foqelasticabundle]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=833</guid>
		<description><![CDATA[This is the fourth in a series of posts about using elasticsearch with Symfony2: Symfony2: Integrating elasticsearch]]></description>
			<content:encoded><![CDATA[<p>This is the fourth in a series of posts about using <a href="http://www.elasticsearch.org/">elasticsearch</a> with <a href="http://symfony.com">Symfony2</a>:</p>
<ol>
<li><a href="/2011/11/11/symfony2-integrating-elasticsearch/">Symfony2: Integrating elasticsearch</a</li>
<li><a href="/2011/11/18/symfony2-improving-elasticsearch-results/">Symfony2: improving elasticsearch results</a</li>
<li><a href="/2011/11/23/symfony2-elasticsearch-analyzers/">Symfony2: elasticsearch custom analyzers</a></li>
<li>Symfony2: elasticsearch custom repositories</li>
</ol>
<p>A new feature of the <a href="https://github.com/Exercise/FOQElasticaBundle">FOQElasticaSearch bundle</a> is the provision of repositories similar to those for Doctrine queries. The first advantage of this is that instead of having to use the finder service specific to a particular entity you can use the same manager service for all mapped entities and use the entity class name to get a repository to run queries against. So using the query we have built up in the previous posts:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$sm</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.manager'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$keywordsQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$urlQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'url_analyzer'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp;
    <span class="re0">$boolQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Bool<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$keywordsQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$urlQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$sm</span><span class="sy0">-&gt;</span><span class="me1">getRepository</span><span class="br0">&#40;</span><span class="st_h">'ExampleBundle:Site'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$boolQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Note that the use of the short syntax <code>ExampleBundle:Site</code> is only available in master, if you are using the branch compatible with 2.0.x Symfony releases then you will need to use the fully qualified class name e.g. <code>LimeThinking\ExampleBundle\Entity\Site</code>.</p>
<p>A much bigger advantage of using this functionality is that we can create a custom repository to encapsulate our query which will clean up our controller method and make it easy to reuse elsewhere. So our custom repository looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">namespace</span> LimeThinking\ExampleBundle\SearchRepository<span class="sy0">;</span>
&nbsp;
<span class="kw2">use</span> FOQ\ElasticaBundle\Repository<span class="sy0">;</span>
&nbsp;
<span class="kw2">class</span> SiteRepository <span class="kw2">extends</span> Repository
<span class="br0">&#123;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> findByNameKeywordsOrUrl<span class="br0">&#40;</span><span class="re0">$searchTerm</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="re0">$keywordsQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="re0">$urlQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'url_analyzer'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="re0">$boolQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Bool<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$keywordsQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$urlQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$boolQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
&nbsp;
<span class="br0">&#125;</span></pre></div></div>

<p>The custom repository must extend the base repository in order to be able to use the relevant finder service, which is automatically injected in. We also need to specify the custom repository class. In master this can be done using an annotation:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">namespace</span> LimeThinking\ExampleBundle\Entity<span class="sy0">;</span>
&nbsp;
<span class="kw2">use</span> Doctrine\ORM\Mapping <span class="kw1">as</span> ORM<span class="sy0">;</span>
<span class="kw2">use</span> FOQ\ElasticaBundle\Configuration\Search<span class="sy0">;</span>
<span class="kw2">use</span> Symfony\Component\Validator\Constraints <span class="kw1">as</span> <a href="http://www.php.net/assert"><span class="kw3">Assert</span></a><span class="sy0">;</span>
&nbsp;
<span class="co4">/**
 * @ORM\Entity
 * @ORM\Table(name=&quot;site&quot;)
 * @ORM\HasLifecycleCallbacks()
 * @Search(repositoryClass=&quot;LimeThinking\ExampleBundle\SearchRepository\SiteRepository&quot;)
 */</span>
&nbsp;
<span class="kw2">class</span> Site
<span class="br0">&#123;</span>
<span class="co1">//--</span>
<span class="br0">&#125;</span></pre></div></div>

<p>For the 2.0 branch we need to specify it in our config, which now looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            //--
            types:
                site:
                    mappings:
                        name: { analyzer: snowball }
                        keywords: { analyzer: snowball }
                        url: { analyzer: url_analyzer }
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        repository: LimeThinking\ExampleBundle\SearchRepository\SiteRepository
                        provider:
                        listener:
                        finder:</pre></div></div>

<p>Our controller method can now be simplified to this:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$sm</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.manager'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$sm</span><span class="sy0">-&gt;</span><span class="me1">getRepository</span><span class="br0">&#40;</span><span class="st_h">'ExampleBundle:Site'</span><span class="br0">&#41;</span>
                <span class="sy0">-&gt;</span><span class="me1">findByNameKeywordsOrUrl</span><span class="br0">&#40;</span><span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>The controller method is now much cleaner with the implementation of the query moved to the repository, the query can now also easily be reused elsewhere.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2011/12/19/symfony2-elasticsearch-custom-repositories/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Symfony2: elasticsearch custom analyzers</title>
		<link>http://richardmiller.co.uk/2011/11/23/symfony2-elasticsearch-analyzers/</link>
		<comments>http://richardmiller.co.uk/2011/11/23/symfony2-elasticsearch-analyzers/#comments</comments>
		<pubDate>Wed, 23 Nov 2011 09:38:48 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[elastica]]></category>
		<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[foqelasticabundle]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=786</guid>
		<description><![CDATA[In my previous posts I looked at integrating elasticsearch into a Symfony2 app and at how to use an alternative analyzer. One thing we did not do last time was indexing the url field of the Site entity. The reason for this is that if you index urls and email addresses using the default settings [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous posts I looked at <a href="http://miller.limethinking.co.uk/2011/11/11/symfony2-integrating-elasticsearch/">integrating elasticsearch into a Symfony2 app</a> and at <a href="/2011/11/18/symfony2-improving-elasticsearch-results/">how to use an alternative analyzer</a>. </p>
<p>One thing we did not do last time was indexing the <code>url</code> field of the <code>Site</code> entity. The reason for this is that if you index urls and email addresses using the default settings they will not be split up for indexing, meaning that you cannot search on part of them. For example if we have index <code>http://www.limethinking.co.uk</code> then a search for <code>limethinking</code> will not return the indexed document.</p>
<p>The reason for this is the way that the strings are analyzed to decide how to index them. An analyzer is a combination of a tokenizer and filters. The tokenizer decides how to split up the string to be indexed into individual tokens, the filters are then applied to the tokens before they are indexed. The default <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/standard-analyzer.html">Standard Analyzer</a> uses the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/standard-tokenizer.html">Standard Tokenizer</a> which, using language specific rules, splits up the string using whitespace and punctuation. It has the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/lowercase-tokenfilter.html">Lowercase Token</a> filter, which lower cases the token to avoid search being case dependant, the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/stop-tokenfilter.html">Stop Token</a> filter, which removes a specified set of words so that words like <code>and</code>, <code>or</code> etc., are not indexed and the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/standard-tokenfilter.html">Standard Token</a> filter. </p>
<p>Unfortunately for us this does not work very well for the urls we want to index because the standard tokenizer does not split on dots followed by whitespace, so urls are not split up but indexed whole. Fortunately for us it is easy to change the analyzer used in the config:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            client: default
            settings:
                index:
                    analysis:
                        analyzer:
                            url_analyzer:
                                type: custom
                                tokenizer: lowercase
                                filter: [&quot;stop&quot;, &quot;url_stop&quot;]
                        filter:
                            url_stop:
                                type: &quot;stop&quot;
                                stopwords: [&quot;http&quot;, &quot;https&quot;]
&nbsp;
            types:
                site:
                    mappings:
                        name: { analyzer: snowball }
                        keywords: { analyzer: snowball }
                        url: { analyzer: url_analyzer }
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        provider:
                        listener:
                        finder:</pre></div></div>

<p>So we are defining a custom analyzer under the settings section, using the name <code>url_analyzer</code>, under the site type we have added url to the mappings, specifying it should use this analyzer. The analyzer uses the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/lowercase-tokenizer.html">Lowercase Tokenizer</a> which splits on any non letter symbol as well as lower casing the resulting tokens. We are also using a couple of filters with this, a custom stop filter which removes http and https so they are not matched in searches as well as the standard stop filter. By removing http and https from the index for urls we can still get meaningful results if we search for these terms and have added sites with http or https in the title.</p>
<p>We now need to add searching the url field to our query from the previous post:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$finder</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.bookmarks.site'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$keywordsQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$urlQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$urlQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'url'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'url_analyzer'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp;
    <span class="re0">$boolQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Bool<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$keywordsQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$urlQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$finder</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$boolQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>This adds another <code>Text</code> query searching the <code>url</code> field using the custom <code>url_analyzer</code>. Now all three fields of the <code>Site</code> entity are being searched on.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2011/11/23/symfony2-elasticsearch-analyzers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Symfony2: improving elasticsearch results</title>
		<link>http://richardmiller.co.uk/2011/11/18/symfony2-improving-elasticsearch-results/</link>
		<comments>http://richardmiller.co.uk/2011/11/18/symfony2-improving-elasticsearch-results/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 09:59:19 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[elastica]]></category>
		<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[foqelasticabundle]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=795</guid>
		<description><![CDATA[In my previous post I looked at integrating elasticsearch into a Symfony2 app using Elastica and the FOQElasticaBundle bundle. By the end we were indexing a Site entity and performing basic searches against the index. In the post I will look at improving how we index and search the Site entities. We can improve the [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="/2011/11/11/symfony2-integrating-elasticsearch/">previous post</a> I looked at integrating <a href="http://www.elasticsearch.org/">elasticsearch</a> into a <a href="http://symfony.com">Symfony2</a> app using <a href="https://github.com/ruflin/Elastica">Elastica</a> and the <a href="https://github.com/Exercise/FOQElasticaBundle">FOQElasticaBundle</a> bundle. By the end we were indexing a Site entity and performing basic searches against the index. In the post I will look at improving how we index and search the Site entities.</p>
<p>We can improve the indexing of the name and keywords by switching to a different analyzer. Currently we are only going to find whole word matches, for example, if we index <code>Lime Thinking</code> as a site name then it will be found by a search for <code>thinking</code>, but not <code>think</code> or <code>thinks</code>. We can change this by instead using the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/snowball-analyzer.html">snowball analyzer</a>, this is a built in analyzer which is the same as the <a href="http://www.elasticsearch.org/guide/reference/index-modules/analysis/standard-analyzer.html">standard analyzer</a> but with the edition of the snowball filter which stems the tokens. This means that words are indexed as their stems, so <code>thinking</code> will be indexed as <code>think</code>. We can then find it with searches for words such as <code>think</code>, <code>thinks</code> and <code>thinkings</code>. I will have a more detailed look at analyzers and filters in a future post.</p>
<p>We just need to make a small config change to start using this analyzer for indexing:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            client: default
            types:
                site:
                    mappings:
                        name: { analyzer: snowball }
                        keywords: { analyzer: snowball }
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        provider:
                        listener:
                        finder:</pre></div></div>

<p>We need to make some further changes though to get the benefits of this. We also need to make sure that the search terms are analyzed with the same analyzer as the indexed field. If this does not happen we will only get matches if we search for the stemmed token e.g. <code>think</code> will find <code>Lime Thinking</code> but <code>thinking</code> will not. Our simple query does not specify which field we are searching, this means its searches the built in <code>_all</code> field which, unsurprisingly, contains all the fields. This means we cannot use different analyzers for searching different fields. We are going to want to add the url at some point using a different analyzer so we need to specify each field we want to search separately.</p>
<p>So we now need to split up our query into several parts. For this we need to use Elastica&#8217;s query builder objects. To search on a specific field we can use a Text query, so to search on the name field we use:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$finder</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.bookmarks.site'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$finder</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Notice that we pass the query object into the same method on the finder as before, this method accepts both simple search strings as well as queries built through objects. According to the elasticsearch documentation the analyzer will default to the field specific analyzer or the default one, to me this suggests that the above query will automatically use the analyzer set for the field. However this does not work for me, fortunately it easy to specify the analyzer to use for the field:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$finder</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.bookmarks.site'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$finder</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Our current query will of course only search the name field, what we want to do is search the name field and the keywords field using the snowball analyzer. This is done by creating another query as above for the keywords field and then using a boolean query to combine the two individual queries into one query:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$finder</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.bookmarks.site'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$nameQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$nameQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'name'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$keywordsQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Text<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldQuery</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$keywordsQuery</span><span class="sy0">-&gt;</span><span class="me1">setFieldParam</span><span class="br0">&#40;</span><span class="st_h">'keywords'</span><span class="sy0">,</span> <span class="st_h">'analyzer'</span><span class="sy0">,</span> <span class="st_h">'snowball'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$boolQuery</span> <span class="sy0">=</span> <span class="kw2">new</span> \Elastica_Query_Bool<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$nameQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$boolQuery</span><span class="sy0">-&gt;</span><span class="me1">addShould</span><span class="br0">&#40;</span><span class="re0">$keywordsQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$finder</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$boolQuery</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Whilst this looks complicate each constituent part is simple and this is a good way to build more complicated queries.</p>
<p>A really helpful recent inclusion to the bundle is logging to the web profiler toolbar so you can see the parsed JSON query that is sent to elasticsearch. The combined query from above looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">Method: GET
{ query: { bool: { should: [{ text: { name: { query: thinking, analyzer: snowball } } }, { text: { keywords: { query: thinking, analyzer: snowball } } }] } } }
Time: 8.19 ms</pre></div></div>

<p>We have seen Text query and Boolean query here, these are just a few of the available query types. There is more information on each in the <a href="http://www.elasticsearch.org/guide/reference/query-dsl/">elasticsearch documentation</a>. There is little in the way of documentation for the Elastica objects for creating these query types but the <a href="https://github.com/ruflin/Elastica/tree/master/test/lib/Elastica/Query">test suite</a> provides quite a lot of example of putting them to use.</p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2011/11/18/symfony2-improving-elasticsearch-results/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Symfony2: Integrating elasticsearch</title>
		<link>http://richardmiller.co.uk/2011/11/11/symfony2-integrating-elasticsearch/</link>
		<comments>http://richardmiller.co.uk/2011/11/11/symfony2-integrating-elasticsearch/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 09:51:14 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[elastica]]></category>
		<category><![CDATA[foqelasticabundle]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=605</guid>
		<description><![CDATA[Over a short series of posts I am going to have a look at using elasticsearch with Symfony2. Elasticsearch is built on top of Lucene and indexes data as JSON documents in a similar way to the way MongoDB stores data. This means as with Mongo that it is schemaless and creates fields on the [...]]]></description>
			<content:encoded><![CDATA[<p>Over a short series of posts I am going to have a look at using <a href="http://www.elasticsearch.org/">elasticsearch</a> with <a href="http://symfony.com">Symfony2</a>.</p>
<p>Elasticsearch is built on top of <a href="http://lucene.apache.org/">Lucene</a> and indexes data as JSON documents in a similar way to the way <a href="http://www.mongodb.org/">MongoDB</a> stores data. This means as with Mongo that it is schemaless and creates fields on the fly. It is queried over HTTP using  queries which are themselves defined in JSON. I am not going to go into details about using elasticsearch in this way, there is plenty of information in its <a href="http://www.elasticsearch.org/guide/">online documentation</a>. </p>
<p>Reading through the documentation makes it look as though there is a steep learning curve to getting started with elasticsearch. What I want to do is look at how you can avoid having to deal with issuing JSON queries over HTTP from a Symfony2 app and actually get started using elasticsearch in a very simple way. This is possible by using <a href="https://github.com/ruflin/Elastica">Elastica</a>, a PHP library which abstracts the details of the queries, along with the <a href="https://github.com/Exercise/FOQElasticaBundle">FOQElasticaBundle</a> which integrates Elastica into Symfony2 applications. This is not just a basic wrapper though to make Elastica into a Symfony2 service, the integration with <a href="http://www.doctrine-project.org/">Doctrine</a> to make indexing of ORM entities or ODM documents is fantastic and what I am going to look at here.</p>
<p>To get started you need to <a href="http://www.elasticsearch.org/guide/reference/setup/installation.html">install elasticsearch</a> itself, as well as <a href="https://github.com/Exercise/FOQElasticaBundle">installing Elastica and the FOQElasticaBundle in the usual way</a>.</p>
<p>As an example of how easy the integration is I will look at a very basic application for bookmarking sites and searching for them. For simplicity&#8217;s sake we are just going to have a single entity to model each site, it is just a name, the URL and some keywords stored as a comma separated list. So here it is as a Doctrine entity class:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw2">namespace</span> LimeThinking\ExampleBundle\Entity<span class="sy0">;</span>
&nbsp;
<span class="kw2">use</span> Doctrine\ORM\Mapping <span class="kw1">as</span> ORM<span class="sy0">;</span>
<span class="kw2">use</span> Symfony\Component\Validator\Constraints <span class="kw1">as</span> <a href="http://www.php.net/assert"><span class="kw3">Assert</span></a><span class="sy0">;</span>
&nbsp;
<span class="co4">/**
 * @ORM\Entity
 * @ORM\Table(name=&quot;site&quot;)
 */</span>
<span class="kw2">class</span> Site
<span class="br0">&#123;</span>
    <span class="co4">/**
     * @ORM\Id
     * @ORM\Column(type=&quot;integer&quot;)
     * @ORM\GeneratedValue(strategy=&quot;AUTO&quot;)
     */</span>
    <span class="kw2">private</span> <span class="re0">$id</span><span class="sy0">;</span>
&nbsp;
    <span class="co4">/**
     * @ORM\Column(type=&quot;string&quot;, length=255)
     * @Assert\NotBlank()
     * @Assert\MaxLength(255)
     */</span>
    <span class="kw2">private</span> <span class="re0">$name</span><span class="sy0">;</span>
&nbsp;
    <span class="co4">/**
     * @ORM\Column(type=&quot;string&quot;, length=255)
     * @Assert\NotBlank()
     * @Assert\Url()
     * @Assert\MaxLength(255)
     */</span>
    <span class="kw2">private</span> <span class="re0">$url</span><span class="sy0">;</span>
&nbsp;
    <span class="co4">/**
     * @ORM\Column(type=&quot;string&quot;, length=255)
     * @Assert\MaxLength(255)
     */</span>
    <span class="kw2">private</span> <span class="re0">$keywords</span><span class="sy0">;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> getId<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">id</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> setName<span class="br0">&#40;</span><span class="re0">$name</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">name</span> <span class="sy0">=</span> <span class="re0">$name</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> getName<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> setUrl<span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">url</span> <span class="sy0">=</span> <span class="re0">$url</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> getUrl<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">url</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> setKeywords<span class="br0">&#40;</span><span class="re0">$keywords</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">keywords</span> <span class="sy0">=</span> <span class="re0">$keywords</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> getKeywords<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">keywords</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
<span class="br0">&#125;</span></pre></div></div>

<p>We can then set up the bundle to index the fields of our entity. By choosing to use the integration with doctrine we can make this very simple:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            client: default
            types:
                site:
                    mappings:
                        name:
                        keywords:
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        provider:</pre></div></div>

<p>Whilst there are quite a few settings here it is fairly straight forward. The client just sets the port to use for the http communication. The bookmarks setting under indexes is the name of the index we will create. Within each index you can have types for each of your entity types, we just have the one type (site) here at the moment.</p>
<p>We have specified that we are using the ORM, the entity class and which fields to map, for now just the name and keywords (I will return to indexing in the url in my next post). That is enough to get any existing Sites stored in the database into the search index. Running the following console command will do this:</p>

<div class="wp_syntax"><div class="code"><pre class="php">php app<span class="sy0">/</span>console foq<span class="sy0">:</span>elastica<span class="sy0">:</span>populate</pre></div></div>

<p>It is as easy as that! All the sites already stored in the database are now indexed without the need for even writing any code, just a small amount of configuration. Great as that is, it would be even better if we could automatically index any new entities, as well as updating and removing entities as they are updated and removed from the database without having to rerun the console command. This is just as easy to achieve with only one extra item added to the configuration:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            client: default
            types:
                site:
                    mappings:
                        name:
                        keywords:
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        provider:
                        listener:</pre></div></div>

<p>This enables the bundle&#8217;s built in doctrine event listeners which will then do just that, keep the search index up to date with any changes we make to the entities, again without any additional code needed in typical CRUD controllers.</p>
<p>Before looking at searching the index there is one more bit of config which can be added to make integration easy:</p>

<div class="wp_syntax"><div class="code"><pre class="txt">foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        bookmarks:
            client: default
            types:
                site:
                    mappings:
                        name:
                        keywords:
                    doctrine:
                        driver: orm
                        model: LimeThinking\ExampleBundle\Entity\Site
                        provider:
                        listener:
                        finder:</pre></div></div>

<p>By adding the finder line we activate the support for returning the search results as Doctrine entities, so the bundle will do the work of fetching the relevant entities from the database after querying the elasticsearch index.</p>
<p>So how do we query the index? The bundle dynamically creates a service you can request from the container with the format <code>foq_elastica.finder.<em>index-name</em>.<em>type-name</em></code>. These match the values in our config, so the service we need is <code>foq_elastica.finder.bookmarks.site</code>. We can now issue queries using this service:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="co4">/**
* @Route(&quot;/sites/search/&quot;, name=&quot;site_search&quot;)
* @Method({ &quot;head&quot;, &quot;get&quot; })
* @Template
*/</span>
<span class="kw2">public</span> <span class="kw2">function</span> searchAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="re0">$finder</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'foq_elastica.finder.bookmarks.site'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$searchTerm</span> <span class="sy0">=</span> <span class="re0">$request</span><span class="sy0">-&gt;</span><span class="me1">query</span><span class="sy0">-&gt;</span><span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'search'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$sites</span> <span class="sy0">=</span> <span class="re0">$finder</span><span class="sy0">-&gt;</span><span class="me1">find</span><span class="br0">&#40;</span><span class="re0">$searchTerm</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'sites'</span> <span class="sy0">=&gt;</span> <span class="re0">$sites</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Elastica provides an OO query builder for creating more complicated queries but I will leave that for another day. Hopefully I have shown just how straightforward it is to get stated using elasticsearch with a Symfony2 app. As always, it is not limited to such simplicity and you can override these built in services to provide your own providers, finders and listeners if you have more complex requirements. </p>
]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2011/11/11/symfony2-integrating-elasticsearch/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Symfony2: Obtaining the Request Object</title>
		<link>http://richardmiller.co.uk/2011/10/26/symfony2-obtaining-the-request-object/</link>
		<comments>http://richardmiller.co.uk/2011/10/26/symfony2-obtaining-the-request-object/#comments</comments>
		<pubDate>Wed, 26 Oct 2011 15:00:16 +0000</pubDate>
		<dc:creator>miller</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dependency injection]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony2]]></category>

		<guid isPermaLink="false">http://miller.limethinking.co.uk/?p=724</guid>
		<description><![CDATA[In this quick post I am looking at how to obtain the Request object in a Symfony2 controller as a service. This is actually covered in the docs but in one of the earlier introductory pieces and so is easily missed or forgotten about by the time you actually need to know it. I know [...]]]></description>
			<content:encoded><![CDATA[<p>In this quick post I am looking at how to obtain the <code>Request</code> object in a <a href="http://symfony.com">Symfony2</a> controller as a service. This is actually covered in the docs but in one of the earlier <a href="http://symfony.com/doc/current/book/controller.html">introductory pieces</a> and so is easily missed or forgotten about by the time you actually need to know it. I know I missed this and have previously not shown the correct way to do this.</p>
<p>If you are extending the base controller then its <code>getRequest()</code> method will retrieve the <code>Request</code> object from the container. If you are making your <a href="http://symfony.com/doc/current/cookbook/controller/service.html">controllers services</a> then you will generally inject in the services, you would have requested from the container, to the constructor or via a setter method. This is not the correct way to work with the <code>Request</code> object as it has a <a href="http://symfony.com/doc/current/cookbook/service_container/scopes.html">narrower scope</a> than the controller. This basically means that the controller can be used for multiple requests whereas a <code>Request</code> object should only be used for the single request it represents. This means that a fresh request object should be injected each time an action of the controller is called rather than just when the controller is created. </p>
<p>The base controller uses its injected container to get a new <code>Request</code> object each time the action is called, so one way would be to inject the controller itself into the service. There are many reasons not do this which I have <a href="http://miller.limethinking.co.uk/2011/05/19/when-dependency-injection-goes-wrong/">covered elsewhere</a>. Fortunately there is a simple way to avoid having to do this, thanks to a cool feature of the framework; Symfony2 will automatically inject the Request object into your actions each time they are called, if you ask for it in the following way:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">use</span> Symfony\Component\HttpFoundation\Request<span class="sy0">;</span>
&nbsp;
<span class="co1">//--</span>
&nbsp;
<span class="kw2">public</span> <span class="kw2">function</span> someAction<span class="br0">&#40;</span>Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="co1">// ...</span>
<span class="br0">&#125;</span></pre></div></div>

<p>The key here is the type hint of <code>Symfony\Component\HttpFoundation\Request</code>, as long as this is in place the <code>Request</code> object will be injected in as a method argument. This avoids any scope issues without having to inject the container. This will work for controllers whether they are services or not and regardless of whether there are any other method arguments. So, for example, you can still combine this with <a href="http://symfony.com/doc/2.0/bundles/SensioFrameworkExtraBundle/annotations/converters.html">annotated parameter conversion</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span class="kw2">use</span> Symfony\Component\HttpFoundation\Request<span class="sy0">;</span>
<span class="kw2">use</span> ExampleBunlde\Entities\BlogPost<span class="sy0">;</span>
&nbsp;
<span class="co1">//--</span>
&nbsp;
 <span class="co4">/**
  * @ParamConverter
  */</span>
<span class="kw2">public</span> <span class="kw2">function</span> someAction<span class="br0">&#40;</span>BlogPost <span class="re0">$blogPost</span><span class="sy0">,</span> Request <span class="re0">$request</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="co1">// ...</span>
<span class="br0">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://richardmiller.co.uk/2011/10/26/symfony2-obtaining-the-request-object/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

