Once upon a time I needed to make custom filters for my admin generator...
Example case
Let's analyse a simple study case. Suppose we are running an online shop. The schema includes a product table which has two properties (among all other properties):
quantity
- the number of products we have on our storequantity_alarm
- the shop manager should get alarmed when the number of products go below this
For example, we have such row in the product table:
name: bicycle
quantity: 1294
quantity_alarm: 100
This means we're having 1294 bikes on the store at the moment and the shop manager gets alarmed when the number of bikes reaches 100.Simply, the manager of the shop wants to find the products he's running out of. He just wants to have something like a checkbox in his product admin generator filters. When he runs the filter with alarming attribute checked, he wants to see only those products which number is below the quantity_alarm.
Programming part
Configure the filters section of your admin generator:
filter:
display: [ alarming ]
fields:
alarming:
label: alarming quantity
help: products needing supplies
Modify ProductFormFilter
class. Let's begin with the configure
method:
public function configure()
{
// ...
$this->manageFieldAlarming();
}
protected function manageFieldAlarming()
{
$this->widgetSchema ['alarming'] =
new sfWidgetFormChoice(array(
'choices' => array(
'' => 'yes or no',
1 => 'yes',
0 => 'no'
)));
$this->validatorSchema ['alarming'] =
new sfValidatorPass();
}
Update the getFields
method:
public function getFields()
{
$fields = parent::getFields();
$fields['alarming'] = 'alarming';
return $fields;
}
Add the following method which will handle the database stuff:
public function addAlarmingColumnQuery($query, $field, $value)
{
Doctrine::getTable('Product')
->applyAlarmingFilter($query, $value);
}
Now we need to create the table class method that we just called in the code above. Go to ProductTable
model class and add the following:
/**
* Applies the alarming attribute to a given query retrieving products.
*
* @param Doctrine_Query $query - query to have alarming attribute applied.
* @param Integer $value - alarming?
*/
static public function applyAlarmingFilter($query, $value)
{
$rootAlias = $query->getRootAlias();
switch ($value)
{
case '0':
$query->where($rootAlias.'.quantity > '.$rootAlias.'.quantity_alarm');
break;
case '1':
$query->where($rootAlias.'.quantity <= '\.$rootAlias.'.quantity_alarm');
break;
}
return $query;
}
The whole thing is complete!
The code could be written in many different ways, of course. The sfValidatorPass
is used to pass unchanged filter values. There are three distinct values possible: empty string for 'yes or no', '0' for 'no' and '1' for 'yes'. If empty string is passed, we ignore it. If '0' or '1' is passed, we check it inside the switch statement.
If you're wondering about sfValidatorBoolean, it can't be used, since there are 3 options (yes, no, yes or no) and the boolean validator can handle only two values (but it can be used in other custom filters with no problems).
Notes
The above article is based on a magnificent symfony forum post by dlepage. It has been tested on symfony 1.4 but should work also with versions 1.2 and 1.3.