Real Content in PHP5 CMS: Part 2

0
52
8 min read

Framework solution

To explore implementation details, we will look at an example that is simple enough to be shown in some detail. It is an application for handling pages composed largely of text and images. After studying the example, we will consider how the application could be made more advanced.

A simple text application

Here, we’ll look at a component that can be used on its own but is also intended as a starting point for more sophisticated uses. Its essence is that it handles a piece of text, created using the site WYSIWYG editor by the administrator. The text can be displayed as the main portion of a Web page. Ancillary information is held about the text. Any particular text can be the target of a menu entry, so the component can be used for simple pages. The WYSIWYG editor provides for moderately complex text layout and the inclusion of images.

We shall see that writing a text handling extension is made very much simpler by the various elements of the CMS framework.

The database table for simple text

After the ID number that is used as the main key we have the primary constituents of a piece of text. They are the headline, the subheading, and the body of the article. Each of these will simply reflect whatever text is put in them by the author, who in this simple implementation must also be an administrator.

Next we have a couple of time stamps that can be automatically maintained by the software. Rather obviously, the created time stamp is set when the row is created, and the modified time stamp is set every time the row is updated.

We then have fields that control the publication of the text. First, there is a simple indicator, which is set to zero if the text is not published and is set to one if it is published. When set to unpublished, the indicator overrides the start and end dates, if they are present. If a non-zero start date is set, then the text will not be published before that date. Likewise, if a non-zero finish date is set, the article will cease to be published after that date. Publishing dates are very useful to control when text will appear as it is often helpful to time the start of publication, and it creates a bad impression if obsolete text is not removed.

Then we have data that describes who has worked on the text. The original creator is recorded as a user ID, and the last modifier is likewise recorded as a user ID. These fields are intended for tracking what is happening to the text rather than for display. On the other hand, the byline is entirely for display.

Version is a character field that has no defined structure in this simple component, but could be elaborated in many different ways.

Storage for metadata is provided as keys and description. This information is not for display on the browser page, but is used to generate meta information in the header of a page containing the text. Tags containing metadata can influence search engines used for indexing of pages, although description is much more influential than keywords, which are believed to be largely disregarded.

Finally, a hit counter is automatically maintained by the system, being set initially to zero and then updated every time the text is shown to a site visitor.

A text data object

When a text item is loaded into memory from the database, a class provides for the definition of the object will be created. For the simple text application, the class is:

class textItem extends aliroDatabaseRow
{
protected $DBclass = 'aliroDatabase';
protected $tableName = '#__simple_text';
protected $rowKey = 'id';
public function store ($updateNulls=false)
{
$userid = aliroUser::getInstance()->id;
if ($this->id)
{
$this->modified = date('Y-m-d H:i:s');
$this->modify_id = $userid;
}
else
{
$ this->created = date('Y-m-d H:i:s');
$this->author_id = userid;
}
parent::store($updateNulls);
}
}

Much of the hard work is done in the parent class, aliroDatabaseRow. Because the database framework derives information from the database itself, there is no need to specify the fields that are in the table, which makes it easier to cope with future changes. The minimum that has to be done is to specify the name of the singleton database class, the name of the table (using a symbol in place of the actual prefix), and to define the name of the primary key field.

In this case, the store method is also extended. This provides an easy way to maintain the time stamps on the text. The current user is found through the aliroUser singleton class. We know whether a text row is new from whether it already has a value for id. The correct date and user field can then be updated. Finally, the standard store method in the parent class is invoked.

Administering text items—controller

The administrator logic for handling simple text follows the usual pattern of first providing a list of items, paged if necessary, then allowing more detailed access to individual items, including the ability to edit. Logic for overall control is provided by the aliroComponentAdminManager class, and the aliroComponentAdminControllers class. In fact, we could nominate in the packaging XML aliroComponentAdminManager as the adminclass for our component, since the dedicated textAdmin class does nothing:

class textAdmin extends aliroComponentAdminManager
{
// This could be omitted - included here in case extra
code needs to be added
public function __construct ($component, $system, $version)
{
parent::__construct ($component, $system, $version);
}
// Likewise, this could be omitted unless extra code is needed
public function activate ()
{
parent::activate();
}
}

Why might we want to write a dedicated extension to aliroComponentAdminManager? Well, this is the common entry point for the administrator side of our component, so if we wanted any processing to exist that could affect every use of the component, this is the place to put it. The two possible locations are the constructor and the activation method. The constructor receives information from the CMS environment in the form of a component object (describing this component), the name of the system that is calling us, and its version. It is invoked as soon as the correct component has been determined. The standard processing in the aliroComponentAdminManager constructor includes creating the controller class, and acquiring some common variables from $_REQUEST. Once setup is completed, the activation method is invoked without any parameters. The activate method of the aliroComponentAdminManager class strips any magic quotes, and decides what method to call.

Of course, the framework allows us to construct a component completely differently if we choose. The only constraint is that we must write a class whose name is given in the packaging XML, and provide it with an activate method. But usually it is a lot easier to follow the standard construction, and the bare bones of a new component can be built and downloaded online from http://developer.aliro.org.

Nothing specific has been done yet, and we have to move into the controller code before we can find anything to do with handling text objects. The controller is subclassed from aliroComponentAdminControllers and starts off as shown:

class textAdminText extends aliroComponentAdminControllers
{
private static $instance = null;
// If no code is needed in the constructor,
it can be omitted, relying on the parent class
protected function __construct ($manager)
{
parent::__construct ($manager);
}
public static function getInstance ($manager)
{
return is_object(self::$instance) ? self::$instance :
(self::$instance = new self ($manager));
}
public function getRequestData ()
{
// Get information from $_POST or $_GET or $_REQUEST
// This method will be called before the toolbar method
}
// If this method is provided, it should return true if
permission test is satisfied, false otherwise
public function checkPermission ()
{
$authoriser = aliroAuthoriser::getInstance();
if ($test = $authoriser->checkUserPermission('manage',
'aSimpleText', '*'))
{
if (!$this->idparm) return true;
if ($authoriser->checkUserPermission('edit', 'aSimpleText',
$this->idparm)) return true;
}
return false;
}

Here, the constructor is not needed; it is shown only to indicate the possibility of having code at the point the controller object is created. The constructor receives the manager object as a parameter, in this case an instance of textAdmin, a subclass of aliroComponentAdminManager.

The controller is a singleton class, and here a form of the getInstance method is shown that can be used completely unchanged from component to component.

Then we have two methods that are standard. Neither has to be provided, and in this case, the getRequestData method is not needed since it does nothing. Its purpose is to run early on (it is called before the toolbar processing and well before the processing specific to the current request) to acquire information from $_REQUEST or $_GET or $_PUT (or possibly other super-globals). They can be saved as object properties so as to be available for toolbar construction or other processing. The checkPermission method provides the component with a way to easily control who is able to access its facilities. If the method returns true then the user will be allowed to continue, but if it returns false, they will be refused access. In this example, there is always a check that the user is permitted to manage objects of the type aSimpleText and if a specific one is identified by its ID, then there is a further check that the user is permitted to edit that particular text item.

LEAVE A REPLY

Please enter your comment!
Please enter your name here