In Elgg 1, we will finally have native support for a River – that is, a stream of short updates of what you and your friends are up to on your profile.

Here is a short post explaining how you as a plugin writer could add river reporting to your code!

Events

The key to how the river works is the Elgg 1 events system and the system log.

The system log will listen to events and some events pass an object. If the object implements the Loggable interface it will automatically be included in the system log.

The view

In order for things to appear in the river you need to provide a view. This view should be /river/CLASSNAME/EVENT, where CLASSNAME is the class you’re interested in and EVENT is the event.

For example, if you want to output create events for all ElggObjects then you would need to create a file called create.php in a directory /river/ElggObject/create.php.

This file will be passed a number of variables via $vars.

  • $vars['performed_by'] : An ElggUser object of the user that performed the action.
  • $vars['log_entry'] : The system log row (which includes the event).
  • $vars['object'] : The subject of the event.

You can use this information to put together a very customisable view, don’t forget to internationalise your strings!

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.