Elgg 1 is introducing a new (to elgg at least) way of executing arbitrary database queries. Basically, SQL is abstracted away into a class that can be used to construct multiple different types of query through a defined interface.

This provides two main advantages:

  1. The application programmer does not have to write the SQL themselves.
  2. It becomes considerably easier to change database back ends later down the line.

In addition, we can add free stuff like access controls etc.

From the documentation:

Query provides a framework to construct complex queries in a safer environment.

The usage of this class depends on the type of query you are executing, but the basic idea is to construct a query out of pluggable classes.

Once constructed SQL can be generated using the toString method, this should happen automatically if you pass the Query object to get_data or similar.

To construct a query, create a new Query() object and begin populating it with the various classes that define the various aspects of the query.

Notes:

  • You do not have to specify things in any particular order, provided you specify all required components.
  • With database tables you do not have to specify your db prefix, this will be added automatically.
  • When constructing your query keep an eye on the error log – any problems will get spit out here. Note also that __toString won’t let you throw Exceptions (!!!) so these are caught and echoed to the log instead.

Here is an example of a select statement:

// Construct the query
$query = new Query();

// Say which table we're interested in
$query->addTable(new TableQueryComponent("entities"));

// What fields are we interested in
$query->addSelectField(new SelectFieldQueryComponent("entities","*"));

// Add access control (Default access control uses default fields on entities table.
// Note that it will error without something specified here!
$query->setAccessControl(new AccessControlQueryComponent());

// Set a limit and offset, may be omitted.
$query->setLimitAndOffset(new LimitOffsetQueryComponent(10,0));

// Specify the order, may be omitted
$query->setOrder(new OrderQueryComponent("entities", "subtype", "desc"));

// Construct a where query
//
// This demonstrates a WhereSet which lets you have sub wheres, a
// WhereStatic which lets you compare a table field against a value and a
// Where which lets you compare a table/field with another table/field.
$query->addWhere(
new WhereSetQueryComponent(
array(
new WhereStaticQueryComponent("entities", "subtype","=", 1),
new WhereQueryComponent("entities","subtype","=", "entities", "subtype")
)
)
);

get_data($query);

Constructing a query out of classes in this way provides a lot of scope for expanding the functionality within a common framework, as well as providing a structured way of constructing complicated database queries.

However, if it looks too complicated, you can use about 99% of Query‘s functionality by using the subclass SimpleQuery, which provides methods for performing much of the standard functionality.

This is just a quick post to introduce a pair of functions I wrote today while working on some of the Elgg 1.0 access control code.

Namely, call_gatekeeper($function, $file = "") and callpath_gatekeeper($path, $include_subdirs = true), both of which return a boolean value.

call_gatekeeper()

This function tests to see whether it has the given method/function (optionally also test that it is defined in a specified file) exists on the call stack.

The function will return true if the called by the named function (or its parent was called by the named function).

Here is an example of its usage:

function my_secure_function()
{
if (!call_gatekeeper("my_call_function"))
return false;
... do secure stuff ...
}

function my_call_function()
{
// will work
my_secure_function();
}

function bad_function()
{
// Will not work
my_secure_function();
}

To specify a method instead of a function, pass an array to $function containing the classname and method name.

callpath_gatekeeper()

This function is similar to call_gatekeeper() but returns true if it is being called by a method or function which has been defined on a given path or by a specified file.

The function accepts two parameters:

$path, which is either the full path of the desired file or a partial path. If a partial path is given and $include_subdirs is true, then the function will return true if called by any function in or below the specified path.

The Elgg team are out in San-Francisco this week meeting up with some of the guys out here and talking about Elgg and ODD.

I will blog a bit more about it when I can, its been a bit mad so this is the first chance I’ve actually had to sit down at the computer since getting here (and I’m only able to do that because the combination of jet lag and the steak the size of my head I had for dinner last night has given me a case of insomnia).

I just wanted to share with you a thought that me and Ben had while enjoying the Californian sunshine inbetween meetings, namely a way to link ODD documents with OpenID.

For descovery of ODD documents, I was planning to use the meta / link approach similar to the way RSS is picked up. Now, it occurs to me that if we modify the spec slightly to say that a UUID should point to a page that can either be an ODD representation of the thing that it’s referring to or knows where to get it – i.e. has the appropriate header tag pointing to the url – then it becomes a trivial matter to turn a UUID into an OpenID URL.

Potentially quite useful.