Warning: WEBUI\SEO\Visitor::Load_Canonical_Object_URI : Content not found in; Unable to load the SEO_URI for Object_Type:Blog, ID:14 in /sites/core2024.dev.kopel.ca/include/WEBUI/SEO/Visitor.class.php on line 91
CORE\DBTable\FilterParameter()


CORE\DBTable\FilterParameter()

Developer documentation

A neat little trickster that solves many headaches. You build a FilterParameter object by combining fields, operators and their values, in an array format. The novelty being the operators currently supported, and how we use this object.

Internally, the FilterParameter object can then be used to generate a convenient SQL WHERE clause (with <, >, != and even the "IN sub-select" operator), and serialized for easy saving and transport between the clients and servers. The convenience offered by its base64 conversion, is that once saved to a database (such as in a Digest table), you can quickly search on the base64 string for equivalence. But most importantly, it has some neat methods for generating hidden input fields on the fly, and maintaining its trueness even through JSON+Ajax+SQL+URLencoding. ;) And you can deal with objects or views composing more than 1 "key" or "filter" field, as 1 variable throughout your scripts.

$filterParameters = new \CORE\DBTable\FilterParameter();

$filterParameters->newFilter("SYS_User.SYS_Group_ID"$session->get_Org_GroupID(), "eq");

A short example on how to instantiate a FilterParameter object for use with our User administrative listing interface, in this case we're limiting the User Listing to the current user's organisational group ID, effectively limiting his view to his organisation colleagues. If the user were an extranet user in this case, his view would be limited to his external organisation.

When using the UI in developer mode, you might see the filterParameter's content decomposed in the developer digests, the format presented in the digests is meant to be human readable, and the closest representation the said content would have when sent through the wire to the client's JS environment through Ajax. Here's an explanation of such digest messages:

&ObjectParams[uiid54c04d4f0a5db6cfaab50873ce069633][Keyname]=Blog_ID
&ObjectParams[uiid54c04d4f0a5db6cfaab50873ce069633][Operator]=eq
&ObjectParams[uiid54c04d4f0a5db6cfaab50873ce069633][Value]=14
&ObjectParams[uiid54c04d4f0a5db6cfaab50873ce069633][displayName]=
&ObjectParams[uiid54c04d4f0a5db6cfaab50873ce069633][DBUIListName]=

This little example, which represents the current ObjectID of this blog, should be self-explanatory. The Blog_ID=14.

As a developer, you shouldn't have to worry about that detail though, this is strictly an internal representation of the data key's details. As a developer using this object at the PHP level, you'll be concerned with the newFilter() and ScanRequest() methods.

/**
* Add a new Filter/Parameter to the current compound list. You can add as many as you like, just don't go insane.
* Technically, we could auto-generate these filters from our DBUI definitions by generating filters for every field (presented in the current view)
* which has a DBUI_ListName defined. And even, from string fields by offering grep/search functionality (turning these filters into advanced search engines after all)
*
@param string $Keyname
* @param $Value
* @param string $Operator
* @param string $displayName this is used to display a label for the filter selector (usually a dropdown)
*
@param string $attachedDisplayListName this should be a DBUI_ListName
*
@return bool
*/
public function newFilter(string $Keyname, $Value, string $Operator = "eq", string $displayName = null, string $attachedDisplayListName = null) : bool

/**
* Scan the incoming $_REQUEST object for a specific (or the default) Parameter definition and initialize a FilterParameter object with it. If there are none, then the returned FilterParameter will be virgin (empty).
*
@param string $Parameter_Name
* @return FilterParameter
*
@throws \CORE\Ex\DBTableException
*
@throws CoreException
*/
public static function ScanRequest($Parameter_Name = self::Filter_Parameter_Name) : FilterParameter

Then, chaining FilterParameters to the DBTable rendering engine involves attaching your read -or- defined instance to the DBTable instance, after instancing the DBTable object, and before using it to Render a view.

Within the 4GL framework, we depend on the ObjectParams FilterParameter which is internally abused for (master) record keying. So anytime you wish to program a custom interface, you can generate your own "ObjectParams" FilterParameters for off-loading related objects, or catch the incoming one to key in the desired Object ID.

This ObjectParams, when automatically generated internally, will sponge up the primary key field(s) of the target table, and compose an array corresponding to the exact key required.

When used for List filters, then the full range of operators can be abused for manipulating list results. Internally, because of the recursive nature of some views, we generate localized "listFilters" for each table presented in the UI. If you're looking into customizing sub-components of master views, it might get tricky to tune in the proper naming constructs to achieve proper overrides, better leave it to the 4GL system -or- fashion your data structure so as to favor presenting heavy-filtering targets as main objects, where the overriding capability is easier to reach. But this is getting in the high-tech details, see our blogs on building dashboard components, where we should be giving out a number of recipes for designing nice little filtered tables.

Allowed Operators

=, eq equality, both forms can be used, although we internally reformat it to "eq" to spare developer eyes.
< lesser than
> greater than
<= less or equal
>= greater or equal
IN IN (sub-query) [SECURITY CONCERN for the freeform nature of sub-queries]
NOT IN NOT IN (sub-query) [SECURITY CONCERN for the freeform nature of sub-queries]
LIKE

as in a search field in SQL parlance, using the * as catch-all placeholder. (ah! not implemented currently)

When using the IN and NOT IN sub-queries, it is necessary to make sure to provide valid SQL queries without possibilities of user-tainting their content. If you are unsure what we mean by "tainted variables" you should probably not use those operators at all. They are exposed in the framework at the PHP level for customising interesting listings and filters, but we might block their re-entry from the Internet completely for the security implications.

FilterParameter as return objects

Its important to note that FilterParameters are also used internally to return ObjectIDs through Ajax, when a client submits records. Born out of a little impasse when adding records without a boring serial number (data insert in SQL parlance), a little despair drove us to write this object. So, the thing to know, is that you should expect ObjectIDs to be returned on successful object insertions and editions, in a JSON-array format which can then be converted to a JS-land ObjectID proper.

In the 4GL framework, we use Update_DBTable_ObjectID(dbtableFormObj,ObjectID,FormName,reloadURI) from the dbtable_library.js script, which will loop through all the Key fields and update the currently presented FormObject in the UI. Typically this allows a quick ajax save without reloading an Edit view, but we still reload an Add view for the potential child that need attaching.

And there is CreateRecordID( ObjectID ), which will convert a raw ObjectID into an URI parameter string ready for quick reading by our engine back on the server. (We normally further serialize our parameters before submitting them through Ajax using the POST method). Ah! Good occasion to remind developers to use the POST method when submitting any kind of data to be saved in a server environment, and save the GETs for actual data-retrieval, as per the web standards.

Important dev-hacker note; Although it might seem tempting to play around with the internals of FilterParameter to patch-in custom interfaces in other languages or environments, we strongly suggest avoiding any such attempt to spare on your mental sanity. Either use the provided PHP and JS methods, or port the object to your favorite language and test it thoroughly. Playing with database primary keys the wrong way can be as dangerous as playing with crypto keys. If compiling filters for rendering listings from an external environment, the same. You'll soon discover how burdensome a measly operator field can be on different technical levels. Here's the gist of the code that would allow one to port solid ObjectIDs;

function CreateRecordID( ObjectID ){
returnstr='';
Object.keys(ObjectID).forEach(function(key) {
console.log(key, ObjectID[key]);
returnstr=returnstr+'&ObjectParams['+key+'][Keyname]='+ObjectID[key]["Keyname"];
returnstr=returnstr+'&ObjectParams['+key+'][Operator]='+ObjectID[key]["Operator"];
returnstr=returnstr+'&ObjectParams['+key+'][Value]='+ObjectID[key]["Value"];
if
(ObjectID[key]["displayName"] !== null && ObjectID[key]["displayName"] !== 'null') {
returnstr = returnstr + '&ObjectParams[' + key + '][displayName]=' + ObjectID[key]["displayName"];
} else {
returnstr = returnstr + '&ObjectParams[' + key + '][displayName]=';
}
if (ObjectID[key]["DBUIListName"] !== null && ObjectID[key]["DBUIListName"] !== 'null') {
returnstr = returnstr + '&ObjectParams[' + key + '][DBUIListName]=' + ObjectID[key]["DBUIListName"];
} else {
returnstr = returnstr + '&ObjectParams[' + key + '][DBUIListName]=' ;
}

});
return
returnstr;
}

The key itself is not that important, the only requirement being that it remains unique to avoid problems. The named keys on the other hand are what makes the ObjectIDs digestible to our engine. Those need to be respected.