For 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.
1 Response
[…] Dit blogartikel was vermeld op Twitter door pderaaij. pderaaij heeft gezegd: Custom symfony filters to filter model relations – http://tinyurl.com/y4y2auf […]