<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Joe Freeman&#039;s Weblog &#187; PHP</title>
	<atom:link href="http://joefreeman.co.uk/blog/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://joefreeman.co.uk/blog</link>
	<description>Musings on Software Development, etc</description>
	<lastBuildDate>Sat, 27 Mar 2010 15:16:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>A Java Swing Application for Testing PHP Snippets</title>
		<link>http://joefreeman.co.uk/blog/2009/11/a-java-swing-application-for-testing-php-snippets/</link>
		<comments>http://joefreeman.co.uk/blog/2009/11/a-java-swing-application-for-testing-php-snippets/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 16:34:44 +0000</pubDate>
		<dc:creator>Joe</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Swing]]></category>

		<guid isPermaLink="false">http://joefreeman.co.uk/blog/?p=210</guid>
		<description><![CDATA[I've put together an application that lets you test PHP snippets without having to save them to a file. This should be useful to testing out built-in functions and regular expressions amongst other things. There's also a built-in web server so you can see the results in your browser. The article talks through how I've put it together. There are links to download the application and it's source code.]]></description>
			<content:encoded><![CDATA[<p>I occasionally find myself needing to try out short chunks of PHP code. For example, to try out a regular expression, or to see how a built-in function behaves if it&#8217;s not documented very well. Creating a file, moving it to my web server&#8217;s document root, loading it up in the browser often seems too much trouble. So I&#8217;ve put together a simple application using Swing to make this easier.</p>
<h2>Overview of the Application</h2>
<p>Let me summarise the functionality of the application, incase you just want to try it out. The app allows you to enter PHP code and then execute it without having to save it to file. You see the results instantly in the bottom half of the window.</p>
<p>There is also a built-in, simple (single-threaded) web server. This means you can view the results of execution in your browser—again, without having to save the file.</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/11/php-snippet-tester.png" alt="php-snippet-tester" title="php-snippet-tester" width="500" height="497" class="aligncenter size-full wp-image-222" /></p>
<p>I&#8217;m going to explain some of the technical aspects of putting the app together. If you&#8217;re just interested in using the app, scroll down to the bottom of the post for the download link.</p>
<h2>Working with the Command Line from Java</h2>
<p>PHP can be run from the command line. Details about this are on the <a href="http://php.net/manual/en/features.commandline.php">PHP website</a>, but in short, if you run <code>php</code> with no arguments, then it will take in source code from the <a href="http://en.wikipedia.org/wiki/Standard_streams">standard input</a>, execute it, and print out the result.</p>
<p>This can be achieve programatically from within the Java environment:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Get the runtime object</span>
<span style="color: #003399;">Runtime</span> rt <span style="color: #339933;">=</span> <span style="color: #003399;">Runtime</span>.<span style="color: #006633;">getRuntime</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Run the command</span>
<span style="color: #003399;">Process</span> process <span style="color: #339933;">=</span> rt.<span style="color: #006633;">exec</span><span style="color: #009900;">&#40;</span>PHP_COMMAND<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Setup buffered input and output streams</span>
<span style="color: #003399;">BufferedReader</span> input <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">BufferedReader</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">InputStreamReader</span><span style="color: #009900;">&#40;</span>process.<span style="color: #006633;">getInputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003399;">BufferedWriter</span> output <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">BufferedWriter</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">OutputStreamWriter</span><span style="color: #009900;">&#40;</span>process.<span style="color: #006633;">getOutputStream</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Send the source code and close the stream (to make EOF)</span>
output.<span style="color: #006633;">write</span><span style="color: #009900;">&#40;</span>code<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
output.<span style="color: #006633;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Read in the result, line by line and print it to the console</span>
<span style="color: #003399;">String</span> line<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">while</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>line<span style="color: #339933;">=</span>input.<span style="color: #006633;">readLine</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>line<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Wait for the process to terminate (not really necessary, because the process will terminate once it has closed the input stream anyway)</span>
<span style="color: #000066; font-weight: bold;">int</span> result <span style="color: #339933;">=</span> process.<span style="color: #006633;">waitFor</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Note that <code>rt.exec(...)</code> and <code>process.waitFor()</code> can both potentially throw exceptions—<code>IOException</code> and <code>InterruptedException</code> respectively—which must be dealt with.</p>
<p>We could get the standard error stream aswell—using the same approach as with the output stream—but PHP doesn&#8217;t send anything to the error stream, so we don&#8217;t need to worry about it. If we wanted to do this, we&#8217;d need to read both streams in separate threads.</p>
<h2>Building the Swing User Interface</h2>
<p>Let&#8217;s look at how to setup the user interface. I&#8217;ll talk through a simplified version of the final application. We&#8217;ll look at a few of the Swing components individually.</p>
<h3><code>JFrame</code></h3>
<p>We&#8217;re going to make use of the <code>JFrame</code> class as our base. A common practice is to extend this class with your own, however, generally a more practical approach is to encapsulate the <code>JFrame</code> object by keeping track of the <code>JFrame</code> as a property within your class, and exposing methods as necessary.</p>
<p>We create a <code>JFrame</code>, set a layout (refer to the next section), a preferred size, the behaviour to associate with the window&#8217;s &#8216;close&#8217; button, pack it (to make sure the components get arranged properly) and then finally make the frame visible to the user:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">frame <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">JFrame</span><span style="color: #009900;">&#40;</span>FRAME_TITLE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
frame.<span style="color: #006633;">setLayout</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">BorderLayout</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
frame.<span style="color: #006633;">setPreferredSize</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Dimension</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">500</span>, <span style="color: #cc66cc;">500</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
frame.<span style="color: #006633;">setDefaultCloseOperation</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">JFrame</span>.<span style="color: #006633;">EXIT_ON_CLOSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Add components to the frame here</span>
&nbsp;
frame.<span style="color: #006633;">pack</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
frame.<span style="color: #006633;">setVisible</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3><code>BorderLayout</code></h3>
<p>Once the <code>JFrame</code> has been setup, we&#8217;ll use a <code>BorderLayout</code> to arrange our components on the window. Border layouts are a fairly common concept in user interface design. One component can be attached to each of five regions. Each region defines the position that the component appears at, and how its size changes as the parent component is resized. Border layouts can be nested within each other. The regions are:</p>
<ul>
<li><strong>PAGE_START</strong> &#8211; generally at the top of the page, resizes to fill the width of the parent component.</li>
<li><strong>PAGE_END</strong> &#8211; opposite side to PAGE_START.</li>
<li><strong>LINE_START</strong> &#8211; generally on the left of the page (but actually dependent on the user&#8217;s language), resizes to fill the height of the parent minus the height of any components at PAGE_START and PAGE_END.</li>
<li><strong>LINE_END</strong> &#8211; opposite side to LINE_END.</li>
<li><strong>CENTER</strong> &#8211; the remaining space in the middle of the layout, resizes to fill the available space.</li>
</ul>
<p>See the example below, which shows the positioning of the components:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/11/border-layout.png" alt="border-layout" title="border-layout" width="500" height="314" class="aligncenter size-full wp-image-213" /></p>
<h3><code>JSplitPane</code></h3>
<p>For our user interface we will divide the window into two: the top half for editing the PHP code, and the bottom half for viewing the results of the execution. We will allow the user to move the separator between the two components using a <code>JSplitPane</code>.</p>
<p>Using a <code>JSplitPane</code> is fairly straight forward. Pass each of the two components you&#8217;re splitting into the constructor, along with a specified orientation (either <code>VERTICAL_SPLIT</code> or <code>HORIZONTAL_SPLIT</code>). The location of the divider can also be given.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">JSplitPane</span> splitPane <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">JSplitPane</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">JSplitPane</span>.<span style="color: #006633;">VERTICAL_SPLIT</span>, inputPanel, outputPanel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
splitPane.<span style="color: #006633;">setDividerLocation</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3><code>JTextArea</code> and <code>JScrollPane</code></h3>
<p>Both the editor and the area for displaying execution results will be based on <code>JTextArea</code>s. On their own, these components don&#8217;t support scrolling (e.g., for when there are more lines of text than will fit in the component). To support scrolling, we need to wrap them with <code>JScrollPane</code>s.</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">JScrollPane</span> inputScrollPane <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">JScrollPane</span><span style="color: #009900;">&#40;</span>inputBox<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3><code>JButton</code> and <code>Action</code>s</h3>
<p>When the user wants to execute their code, they will click on an &#8216;Execute&#8217; button (which will be a <code>JButton</code>). There are a few ways to handle button clicks in Swing. One such method is to define an <code>Action</code> that will be associated with the button. This is a nice way to separate logic from the design of the user interface.</p>
<p>A button can be created like this:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #003399;">JButton</span> executeButton <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">JButton</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> ExecuteAction<span style="color: #009900;">&#40;</span>inputBox, outputBox<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The easiest way to create the action is to extend from <code>AbstractAction</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ExecuteAction <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #003399;">AbstractAction</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">JTextArea</span> inputBox<span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">JTextArea</span> outputBox<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> ExecuteAction<span style="color: #009900;">&#40;</span><span style="color: #003399;">JTextArea</span> inputBox, <span style="color: #003399;">JTextArea</span> outputBox<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Save these components for later</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">inputBox</span> <span style="color: #339933;">=</span> inputBox<span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">outputBox</span> <span style="color: #339933;">=</span> outputBox<span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Set the name of the button</span>
        putValue<span style="color: #009900;">&#40;</span><span style="color: #003399;">AbstractAction</span>.<span style="color: #006633;">NAME</span>, <span style="color: #0000ff;">&quot;Execute&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> actionPerformed<span style="color: #009900;">&#40;</span><span style="color: #003399;">ActionEvent</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Event will be handled here</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Any objects that the action needs to access get passed to the constructor, and stored as properties of the action for use later. In this case, we&#8217;ll want to be able to get the source code from the input box and then put the result into the output box.</p>
<h2>Putting Together the <code>PhpRunner</code> Class</h2>
<p>We will put our earlier PHP-running code into it&#8217;s own class and package (<code>runner.PhpRunner</code>). The class will be constructed with two parameters:</p>
<ul>
<li>The PHP code to be run</li>
<li>An event listener (an object implementing the <code>OutputConsumer</code> interface)</li>
</ul>
<p>The <code>execute()</code> method can then be called. This will start the execution, and notify the event listener every time we get a new line of output back. This approach means that if a PHP script takes a long time to complete, we&#8217;ll be able to see the output as it happens, rather than having to wait for the whole script to finish executing.</p>
<p>The code is similar to the code at the top of the post, so I won&#8217;t paste it again. I have added calls to the event listener though. Refer to the source code if you&#8217;re interested.</p>
<h2>Threads and Thread Safety</h2>
<p>Introducing threads into a Swing application can be dangerous, since <strong>Swing&#8217;s components are not thread safe</strong>. Only one thread should be allowed to access the Swing components at any one time—this is known as the <em>event-dispatching thread</em> (EDT).</p>
<p>However, we don&#8217;t want the user interface to freeze whilst the PHP code is being executed, so it&#8217;s important that we don&#8217;t wait for output from within the EDT. The swing library provides a <a href="http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html"><code>SwingWorker</code></a> class, which makes working with threads a bit easier and safer. Fortunately, our <code>PhpRunner</code> fits nicely into this pattern. A cut-down version of the code looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">new</span> SwingWorker<span style="color: #339933;">&lt;</span>String, String<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #003399;">String</span> doInBackground<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Setup the PHP runner, and listen for any lines of output</span>
        PhpRunner runner <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PhpRunner<span style="color: #009900;">&#40;</span>code, <span style="color: #000000; font-weight: bold;">new</span> OutputConsumer<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            @Override
            <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> output<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> line<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #666666; font-style: italic;">// Let the SwingWorker know there are more lines</span>
                publish<span style="color: #009900;">&#40;</span>line<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Execute, and return the result</span>
        <span style="color: #000000; font-weight: bold;">return</span> runner.<span style="color: #006633;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> process<span style="color: #009900;">&#40;</span>List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> chunks<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Add any output to the output box</span>
        <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> chunk <span style="color: #339933;">:</span> chunks<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            outputBox.<span style="color: #006633;">append</span><span style="color: #009900;">&#40;</span>chunk <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    @Override
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> done<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// The operation has completed</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>.<span style="color: #006633;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>Adding a Built-in Web Server</h2>
<p>Sometimes it&#8217;s useful to be able to test the PHP output in a web browser. So we will add a very basic web server to the application. The user will be able to request execution of the code by loading a URL in their web browser.</p>
<p>First of all, we need to add a button to the user interface to allow the user to manually start and stop the web server. When the associated action is performed, we will either create a new HTTP server object, or stop an existing one.</p>
<p>The HTTP server doesn&#8217;t need to be very complicated at all. We don&#8217;t have to handle POST requests (just GET and HEAD requests) or even URLs since all requests to the server will execute the same script. We also only need to handle one request at a time—so the server can happily run on a single thread.</p>
<p>I don&#8217;t want to go into details of the server implementation here, but it&#8217;s worth nothing that this use of a web server does bring up the slightly unconventional approach of trying to get the contents of a Swing component from outside the EDT:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> value <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&quot;&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003399;">SwingUtilities</span>.<span style="color: #006633;">invokeAndWait</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Runnable</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            value<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> inputBox.<span style="color: #006633;">getText</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Exception</span> e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// Do nothing</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">return</span> value<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The <code>value</code> variable must be declared final, since it&#8217;s accessed from a different thread. However, we want to be able to update the value, so the use of a single-element array is a bit of a hack to bypass the compiler&#8217;s warnings. A more elegant solution to this might involve wrapping the method in it&#8217;s own class, and using a class property instead of a final variable.</p>
<h2>Saving User Settings with the Preferences API</h2>
<p>Java provides an API that makes it very straight-forward to store and retrieve user preferences. These are used in our application to save a number of different parameters:</p>
<ul>
<li>The position and location of the window on the screen.</li>
<li>The position of the resizable split pane.</li>
<li>The last-used PHP code.</li>
<li>The specified font size.</li>
<li>The directory of the last file that was loaded.</li>
</ul>
<p>We can wrap the <code>Preferences</code> class in our own <code>Settings</code> class, which provides methods to get the required properties. Attaching a <code>WindowListener</code> to our <code>JFrame</code> means that we can attempt to save the settings when the application is closed.</p>
<h2>Conclusions</h2>
<p>I ended up making a few more changes to the application to those mentioned above. The buttons that are referred to above have been move to the menu bar (which was easy to do, since I was using <code>Action</code>s), and have associated keyboard shortcuts which make the application much easier to use. It&#8217;s now also possible to load files from disk, change the font size of the input and output boxes. I&#8217;ve also added a status bar which shows status messages for a period of time, and a &#8216;preferences&#8217; dialog which allows you to change the PHP command path and the web server port.</p>
<p>If the implementation of any of these features interests you, I suggest you download the source code to have a look.</p>
<p>To get a grasp of the structure of the project, the layout below may help:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/11/project-layout.png" alt="project-layout" title="project-layout" width="269" height="572" class="aligncenter size-full wp-image-230" /></p>
<p>I&#8217;m very pleased with the final product. The application&#8217;s concept is simple, but I think it adheres well to the <a href="http://en.wikipedia.org/wiki/Unix_philosophy">&#8220;do one thing and do it well&#8221;</a> philosophy.</p>
<p>I&#8217;ve also made a few minor tweaks to the application that will affect Mac users: moving the menu bar to the top of the screen, and setting the application&#8217;s title.</p>
<h2>Download</h2>
<p>If you&#8217;d like to download the application to give it a try yourself, or if you&#8217;d like to download the source code in its entirety, use the links below:</p>
<ul>
<li><a href="http://joefreeman.co.uk/blog/wp-content/uploads/2009/11/PHPTester.jar">Download application (packaged as a .jar file)</a></li>
<li><a href="http://joefreeman.co.uk/blog/wp-content/uploads/2009/11/php-tester-src.zip">Download source code (.zip archive)</a></li>
</ul>
<p>If you do try out the application, please let me know what you think.</p>
<h3>Requirements</h3>
<p>The application requires that you have both Java (version 1.6—although 1.5 might work) and PHP installed. The PHP executable must be accessible on your &#8216;path&#8217;. I have tested this on OS X and on a vanilla install of Vista (after installing Java and PHP).</p>
]]></content:encoded>
			<wfw:commentRss>http://joefreeman.co.uk/blog/2009/11/a-java-swing-application-for-testing-php-snippets/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>FULLTEXT Search with MySQL and CodeIgniter</title>
		<link>http://joefreeman.co.uk/blog/2009/10/fulltext-search-with-mysql-and-codeigniter/</link>
		<comments>http://joefreeman.co.uk/blog/2009/10/fulltext-search-with-mysql-and-codeigniter/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 10:17:27 +0000</pubDate>
		<dc:creator>Joe</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://joefreeman.co.uk/blog/?p=187</guid>
		<description><![CDATA[This article demonstrates how to use MySQL's FULLTEXT search feature from within CodeIgniter with a sample search application. It highlights a few of CodeIgniter's features such as the MVC pattern, pagination, custom configuration, custom helpers and profiling.]]></description>
			<content:encoded><![CDATA[<p>I was required to use CodeIgniter for a project recently. I&#8217;m generally not a big fan of the framework, but I have grown to like aspects of it. A lot of people seem to praise the documentation, the mass of examples and the active community. Maybe my hopes were set too high, but I was disappointed with all of these.</p>
<p>The thing I like about using a framework is <em>being told</em> how to do things, but for many the big attraction to CodeIgniter seems to be that it&#8217;s lightweight and you can do things how you like. I think this is the reason for the inconsistencies and low quality of example code. So I thought that I&#8217;d put together an article and example project showing a few of the tricks I&#8217;ve learnt, and <em>my</em> preferred CodeIgniter style.</p>
<p>I&#8217;m going to put together a simple application which shows off the search capabilities of MySQL, whilst exploring some of CodeIgniter&#8217;s features.</p>
<h2>Getting CodeIgniter Ready</h2>
<p>This is pretty basic stuff. <a href="http://codeigniter.com/downloads/">Download</a>, unzip, and dump the files somewhere into your web server&#8217;s directory. Setup a MySQL database and associated user and fill in the connection details in <code>application/config/database.php</code>.</p>
<p>Open up <code>application/config/config.php</code> and edit the <code>base_url</code> setting. This needs to be the web-visible URL to the directory that you put the CodeIgniter files into. If you did put them into your local web server&#8217;s root directory, this may be as simple as &#8216;http://localhost/&#8217;.</p>
<h2>Setting Up the Database</h2>
<p>You should already have a database setup, but we need a table to store the data. I&#8217;ve created a simple &#8216;pages&#8217; table. To make use of MySQL&#8217;s FULLTEXT search capabilities, you must setup an index on any fields that you want to be searchable. See the the SQL below:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> pages <span style="color: #66cc66;">&#40;</span>
  id int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
  url text <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  title text <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  content text <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  updated datetime <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
  FULLTEXT <span style="color: #993333; font-weight: bold;">KEY</span> content <span style="color: #66cc66;">&#40;</span>content<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE<span style="color: #66cc66;">=</span>MyISAM</pre></div></div>

<p>I&#8217;ve setup an index on the &#8216;content&#8217; field so that it will be searchable. Note also that FULLTEXT search is only available when using the MyISAM engine.</p>
<h2>Some Test Data</h2>
<p>In order to perform a decent evaluation of the searching mechanism, I realised that I would need some substantial data. I decided Wikipedia would make a good source of this data. Rather than export all three million articles, I limited myself to about two thousand of the <a href="http://en.wikipedia.org/wiki/Wikipedia:Featured_articles">featured articles</a>. I setup a script to scrape the list of featured articles and then used the Wikipedia <a href="http://en.wikipedia.org/wiki/Special:Export">export</a> feature to automatically copy across all the data into my database.</p>
<p>After over-coming an issue with the character encoding it soon because obvious that the Wikipedia markup wasn&#8217;t quite the format that I wanted. Hacking together a few regular expressions meant I could strip most of this out, leaving plain and readable content.</p>
<h2>Searching the Data</h2>
<p>At this point, the magic SQL to use takes the form: <code>MATCH (columns) AGAINST ('terms')</code>. Note that when <code>MATCH ... AGAINST</code> is used in the <code>WHERE</code> clause, the results are automatically sorted, so there&#8217;s no need to add an <code>ORDER BY</code> clause. An example:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span>
<span style="color: #993333; font-weight: bold;">FROM</span> pages
<span style="color: #993333; font-weight: bold;">WHERE</span> MATCH <span style="color: #66cc66;">&#40;</span>content<span style="color: #66cc66;">&#41;</span> AGAINST <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'test'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span></pre></div></div>

<p>There are a few FULLTEXT gotchas you should be aware of:</p>
<ul>
<li>Something that I was stung by: if you have fewer than three rows of data, you won&#8217;t get any search results back.</li>
<li>Search strings have a minimum length. This is generally three or four characters, but depends on configuration. See below.</li>
<li>There is a collection of &#8216;<a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-stopwords.html">stopwords</a>&#8216; that MySQL will ignore (words like &#8216;the&#8217;, &#8216;however&#8217;, &#8216;hello&#8217;). If you try a search for any of these, you won&#8217;t get any results back.</li>
</ul>
<p>You can find out some of the configuration details by executing <code>SHOW VARIABLES LIKE  'ft%'</code>. You should get something like this:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/10/mysql-variables.png" alt="mysql-variables" title="mysql-variables" width="210" height="96" class="aligncenter size-full wp-image-203" /></p>
<p>A few different &#8216;modes&#8217; are available for searching. By default, a <a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-natural-language.html">natural language</a> search is performed. A boolean search is also possible, and allows a number of powerful operators to be used &#8211; refer to the <a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-boolean.html">documentation</a> for details.</p>
<p>It is also possible to use <a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-query-expansion.html">query expansion</a>. This roughly means that the search may return items where the search terms aren&#8217;t actually in the content, but instead there are words that are deemed similar. This is achieved by performing two searches. Where the second search uses content from high-ranking rows in the first search to perform the second search. This only tends to work well for short queries, otherwise less-relevant results will be returned.</p>
<p>More details on the full-text functionality can be found in the <a href="http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html">MySQL documentation</a>.</p>
<h2>CodeIgniter and the MVC Pattern</h2>
<p>Let us return our attention to CodeIgniter&#8230;</p>
<p>The framework takes advantage of the ever-popular model-view-controller (MVC) pattern. Everyone knows you&#8217;re supposed to separate your domain-logic from presentation code, but the nice thing about the MVC pattern is that it&#8217;s constantly there to remind you.</p>
<p>I stick to a few basic rules:</p>
<ul>
<li>you can only touch the database from within the model</li>
<li>nothing should be echo-ed from the controller (or the model)</li>
<li>only one statement can appear inside each set of &lt;?php-tags and it should generally be either en echo or a control structure (use the <a href="http://php.net/manual/en/control-structures.alternative-syntax.php">alternative syntax</a>)</li>
</ul>
<p>If you find yourself breaking any of these rules, it&#8217;s probably a sign that it&#8217;s time to step back and re-think what you&#8217;re trying to achieve.</p>
<p>Let&#8217;s start off with the model. I only have one method here, which performs the searching. You may note that I&#8217;m using raw SQL here rather than using CodeIgniter&#8217;s Active Record implementation. This is just a personal preference &#8211; I think the CodeIgniter implementation is a bit messy compared to something <a href="http://www.phpactiverecord.org/">more RoR-like</a>.</p>
<p>The following code needs to go into <code>application/models/page_model.php</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Page_model <span style="color: #000000; font-weight: bold;">extends</span> Model
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">function</span> Page_model<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        parent<span style="color: #339933;">::</span><span style="color: #004000;">Model</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Make the database available to all the methods</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">database</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Execute our SQL statement and return the result</span>
        <span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT url, title
                    FROM pages
                    WHERE MATCH (content) AGAINST (?) &gt; 0&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #339933;">,</span> <span style="color: #000088;">$terms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Next up is the view. Note that I&#8217;m religiously using the form helpers. This needs to go into <code>application/views/search_results.php</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">helper</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_open<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">uri</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">uri_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_label<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Search:'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'search-box'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_input<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'q'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'search-box'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'value'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_submit<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Search'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_close<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;ul&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
            &lt;li&gt;&lt;a href=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/a&gt;&lt;/li&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endforeach</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;/ul&gt;
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">else</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;p&gt;&lt;em&gt;There are no results for your query.&lt;/em&gt;&lt;/p&gt;
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Finally, pulling both the model and view together with the controller. The following code should go into <code>application/controllers/pages.php</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Pages <span style="color: #000000; font-weight: bold;">extends</span> Controller <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// If the form has been submitted, rewrite the URL so that the search</span>
        <span style="color: #666666; font-style: italic;">// terms can be passed as a parameter to the action. Note that there</span>
        <span style="color: #666666; font-style: italic;">// are some issues with certain characters here.</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">post</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'q'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            redirect<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/pages/search/'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">post</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'q'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// Load the model and perform the search</span>
            <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">model</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'page_model'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">page_model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Render the view, passing it the necessary data</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">view</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search_results'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'search_terms'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$search_terms</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'results'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">@</span><span style="color: #000088;">$results</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>At the beginning of the method, there is a reference to a <code>redirect</code> function. This is a helper function, and it&#8217;s part of the &#8216;url&#8217; group of helper functions. To use it, we could load the helper manually using: <code>$this->load->helper('url');</code>. However, because this group of helper functions is quite commonly used, we can load them automatically. To do this, we need to edit the <code>application/config/autoload.php</code> file:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$autoload</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'helper'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'url'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>We should now have a working prototype. Make sure you have some data in your database (remember, at least three rows). Then steer your browser to the relevant URL, which should be something like: &#8216;http://localhost/index.php/pages/search&#8217;, enter some text to search (something that you know is in the database) and hit the &#8216;Search&#8217; button.</p>
<p>You should get something like this:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/10/screenshot-1.png" alt="screenshot-1" title="screenshot-1" width="500" height="505" class="aligncenter size-full wp-image-191" /></p>
<h2>Adding More Features</h2>
<p>To show off a bit more of CodeIgniter, I&#8217;ll add a few more features, including pagination, custom configuration files and custom helpers.</p>
<p>The CodeIgniter user guide boasts that the pagination class is &#8220;100% customizable&#8221;. I wouldn&#8217;t go that far, but you can certainly change a few things.</p>
<p>First of all, we need to modify our model so that it only returns a portion of the results, and also so that we can find out how many results in total our query would return.</p>
<p>The first problem is easily solved by adding an argument to the method, and a <code>LIMIT</code> to our SQL query. For the second problem, there are a few solutions, none of which seem very elegant:</p>
<ul>
<li>We can add a separate method to the model, which will return the total number of results. This means that generally we will always have to call both routines. Certainly not a disaster, but it just doesn&#8217;t seem very refined.</li>
<li>Alternatively, we can calculate this count from within our &#8217;search&#8217; method, and return both a collection of results and the total count together in some form of array structure. This is a bit abusive of the only-return-one thing methodology.</li>
<li>Or, we can pass a reference parameter to the method, set the value inside the method, and then access this variable from the controller. I think this works quite nicely because it&#8217;s discrete, but possibly a bit too subtle to be obvious to other developers.</li>
</ul>
<p>To keep things simple, I&#8217;m going to go with the first option. Let&#8217;s refactor the model:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Page_model <span style="color: #000000; font-weight: bold;">extends</span> Model <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Constructor as before</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #339933;">,</span> <span style="color: #000088;">$start</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$results_per_page</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Determine whether we need to limit the results</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results_per_page</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$limit</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;LIMIT <span style="color: #006699; font-weight: bold;">$start</span>, <span style="color: #006699; font-weight: bold;">$results_per_page</span>&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$limit</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Execute our SQL statement and return the result</span>
        <span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT url, title, content
                    FROM pages
                    WHERE MATCH (content) AGAINST (?) &gt; 0
                    <span style="color: #006699; font-weight: bold;">$limit</span>&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #339933;">,</span> <span style="color: #000088;">$terms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> count_search_results<span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Run SQL to count the total number of search results</span>
        <span style="color: #000088;">$sql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT COUNT(*) AS count
                    FROM pages
                    WHERE MATCH (content) AGAINST (?)&quot;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sql</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$terms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">row</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Note that I&#8217;m also returning the &#8216;content&#8217; field in the SQL &#8211; this will be useful later. The next thing to do is to modify our controller. We need to load and initialise the pagination library. Here&#8217;s the modified &#8217;search&#8217; method:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Pages <span style="color: #000000; font-weight: bold;">extends</span> Controller <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> search<span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$start</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// If the form has been submitted, rewrite the URL so that the search</span>
        <span style="color: #666666; font-style: italic;">// terms can be passed as a parameter to the action. Note that there</span>
        <span style="color: #666666; font-style: italic;">// are some issues with certain characters here.</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">post</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'q'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            redirect<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/pages/search/'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">input</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">post</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'q'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">// Determine the number of results to display per page</span>
            <span style="color: #000088;">$results_per_page</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">item</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'results_per_page'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">// Load the model, perform the search and establish the total</span>
            <span style="color: #666666; font-style: italic;">// number of results</span>
            <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">model</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'page_model'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">page_model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #339933;">,</span> <span style="color: #000088;">$start</span><span style="color: #339933;">,</span> <span style="color: #000088;">$results_per_page</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$total_results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">page_model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count_search_results</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">// Call a method to setup pagination</span>
            <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_setup_pagination<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/pages/search/'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$search_terms</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$total_results</span><span style="color: #339933;">,</span> <span style="color: #000088;">$results_per_page</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">// Work out which results are being displayed</span>
            <span style="color: #000088;">$first_result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$start</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$last_result</span> <span style="color: #339933;">=</span> <span style="color: #990000;">min</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$start</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$results_per_page</span><span style="color: #339933;">,</span> <span style="color: #000088;">$total_results</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Render the view, passing it the necessary data</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">view</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search_results'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'search_terms'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$search_terms</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'first_result'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">@</span><span style="color: #000088;">$first_result</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'last_result'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">@</span><span style="color: #000088;">$last_result</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'total_results'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">@</span><span style="color: #000088;">$total_results</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'results'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #339933;">@</span><span style="color: #000088;">$results</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">function</span> _setup_pagination<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #339933;">,</span> <span style="color: #000088;">$total_results</span><span style="color: #339933;">,</span> <span style="color: #000088;">$results_per_page</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">// Ensure the pagination library is loaded</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">library</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'pagination'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// This is messy. I'm not sure why the pagination class can't work</span>
        <span style="color: #666666; font-style: italic;">// this out itself...</span>
        <span style="color: #000088;">$uri_segment</span> <span style="color: #339933;">=</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">explode</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Initialise the pagination class, passing in some minimum parameters</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pagination</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">initialize</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'base_url'</span> <span style="color: #339933;">=&gt;</span> site_url<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'uri_segment'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$uri_segment</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'total_rows'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$total_results</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'per_page'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$results_per_page</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Let&#8217;s look at the changes we&#8217;ve made&#8230;</p>
<p>We have added an extra argument to the method. This means the URL will have another (optional) segment to it. It will be a number representing the record that we are starting on, and will get set automatically by the pagination code.</p>
<p>In order to determine the number of results to show on a page at a time, I have used the <a href="http://codeigniter.com/user_guide/libraries/config.html">config library</a>. In order to setup custom configuration for your application, it&#8217;s best to add a new file to the <code>application/config</code> directory, then set it to be autoloaded. Edit the <code>application/config/autoload.php</code> file again, and add &#8216;application&#8217; to the <code>$autoload['config']</code> array. Then create the <code>application/config/application.php</code> file, and put the following line in it:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$config</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'results_per_page'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">;</span></pre></div></div>

<p>The next change we have made is to setup the pagination. I have put this code into a separate method. Note that the method name is prefixed with an underscore. This prevents the private method being called as an action on the controller. The code here is fairly self-explanatory.</p>
<p>We also pass some extra information over to our view. Which leads us to our next task of updating the view. But first, we will write our own custom helper functions for use within the view. These go into <code>application/helpers/search_helper.php</code>. The first function &#8211; <code>search_highlight($text, $search_terms)</code> &#8211; provides a way to highlight search terms in a string (there is a similar CodeIgniter helper, but it doesn&#8217;t quite do what we want). The second function &#8211; <code>search_extract($content, $search_terms, $number_of_snippets = 3, $snippet_length = 60)</code> &#8211; is a flaky attempt to generate an &#8216;excerpt&#8217; to accompany each result. An excerpt is made up of a number of &#8217;snippets&#8217; which should each contain at least one of the search terms. I won&#8217;t paste the code here since it&#8217;s far from elegant, but it&#8217;s available in the download.</p>
<p>Finally, the updated view. Note that we have to manually load the helper before using the helper functions. The pagination links are created using the <code>create_links</code> method.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">helper</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'search'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_open<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">uri</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">uri_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_label<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Search:'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'search-box'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_input<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'q'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'search-box'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'value'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_submit<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Search'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> form_close<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
        &lt;p&gt;Showing search results for '<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$search_terms</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>' (<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$first_result</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&amp;ndash;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$last_result</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span> of <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$total_results</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>):&lt;/p&gt;
&nbsp;
        &lt;ul&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$result</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
            &lt;li&gt;&lt;a href=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> search_highlight<span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span><span style="color: #339933;">,</span> <span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/a&gt;&lt;br /&gt;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> search_extract<span style="color: #009900;">&#40;</span><span style="color: #000088;">$result</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">content</span><span style="color: #339933;">,</span> <span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/li&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endforeach</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;/ul&gt;
&nbsp;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pagination</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">create_links</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">else</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;p&gt;&lt;em&gt;There are no results for your query.&lt;/em&gt;&lt;/p&gt;
    <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Here&#8217;s the result of trying it out in the browser again:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/10/screenshot-2.png" alt="screenshot-2" title="screenshot-2" width="500" height="605" class="aligncenter size-full wp-image-193" /></p>
<h2>Evaluation</h2>
<p>CodeIgniter comes with <a href="http://codeigniter.com/user_guide/libraries/benchmark.html">benchmarking</a> and <a href="http://codeigniter.com/user_guide/general/profiling.html">profiling</a> features. We can mark points in the execution, enable profiling, and have them have them output to the browser. For example, I might add marks around the calls to the model:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Mark the start of search</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">benchmark</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">mark</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search_start'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Load the model, perform the search and establish the total</span>
<span style="color: #666666; font-style: italic;">// number of results</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">model</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'page_model'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">page_model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #339933;">,</span> <span style="color: #000088;">$start</span><span style="color: #339933;">,</span> <span style="color: #000088;">$results_per_page</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$total_results</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">page_model</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count_search_results</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$search_terms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Mark the end of search</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">benchmark</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">mark</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'search_end'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The output at the bottom of the page would look something like this:</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/10/profiling.png" alt="profiling" title="profiling" width="500" height="480" class="aligncenter size-full wp-image-196" /></p>
<p>We can see that the search on 1800 rows took 0.0138 seconds. This is 49% of the total execution time.</p>
<p>It is also possible to measure the time it takes to render the view by putting marks in the controller on either side of the <code>$this->load->view(...)</code> call. The view takes about 0.007 seconds to load. Without the generation of a page extract, it takes significantly less time: 0.002 seconds.</p>
<h2>Download</h2>
<p>I have packaged up the code for this example. Feel free to <a href="http://joefreeman.co.uk/blog/wp-content/uploads/2009/10/fulltext-search-with-mysql-and-codeigniter.zip">download</a> it.</p>
<h2>Other Search Solutions</h2>
<p>There are, of course, other search solutions available. Two such popular projects are <a href="http://www.sphinxsearch.com/">Sphinx</a> and <a href="http://lucene.apache.org/java/docs/">Lucene</a>. However, getting them compiled, installed and running doesn&#8217;t appear to be any simple task.</p>
]]></content:encoded>
			<wfw:commentRss>http://joefreeman.co.uk/blog/2009/10/fulltext-search-with-mysql-and-codeigniter/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>PHP Script to Compare MySQL Database Schemas</title>
		<link>http://joefreeman.co.uk/blog/2009/07/php-script-to-compare-mysql-database-schemas/</link>
		<comments>http://joefreeman.co.uk/blog/2009/07/php-script-to-compare-mysql-database-schemas/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 19:40:46 +0000</pubDate>
		<dc:creator>Joe</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://joefreeman.co.uk/blog/?p=110</guid>
		<description><![CDATA[A brief description of the process involved in determining the schema of a MySQL database, and an accompanying tool, which will compare schemas of databases. The tool is able to compare databases that reside on separate hosts. This may be a useful tool for checking that databases have the same schema when deploying an application to separate hosts.]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>I&#8217;ve been working on a project recently that has a rather messy deployment strategy. This resulted in a minor glitch occurring during a recent deployment to a fairly high-profile site when a database table wasn&#8217;t updated.</p>
<p>Clearly the best solution to this problem would be to come up with a better deployment strategy, which is something we have been looking into. However, the problem has inspired me to write a small tool which collects information on the schema of a database so that it can be compared with other databases.</p>
<p>A slight twist to the problem comes from the requirement that the databases are more than likely to be hosted on different servers. Since the database servers are setup to only allow connections locally, we aren&#8217;t able to access both databases at the same time. Additionally, some of these servers are running PHP 4, so are lacking some newer PHP features.</p>
<h2>Fetching Schema Information from MySQL</h2>
<p>The MySQL queries to get information about tables are fairly straight-forward.</p>
<p>To get a list of the tables in a database, we can do:</p>

<div class="wp_syntax"><div class="code"><pre class="mysql" style="font-family:monospace;"><span style="color: #990099; font-weight: bold;">SHOW</span> <span style="color: #990099; font-weight: bold;">TABLES</span></pre></div></div>

<p>To get information about the fields in a specific table, we can do:</p>

<div class="wp_syntax"><div class="code"><pre class="mysql" style="font-family:monospace;"><span style="color: #990099; font-weight: bold;">SHOW</span> <span style="color: #990099; font-weight: bold;">COLUMNS</span> <span style="color: #990099; font-weight: bold;">FROM</span> table_name</pre></div></div>

<p>This returns a collection of information on each field:</p>
<ul>
<li>the names of fields,</li>
<li>the data type,</li>
<li>whether null values can be stored,</li>
<li>whether the column is indexed,</li>
<li>the default value of the field, and</li>
<li>whether the field uses <code>auto_increment</code></li>
</ul>
<p>Full details can be found on the <a href="http://dev.mysql.com/doc/refman/5.0/en/show-columns.html">manual page</a>.</p>
<h2>The PHP Script</h2>
<p>The tool consists of:</p>
<ul>
<li>a simple class for extracting the schema and performing the comparison between extracted schemas</li>
<li>a user interface to the class</li>
</ul>
<p>Since we need to be able to access databases on different hosts, the solution I am using is to serialise the schema information and give it back to the user. The user is then required to copy and paste this data from separate instances back into a form so that the comparison can be performed.</p>
<p>The user interface provides the user with a list of pre-configured databases to choose from, and also allows the user to enter connection details in the form. Arguably, the first option is more convenient and more secure.</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/options.png" alt="options" title="options" width="500" height="332" class="aligncenter size-full wp-image-117" /></p>
<p>The actual comparison of schemas works on three levels:</p>
<ol>
<li>We check both databases have the same tables</li>
<li>For each table, we check that the same fields are present</li>
<li>For each field, we check that the field&#8217;s parameters are the same</li>
</ol>
<p>Any discrepancies are then displayed to the user on a per-table basis.</p>
<p><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/comparison.png" alt="comparison" title="comparison" width="500" height="245" class="aligncenter size-full wp-image-116" /></p>
<h2>Download this Tool</h2>
<p>If you have a use for this tool, or are just interested to see how it works, feel free to <a href="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/php-script-to-compare-mysql-database-schemas.zip">download the code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://joefreeman.co.uk/blog/2009/07/php-script-to-compare-mysql-database-schemas/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Stock Quotes with Ext JS Charts</title>
		<link>http://joefreeman.co.uk/blog/2009/07/stocks-with-ext-js-charts/</link>
		<comments>http://joefreeman.co.uk/blog/2009/07/stocks-with-ext-js-charts/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 23:02:01 +0000</pubDate>
		<dc:creator>Joe</dc:creator>
				<category><![CDATA[Ext JS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://joefreeman.co.uk/blog/?p=4</guid>
		<description><![CDATA[An example to display stock indexes in an Ext JS chart. Including an introduction to Ext JS, a simple introductory Ext JS example and an introduction to the new charts feature. Concludes with a more comprehensive demo, showing some more of Ext's features.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll keep the introduction to <a href="http://extjs.com">Ext JS</a> brief, and then give a short primer to using Ext. Skip to the charts section if you&#8217;re already familiar with Ext. Or skip straight to the end if you just want to see the final demo.</p>
<p>Ext JS is yet another JavaScript library. However the emphasis is on UI widgets that allow you to build user interfaces in the browser. The concept is far from new, but the way Ext JS stands out from the contenders must be embarrassing. The library&#8217;s widgets are visually stunning, feature-rich, and yet still maintains high performance.</p>
<p>I will admit that I hadn&#8217;t heard of Ext JS before working on a project last year that used it. I&#8217;ve been doing freelance web development for about five years and I tend to keep quite up-to-date with web technologies, so I&#8217;m surprised that it had slipped under my radar.</p>
<p>Fairly recently, the team <a href="http://extjs.com/blog/2009/06/03/ext-js-30-rc2-release-stable-robust-and-enhanced/">announced</a> the latest release candidate of Ext 3.0. I wanted to experiment with some of the lesser-hyped new features, and so I&#8217;ve been working on a small experiment to display stock indexes using the new charts feature.</p>
<h2>Hello, world!</h2>
<p>Let&#8217;s start by walking through a really simple Ext example before we look at the charts.</p>
<p><a href="http://extjs.com/products/extjs/download.php">Download</a> the latest Ext release. Setup a simple HTML page and add a few includes:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;ext-3.0-rc3/resources/css/ext-all.css&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;ext-3.0-rc3/adapter/ext/ext-base.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;ext-3.0-rc3/ext-all-debug.js&quot;&gt;&lt;/script&gt;</pre></td></tr></table></div>

<p>At this point, we should be able to load the blank page in the browser without any errors.</p>
<p>The next step is to write some code to do something with the Ext library. So as not to upset the gods, we&#8217;re going to make a pop-up &#8216;hello world&#8217; window. The following is JavaScript code, so put it in a &lt;script&gt; tag or an external .js file.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">Ext.<span style="color: #660066;">onReady</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">new</span> Ext.<span style="color: #660066;">Window</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    title<span style="color: #339933;">:</span> <span style="color: #3366CC;">'Hello, world!'</span><span style="color: #339933;">,</span>
    width<span style="color: #339933;">:</span> <span style="color: #CC0000;">280</span><span style="color: #339933;">,</span>
    height<span style="color: #339933;">:</span> <span style="color: #CC0000;">120</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>We use <code>Ext.onReady(...)</code> to setup a callback for when the DOM is loaded. This callback will create a new <code>Ext.Window</code> object, and show it. The parameter to the <code>Ext.Window</code> constructor is a configuration object.</p>
<p>The concept of configuration objects is used extensively throughout Ext, and it can be rather fiddly and difficult to get used to. You <i>have</i> to keep the Ext documentation open (see below) to know what parameters to use. In our simple example, all we do is specify the title and dimensions of the window.</p>
<p>Load the page in your browser. The result should look something like this:</p>
<p><a href="http://joefreeman.co.uk/projects/extstock/part-1.html"><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/hello-world.png" alt="hello-world" title="hello-world" width="290" height="128" class="aligncenter size-full wp-image-11" /></a></p>
<p>Notice that you can drag the window around the screen and resize it to your hearts content.</p>
<p>See the <a href="http://joefreeman.co.uk/projects/extstock/part-1.html">demo</a> or <a href="http://joefreeman.co.uk/projects/extstock/stocks-with-ext-js-charts.zip">download</a> the code.</p>
<p>For a nice collection of more advanced examples, check out the <a href="http://extjs.com/deploy/dev/examples/samples.html">samples</a> on the Ext site (they are also contained in the Ext download). These samples are great. My only criticism is that they can be a bit inconsistent in the way they implement features.</p>
<p>Another indispensable resource is the Ext <a href="http://extjs.com/deploy/dev/docs/">documentation</a> (this is also included in the download).</p>
<h2>Ext JS Charts</h2>
<p>In a way, it&#8217;s a shame that Flash has been used to implement the charts feature, since the library has achieved so much without resorting to it in the past. Nevertheless, the actual Flash applet has been well contained and even resizes smoothly with it&#8217;s container.</p>
<p>We can build on our simple example from above to add a chart to the window.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">Ext.<span style="color: #660066;">onReady</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #003366; font-weight: bold;">var</span> store <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Ext.<span style="color: #660066;">data</span>.<span style="color: #660066;">JsonStore</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    url<span style="color: #339933;">:</span> <span style="color: #3366CC;">'data.php'</span><span style="color: #339933;">,</span>
    baseParams<span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
      symbol<span style="color: #339933;">:</span> <span style="color: #3366CC;">'GOOG'</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    autoLoad<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
    root<span style="color: #339933;">:</span> <span style="color: #3366CC;">'data'</span><span style="color: #339933;">,</span>
    fields<span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'date'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'close'</span><span style="color: #009900;">&#93;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #003366; font-weight: bold;">new</span> Ext.<span style="color: #660066;">Window</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    title<span style="color: #339933;">:</span> <span style="color: #3366CC;">'GOOG'</span><span style="color: #339933;">,</span>
    width<span style="color: #339933;">:</span> <span style="color: #CC0000;">400</span><span style="color: #339933;">,</span>
    height<span style="color: #339933;">:</span> <span style="color: #CC0000;">300</span><span style="color: #339933;">,</span>
    items<span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
      <span style="color: #003366; font-weight: bold;">new</span> Ext.<span style="color: #660066;">chart</span>.<span style="color: #660066;">LineChart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
        store<span style="color: #339933;">:</span> store<span style="color: #339933;">,</span>
        xField<span style="color: #339933;">:</span> <span style="color: #3366CC;">'date'</span><span style="color: #339933;">,</span>
        yField<span style="color: #339933;">:</span> <span style="color: #3366CC;">'close'</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#93;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">show</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>We are introducing two new concepts here. First of all, the use of a &#8217;store&#8217;. In this case, a <code>JsonStore</code>. To quote the documentation:</p>
<blockquote><p>The Store class encapsulates a client side cache of Record objects which provide input data for Components [...]</p></blockquote>
<p>So basically, the store takes care of fetching and storing our data. The <code>JsonStore</code> uses a <code>JsonReader</code> to fetch the data in <a href="http://www.json.org">JSON</a> format, keeping the data completely separate from the UI component. The data is then represented internally as a series of <code>Record</code>s.</p>
<p>Let&#8217;s look at the configuration parameters we have set. The first parameter, <code>url</code>, is the URL that we will be loading the data from and <code>baseParams</code> specifies the parameters to send to this URL. By default the store doesn&#8217;t attempt to load the data straight away, so we specify the <code>autoLoad</code> parameter so that we don&#8217;t have to call <code>store.load()</code> ourselves later on. The <code>root</code> parameter tells the store where to look in the returned object for the bulk of the records, and <code>fields</code> is a short-hand way to specify the structure of the individual records.</p>
<p>The second new concept we have introduced is the addition of a component to the window. We have done this by specifying an array of components in the &#8216;items&#8217; property. The single item that we are adding is a <code>LineChart</code> component. The configuration here just links the component to the store we have defined, and specifies the fields to bind to the axes of the chart.</p>
<p>Once the store has been loaded, we should end up with this:</p>
<p><a href="http://joefreeman.co.uk/projects/extstock/part-2.html"><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/goog.png" alt="goog" title="goog" width="410" height="311" class="aligncenter size-full wp-image-13" /></a></p>
<p>See the <a href="http://joefreeman.co.uk/projects/extstock/part-2.html">demo</a> or <a href="http://joefreeman.co.uk/projects/extstock/stocks-with-ext-js-charts.zip">download</a> the code.</p>
<p>The current Ext documentation for styling the charts is fairly minimal. Since the underlying Flash applet for the charts is based on the one from the Yahoo UI Library, further information on styling the charts can be obtained from <a href="http://developer.yahoo.com/yui/charts/">their documentation</a>.</p>
<h2>Fetching the Data</h2>
<p>Let&#8217;s take a look now at the server-end of the process.</p>
<p>The data is generated by a PHP script which in turn gets the stock data from Yahoo. Yahoo kindly provide a CSV-formatted data set of the daily stock prices (including open, close, high and low values) which go back about five years. We don&#8217;t want to be pumping this much data to the browser, so we will take a few steps:</p>
<ol>
<li>Fetch the data if not already cached</li>
<li>Extract the closing price for each day</li>
<li>Cache the data</li>
<li>Choose an appropriate range of dates to display</li>
<li>Sample the remaining data to leave us with a suitable number of points that can be plotted</li>
<li>Return the data encoded as JSON</li>
</ol>
<p>We now have a simple web service that allows us to specify a number of parameters:</p>
<ul>
<li><b>symbol</b> — The stock ticker symbol. Required. Note that because we are using the Yahoo stock data we are limited to stocks listed on the NASDAQ.</li>
<li><b>start</b> — The start date. Specified as a Unix timestamp. Defaults to roughly one year ago.</li>
<li><b>span</b> — The timespan to get data for. Also given as a Unix timestamp. Defaults to roughly one year.</li>
<li><b>points</b> — The number of points to sample. Defaults to 20.</li>
</ul>
<p>An example result from the service would look a little like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;symbol&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;MSFT&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;data&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
  <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;date&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;2008-07-24&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;close&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">25</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;date&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;2008-08-12&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;close&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">28</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
  <span style="color: #006600; font-style: italic;">//...</span>
<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>I won&#8217;t paste the PHP script here. It can, however be <a href="http://joefreeman.co.uk/projects/extstock/stocks-with-ext-js-charts.zip">downloaded</a>.</p>
<p>Once the data has been successfully loaded, an event is raised, which the chart has been listening for. The chart can then re-draw itself using the new data.</p>
<h2>Taking Things Further</h2>
<p>In an attempt to mature our example a little, and to highlight a few of Ext&#8217;s other features, I&#8217;ve put together a more substantial example. See the screenshot below, and refer to the <a href="http://joefreeman.co.uk/projects/extstock/">live demo</a>.</p>
<p><a href="http://joefreeman.co.uk/projects/extstock/"><img src="http://joefreeman.co.uk/blog/wp-content/uploads/2009/07/extstock.png" alt="extstock" title="extstock" width="500" height="324" class="aligncenter size-full wp-image-56" /></a></p>
<p>I won&#8217;t go into much detail here, other than to list some of the features that I&#8217;ve used:</p>
<ul>
<li>A <code>Viewport</code> together with the <code>BorderLayout</code> to ensure that the interface takes over all the space offered by the browser window.</li>
<li>A modal pop-up window which contains an auto-complete <code>ComboBox</code>. A list of the NASDAQ-100 are presented for the user to choose from.</li>
<li>A <code>TabPanel</code> to organise the different stocks that have been loaded. Selecting a different tab will change the chart being displayed, and closing a tab will unload the data and chart.</li>
<li>A <code>ListView</code> component, which is the new lightweight version of the <code>GridPanel</code>.</li>
<li>Some more advanced features of the <code>Chart</code> object—including making use of the <code>TimeAxis</code>, linking mouse movements to the <code>ListView</code> component, and making some changes to the chart&#8217;s style.</li>
</ul>
<p>I have left the JavaScript <a href="http://joefreeman.co.uk/projects/extstock/js/extstock.js">un-minified</a> so feel free to take a look at it.</p>
]]></content:encoded>
			<wfw:commentRss>http://joefreeman.co.uk/blog/2009/07/stocks-with-ext-js-charts/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
