Search feature to CakePHP blog example

by calin
Using searchable behavior, exemplified on CakePHP's blog example from documentation.

Hello everybody!

First of all I assume that you have read and tried the blog example form documentation http://book.cakephp.org/view/219/blog).

Setup

So to get things started, we need to download seachable behavior from (http://code.google.com/p/searchable-behaviour-for-cakephp). Then we copy the archive contents to the /app folder. To complete the installation process there is one more thing to do: create the search table. So we run the following sql code:


CREATE TABLE `search_index` (
    `id` int(11) NOT NULL auto_increment,
    `association_key` int(11) NOT NULL,
    `model` varchar(128) collate utf8_unicode_ci NOT NULL,
    `data` longtext collate utf8_unicode_ci NOT NULL,
    `created` datetime NOT NULL,
    `modified` datetime NOT NULL,
    PRIMARY KEY  (`id`),
    KEY `association_key` (`association_key`,`model`),
    FULLTEXT KEY `data` (`data`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

So we are set up now, ready to add our nice search feature!

The actual search

First we need to add the searchable behavior to Post model.

Model Class:

<?php 
<?php
// app/models/post.php
class Post extends AppModel
{
    var 
$name 'Post';
    var 
$actsAs = array ('Searchable');

    var 
$validate = array(
        
'title' => array(
            
'rule' => array('minLength'1)
        ),
        
'body' => array(
            
'rule' => array('minLength'1)
        )
    );
}
?>
?>

To be able to search, we need to place a search box somewhere. Add the following snippet of code just after the page heading.


<?php 
    
echo $form->create("Post",array('action' => 'search'));
    echo 
$form->input("q", array('label' => 'Search for'));
    echo 
$form->end("Search");
?>

We need to define the search action in our post controller.


<?php
    
function search() {
        
$this->set('results',$this->Post->search($this->data['Post']['q']));
    }
?>

Finally we create the view for search results (which is just a slightly modified version of posts index):

View Template:


<?php // app/views/posts/search.ctp ?>
<h1>Blog posts</h1>
<?php 
    
echo $form->create("Post",array('action' => 'search'));
    echo 
$form->input("q", array('label' => 'Search for'));
    echo 
$form->end("Search");
?>
<p><?php echo $html->link("Add Post""/posts/add"); ?>
<table>
    <tr>
        <th>Id</th>
        <th>Title</th>
                <th>Action</th>
        <th>Created</th>
    </tr>

<!-- Here's where we loop through our $results array, printing out post info -->

<?php foreach ($results as $post): ?>
    <tr>
        <td><?php echo $post['Post']['id']; ?></td>
        <td>
            <?php echo $html->link($post['Post']['title'],'/posts/view/'.$post['Post']['id']);?>
                </td>
                <td>
            <?php echo $html->link(
                
'Delete'
                
"/posts/delete/{$post['Post']['id']}"
                
null
                
'Are you sure?'
            
)?>
            <?php echo $html->link('Edit''/posts/edit/'.$post['Post']['id']);?>
        </td>
        <td><?php echo $post['Post']['created']; ?></td>
    </tr>
<?php endforeach; ?>
</table>

That's it! You now have a blog with a fully featured search engine.

For other ways of using the searchable behavior, check the project page on Google Code (http://code.google.com/p/searchable-behaviour-for-cakephp).

Report

More on Tutorials

Tags

Advertising

Comments

  • Southpaw posted on 03/17/11 06:30:28 AM
    I have an authoriziation system set up for my blog, but I am trying to search as an admin who has access to everything, yet everytime I try to search I get this error
    'You are not authorized to access this location'.

    So i'm guessing it's a possibility my authorization system is faulty, but I don't really know where to look to fix it. Could someone please give me some advice and what the search function is actually accessing. e.g. post Model and post controller

    Thanks in advance for your help
  • kevinparker posted on 07/12/10 06:07:59 AM
    Hi all,

    I did all the steps mentioned and i get this error when debug is 1

    "Missing Database Tables"

    Can anyone guide me on this.

    Thanks
    Kevin
  • bruno88 posted on 06/07/10 01:09:18 PM
    Hello!

    I'm new to CakePHP and I'm trying to use this behaviour but I'm having some problems:

    1- My Users table has the password attribute and this behaviour allow other users to search for passwords XD well they are hashed but I think this isn't a good ideia can I change that?

    2- When I use saveAll only the last one saved goes to search_index table is there anyway to change this? :(

    3- When I edit something on my models I can't search that field anymore what must I do? :/

    Thanks,
    Bruno Sampaio
  • tokasa posted on 04/20/10 10:04:51 AM
    Hi, I am having trouble with two models using this behavior.

    I have following models - Brand and Product. I need to index both of them. Generally it works well, but...

    When I use them in different controller with this initialization:
    $uses = array('Brand', 'Product', ...)

    it always index only brand name, but product name not; both are saved ok. and if I remove 'Brand' from $uses, it starts indexing 'Product'

    anybody knows what this is?? how to solve it? cake bug? or behavior bug?

    Thanks, help appreciated.
    Tomas
  • tsmienk posted on 03/04/10 05:52:28 AM
    I have recursive set to -1 in my AppModel and the code didn't work.
    Adding var $recursive = 1;  to the SearchIndex model fixed the problem.
  • foroctfralion posted on 02/28/10 02:11:09 PM
    I am using this behavior on two different models (User and Post). It is working fine when I add a new user or when I search posts or users but when I try to add a new post I get the following errors.
    Undefined index: User [APP/models/behaviors/searchable.php, line 77] Invalid argument supplied for foreach() [APP/models/behaviors/searchable.php, line 78] SQL Error: 1048: Column 'association_key' cannot be null [CORE/cake/libs/model/datasources/dbo_source.php, line 525] Query: INSERT INTO `search_index` (`model`, `association_key`, `data`, `modified`, `created`) VALUES ('User', NULL, '', '2010-02-28 12:04:11', '2010-02-28 12:04:11')

    Query: INSERT INTO `search_index` (`model`, `association_key`, `data`, `modified`, `created`) VALUES ('User', NULL, '', '2010-02-28 12:04:11', '2010-02-28 12:04:11')

    Cannot modify header information - headers already sent by (output started at /home/xxx/example.com/cake/basics.php:307) [CORE/cake/libs/controller/controller.php, line 644]
    So from what I can tell when I add a post something with the user model is conflicting with my add posts function. I would expect to see the query values start with the 'Post' model then the post id and then some data.

    Is there something I need to do when using this behavior on two different models?
    • tokasa posted on 04/20/10 10:00:24 AM
      Hi,
      association_key id database is set to be "not null". I recomend you to change your indexData() function in every model to return 'false' if variable you want to index is null or not set - in my example I do index only 'Brand Name';

      my example:

      function indexData() {
      if(isset($this->data['Brand']['name'])){
      return $this->data['Brand']['name'];
      }else {
      return false;
      }
      }


      I am using this behavior on two different models (User and Post). It is working fine when I add a new user or when I search posts or users but when I try to add a new post I get the following errors.
      Undefined index: User [APP/models/behaviors/searchable.php, line 77] Invalid argument supplied for foreach() [APP/models/behaviors/searchable.php, line 78] SQL Error: 1048: Column 'association_key' cannot be null [CORE/cake/libs/model/datasources/dbo_source.php, line 525] Query: INSERT INTO `search_index` (`model`, `association_key`, `data`, `modified`, `created`) VALUES ('User', NULL, '', '2010-02-28 12:04:11', '2010-02-28 12:04:11')

      Query: INSERT INTO `search_index` (`model`, `association_key`, `data`, `modified`, `created`) VALUES ('User', NULL, '', '2010-02-28 12:04:11', '2010-02-28 12:04:11')

      Cannot modify header information - headers already sent by (output started at /home/xxx/example.com/cake/basics.php:307) [CORE/cake/libs/controller/controller.php, line 644]
      So from what I can tell when I add a post something with the user model is conflicting with my add posts function. I would expect to see the query values start with the 'Post' model then the post id and then some data.

      Is there something I need to do when using this behavior on two different models?
  • ngoni.chibamu posted on 01/19/10 05:26:28 AM
    I am getting a SQL error: "....right syntax to use near 'search' at line...". I put the search_index.php file in models and the searchable.php in models/behaviors, but i don't know what going on. can somesone please help
  • WhyNotSmile posted on 01/07/10 12:04:25 PM
    Thanks for this tutorial, it was helpful.

    For those who are getting empty results sets, I've just realised that it's because the search code creates an index table for itself, which it populates as you add and modify pages on the site. This means that any pages which were on the site when you added the search code won't be searched on - so you'll need to modify them or add new ones.
  • danno23123 posted on 12/30/09 12:10:20 AM
    Becuase the behaviour only adds data after its been installed.

    There are some functions below for having all existing data added into the search index.

    http://code.google.com/p/searchable-behaviour-for-cakephp/issues/detail?id=1
  • nachocasas posted on 11/18/09 10:18:12 AM
    In the controller change this:
     <?php
      $this
    ->set('results',$this->Post->search($this->data['Post']['q'])); 
    ?> 

    to this:

    <?php
      $this
    ->set('results',$this->Post->search($this->data['Post']['q'], array('recursive' => 2))); 
    ?> 

    As you can see, you can use the same options for "find" method as second parameter for search method.

    In this example you will obtain the associated data to your Post model, in the result you will have 3 models (SearchIndex, Post and a associated model to post)

    =).

    great tutorial, thanks!
  • Rahu1 posted on 10/15/09 03:04:48 PM
    i am new to cakephp and i have an application wherein i would like to add this search feature. i have gone through these following links provided by you.
    http://bakery.cakephp.org/articles/view/search-feature-to-cakephp-blog-example http://code.google.com/p/searchable-behaviour-for-cakephp/ but to no avail. basically i have table or a set of tables with appropriate associations among them. each table have an id and other related fields. some of the tables are admin, profile, country, state etc i have worked with the provided examples but it is returning an empty search_index table?. and i have some questions:

    1. what is this association key? is it some kind of id of the tables we need to search?
    2. there is a field association key provided in the tables but it has a different datatype in the two examples. why and which one would be correct.
    3. what procedure should i employ to make the search work?
    4. what customizations do i need to put in?
    5. table: admin - id, fname(e.g 1,rahul)
    state - id,admin_id (e.g 1,1)
    locality - id, admin_id (e.g 1,1)
    how do i get search for rahul in state-1 and locality-1 and how to search from associted tables of admin?
    6. moreover after this text search feature i'm looking for a dropdown search feature using ajax. it would provide results after filtering the country, state, locality dropdown menus. please provide some tutorials, or elements, behaviour, plugins. any kind of help would be highly appreciable.
    thanx & regards
    rahul
  • benpawsey posted on 09/11/09 06:31:50 AM
    Hi, I am admittedly new to CakePHP but have managed to get the blog system working and with pagination. I then expanded the system to handle more data columns but I can't get the search function to work! Instead of Author and Body I now have Address, Move In, Move Out and RSL fields but have kept the table name 'posts'. I get two error messages:

    Warning (512): SQL Error: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'search' at line 1 [CORE\cake\libs\model\datasources\dbo_source.php, line 524]

    Warning (2): Invalid argument supplied for foreach() [APP\views\posts\search.ctp, line 26]
    My index.ctp table matches the search.ctp table. Do I need to add more fields to the search_index table? The foreach section in search reads:


    <?php foreach ($results as $post): ?>
        <tr>
            <td><?php echo $post['Post']['id']; ?></td>
            <td><?php echo $post['Post']['moveout']; ?></td>
            <td><?php echo $post['Post']['movein']; ?></td>
            <td><?php echo $html->link($post['Post']['address'],'/posts/view/'.$post['Post']['id']);?></td>
            <td><?php echo $post['Post']['rsl']; ?></td>
            <td><?php echo $post['Post']['notes']; ?></td>
            <td><?php echo $post['Post']['created']; ?></td>
            <td><?php echo $post['Post']['modified']; ?></td>
            <td><?php echo $html->link(
                    
    'Delete'
                    
    "/posts/delete/{$post['Post']['id']}"
                    
    null
                    
    'Are you sure?'
                
    )?>
                <?php echo $html->link('Edit''/posts/edit/'.$post['Post']['id']);?>
            </td>
        </tr>
    <?php endforeach; ?>

    Any help would be extremely appreciated and thanks for writing this tutorial in the first place!
  • kittenhuffer posted on 09/01/09 09:58:14 PM
    By the way, I didn't know that the search_index table isn't updated until you save your Posts. So any Posts that are in your database before you add the searchable behavior won't actually be searched until you either (a) edit-save each one in turn, or (b) figure out how to index your current data (see 26 Current Data Requires Indexing).
  • novon posted on 08/26/09 05:08:30 PM
    I installed this according to the instructions and latest code, but for the "results" array I get data from the "search_index" table instead of from "posts" in my view, so listing post title doesn't work.

    Any ideas why?
  • ryanbarrett posted on 05/19/09 11:40:37 AM

    This tutorial does not discuss indexing Current data. To do that please visit:

    http://code.google.com/p/searchable-behaviour-for-cakephp/issues/detail?id=1
    The second post has a nice example of how to index your current data. Just change the models you want indexed. Execute the page. Voila.

  • goggarvey posted on 03/26/09 07:01:05 AM
    Has anybody got this working? when I click 'Search' it responds with an empty table. Any help would help me out a lot.
  • goggarvey posted on 03/26/09 07:00:54 AM
    Has anybody got this working? when I click 'Search' it responds with an empty table. Any help would help me out a lot.
  • mryakodzun posted on 03/18/09 05:33:50 PM
    result array from this tutorial is empty.
  • zafi posted on 03/16/09 05:51:46 AM
    i got these errors.. what went wrong?


    Query: search
    Warning: SQL Error: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'search' at line 1 in /home/jb/Desktop/cakeblog/cake/libs/model/datasources/dbo_source.php on line 439


    Fatal error: Call to undefined method FormHelper::create() in /home/jb/Desktop/cakeblog/app/views/posts/search.ctp on line 4


  • abhishek198 posted on 01/30/09 06:42:49 AM
    Hi,
    The example above doesn't search the associated tables.

    e.g .. suppose i have 2 tables as
    1.listings - id,user_id (e.g 1,1)
    2. users - id,name (e.g 1,abhishek)

    Now if am looking for all listings by abhishek .. how do i do that search


    Thanks in advance

    Regards
    Abhishek
  • abhishek198 posted on 01/30/09 01:33:28 AM
    Hi,
    How do i fetch data from associated tables. One more thing.. when i edit a record does the search index table get updated automatically ...

    Regards
    Abhishek Jain
  • wittedruif posted on 01/16/09 08:27:26 AM
    Good idea for a tutorial, having just started with the blog example i found this tutorial to be a welcome addition to my experimentating. Having said that i would like to say that 1 part is unclear, youre not very specific on where to place the search input. Im guessing its in the index.ctp and im probably wrong because when i submit i get the following error:

    Error: The requested address '/posts/search' was not found on this server.

    edit: I found that setting debug level to 2 removes the error and instead i get the same null string error previously mentioned. Although the posted solution is poorly documented for newbies as well.

    edit again: For those running into the same issue: I found the _index() function the solution is referring to as part of the downloaded searchable.php file stored under models/behaviours on line 70.
  • excelf posted on 01/05/09 07:56:37 AM
    Good tutorial

    I read and practise all this tutorial's steps carrefully and double check it before being sure that search return nothing. I appreciate this, It looks useful way to set search machine on our web specially for cakephp programmer, but in fact the search return nothing.

    Is there anybody having success with this? please let me know if there's something wrong or should be fixed in this tutorial.

    really thank for you all who make this tutorial more clear and usefull
  • MudMonkey posted on 01/01/09 02:51:32 PM
    While it is true that not all programmers can write good tutorials and documentation, IMHO it's articles like this one that gives CakePHP the reputation of having poor documentation. It could and should have been a very useful article but just ended up being frustrating and depressing. At the very least one should have been able to follow it and end up with the advertised conclusion.

    I can also write a tutorial that doesn't do what it's suppose to do (i.e. teach) but, like this article, it would not have been useful.

    Here ends my bitter frustrated rant.
  • pooja2283 posted on 12/20/08 11:36:21 AM
    I m new to cakePhp and i don't know how to install cake php please tell me the simple to install cake php i have already installed apache server and mysql and i don't know how to install cakephp in windows can anybody tell me step by step procedure of installition because i can't understand the manual
    • adriano posted on 12/20/08 12:22:24 PM
      I m new to cakePhp and i don't know how to install cake php please tell me the simple to install cake php i have already installed apache server and mysql and i don't know how to install cakephp in windows can anybody tell me step by step procedure of installition because i can't understand the manual
      You're spamming. This is a tutorial about a search feature to cake, not a general help site. Try not to be so selfish (reading three comments above this, you would have seen this same answer). Go to http://groups.google.com/group/cake-php and ask there, possibly with something better than 'I don't know how to install cakephp'.
  • amarradi posted on 12/20/08 05:08:46 AM
    Thanks you for your help to the inputfields. I forgot that it is no forum but a tutorial. im sorry.
  • amarradi posted on 12/19/08 12:04:32 PM
    Hello

    i've an little Question
    I tried to understand the add.ctp from blog tutorial,
    so i tried to implement it by myself
    /app/views/posts/edit.ctp
        
    <h1>Edit Post</h1>
    <?php
        
    echo $form->create('Post', array('action' => 'edit'));
        echo 
    $form->input('title');
        echo 
    $form->input('body', array('rows' => '3'));
            echo 
    $form->input('id', array('type'=>'hidden')); 
        echo 
    $form->end('Save Post');
    ?>
    How can i get the 2 Inputfields side by side not about each other. Is it a thing from the css?

    Many greetings

    Marcus Radisch
    • adriano posted on 12/19/08 01:58:23 PM
      Hello

      i've an little Question
      I tried to understand the add.ctp from blog tutorial,
      so i tried to implement it by myself
      /app/views/posts/edit.ctp
          
      <h1>Edit Post</h1>
      <?php
          
      echo $form->create('Post', array('action' => 'edit'));
          echo 
      $form->input('title');
          echo 
      $form->input('body', array('rows' => '3'));
              echo 
      $form->input('id', array('type'=>'hidden')); 
          echo 
      $form->end('Save Post');
      ?>
      How can i get the 2 Inputfields side by side not about each other. Is it a thing from the css?

      Many greetings

      Marcus Radisch

      Ok, now the problem is that you're spamming this tutorial: your question doesn't have anything to do with the subject of the tutorial. Go to http://groups.google.com/group/cake-php and ask the questions there.
      But just because I'm nice: $form->input() is very thorough: it creates a div, a label and the input field. Try using just $form->text() and $form->textarea().
  • amarradi posted on 12/19/08 11:46:57 AM
    Hello,

    thanks a lot for the great help. My Question is now, i have an DB-Table with 2 Columns. How can i great an searchindex over the Table?

    many greatings

    Marcus Radisch
    • adriano posted on 12/19/08 11:57:14 AM
      Hello,

      thanks a lot for the great help. My Question is now, i have an DB-Table with 2 Columns. How can i great an searchindex over the Table?

      many greatings

      Marcus Radisch

      I understand you're not familiar with English, and that's not a problem. What is a problem is that you don't give us enough information to help you.
      If you say 'I have a table with two columns, how can I get a searchindex', I'll answer 'read the tutorial and follow the instructions'. After all, they worked for me. Please say in detail what you've done, where you got stuck. 'It doesn't work' is not a good report.

      Cheers
      Adriano.
  • amarradi posted on 12/19/08 08:50:02 AM
    Hello

    can everyone help me? I have added an Bug for this component under this link->http://code.google.com/p/searchable-behaviour-for-cakephp/issues/detail?id=9 Until this moment i don't found any solution

    Many greeting

    marcus radisch
  • amarradi posted on 12/17/08 02:54:04 PM
    Hello

    now i tried it with the official Blog Tutorial, but there is no way it doesnt search. Can every help me a little bit

    many greetings

    Marcus Radisch
  • amarradi posted on 12/17/08 01:36:40 PM
    Hello together,

    i've tried it with my own application(a very very simple dictionary) I implemented directly to this docu...
    But the searchreslut is always empty....

    What i have to do that the result is correct.

    my translation DB is

    CREATE TABLE translates (
    id int(10) unsigned NOT NULL auto_increment,
    language1 varchar(255) NOT NULL,
    language2 varchar(255) NOT NULL,
    created datetime default NULL,
    modified datetime default NULL,
    PRIMARY KEY (id)
    );

    The search_index is the same...

    Can erveryone help me. If i search then is no error message...

    Thanks

    Many greetings

    Marcus Radisch
  • adriano posted on 12/09/08 07:27:48 AM
    Something I'm struggling with is searching belongsTo relationships and returning the id of the object's parent, not of the actual object found.
    Example:
    I have a 'paintings' table (not the actual table/class name) that hasMany 'titles'. I'd like to search for one of the 'titles' (bonus points if that search can be done from the 'painting' views) and that the returned list showed the link to the actual 'painting', not to the 'title'.

    I understand it's a lot to ask, so thanks in advance for _any_ help.
  • adriano posted on 11/27/08 09:31:59 AM
    Thankyouthankyouthankyou! This is what I've been looking for all along!
  • adriano posted on 11/27/08 08:46:36 AM
    In the code shown for the model class, you open and close the ?php tag twice.
  • toste posted on 11/12/08 08:10:30 PM
    Hello,

    You say that «By default all varchar, char and text fields are indexed.»
    But this is not true because getColumnTypes will say varchar is 'string'

    $columns = $this->model->getColumnTypes();

    so just add

    if (isset($columns[$key]) && in_array($columns[$key],array('string','text','varchar','char'))) {...}

    Thanks for the behavior, great work :D
login to post a comment.