Custom symfony filters to filter model relations
Posted by Paul de Raaij on april 21st, 2010For an application I was looking for a way to add filters in the generated admin application. We’de like to filter clients based on the articles or orders they have. Lets take a look at the (simplified) schema:
Account:
columns:
id: { type: integer, primary: true, autoincrement: true, notnull: true }
accountNumber: { type: integer, notnull: true }
accountName: { type: string(255), notnull: true }
Order:
columns:
id: { type: integer, primary: true, autoincrement: true, notnull: true }
internID: { type: string(20) }
accountID: { type: integer, notnull: true }
locationID: { type: integer }
orderDate: { type: timestamp }
orderedBy: { type: integer, notnull: true }
remarks: { type: string(3000) }
orderDelivered: { type: boolean }
placedOrder: { type: boolean }
relations:
Account: { onDelete: CASCADE, local: accountID, foreign: id, foreignAlias: accountOrders }
Article:
columns:
id: { type: integer, primary: true, autoincrement: true, notnull: true }
accountID: { type: integer, notnull: true }
articleNumber: { type: string(15) }
description: { type: string(255) }
currentStock: { type: integer }
minimumStock: { type: integer }
packageAmount: { type: integer }
previewFile: { type: string( 255 ) }
remarks: { type: string( 3000 ) }
internRemarks: { type: string( 5000 ) }
image: { type: string( 255 ) }
relations:
Account: { onDelete: CASCADE, local: accountID, foreign: id, foreignAlias: articleAccount }
In short. We have an account and each account has it own articles. The can order these articles and this is stored in the Order model ( and a bunch of others, which aren’t relevant for this post).
What we want to achieve is that we can filter the client list based on a article number or order id.
To do this I extended the generator.yml to add the two new fields.
config:
fields:
articleNumber: {label: Artikel nummer, type: string }
orderNumber: {label: Order nummer, type: string }
Next thing to do is to modify the filter form of the account model. Here we’re going to add the two new fields to the filter form and give them a simple validator.
public function configure()
{
parent::configure();
$this->widgetSchema['articleNumber'] = new sfWidgetFormInputText();
$this->validatorSchema['articleNumber'] = new sfValidatorPass(array('required'=>'false'));
$this->widgetSchema['orderNumber'] = new sfWidgetFormInputText();
$this->validatorSchema['orderNumber'] = new sfValidatorPass(array('required'=>'false'));
}
Now we want to add the filter values to the query so that the list actually gets filtered by the given values. Therefore were going to add a function for each of the filter fields. The function has one purpose and that is to add a where to the doctrine query.
protected function addArticleNumberColumnQuery( Doctrine_Query $query, $field, $values) {
$rootAlias = $query->getRootAlias();
$fieldName = 'articleNumber';
$query->addWhere( sprintf('%s.articleAccount.%s = ?', $rootAlias, $fieldName), $values );
}
protected function addOrderNumberColumnQuery( Doctrine_Query $query, $field, $values) {
$rootAlias = $query->getRootAlias();
$fieldName = 'id';
$query->addWhere( sprintf('%s.accountOrders.%s = ?', $rootAlias, $fieldName), $values );
}
The name of the function is specific and has to match the format add%fieldname%ColumnQuery. The code in the functions are pretty self-explanatory. Somethings are hard coded and could be a nicer. For example you could name the field accountOrders instead of orderNumber so that you can use the value of $field.
This is the simplest solution I could find for filtering a model based on its relations. If someone knows a better way I’d love to hear about it.
Tags: symfony

[...] Dit blogartikel was vermeld op Twitter door pderaaij. pderaaij heeft gezegd: Custom symfony filters to filter model relations – http://tinyurl.com/y4y2auf [...]