/cakephp-filter-plugin

THIS IS BROKEN DO NOT USE

Primary LanguagePHP

CakePHP Filter Plugin
Paginates Filtered Records

Background

This plugin is a fork of Jose Diaz-Gonzalez’s Filter component, which is something of a fork of James Fairhurst’s Filter Component, which is in turn a fork by Maciej Grajcarek, which is ITSELF a fork from Nik Chankov’s code. Chad Jablonski then added RANGE support with a few bug fixes. jmroth pointed out a pretty bad redirect issue and “fixed it”. Then Jose Diaz-Gonzalez took everyone’s changes, merged them together, and updated the Component to be a bit more 1.3 compliant.

That’s a lot of forks…

This also contains a view helper made by Matt Curry.

This also uses a behavior adapted from work by Brenton to allow for HasAndBelongsToMany and HasMany relationships.

This works for all relationships.

Installation

  1. Clone from github : in your plugin directory type
    git clone git://github.com/josegonzalez/cakephp-filter-plugin.git filter
  2. Add as a git submodule : from your app/ directory type
    git submodule add git://github.com/josegonzalez/cakephp-filter-plugin.git plugins/filter
  3. Download an archive from github and extract the contents into /plugins/filter

Usage

  1. Include the component in your controller (AppController or otherwise)
    var $components = array('Filter.Filter');
  2. Use something like the following in your index
function index() {
	$this->paginate = $this->Filter->paginate;
	$posts = $this->paginate();
	$this->set(compact('posts'));
}
  1. Finished example:
<?php
class PostsController extends AppController {
	var $components = array('Filter.Filter');

	function index() {
		$this->paginate = $this->Filter->paginate;
		$posts = $this->paginate();
		$this->set(compact('posts'));
	}
}
?>

Note on 1.2 usage

In order for this to work in 1.2, you need to have the following in your controller:

<?php
class PostsController extends AppController {
	var $components = array('Filter.Filter');

	function index() {
		$this->paginate = $this->Filter->paginate;
		$filterOptions = $this->Filter->filterOptions;
		$posts = $this->paginate();
		$this->set(compact('filterOptions', 'posts'));
	}
}
?>

And then merge the $filterOptions variable on anything pagination uses. It can be set globally using PaginatorHelper::options() as follows (in the view):

<?php $paginator->options($filterOptions); ?>

Advanced Usage

Overriding the Filter pagination

Option 1: Controller-wide

By setting the $paginate variable for your controller, the Filter component merges those into it’s own rules before processing incoming information.

<?php
class PostsController extends AppController {
	var $name = 'Posts';
	var $components = array('Filter.Filter');
	var $paginate = array('contain' => array('Comment'), 'limit' => 5);

	function index() {
		$this->paginate = $this->Filter->paginate;
		$posts = $this->paginate();
		$this->set(compact('posts'));
	}
}
?>

Option 2: Action-specific

You can merge in things to the paginate array before any pagination happens if necessary.

<?php
class PostsController extends AppController {
	var $name = 'Posts';
	var $components = array('Filter.Filter');

	function index() {
		$this->paginate = array_merge($this->Filter->paginate,
			array('contain' => array('Comment'), 'limit' => 5)
		);
		$posts = $this->paginate();
		$this->set(compact('posts'));
	}
}
?>

Setting up search forms

Option 1: Helper

Use the helper In between the row with all the column headers and the first row of data add:

<?php echo $this->Filter->form('Post', array('name')) ?>

The first parameter is the model name. The second parameter is an array of fields. If you don’t want to filter a particular field pass null in that spot.

Option 2: Manually

Create your own form however you want. Below is such an example.

<?php echo $this->Form->create('Post', array('action' => 'index', 'id' => 'filters')); ?>
	<table cellpadding="0" cellspacing="0">
		<thead>
			<tr>
				<th><?php echo $this->Paginator->sort('Post.name'); ?></th>
				<th class="actions">Actions</th>
			</tr>
			<tr>
				<th><?php echo $this->Form->input('Post.name'); ?></th>
				<th>
					<button type="submit" name="data[filter]" value="filter">Filter</button>
					<button type="submit" name="data[reset]" value="reset">Reset</button>
				</th>
			</tr>
		</thead>
		<tbody>
			// loop through and display your data
		</tbody>
	</table>
<?php echo $this->Form->end(); ?>
<div class="paging">
	<?php echo $this->Paginator->prev('<< '.__('previous', true), array(), null, array('class' => 'disabled')); ?>
	<?php echo $this->Paginator->numbers(); ?>
	<?php echo $this->Paginator->next(__('next', true).' >>', array(), null, array('class' =>' disabled')); ?>
</div>

Filtering hasMany and hasAndBelongsToMany relationships

Add Behavior to model (only necessary for HABTM and HasMany):

<?php
class Post extends AppModel {
	var $name = 'Post';
	var $actsAs = 'Filter.Filter';
}
?>

Initialization Tips

These different initialization options are combined in the setup array. Defaults are shown below.

<?php
class PostsController extends AppController {
	var $name = 'Posts';
	var $components = array('Filter.Filter' => array(
		'actions' => array('index'),
		'defaults' => array(),
		'fieldFormatting' => array(
			'string'	=> "LIKE '%%%s%%'",
			'text'		=> "LIKE '%%%s%%'",
			'datetime'	=> "LIKE '%%%s%%'"
		),
		'formOptionsDatetime' => array(),
		'paginatorParams' => array(
			'page',
			'sort',
			'direction',
			'limit'
		),
		'parsed' => false,
		'redirect' => false,
		'useTime' => false,
		'separator' => '/',
		'rangeSeparator' => '-',
		'url' => array(),
		'whitelist' => array()
	));
}
?>
  1. actions: Array of actions upon which this component will act upon.
  2. defaults: Holds pagination defaults for controller actions. (syntax is array('Model' => array('key' => 'value'))
  3. fieldFormatting: Fields which will replace the regular syntax in where i.e. field = ‘value’
  4. formOptionsDatetime: Formatting for datetime fields (unused)
  5. paginatorParams: Paginator params sent in the URL
  6. parsed: Used to tell whether the data options have been parsed
  7. redirect: Used to tell whether to redirect so the url includes filter data
  8. useTime: Used to tell whether time should be used in the filtering
  9. separator: Separator to use between fields in a date input
  10. rangeSeparator: Separator to use between dates in a date range
  11. url: Url variable used in paginate helper (syntax is array('url' => $url));
  12. whitelist: Array of fields and models for which this component may filter

Todo

  1. Better code commenting – Done, left to help enforce the habit
  2. Support Datetime Done
  3. Support URL redirects and parsing Done
  4. Refactor datetime filtering for ranges Done
  5. Allow the action to be configurable Done
  6. Support jQuery Datepicker Outside scope
  7. Support Router prefixes, plugins, and named parameters in a “scope” instead of “actions” key.
  8. Expand hasMany and hasAndBelongsToMany support. Refactor behavior to conform with established practices.