Jump to content

4.0 - Nodes & Content Items

Reminder: this blog covers the technical details of 4.0's programming. For details on 4.0's features, follow our main blog.


For almost all applications in the IPS Social Suite (IP.Chat being the notable exception), there are three components: Each of these different types of items share many common features. For example, in all applications you can "follow" nodes and Content Items, you can like (or give reputation on) Content Items and comments. There's also searching, tagging, moderator controls (pinning, locking, etc.), sharing, reports and so on. Up until now, applications were largely in charge of managing these different components and their relationships themselves, and utilised often complicated extensions to implement the common features. In 4.0, these components are handled differently. Each component follows an , extending a central class for the component, and implementing interfaces to enable additional features. Working with objects So, taking IP.Board as an example, the classes for each of the components (forums, topics and posts) will start off like this:

    [*]Categories created by the administrator. For example, forums in IP.Board, categories in IP.Downloads, calendars in IP.Calendar). In 4.0, the terminology used throughout the code for these is "Nodes". [*]Content created by users, usually (though, not always) within categories. For example, topics in IP.Board, files in IP.Downloads, events in IP.Calendar, images in IP.Gallery, personal conversations). In 4.0, the terminology used throughout the code for these is "Content Items". [*]Comments posted on Content Items by other users. In most applications these are simply called "comments" though in IP.Board they are called "posts" and in IP.Nexus and IP.Downloads they take the form of reviews.

    Active Record design pattern

    namespace IPSforums;
    class Forum extends IPSNodeModel { ... }
    class Topic extends IPSContentItem { ... }
    class Post extends IPSContentComment { ... }

    In , I already talked about how Nodes work and showed how easy it is to start using them. Content Items and comments are the same, with very little additional programming (only specifying a few properties to specify what database table to use and the names of the other classes they relate to), we can start using them. For example, to get a topic from the database, I just do:

    an earlier blog entry

    $topic = IPSforumsTopic::load( 1 );

    In this example, 1 is the ID number. If I was accepting user input, I could just wrap it in a try/catch statement. I could also, rather than using load() use an alternative factory method, loadAndCheckPerms(), which automatically checks if the currently logged in user has permission to view and throws an exception if not:

    	$topic = IPSforumsTopic::loadAndCheckPerms( IPSRequest::i()->id );
    catch ( IPSContentNoPermissionException $e )
    	IPSOutput::i()->error( "You do not have permission to view that topic.", 1, 403 );
    catch ( OutOfRangeException $e )
    	IPSOutput::i()->error( "Could not find topic. It may have been deleted.", 2, 404 );

    In the object, properties match the columns from the database table. For example, to set the page title to the topic title, I just do:

    IPSOutput::i()->title = $topic->title;

    There's also lots of methods available. For example, to get the IPSforumsForum object of the forum the topic belongs to, I just do:

    $forum = $topic->container();

    Or to get the IPSMember object of the member that posted the topic, I just do:

    $author = $topic->author();

    An Example: Getting the latest 5 topics One thing which is particularly easier now is that now the central classes handle common functionality, you can easily obtain data without having to worry about if everything has been accommodated - the class handles it automatically. I already showed how loadAndCheckPerms() works - for a more complicated example, let's say you wanted to get the 5 most recent topics to display in the sidebar. Previously you'd have to do a query, joining on the permissions table, providing the permission mask IDs of the current user manually, remembering to check to exclude hidden topics (unless of course, the user had permission to view hidden topics). In 3.x, it would have looked something like this:

    $member = ipsRegistry::instance()->member()->fetchMemberData();
    $topics = ipsRegistry::DB()->buildAndFetchAll( array( 
    	'select'   => '*',
    	'from'     => array( 'topics' => 't' ),
    	'where'    => ipsRegistry::getClass('class_public_permissions')->buildPermQuery( 'p', 'perm_2' ) . ( !$member['g_is_supmod'] ? ' AND queued=0' : '' ),
    	'add_join' => array(
    			'select'	=> 'p.*',
    			'from'		=> array( 'permission_index' => 'p' ),
    			'where'		=> 'p.perm_app="forums" AND p.perm_type="forum" AND p.perm_type_id=t.forum_id',
    			'type'		=> 'left',
    ) );

    In 4.0, the same thing can be done with just one line of code:

    $topics = IPSforumsTopic::getItemsWithPermission( NULL, 'start_date DESC', 5 );

    Naturally, one could have written a method to do this in 3.x, but in 4.0, because it is handled centrally, it is common to all applications. If a new feature is added which affects the functionality (such as when hiding content was added), each application does not have to be updated. Adding Features I already mentioned how there are certain features, like tagging, reputation, searching, etc. which are common to Nodes and Content Items throughout all applications. In 3.x, integrating these features involved writing a usually lengthy, extension. In 4.x, implementing most of these features is as simple as adding a few elements to your class. For example, let's take tagging. In 3.x, we have lengthy . It involves creating an extension, which in the IP.Board application totals 360 lines of code. In 4.x, you simply add an interface to your class - changing this:

    developer documentation for implementing tagging

    class Topic extends IPSContentItem { ... }

    Into this:

    class Topic extends IPSContentItem implements IPSContentTags { ... }

    That's all there is to it. Having done that, the form where a user adds or edits a topic will immediately gain a tags input field (the elements included on the form is handled centrally) and I can now call an additional method to get the tags on any topic so that I can display them in the HTML:

    $tags = $topic->tags();

    Here is a screenshot of the full developer documentation for tagging in 4.x: The programming method employed here is actually more suited to traits, as implementing the interface does not involve adding any additional code to your class. The reason we've chosen to do it this way though is because traits are only a feature in PHP 5.4 and above, and we wanted to support PHP 5.3. It is likely that in a future version of IPS Social Suite we will switch to using traits. Other examples Reporting In 3.x: - 502 lines for IP.Board. In 4.0: Read Markers (shows if content has been read or not) In 3.x: - 146 lines for IP.Board, plus manually marking items as read. In 4.0: Liking / Reputation In 3.x: - 222 lines for IP.Board. In 4.0: Following In 3.x: - 357 lines for forums, plus 361 lines for topics in IP.Board. In 4.0: For content items: For comments:





  • Create New...