To get started we need to create a PHP file named after the component in the component's frontend folder and we need to create a PHP file named after the component and prefixed with admi
Trang 1For each major entity, you should identify the tasks associated with each You can use the table in the previous section, which identified common task and method names to help identify tasks.
We have seen how to build models, views, and controllers but we have yet to see how we actually use them To get started we need to create a PHP file named after the component in the component's frontend folder and we need to create a PHP file named after the component and prefixed with admin in the component's
backend folder
These files are executed when the component is invoked via the frontend and backend respectively This example shows how we might implement one of these files:
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted Access');
// get the controller
require_once(JPATH_COMPONENT.DS.'controller.php');
// instantiate and execute the controller
$controller = new MyextensionController();
We can do far more with these files if we wish, but often we do not need to;
generally, it is better to keep the processing encapsulated in controllers
It is common practice to use multiple controllers, one for each entity These are generally stored in a folder called controllers in files named after the entity Each controller class is named after the entity and prefixed with MyextensionController When we use multiple controllers, we generally use the URI query request value c
to determine the controller to instantiate This demonstrates how we can deal with multiple controllers:
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted Access');
// get the base controller
require_once(JPATH_COMPONENT.DS.'controller.php');
Trang 2// controller does not exist
JError::raiseError('500', JText::_('Unknown controller')); }
/**
* Gets a reference to a subclass of the controller.
*
* @static
* @param string entity name
* @param string controller prefix
* @return MyextensionController extension controller
Trang 3// check if we already instantiated this controller
// create controller instance
$instances[$class] = new $class();
}
// return a reference to the controller
return $instances[$class];
}
We can now alter the component root file to use the getInstance() method:
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted Access');
// get the base controller
Trang 4This list details some important things to consider when designing and
building controllers:
If you have one major entity, you should consider building one controller
If you have a number of entities, you should consider using a separate controller for each
To manage multiple controllers, it can be useful to create another controller, which instantiates the controllers and siphons tasks to them
If you have a number of similar entities, you should consider building an abstract controller, which implements common tasks
Up to this point, we have hardly mentioned the back and frontends in relation to the MVC The way in which the MVC library is constructed leads us to using separate controllers, views, and models for the front and back ends
Since we will generally be using the same data in the front and backend, we might want to use some of the same MVC elements in the frontend and backend If you do choose to do this, it is normal to define the common MVC elements in the backend
To access models and views located in the backend from the frontend we can
manually tell Joomla! about additional paths to look in It is relatively unlikely that you would want to use the same view in the front and back-end If you do want to
do this, you should carefully consider your reasons
This is an example of an overridden controller constructor method It tells the
controller that there are other places to look for models and views
•
•
•
•
Trang 5precedence, all we would need to do is move the parent:: construct() call to the end of the overridden constructor method.
Rendering Other Document Types
We mentioned earlier that you can create a view for the document types, feed, HTML, PDF, and RAW We have already briefly explained how to implement views for the HTML document type This section describes how to create feed, PDF, and RAW views
Every view, created in the views folder as a separate folder, can support any number
of the document types This table shows the naming convention we use for each
Document Type File Name Description
Feed View.feed.php Renders an RSS 2.0 or Atom feed
HTML view.html.php Renders a text/html view using the site template
RAW view.raw.php Renders any other type of document; defaults to
text/html, but we can modify this
There is a fifth document type, error We cannot create views within our components for this document type The error document renders using a template from the site template or core error templates
To request a page as a different document type, we use the request value format For example to request the component My Extension in feed format, we might use this URI:
http://www.example.org/joomla/index.php?option=com_
myextension&format=feed
The four document types might sound restricting However, the RAW document type has a clever trick up its sleeve When Joomla! encounters a unknown format, it uses the RAW document This means that we can specify bespoke formats We will discuss this in more detail in a moment
Feed
Before you choose to create a feed view you should consider whether the data is worthy of a feed The data in question should be itemized and it should be likely to change on a regular basis
Joomla! supports RSS 2.0 (Really Simple Syndication) and Atom (Atom Syndication
Format) feeds; which is being used makes no difference as to how we build a feedmakes no difference as to how we build a feedas to how we build a feed view class
Trang 6We use the JFeedItem class to build feed items and add them to the document JFeedItem objects include properties that relate to the corresponding RSS and Atom tags The properties marked with a dash are not used by the corresponding feed format.
Property
Required by RSS Required by Atom
Description
authorEmail - - Author's email address, not currently supported by Joomla!
Comments - URI to comments about the item
Date - Date on which the item was created (UNIX timestamp)Description Description of the item
Enclosure JFeedEnclosure object; describes an external source, for example a video file
Source - - 3rd party source name, not currently supported by Joomla!
For more information about how these tags work in RSS please refer to
http://www.rssboard.org/rss-specification For more information about how these tags work in Atom please refer to http://tools.ietf.org/html/rfc4287 This example shows how we can build a feed; this would be located in a display()method in a view class that deals with feeds
// set the basic link
$document =& JFactory::getDocument();
$document->setLink(JRoute::_('index.php?option=com_myextension'); // get the items to add to the feed
Trang 7// create a new feed item
$item = new JFeedItem();
// assign values to the item
$item->author = $row->author;
$item->category = $row->category;
$item->comments = JRoute::_(JURI::base().'index.php?option= com_myextension&view=comments&id='.$row->id); $item->date = date('r', strtotime($row->date));
Trang 8// add the links
$document =& JFactory::getDocument();
$document->addHeadLink(JRoute::_($feed.'&type=rss'), 'alternate', 'rel', $rss);
$document->addHeadLink(JRoute::_($feed.'&type=atom'), 'alternate', 'rel', $atom);
To use this you will need to modify $feed to point to the correct location for your component
Views that support the PDF document type build the data to be rendered in PDF format in HTML Joomla! uses the TCPDF library to convert that HTML into a PDF document Not all HTML tags are supported Only the following tags will affect the layout of the document; all other tags will be removed
Trang 9This screenshot depicts the properties of the resultant PDF document:
To add content to the document all we need to do is output the data as we would normally.
$document =& JFactory::getDocument();
$document->setMimeEncoding('text/xml');
Trang 10If we are outputting a document in which the content has been modified at
a set date, we may want to set the document modified datẹ We can use the
setModifiedDate() method to do this In this example you would need to replace time() with an appropriate UNIX timestamp to suit the date to which you are trying
to set the modified date:
$document =& JFactory::getDocument();
$date = gmdate('D, d M Y H:i:s', time()).' GMT';
Imagine we want to create an XML response using the RAW document First, let
us choose a name for the document format The name must not be the same as any
of the existing formats and although we could use the name 'raw', it is not very descriptivẹ Instead, we will use the name xml This URI demonstrates how we would use this:
http://www.examplẹorg/joomla/index.php?option=com_
myextension&format=xml
When we do this, the document will be of type JDocumentRaw
The next thing we need to do is create the view class This name of the file includes the format name, note that we use the format name 'xml', not 'raw For example, the file might be named myview.xml.php This example demonstrates how we might construct the view class:
class MyextensionViewMyview extends JView
{
function display($tpl = null)
{
// modify the MIME type
$document =& JFactory::getDocument();
$document->setMimeEncoding('text/xml');
// ađ XML header
echo '<?xml version="1.0" encoding="UTF-8" ?>';
// prepare some data
$xml = new JSimpleXMLElement('element');
$xml->setDatắThis is an xml format document');
Trang 11// output the data in XML format
<element>This is an xml format document</element>
The great thing about this is it enables us to create many formats for one view
Dealing with Component Configuration
The chances are that a component that we are building is going to need some
configuration options Every component can store default parameters about itself
A relationship exists between menu items and the component configuration The configuration edited from within the component defines the default configuration When we create a new menu item, we can modify the component configuration specifically for the menu item This enables us to override the default configuration
on a per-menu-item basis
To define component parameters we must create an XML metadata file, called config.xml, in the root of our component in the backend The file contains a root element config, and nested within this is a params tag In this tag, we define
different parameters, each in its own param tag
This example defines two parameters, a title and a description (a complete description
of the different parameters and their XML definition is available in the Appendix):
<?xml version="1.0" encoding="utf-8"?>
<config>
<params>
<param name="title" type="text" default="My Title"
label="Title" description="Title of page" size="30" /> <param name="description" type="textarea" default=""
label="Description" rows="5" cols="50" description= "Description to display at top of page." /> </params>
</config>
Trang 12Once we have created the XML file, the next step is to use the file to allow an
administrator to edit the component parameters Joomla! provides us with an easy way of doing this
In the backend, components have a customizable menu bar There is a special button
we can add to this menu bar, called preferences, which is used to enable editing of
a component's parameters A complete description of the menu bar is available in Chapter 8
This example shows how we add the button We use two parameters to define the name of the component and the height of the preferences box Adding buttons to the administration toolbar is explained in detail in Chapter 8
JMenuBar::preferences('com_myextension', '200');
When an administrator uses this button, they will be presented with a preferences box The first parameter determines which component's parameters we want to modify The second parameter determines the height of this box This screenshot depicts the preferences box displayed for com_myextension using the XML file we described earlier:
Now that we can define and edit parameters for a component, we need to know how
to access these parameters from within the frontend of our component To achieve this we use the application getPageParameters() method:
$params =& $mainframe->getPageParameters('com_myextension');
The great thing about this method is that it will automatically override any of the component's default configuration with the menu item's configuration If it did not,
we would have to merge the two manually
The returned object is of type JParameter This class deals specifically with XML metadata files, which define parameters To get a value from the component
parameters we use the get() method:
$title = $params->get('title');
We can use this snippet of code anywhere in our component Many of the core components retrieve component parameters in models, views, and controllers
Trang 13Elements and Parameters
We have mentioned using parameters in the component configuration file; there are many other instances where we can use the param tag, for example defining module parameters When we use the param tag in XML files, we are defining data items As part of this we use the XML to produce rendered forms JElement is the abstract class subclasses of which can be used to render each of the parameters.of which can be used to render each of the parameters
JElement subclasses are used in conjunction with a single param tag and render a form input tag based upon it There are a number of predefined parameter types (JElements) that we can use:
A full description of each of these is available in the Appendix.
Before we move on, it is important that we understand a bit more about JElement In Chapter 3, we talked about the use of the parameter fields in databases Theses fields are INI strings, which we can use in conjunction with the JParameter class
Trang 14The JParameter class handles these strings and uses XML definitions, like the
ones we have discussed in this chapter, to help comprehend the data As part of JParameter we can render the INI string using an XML definition It is at this point that JElement kicks in
A JElement subclass always overrides the fetchElement() method This method is what renders a single form input element Because JParameter deals with INI strings,
a JElement form element can only return a single value For example, we cannot define a JElement subclass that renders a select list that allows multiple options to
be selected
Extending JElement
Before we create a new JElement subclass, we should carefully consider if we need
to If the data is coming from the database, we should always think about using the sql element; this is a very generic element, which allows us to create a select list based on a database query
When we create new JElement subclasses, we must follow some specific naming conventions JElement subclasses are named after the element type and prefixed with the word JElement The class is stored in a separate file named after the element type The file is in the elements folder in the component's administrative root
Imagine we want to create a new element type, menus The class would be called JElementMenus and be located in the file menus.php The class needs to extend the core JElement class; we do not need to import the joomla.html.parameter.elementlibrary because the JParameter class does this atomically when it loads JElements
In order to build the class, we need to decide on the XML we are going to use
to define a JElementMenus parameter This element is very similar to the listselement so we may as well use a similar structure This example demonstrates the XML we are going to use:
<param name="name" type="menus" label="Menus" description=
"A Grouped List" default="1" class="Some CSS"> <group>Group 1
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
</group>
<group>Group 2
<option value="4">Value 4</option>
<option value="5">Value 5</option>
</group>
</param>
Trang 15We use nested group tags to group the different options together The option tags are identical to those used by JElementList For a complete description of menu select lists, please refer to http://www.w3schools.com/tags/tag_optgroup.asp.
To build the JElementMenus class, there are two things we should always do when defining JElement subclasses: override the fetchElement() method and set the _name property
To implement our fetchElement() method we will use the static JHTMLSelectclass; this class is used to build select lists and menu select lists There are two
methods that we need to be aware of: JHTMLSelect::option() and JHTMLSelect::genericList()
JHTMLSelect::option() returns an object that represents a list option
JHTMLSelect::genericList() returns a rendered HTML string of a form select tag based on an array of objects and a few additional parameters
This example shows how we can implement the JElementMenus class:
* @param string Name of the form element
* @param string Value
* @param JSimpleXMLElement XML node in which the element is defined
* @param string Control set name, normally params
*/
function fetchElement($name, $value, &$node, $control_name)
{
// get the CSS Style from the XML node class attribute
$class = $node->attributes('class') ? 'class="'.$node-> >
attributes('class').'"' : 'class="inputbox"';
Trang 16// prepare an array for the options
''.$control_name.'['.$name.']', $class, 'value', 'text', $value, $control_name.$name); }
}
Using Custom JElement Classes
To use our JElementMenus class we need to do more than add a param tag
of type 'menus' to our XML file We need to tell Joomla! where it can find the
JElementMenus class To do this we use the addpath attribute
Building on our previous example of a component config.xml file, this XML defines another parameter, using the menus type JElement (assuming that
the JElementMenus class is located in the administrator/components/
<param name="title" type="text" default="My Title"
label="Title" description="Title of page" size="30" />
<param name="description" type="textarea" default=""
Trang 17label="Description" rows="5" cols="50"
description="Description to display at the top of the page." /> <param name="menus" type="menus" label="Select Menus"
description="Test JElementMenus" default="3">
<group>Group 1
<option value="1">Value 1</option>
<option value="2">Value 2</option>
<option value="3">Value 3</option>
</group>
<group>Group 2
<option value="4">Value 4</option>
<option value="5">Value 5</option>
Trang 18Core help files are located in the administrator/help directory To support multilingual requirements, the help directory contains one folder for each installed language, for example en-GB Located in these folders are the HTML help files.
We can use a similar implementation for our components We must create a helpfolder in the administration root of our component and add a subfolder for every help language that we support
Imagine we want to create a generic help file for the component 'My Extension' In the component's administrative root we need to create a folder called help and in there we need to create a folder called en-GB Now if we create a file called help.html and save it into the help\en-GB folder, we can use the administration menu-bar help button to view it, as this example demonstrates:
to use SEF (Search-Engine Friendly) URIs.
In order to take advantage of SEF URIs, when we render any URI we need to use the JRoute::_() method This method converts normal URIs into SEF URIs; this will only happen if the component we are trying to link to has a router and the SEO options are enabled In this example we parse the URI 'index.php?option=com_myExtension&category=3&item=6' into an SEF URI
Trang 19To create a router for a component we must create a file called router.php in the root of the component In the file we need to define two functions, BuildRoute()and ParseRoute(), both prefixed with the name of our component These functions build and parse between a URI query and an array of SEF segments.
The BuildRoute() function is used to build an array of SEF segments The function
is passed an associative array of URI query values
This is an example of the BuildRoute() function that we might have been using
in the previous example We must return the array of data segments in the order they will appear in the SEF URI We must remove any elements from the referenced
$query associative array parameter; any elements we do not remove will be
appended to the end of the URI in query format For example, if we passed the value 'index.php?option=com_myExtension&category=3&item=6&foo=bar' to the JRoute::_() method, we would get the route:
http://example.org/joomla/index.php/component/myExtension/3/6?foo=bar./**
* Builds route for My Extension.
*
* @access public
* @param array Query associative array
* @return array SEF URI segments
Trang 20With this function implemented, JRoute::_() can build SEF URIs for our
component The next step is to decode SEF URIs This is an example of the
ParseRoute() function that we might use to decode the URI:
/**
* Decodes SEF URI segments for My Extension.
*
* @access public
* @param array SEF URI segments array
* @return array Query associative array
Components are packaged in archive files A number of archive formats are
supported: gz, tar, tar.gz, and zip There is no specific naming convention for component archive files; however, the following is often used: com_name-version For example, the package for version 1.0.0 of My Extension would be called
com_myextension-1.0.0
When you package a component, ensure you do not include any system files Mac developers should be especially vigilant and consider using the CleanArchiver utility
http://www.sopht.jp/cleanarchiver/
Trang 21Within the package, as well as the component files, are some special files, which tell Joomla! what to do during installation and un-installation of a component These include the XML manifest file, an install, uninstall PHP script, and an install and uninstall S�L file.
XML Manifest File
The XML manifest file details everything the installer needs to know about an extension Any mistakes in the file may result in partial or complete installation failure XML manifest files should be saved using UTF-8 encoding
Based on the XML manifest file that we defined at the start of this chapter to create
a sandbox, this example demonstrates a large number of the XML manifest file elements that we can use:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE install SYSTEM install.dtd"> <install type="component" version="1.5">
Trang 22<folder>tables</folder>
</files>
<languages folder="administration">
<language tag="en-GB">en-GB.com_myextension.ini</language> <language tag="de-DE">de-DE.com_myextension.ini</language> </languages>
<file driver="mysql" charset="utf8">install.sql</file>#
<file driver="mysql" charset="">install.noutf8.sql</file> </sql>
Trang 23The following table describes the tags you can use in your XML manifest file in detail:
install (Root tag)
There are two different install tags The root tag called install identifies the type of extension and the version Joomla! for which the extension is written
Example <install type="component" version="1.5">
<! sub-tags >
</install>
Attributes type Type of extension.
version Version of Joomla! the extension is for
Sub-tags administration, author, authorEmail, authorUrl, copyright, creationDate,
description, files*, install, installfile, languages*, license, media*, name, params, uninstall, uninstallfile, version
administration
Container for all the component's backend tags This tag is required even if your
component needs no back-end tags
Trang 24Example <query charset="utf8" driver="mysql">install.sql</query>
<query charset="" driver="mysql">install.noutf8.sql</query>
Attributes charset UTF-8.
(mysql and mysqli are synonymous in this context)
files
Files and folders that belong in the component's frontend folder To prevent confusion we normally use the optional 'folder' attribute to make the archive tidier This tag has two sub-tags, filename and folder, which can be used zero to many times
Example <files folder="site"><! sub-tags ></files>
Attributes [folder] Folder in the archive where the files reside
Sub-tags filename, folder
Database installation options Do not confuse this with the root install tag!
Example <install><! sub-tags ></install>
Sub-tags queries, sql