Earlier this week, I talked about our custom datagrid for Propel and
how it was being rewritten to interact with our CriteriaBuilder (read
more). Well, I’ll give you another glance into our coding
efforts.
an object, which would manipulate the data being shown in our
grid_propel. For normal people, this means: to filter the data.
Early on, we
decided it had to ‘build a Criteria‘ (because Propel rules!), which
then could be used by our grid_propel.
CriteriaBuilder is in essence nothing but an array of FilterData
objects, which is indexed by the FilterColumn’s name (Propel peer
constant), so there could only be one FilterData object per
FilterColumn.
Of course, there’s more to it, about a thousand
lines of code actually (phpDoc included), but almost half of that are
xajax functions for user interaction, and then there are methods like
addAvailableColumn & qAddAvailableColumn to initialize the
CriteriaBuilder, and internal functions, which I’m not all going to
explain here. I’ll touch some of them in the next section.
Behind
The __toString
function, will loop all FilterData objects and create a selector,
with their column name or with a more human readable alias, using our
XHTML package, which I’ll perhaps tell you more about on a
quite/rainy day. It’s an object-oriented package to quickly create
readable and XHTML valid code, I can tell you that.
The add filter
button will trigger the xajax function addFilter, which adds a
UserFilter to the FilterData object related to the selected/passed
value and then updates the ‘criteriaform’.
This criteriaform
shows for every UserFilter a ‘criteriaLine’, with a combination box
(disabled if only one line present), a filter method selector and
something to determine the search value.
Clicking ‘apply
filters’ will trigger another xajax function, which will build the
Criteria based on the current UserFilters, and pass it to all
registered CriteriaClients through the CriteriaClient interface
method processCriteria. This is an implementation of what Java
programmers probably know as the Listener pattern, meaning that an
object implementing the CriteriaClient interface registers itself as
Listener/CriteriaClient, by calling
CriteriaBuilder::addClient(CriteriaClient).
This means that the
CriteriaBuilder can serve any (and more than one) object implementing
the CriteriaClient interface, not just our grid_propel!
The ‘remove this
filter’ button will trigger a xajax fuction, which will remove the
UserFilter from the FilterColumn’s UserFilter array, reorder its
keys, and update the criteriaform.
The ‘clear all
filters’-button, naturally, deletes all UserFilters and also updates
the CriteriaForm. Because there are no filters left, the criteriaform
will disappear again.
Both functions will also immediately update
the grid by calling buildCriteria (which calls processCriteria on its
clients).
I’ve recently
added a ’save filter’-button, which makes this box appear,
giving the user
the option to save his filter combination. Which is then linked to
the CriteriaBuilder’s name and saved in our database. When a
CriteriaBuilder is ‘__tostringed’, it will search for these filters,
and if one’s found, you’ll get something like this.
Selecting a saved
filter will once again trigger a xajax function, which will load the
filter (update criteriaform and build Criteria, and thus updating the
grid).
For now, these are personal filters, because they’re linked
to the user who’s created them. Later, we could easily extend the
code, so they can be shared, or something like that…
Note that
by linking the saved filters to the CriteriaBuilder’s name, we’re
able to use the same filters on different pages, by naming the
CriteriaBuilders the same.
Everything
Now, you know
what’s happening behind the scenes when a user uses our
CriteriaBuilder, but that’s not even half the story. Still using our
user grid, I’ll explain how the CriteriaBuilder’s FilterData objects
are being initialized.
We
use this code on our page (FYI: our pages are also created using an
object-oriented framework)
[code]CB_pageContent[/code]
that I come to think of it, this should be stored in the grid_propel,
not in the CriteriaBuilder, because the original Criteria can be
different per client!
You see this is code in progress… We
actually don’t use multiple CriteriaBuilders nor CriteriaClients
ourselves, yet…
I simply added the method getOriginalCriteria
to the interface class CriteriaClient. CriteriaBuilder::buildCriteria
now retrieves its ‘Criteria to work with’ via that method, thus from
the grid_propel, which of course has an extra variable
originalCriteria now. Grid_propel::setCriteria is now
[code]CB_setCriteria[/code]
Voila,
solved!
Ok,
to continue… $cb->qAddUserColumnSet
is a convenience method.
Admitted, these functions should better
be in an extending class, but nobody’s perfect
And since we’re
the only ones using it…
[code]CB_qAddUserColumnSet[/code]
As
you can see, this method adds the columns we say the grid can be
filtered on. These could also be columns which aren’t shown in the grid_propel.
[code]CB_qAddAvailableColumn[/code]
UserFilter
This
defines which ‘type’ of UserFilter will be used. For each constant,
there’s a descendant of UserFilter. They complete UserFilter by
defining the abstract __toString function. So each descendant will be
shown different.



dynamic)

not contain’. When this filter is selected the search value
determinator, will change into an inputfield.
First
Then


how it was being rewritten to interact with our CriteriaBuilder (read
more). Well, I’ll give you another glance into our coding
efforts.
Goal
We wanted to makean object, which would manipulate the data being shown in our
grid_propel. For normal people, this means: to filter the data.
Early on, we
decided it had to ‘build a Criteria‘ (because Propel rules!), which
then could be used by our grid_propel.
Structure
TheCriteriaBuilder is in essence nothing but an array of FilterData
objects, which is indexed by the FilterColumn’s name (Propel peer
constant), so there could only be one FilterData object per
FilterColumn.
Of course, there’s more to it, about a thousand
lines of code actually (phpDoc included), but almost half of that are
xajax functions for user interaction, and then there are methods like
addAvailableColumn & qAddAvailableColumn to initialize the
CriteriaBuilder, and internal functions, which I’m not all going to
explain here. I’ll touch some of them in the next section.
Behind
the scenes
The __toStringfunction, will loop all FilterData objects and create a selector,
with their column name or with a more human readable alias, using our
XHTML package, which I’ll perhaps tell you more about on a
quite/rainy day. It’s an object-oriented package to quickly create
readable and XHTML valid code, I can tell you that.

button will trigger the xajax function addFilter, which adds a
UserFilter to the FilterData object related to the selected/passed
value and then updates the ‘criteriaform’.

shows for every UserFilter a ‘criteriaLine’, with a combination box
(disabled if only one line present), a filter method selector and
something to determine the search value.
Clicking ‘apply
filters’ will trigger another xajax function, which will build the
Criteria based on the current UserFilters, and pass it to all
registered CriteriaClients through the CriteriaClient interface
method processCriteria. This is an implementation of what Java
programmers probably know as the Listener pattern, meaning that an
object implementing the CriteriaClient interface registers itself as
Listener/CriteriaClient, by calling
CriteriaBuilder::addClient(CriteriaClient).
This means that the
CriteriaBuilder can serve any (and more than one) object implementing
the CriteriaClient interface, not just our grid_propel!
The ‘remove this
filter’ button will trigger a xajax fuction, which will remove the
UserFilter from the FilterColumn’s UserFilter array, reorder its
keys, and update the criteriaform.
The ‘clear all
filters’-button, naturally, deletes all UserFilters and also updates
the CriteriaForm. Because there are no filters left, the criteriaform
will disappear again.
Both functions will also immediately update
the grid by calling buildCriteria (which calls processCriteria on its
clients).
I’ve recently
added a ’save filter’-button, which makes this box appear,

the option to save his filter combination. Which is then linked to
the CriteriaBuilder’s name and saved in our database. When a
CriteriaBuilder is ‘__tostringed’, it will search for these filters,
and if one’s found, you’ll get something like this.

filter will once again trigger a xajax function, which will load the
filter (update criteriaform and build Criteria, and thus updating the
grid).
For now, these are personal filters, because they’re linked
to the user who’s created them. Later, we could easily extend the
code, so they can be shared, or something like that…
Note that
by linking the saved filters to the CriteriaBuilder’s name, we’re
able to use the same filters on different pages, by naming the
CriteriaBuilders the same.
Everything
configurable!
Now, you knowwhat’s happening behind the scenes when a user uses our
CriteriaBuilder, but that’s not even half the story. Still using our
user grid, I’ll explain how the CriteriaBuilder’s FilterData objects
are being initialized.
We
use this code on our page (FYI: our pages are also created using an
object-oriented framework)
[code]CB_pageContent[/code]
So…
We initialize our grid_propel, grid_users (see this post), and
specify its starting Criteria. You can also neglect this, then a new
(empty) Criteria will be used. Next, we use the CiteriaBuilder’s
constructor to pass the grid as CriteriaClient, set its name, and set
the original Criteria, which is used to restore the grid to its
original state.
Now,We initialize our grid_propel, grid_users (see this post), and
specify its starting Criteria. You can also neglect this, then a new
(empty) Criteria will be used. Next, we use the CiteriaBuilder’s
constructor to pass the grid as CriteriaClient, set its name, and set
the original Criteria, which is used to restore the grid to its
original state.
that I come to think of it, this should be stored in the grid_propel,
not in the CriteriaBuilder, because the original Criteria can be
different per client!
You see this is code in progress… We
actually don’t use multiple CriteriaBuilders nor CriteriaClients
ourselves, yet…
I simply added the method getOriginalCriteria
to the interface class CriteriaClient. CriteriaBuilder::buildCriteria
now retrieves its ‘Criteria to work with’ via that method, thus from
the grid_propel, which of course has an extra variable
originalCriteria now. Grid_propel::setCriteria is now
[code]CB_setCriteria[/code]
Voila,
solved!
Ok,
to continue… $cb->qAddUserColumnSet
is a convenience method.
Admitted, these functions should better
be in an extending class, but nobody’s perfect
And since we’re
the only ones using it…
[code]CB_qAddUserColumnSet[/code]
As
you can see, this method adds the columns we say the grid can be
filtered on. These could also be columns which aren’t shown in the grid_propel.
[code]CB_qAddAvailableColumn[/code]
So…
In our case, we use the CriteriaBuilder’s constants, for example
CriteriaBuilder::FILTERSET_TEXT
stands for the array
[code]CB_ex_array[/code]In our case, we use the CriteriaBuilder’s constants, for example
CriteriaBuilder::FILTERSET_TEXT
stands for the array
UserFilter
types
Thisdefines which ‘type’ of UserFilter will be used. For each constant,
there’s a descendant of UserFilter. They complete UserFilter by
defining the abstract __toString function. So each descendant will be
shown different.
TYPE_TEXT
simple inputfieldTYPE_BOOLEAN
simple select
TYPE_DATE
JavaScript calendar widget
TYPE_SPECIFIC
selector with values available in database for that column (=dynamic)

TYPE_SPECIFIC_SWITCH
special specific, it has extra filtermethods ‘contains’ & ‘doesnot contain’. When this filter is selected the search value
determinator, will change into an inputfield.
First


Of course, you can combine as many filters as you want.

No comments:
Post a Comment