Step 3 Adding the Model
Introduction
In this step we add another landmark - the Giant's Causeway in Northern Ireland.
This involves making 2 significant changes:
-
when defining the menuitem we need to provide a choice of which landmark to choose
-
when displaying the site page we need to work out which landmark to display, and to do this we'll introduce a Model.
The code is available at com_example step 3.
Learning Points
Creating a request part for a menuitem
Introduction to Joomla standard form fields
Including a Model
Joomla Factory, Application and Input classes
Error handling
Request part for Menuitem
The default.xml file, which defines the menuitem, needs to change to:
<?xml version="1.0" encoding="utf-8"?>
<metadata>
<layout title="COM_EXAMPLE_LANDMARK_MENUITEM_TITLE">
<message>COM_EXAMPLE_LANDMARK_MENUITEM_DESCRIPTION</message>
</layout>
<fields name="request">
<fieldset name="request">
<field
name="id"
type="list"
label="COM_EXAMPLE_LANDMARK_FIELD_SELECT_TITLE"
description="COM_EXAMPLE_LANDMARK_FIELD_SELECT_DESC"
>
<option value="1">The Eiffel Tower</option>
<option value="2">The Giant's Causeway</option>
</field>
</fieldset>
</fields>
</metadata>
We've introduced 2 new language strings which must be defined in the administrator .ini file:
COM_EXAMPLE_LANDMARK_FIELD_SELECT_TITLE="Landmark"
COM_EXAMPLE_LANDMARK_FIELD_SELECT_DESC="Select a landmark"
The effect of these changes is shown below. (You can reinstall com_example with just the changes above if you want to see the effect at this stage).

The section of the default.xml file within <fields> is responsible for creating the part outlined in red:
The "name" attribute for both <fields> and <fieldset> has to be set to "request".
The <field> tag encloses the definition of a Joomla form field,
which maps to the HTML input element and associated label.
The field description is shown when the Toggle Inline Help button is pressed.
Joomla has a rich set of standard form fields,
which greatly simplify the task of building HTML forms.
The code above uses a list form field,
which creates an HTML <select> element for selecting the landmark.
When the menuitem is Saved, then the Link field is filled in. This will be set to:
-
index.php?option=com_example&view=landmark&id=1if the Eiffel Tower is selected -
index.php?option=com_example&view=landmark&id=2if the Giant's Causeway is selected
Joomla gets:
-
view=landmark from the path of the default.xml file (in tmpl/landmark/)
-
id=1 from the "name" attribute in the
<field>tag, and "value" attribute within the<option>.
This indicates the HTTP parameters which will be passed in the HTTP GET request which will be generated when the menuitem is selected, and our code will examine these parameters in order to determine what to display.
Site DisplayController
We're going to need a Model instance, and this will be instigated by the Controller. The code in the display method should now be:
public function display($cachable = false, $urlparams = array())
{
$view = $this->getView('landmark', 'html');
$model = $this->getModel('landmark');
$view->setModel($model, true);
$view->display();
}
The call to $this->getModel('landmark') will result in a LandmarkModel instance being created
(actually by the MVC Factory object, similarly to how to LandmarkView instance is created).
The View has setter and getter functions for the Model,
and the 2nd parameter in $view->setModel($model, true)
means that it will be set as the default Model.
Site View
The display function of the View class changes to:
function display($tpl = null)
{
$this->data = $this->getModel()->getItem();
parent::display($tpl);
}
The View code calls its getModel() method to return the default Model,
and then calls getItem() to return the data.
Site Model
Our new code file is
<?php
namespace My\Component\Example\Site\Model;
\defined('_JEXEC') or die;
use Joomla\CMS\MVC\Model\ItemModel;
use Joomla\CMS\Factory;
class LandmarkModel extends ItemModel
{
function getItem($pk = null)
{
$app = Factory::getApplication();
$input = $app->getInput();
$id = $input->get('id', 0, 'INT');
switch ($id) {
case 1:
return "The Eiffel Tower";
case 2:
return "The Giant's Causeway";
default:
throw new \UnexpectedValueException("id out of range");
}
}
}
ItemModel
use Joomla\CMS\MVC\Model\ItemModel;
class LandmarkModel extends ItemModel
ItemModel is used as a base model to inherit from if your Model is just returning a single item.
Application instance
use Joomla\CMS\Factory;
$app = Factory::getApplication();
The Factory class has a static method which enables us to get the Application instance.
The Application instance is the central object controlling the overall flow of control in Joomla, and there are separate variants for the Joomla site, administrator, API, etc. By means of the SiteApplication APIs, we can gain access to many other key Joomla objects.
Input
The method $app->getInput() returns the Input object,
which is what is used within Joomla to access the HTTP parameters.
$id = $input->get('id', 0, 'INT');
As described in the Input documentation, this code
-
gets the value of the 'id' HTTP parameter (which should be 1 or 2, based on what was selected in the menuitem)
-
sets a default value of 0, which is what will be returned if the 'id' HTTP parameter is not present
-
passes the HTTP parameter through an INT filter, so that an integer is always returned.
You should always use Input to access the HTTP parameters, and ensure that you use an appropriate filter.
Error Handling
If the id value is out of range, then the code throws an exception:
throw new \UnexpectedValueException("id out of range");
This is the standard Joomla way of handling this sort of error. You can use a language string instead of the hard-coded text, but generally Joomla code doesn't; it would tend to over-complicate the language .ini files.
After you install this version, you can demonstrate this exception
by clicking on the menuitem you created in the previous step.
Because it didn't include an id parameter, $id gets set to the default 0,
and the exception is thrown.
You can also navigate to the administrator Global Configuration / System tab, and set Debug System to Yes or No. With Debug System set to Yes, you'll find that the thrown exception causes a stack trace to appear.
Behind the scenes, the Joomla core code is catching this exception, and then generating an error page using the template at templates/cassiopeia/error.php.
Installation
Install the new version after updating the version number in the manifest file:
<version>0.3.0</version>
You can then explore the functionality of configuring the menuitems with the administrator back-end, and seeing them appear on the site pages.
Challenge
Can you add another landmark to provide a third choice for the menuitem? You obviously have to be able to click on the menuitem to display it as well.
Footnote
If you have examined the SiteApplication APIs,
and been surprised not to find the method getInput there, the reason is described in
Libraries Classes.
The SiteApplication class (within the CMS side, in libraries/src/Application/SiteApplication.php)
inherits (eventually) from AbstractWebApplication (within the Framework side, in libraries/vendor/joomla/application/src/AbstractWebApplication.php),
so methods which are defined in the latter will not be visible within the APIs of SiteApplication,
and this includes getInput.