Quick search:

9. Global Filter

This application is situated in the example9 folder. To run it on your own server you need the same data as for example3. To try it out on the phpPeanuts website click here.

It extends a copy from example 8 with a global filter for filtering employee hours by date. The global filter is set and removed through the dialog you get by clicking the 'Filter' button in the 'Hours' page of an Employee. The global filter is set in the session and remains there until it is removed or the session ends. It causes the property Employee>>hours to be filtered. To see the result look at the hours of an employee, or at the employee report.

The support of the framework for global filters is limited: It only puts filters in the session, gets them out later, and shows a description of the active filters in most pages. The creation of the filters and the actual filtering is up to the application developer. See how to use global filters.

In order to set and remove the global filter, we needed a custom dialog. The content of the dialog is created by PntSqlFilterGlobalDialog. It uses skinGlobalFilterPart.php from the application folder to show the existing filter and print GlobalFilterFormPart. This part includes skinGlobalFilterFormPart.php to print the form and its input fields and buttons. For further details click one of the above classes and read the method documentation in the source.

To open the dialog window we added a button to the 'Hours' page of employee. This was done by overriding the getButtonsList method on the EmployeePropertyHoursPage class.  

When the form is submitted, a hidden field for 'pntHandler' set to 'GlobalAction' in combination with a hidden field 'pntType' set to 'PntSqlFilter' causes the request to be forwarded to an instance of PntSqlFilterGlobalAction. This action looks what button has been pressed and either builds a filter and puts it in the session, or removes the existing filter from the session. It outputs a small script to refresh the opener window and closes the dialog window.

The actual filtering is done in the method Employee::getHours. The way this method works is very similar to the method Employee::getHoursSince we created in example 7, except that it obtains the date filter from the session, and does not apply a date filter if there is no global date filter.

To show the result of the filtering in the Employee>>hours PropertyPage, 
we made the method getPropertyValueFor check for a filter. Of course the "Since' text input field and button are no longer needed if a global filter is available, so we wanted to override the printPart behavior for the PropertyPart to make it include the normal skinPropertyPart.php instead of skinEmployeeHoursPropertyPart.php if there is a global filter. See EmployeePropertyHoursPage::printPropertyPart.

The result of the filtering does not only affect the property Employee>>hours, but also derived properties that use this property. You can see the value of Employee>>nHours change if you look at the Employee report you get when you press the report button in the EditDetailsPage of an Employee before and after setting or removing a global filter.

Since version 1.1 the global fiter is also applied by the Employee SearchPage: If you search for some hours, the global filter is ANDed with the search filters. This is supported by the framework, all we had to do was activate it from a getFilterFormPart method on a new class example9.HoursSearchPage and from there call  setImplicitCombiFilter with the result of getGlobalCombiFilter. Because the global fiter is now used not only in the 'Hours' page of Employee we also added a link in the application submenu to open the global filter dialog. (Specifying a script from initMenuData requires version 1.1. of th examples).

Maybe the use of a global filter for only two properties and a search is somewhat overkill. The nice side of global filters is that the user can set a global filter and see all data the filter applies to filtered accordingly. The example application is too limited to really profit from that, so it's up to your imagination how global filters can be really useful.

Finally a remark on the OOP side of global filtering: The way it is implemented here is specific to languages like php, where domain model objects only exist within the context of a single http request. If for example you use Java or Smalltalk, you may for reasons of performance have a multi threaded multi user domain model serving for the processing of several HTTP requests at the same time. In that case you will need a more complicated design in order to prevent the filter from one user to influence the results seen by another user. For that reason some developers will say our implementation of global filters is badly designed. We say it's extreme programming to keep it simple as long as multi threading is not a requirement.