— Barnaby Scott

Archive
Development

I have been working on a project that required a fairly interactive SVG recently and ran into a small snag with links. To set an attribute of an SVG element you would normally do something like this:

el.setAttributeNS(null, "visibility", 'visibile');

This doesn’t work with links because the href attribute is namespaced with xlink (It looks like this is being removed in SVG 2). So you would embed a link in a page like this:

<a xlink:href="/about" id="InfoLink" target="_top">..wrapped nodes..</a>

And set the href attribute like this:

el.setAttributeNS( "http://www.w3.org/1999/xlink", "href", "/otherpage");
Read More

I have recently been trying to insert channel data directly into an ExpressionEngine site using their API. The situation is a little better than that of my previous post regarding members as there is an API there for you to use. There are still some gotchas to the process tho. The most troublesome so far has been when the channel has a file field on it.In this post i’ll cover how to add the path to a file when inserting data without the need to have POST’d the data.

To begin, if you look at the data stored for an existing entry with a file in the channel_data table in your EE database you will see that it is stored in the format:

{filedir_3}imagename.jpg

So your first attempt at uploading the data you would probably try moving the image file to the correct directory then inserting the previous string with the correct directory id and field id. Like so:

$this->EE->load->library('api');
$this->EE->api->instantiate(array('channel_entries', 'channel_categories', 'channel_fields'));
$data['field_id_24'] = sprintf('{filedir_%u}%s', $dir_id, $filename);
$this->EE->api_channel_entries->submit_new_entry($channel_id, $data);

N.b. You can get the directory ids from the upload_prefs table and the field ids from the channel_fields table.

Doing that however results in the following:

{filedir_}{filedir_3}imagename.jpg

It looks like the Channel API inserts the directory id itself and as we didn’t pass it we get an empty string. Checking out the Publish form with Firebug we see that in addition to the field_id_24 field it is sending a field called field_id_24_directory containing the directory id to store the image in. The next attempt now looks something like this:

$this->EE->load->library('api');
$this->EE->api->instantiate(array('channel_entries', 'channel_categories', 'channel_fields'));
$data['field_id_24'] = $filename;
$data['field_id_24_directory'] = $dir_id;
$this->EE->api_channel_entries->submit_new_entry($channel_id, $data);

The still doesn’t work as you are left with this:

{filedir_}imagename.jpg

So you are passing all of the correct data but for some reason the directory id isn’t being recognised. After a lot of digging the trail eventually leads to the File fieldtype class’ save method. which i will reproduce in full:

function save($data)
{
    if ($data != '')
    {
        $directory = 'field_id_'.$this->field_id.'_directory';
        $directory = $this->EE->input->post($directory);
        return '{filedir_'.$directory.'}'.$data;
    }
}

Do you see the problem? After the Channel API being perfectly happy to run with data that you provide it rather than resorting to checking the $_POST variables the file fieldtype lets us down by requiring that the directory id is set in the POST data. Now we know what the problem is we can fix it, in a fairly hacky way. Our next and final attempt would look something like this:

$this->EE->load->library('api');
$this->EE->api->instantiate(array('channel_entries', 'channel_categories', 'channel_fields'));
$data['field_id_24'] = $filename;
$_POST['field_id_24_directory'] = $dir_id;
$this->EE->api_channel_entries->submit_new_entry($channel_id, $data);

And thats it, we have successfully added an image to a channel entry without needing to POST the data through a form, the only side affect is that we are left feeling slightly dirty about our code.

Read More

A recent project used Expression Engine which was on the whole a pleasant experience there was however an inevitable sour note. I found the process of developing a module slightly cumbersome. They seem to have emulated WordPress (or vice versa) with regard to the basic hooks and filters approach, which although meeting some simple needs, falls short of full utility.

My aim was to create a module that among other things would add a new member to the site under a specific member group. This seemed like it would be a common use case that would be well covered by the core libraries. I started off digging through the user guide with no success so moved on to the forums. Here again I was stumped mainly being pointed in the direction of third party modules like the Solspace User module. I decided i would look at the ExpressionEngine core to see how it was done there before shelling out $99 on something i might not need.

After a dig about the result was the member module containing the register_member method which used the Member_register class, Bingo! A cursory check showed that it could meet my needs but being PHP4 and having no DocBlock  i was worried that it might be intended to be a private method and subject to change. I posted a simple query to the official support forum, which was awarded with defining silence. This point i am a little disappointed in given that ExpressionEngine is a commercial product.

Moving on i dug deeper into the register_member function and discovered quite apart from my expectations that it was getting it’s data directly from $_POST and littered with calls to output methods. This class is seems, is to be used for one thing only: adding members based on the specific input of the registration form. I was left with rolling my own member code and inserting them directly into the database.

This strikes me as a missed opportunity for ExpressionEngine both for maintaining the quality of plugins and easing developer involvement. By providing and API for modules to perform CRUD operations on the database you could better ensure the quality of the data and the security of the system. The following code is an example of how this interface might function:

1
2
3
4
5
6
7
8
9
10
try {
   $this->EE->load->library('member');
   $user_id = $this->EE->Member->addMember(array(
      'username' => 'dave',
      'password' => 'ilovehorses',
      'email' => 'dave@example.com'
   ));
} catch( Exception $e) {
   // Do stuff
}

Hopefully EllisLabs are moving towards this sort of core, as providing this sort of API not just for members but for all CRUD operations that a module would need could massively improve the ExpresisonEngine ecosystem for developers. An additional benefit of creating these APIs and making the core classes consumers of them is that you make it easier to run unit tests on ExpressionEngine.

Read More