Ask John – Part 1

We got a lot of great questions from all of you for our ASK JOHN feature. It was hard to narrow it down to just a few questions for the inaugural article, but without further ado, here are your answers straight from the source!

Storage System

Steve R. asks, “What is possible with upcoming SE releases and what are best practices when delivering files via CDNs?”

The SocialEngine storage system is an abstract system designed to simply store and retrieve files and map a URL to their location. By implementing this system in your plugins, you will be able to use the CDN support that will be integrated into SocialEngine. It is also possible write your own storage adapters.

The storage system exists within the storage module (application/modules/Storage). There are several very basic methods to access the files stored within. A database row is created for each file containing the file path, which storage service the file is stored in, and other metadata.

Basic Usage

Starting in 4.1.0, all of the basic methods to access the storage system are in the class Storage_Model_DbTable_Files. You can get this class using:

Engine_Api::_()->getDbtable('files', 'storage');

Getting a file object is simple, you can use either of the following methods:

$file = Engine_Api::_()->getItem('storage_file', 1);
$file = Engine_Api::_()->getDbtable('files', 'storage')->find(1)->current();

To get the URL of the file, simply call the map method. This method may return a relative URL for local storage.

$url = $file->map();

You can read the contents of the file into a string or have the service transfer it to a temporary file using the read() and temporary() methods:

$contents = $file->read();
$tmpFile = $file->temporary();

Note that because the file is not guaranteed to be local, a file system path cannot be retrieved from the storage system. You will need to use one of the above methods to access the file.

You can delete a file using the remove method:


In order to create a file, you must have certain information about the file:
1) The file is owned by a user, so you need the ID of the user that it belongs to.
2) The file is associated with an item, which can also be the user. This tells what specific item the file is associated with. The parent type must be part of the item system. For example, a group photo is owned by the user that uploads it, but it is associated with the group.
3) The file path, or $_FILES array. If you use the $_FILES array, the name and other metadata will be pulled from it instead of automatically generated.

The storage service will throw an exception if the user’s quota is reached or it could not store the file. It it your responsibility to remove the original copy of the file after it’s been imported into the storage system.

Here is an example of how to store a file:

$storage = Engine_Api::_()->getDbtable('files', 'storage');
$file = $storage->createFile($_FILES['Filedata'], array(
	'user_id' => $user_id,
	'parent_type' => 'group',
	'parent_id' => $group_id,
$file_id = $file->getIdentity();

Using Thumbnails

The files table also can keep track of different versions of files. This is mainly used for thumbnails. You can access a thumbnail using the ID of the original image using the getFile() method in Storage_Model_DbTable_Files. Note that if there is no alternate file of the specified type, it will return the original file instead. Example usage:

$file = Engine_Api::_()->getDbtable('files', 'storage')->getFile(100, 'thumb.icon');
echo $file->getIdentity(); // 103

In order to associate two files, you call the bridge() method on the original file and pass it the second file, and give it a string type that is used to access it:

$file->bridge($otherFile, 'thumb.icon');

Search System

Steve R. also asks, “How does Search code work and how can devs plug into the code to extend to 3rd party plugins and/or custom mods?”

The search system is used to build a search index of text associated with various content. A dedicated table, engine4_core_search, contains this information and is stored using MyISAM in order to utilize it’s fulltext search capabilities. Using a single table allows all content to be searched through at once, and using a table separate from the original allows the original tables to be stored using InnoDB.

In order to use the search indexer, your content must be loadable using the item system. If your item class extends Core_Model_Item_Abstract, the insert and update hooks will be used to index the item’s content.

There are a couple things that need to be configured in order to correctly use the search indexer:
1) There is a property Core_Model_Item_Abstract::$_searchTriggers that defines which columns will trigger an index update when changed. You may need to override this value if you use different column names.
2) You may want to define a search column in the table row or override the isSearchable() method to determine if the item should be indexed.
3) The search indexer requires the getTitle() and getDescription() methods to return data.
4) There is also a getKeywords() and getHiddenSearchData() method that is supported. The latter will not be displayed to a user.

For rendering purposes, you should implement the getTitle(), getDescription() and getPhotoUrl() methods such that the proper information is rendered in the search results.


Rich asks, “What IDE do you recommend for SE development and how do you recommend setting it up?”

We recommend Netbeans as an IDE. One of the primary reasons for this choice (at the time) was the lack of a decent FTP plugin for Eclipse. We also prefer the simplicity of Netbeans’ UI over Eclipse.

If you’re looking for a slightly better text editor rather than a full IDE, we recommend Geany, Programmer’s Notepad, or TextMate.

We use two spaces as indentation within SocialEngine.

If you plan to use Subversion with Netbeans on Windows, we recommend the SlikSVN client. For Linux or OSX, you can use the Subversion CLI binaries.

Netbeans supports uploading files over FTP/SSH as they are saved and has options to preserve existing file permissions.

That’s all for now! As mentioned before, we will run this feature every few weeks, so post any questions you have below. Don’t be shy about letting us know if this is too technical, not technical enough, or exactly what you’d hoped for!

Leave a comment

Your email address will not be published. Required fields are marked *