First I'll admit I did not read through all your code. But I think I
get what you are doing.
I created a filtering system about a year ago. I wanted/needed
something that worked a bit like the find feature in Mac OS X Finder,
or in some SQL-GUIs I have used. If you have see this you know what I
am talking about. I also needed these to be saved and recalled later.
Anyway.
I ended up with something that is a lot more streamlined in the
controller but with a bit more work done in the Models.
Filter is the whole search setup for a particular search.
Rule is a single filtering rule.
Filter hasMany Rule
One Rule can have:
- a property to filter
- an operator
- a value entered by the user
End result might be "email ends with gmail.com" for a single rule.
Adding more rules to a Filter would narrow the search using "AND".
This turned out the be very flexible. A filter can be attached to any
other model and do filtering on it.
The rule model contained a big data array with different operators
(sql fragments) for different types of data. Since humans want to
filter numbers differently from email addresses I created a number of
these preset custom fragments that could be selected from drop-downs
in the gui. The rule model also contained a method for converting the
stored parameters (field, match, value) to an sql fragment for a given
model.
Some examples of fragments:
$this->types['Text']['equals'] = '%s LIKE \'%s\'';
$this->types['Text']['contains'] = '%s LIKE \'%%%s%%\'';
$this->types['Text']['starts_with'] = '%s LIKE \'%s%%\'';
$this->types['Text']['ends_with'] = '%s LIKE \'%%%s\'';
$this->types['Date']['days_ago'] = 'FLOOR(DATEDIFF(CURDATE(),
DATE(%s))) = \'%s\'';
$this->types['Date']['weeks_ago'] = 'FLOOR(DATEDIFF(CURDATE(),
DATE(%s))/7) = \'%s\'';
Each field is mapped to a type. Datetime fields becomes the "Date"
type. Text fields could be set to email or anything but defaults to
"Text".
The filter code was nothing special. The only special method there was
"getFilterFor($model_name)" which gathers the results from each rule.
The reason for this setup was partly flexibility and partly the GUI. I
really wanted a humane gui. No wildcards or pseudo-sql. Simple selects
and meaningful words. Looking back it is not a very difficult setup
but it did take some time to come up with the right way to set it all
up.
I hope that gives you some ideas.
Let me know if you want a few more boring details of the
implementation.
/Martin
On Oct 30, 3:43 pm, mario <[EMAIL PROTECTED]> wrote:
> Hello everyone,
>
> I'm planning to include filters in my new project wherein it will
> allow the user to filter or show only the information that he/she
> wants. Of course there would be a search form
> (textfield,combobox,checkbox, submit button) for this relative to my
> tables' fieldnames in the database.
>
> I've already done this before on my recent project using cakephp. I
> will post some of my code snippets here for you to make some
> suggestion and for me to find out if what I'm doing is correct or not.
> I'm also looking forward on recommendations on how to improve my
> filtering process (which I'm gonna use on my next project).
>
> Here is the code snippet of my controller (I've placed the filters in
> my index view):
> ---------------------------------------------------------------------------
> ----------
> function index($title = null, $location = null, $date_from = null,
> $date_to = null) {
> if (empty($this->data) &&
> (!$title || ($title == 'allTitle')) &&
> (!$location || $location == 'allLocation') &&
> (!$date_from || !$date_to))
> {
> $this->paginate['Exhibit'] = array(
> 'limit' => 1,
> 'page' => 1,
> 'order' => array
> ('Exhibit.title' => 'asc')
> );
> $this->set('exhibits', $this->paginate());
> $this->set('reportTitle',null);
> $this->set('reportLocation',null);
> $this->set('reportDateFrom',null);
> $this->set('reportDateTo',null);
> }
> else
> {
> if(!$title || $title == 'allTitle')
> {
> $title = $this->data['Search']['title'];
> }
> else
> {
> $this->data['Search']['title'] = $title;
> }
> if(!$location || $location == 'allLocation')
> {
> $location = $this->data['Search']['location'];
> }
> else
> {
> $this->data['Search']['location'] = $location;
> }
> if(!$date_from)
> {
> $date_from =
> $this->data['Search']['date_from'];
> }
> else
> {
> $this->data['Search']['date_from'] =
> $date_from;
> }
> if(!$date_to)
> {
> $date_to = $this->data['Search']['date_to'];
> }
> else
> {
> $this->data['Search']['date_to'] = $date_to;
> }
>
> if($title != '')
> {
> $this->set('reportTitle',$title);
> }
> else
> {
> $this->set('reportTitle','allTitle');
> }
>
> if($location != '')
> {
> $this->set('reportLocation',$location);
> }
> else
> {
> $this->set('reportLocation','allLocation');
> }
>
> if($date_from == '' || $date_to == '')
> {
> $this->paginate['Exhibit'] = array(
> 'conditions'=>
> array("Exhibit.title LIKE '%$title%'",
>
> "Exhibit.location LIKE '%$location%'"),
> 'limit' => 1,
> 'page' => 1,
> 'order' => array
> ('Exhibit.title' => 'asc')
> );
> $this->set('exhibits', $this->paginate());
>
> $this->set('reportDateFrom',null);
> $this->set('reportDateTo',null);
> }
> else
> {
> $token_date_from = explode("/", $date_from);
> if(count($token_date_from) == 3)
> {
> $date_from =
> $token_date_from[2].'-'.$token_date_from[1].'-'.
> $token_date_from[0];
> }
>
> $token_date_to = explode("/", $date_to);
> if(count($token_date_to) == 3)
> {
> $date_to =
> $token_date_to[2].'-'.$token_date_to[1].'-'.
> $token_date_to[0];
> }
>
> $this->paginate['Exhibit'] = array(
> 'conditions'=>
> array("Exhibit.date_accessioned BETWEEN
> '$date_from' AND '$date_to'",
>
> "Exhibit.title LIKE '%$title%'",
>
> "Exhibit.location LIKE '%$location%'"),
> 'limit' => 1,
> 'page' => 1,
> 'order' => array
> ('Exhibit.title' => 'asc')
> );
> $this->set('exhibits', $this->paginate());
> $this->set('reportDateFrom',$date_from);
> $this->set('reportDateTo',$date_to);
> }
> }
> }
>
> ---------------------------------------------------------------------------
> ----------
>
> Here is the code snippet of my index view:
>
> <?php
> $paginator->options = array('url'=>
> array("$reportTitle","$reportLocation","$reportDateFrom","$reportDateTo"));
> ?>
> <div class="exhibits index">
> <h2><?php __('Collections');?></h2>
> <?php
> if ($session->check('Message.flash')):
> $session->flash();
> endif;
> ?>
> <?php echo $form->create('Search',array('url' => '/exhibits/index'));?
>
> <table>
> <tr>
> <td>Title</td>
> <td><?php echo $form->input('title', array('label'=> false)); ?></
> td>
> </tr>
> <tr>
> <td>Location</td>
> <td><?php echo $form->input('location',array('options'=>array(
> '' => '--all
> locations--',
> 'Ledesma
> Collection'=>'Ledesma Collection',
> 'Alonzo
> Collection'=>'Alonzo Collection',
> 'Vega Collection'=>'
> Vega Collection',
> 'Esteban
> Collection'=>'Esteban Collection',
> 'Puentevella
> Collection'=>'Puentevella Collection',
> 'Velayo-Javelosa
> Collection'=>'Velayo-Javelosa Collection',
> 'Bishop
> Collection'=>'Bishop Collection'), 'label' => false)); ?></td>
>
> </tr>
> <tr>
> <td>Date Accessioned:</td>
> </tr>
> <tr>
> <td>Date From </td>
> <td><?php echo $form->input('date_from',array('class'=>'w8em
> format-d-m-y highlight-days-67','id'=>'sd', 'label' => false)); ?></
> td>
> </tr>
> <tr>
> <td>Date To </td>
> <td><?php echo $form->input('date_to',array('class'=>'w8em format-
> d-m-y highlight-days-67','id'=>'ed', 'label' => false)); ?></td>
> </tr>
> <tr>
> <td> </td>
> <td><?php echo $form->submit('search', array('div' => false)); ?></
> td>
> </tr>
> </table>
> <?php echo $form->end();?>
>
> <?php
> echo $paginator->counter(array(
> 'format' => __('Page %page% of %pages%, showing %current% records out
> of %count% total, starting on record %start%, ending on %end%', true)
> ));
> ?></p>
> <table width="860" border="1" cellpadding="3" cellspacing="0"
> bordercolor="#999999">
> <tr>
> <th width="35"><?php echo $paginator->sort('id');?></th>
> <th width="291"><?php echo $paginator->sort('title');?></th>
> <th width="144">Thumbnail</th>
> <th width="160"><?php echo $paginator->sort('date_accessioned');?></
> th>
> <th width="100"><?php echo $paginator->sort('remarks');?></th>
> <th width="80"><?php __('Actions');?></th>
> </tr>
> <?php
> $i = 0;
> foreach ($exhibits as $exhibit):
> $class = null;
> if ($i++ % 2 == 0) {
> $class = ' class="altrow"';
> }
> ?>
> <tr<?php echo $class;?>>
> <td>
> <?php echo $exhibit['Exhibit']['id']; ?>
> </td>
> <td>
> <?php echo $exhibit['Exhibit']['title']; ?>
> </td>
> <td>
> <?php
> if($exhibit['Exhibit']['image_filename'])
> {
> echo
> $html->image('exhibits/small/'.$exhibit['Exhibit']
> ['image_filename']);
> }
> else
> {
> echo 'no image';
> }
> ?> </td>
> <td>
> <?php
> echo $time->format('M d, Y (D)',
> $exhibit['Exhibit']
> ['date_accessioned']);
> ?>
> </td>
> <td>
> <?php echo $exhibit['Exhibit']['remarks']; ?>
> </td>
> <td class="tactions">
> <?php echo $html->link(__('View', true),
> array('action'=>'view',
> $exhibit['Exhibit']['id'])); ?>
> <?php echo $html->link(__('Edit', true),
> array('action'=>'edit',
> $exhibit['Exhibit']['id'])); ?>
> <?php echo $html->link(__('Delete', true),
> array('action'=>'delete', $exhibit['Exhibit']['id']), null,
> sprintf(__('Are you sure you want to delete # %s?', true),
> $exhibit['Exhibit']['id'])); ?>
> </td>
> </tr>
> <?php endforeach; ?>
> </table>
> </div>
> <div id="paging"> <?php echo $paginator->prev('<< '.__('previous',
> true), array(), null, array('class'=>'disabled'));?> <?php echo
> $paginator->numbers();?> <?php echo $paginator->next(__('next',
> true).' >>', array(), null, array('class'=>'disabled'));?> </div>
> <div class="actions">
> <?php echo $html->link(__('New Exhibit', true),
> array('action'=>'add')); ?>|
> <?php echo $html->link(__('Save as excel file', true),
> array('action'=>'report',$reportTitle,$reportLocation,$reportDateFrom,
> $reportDateTo)); ?>
> </div>
> ---------------------------------------------------------------------------
> -------
> End of code:
>
> What I hate in my controller code is that it has many if-then-else
> conditions. The number of if-then-else conditions mainly depends on
> the number of fields that I want to use in my filter. The controller
> code could produce a massive if-then-else structure if the search
> fields in my index view continue to grow in number.
>
> Is there any way to optimize this? I've seen many filter component in
> cakephp as I search in google but they all have their own limitations
> (cannot filter deep nested models).
>
> I really need all of your help guys. Please make any suggestion.
>
> Thanks,
>
> Mario
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"CakePHP" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---