Sie sind auf Seite 1von 5

MVC workflow with JPagination

The MVC architecture is something that probably can not be explained without solid examples. In this
example we will concentrate on showing a list using pagination. We will assume a component called
"com_example" which just shows a single page with multiple items. If there are more items then
defined by the "List Limit" within the Global Configuration, pagination is added.

The entry-point and the controller


Joomla!  sees the "option" variable in the URL and there for knows it should look for the component
TM

"com_example". Within the database table "#__components" a check is performed to see if the
component is active and if it is, Joomla! will call the entry-point file "example.php".
<?php
// File "example.php"
defined( '_JEXEC' ) or die( 'Restricted access' );

require_once JPATH_COMPONENT.DS.'controller.php';

$controller = new ExampleController( );


$controller->execute();
?>

First of all there is a security check on _JEXEC. After that we can start by including the controller-file
("components/com_example/controller.php") and initialize the controller. The controller-class
ExampleController just serves one purpose, there is only one task. There for we need not to pass any
$task to the execute() method. We even don't need the $controller->redirect() statement - we will
never set any redirects!

The controller-class is even more simple. We need to create it to tell Joomla! that we have a controller,
but it doesn't add anything to the JController-class.

<?php
// File "controller.php"
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

class ExampleController extends JController


{
function display()
{
parent::display();
}
}
?>

The view and the layout file


The controller points straight to the only view and its display() method. We need a directory called
"views" and put an "items" folder inside. That's our view-name so the file "views/items/view.html.php"
should contain a class named ExampleViewItems.

<?php
// File "views/items/view.html.php"
defined('_JEXEC') or die( 'Restricted access' );

jimport( 'joomla.application.component.view');

class ExampleViewItems extends JView


{
function display($tpl = null)
{

$items = $this->get('Data');
$this->assignRef( 'items', $items );

$pagination = $this->get('Pagination') ;
$this->assignRef( 'pagination', $pagination );

parent::display($tpl);
}
}
?>

The view-class is initialized in the normal way. From our view we then obtain data from the model by
using the shortcut-method $this->get('Data'). But instead of only importing $items from the model, we
also import $pagination.

Before we have a look at the model, we first show our layout-file.

<?php
// File "views/items/tmpl/default.php"
defined('_JEXEC') or die( 'Restricted access' );
?>

<?php echo $this->pagination->getPagesCounter(); ?>

<?php if( count( $this->items )) : ?>


<table>

<?php foreach( $this->items as $item ) : ?>


<tr>
<td><?php echo $item->title; ?></td>
</tr>
<?php endforeach; ?>

</table>
<?php endif; ?>

<?php echo $this->pagination->getPagesLinks(); ?>

We can see now that the JPagination-object that we fetched from the model, contains two methods:
The "getPagesCounter()" method prints a little message saying something like "Page 1 of 2", while the
"getPagesLinks()" method prints the navigation box.

The model - an overview


So far we have seen just a few things of the JPagination-class. The most interesting in this example is
the actual methods within the model. Somewhere we need to tell the model that we don't want all
items, but only those that are within the current page. We will first draw an outline of the class with the
method-code missing.
<?php
// File "models/items.php"

defined('_JEXEC') or die( 'Restricted access' );

jimport('joomla.application.component.model');

class ExampleModelItems extends JModel


{
var $_data = null;
var $_total = null;
var $_pagination = null;

function __construct() {}
function _loadData() {}
function getData() {}
function getTotal() {}
function getPagination() {}
}
?>

What you can see from this outline is that we need at least internal variables ($_data, $_total and
$_pagination) for the JPagination-trick to work. The variable $_data is an array containing all our items
that are going to be fetched from the database. It is initialized through the _loadData() function.
Because this array contains all the records from the table, we can also generate a $_total variable
which holds the total number of records found in the database.

Because we needed both the data ($_data) as a JPagination-object from the model (see the previous
chapter in this appendix) we define also a $_pagination variable. The $_data variable is a private
member but can be obtained from the model using the "getData()" method. The same goes for the
$_total variable which has a getTotal() method and the $_pagination variable which has a
getPagination() method. Later we will check if these are simple getters or if they contain a bit more
logic.

The model constructor


Now we dive into the methods themselves. The constructor has been extended a little bit by setting
the $limitstart and $limit variables. The $limitstart variable defines the page we are currently viewing -
pages are counted from 0. This variable is pointless unless we define as well how many items should
appear on a single page - the $limit variable.

function __construct()
{
parent::__construct();

$application = JFactory::getApplication() ;

$config = JFactory::getConfig() ;

$limitstart = JRequest::getInt( 'limitstart', 0 );


$limit = $application->getUserStateFromRequest( 'global.list.limit',
'limit', $config->getValue('config.list_limit'), 'int' );

$this->setState('limitstart', $limitstart);
$this->setState('limit', $limit);
}
The $limit variable is first of all read from the Global Configurations "list.limit" option. To read this we
need to instantiate a JRegistry-object through JFactory::getConfig(). We set this as default, but we
could also allow an user to change the limit through some kind of selectbox. Because of this we want
check $_POST, $_GET and $_SESSION to see if the user defined its own list-limit. This is done
through the JApplication::getUserStateFromRequest() method.

Instead of setting the variables $limitstart and $limit just as private internal variables, they are saved
through the JModel::setState() method instead. The point of this is just a theoratical one: While $_data
and $_pagination can be seen as solid variables that are part of the data-model, the $limit and
$limitstart variables are seen as user-variables - which means the user could change these variables
when the right form-elements are available. If you don't believe this, forget about this and just use
private variables instead.

The model: Loading the data


We have initialized some user-preferences ($limit and $limitstart) to build a pagination mechanism. But
we also need data from the database. That's the purpose of the _loadData() method. It first checks
with empty() functions whether the $_data array is already filled - and if not, it performs a simple
database query.

function _loadData()
{
if (empty($this->_data) && empty($this->_total))
{

$query = 'SELECT * FROM #__example' ;


$this->_db->setQuery($query);

$this->_data = $this->_db->loadObjectList();
$this->_total = count( $this->_data ) ;

return $this->_data ;
}

After we have filled $_data with the records from the database, we also calculate the total of records
and put it in $_total.

The model: Fetching the data


Now that we have a perfect _loadData() method to grab the items from the database, we are ready to
hand them over to the outside world. Within the getData() method we first of all call _loadData(). We
can do this multiple times without a harm. The method detects by itself whether $_data is already filled
or not, and only performs a database query when it has been called for the first time.

function getData()
{
$this->_loadData() ;

$limitstart = $this->getState('limitstart');
$limit = $this->getState('limit');
return array_slice( $this->_data, $limitstart, $limit );
}

But we don't want to return the full $_data array. We just want to return that part which is indicated by
the pagination: Either the first page or the page indicated by $limitstart. We simply use array_slice() to
return only the items needed.

The model: Pagination


Before we finish the model by explaining the getPagination() function, here is the getTotal() method. It
is just a simple getter:

function getTotal()
{
return $this->_total;
}

The getPagination() method starts with a call to _loadData(). It doesn't matter if we call getData() or
getPagination(). The first thing we do is get the data from the database and we only do it once.

The same applies to $_pagination. If there is no $_pagination available yet, we create it. Otherwise we
just return the existing object.
function getPagination()
{
$this->_loadData() ;

if (empty($this->_pagination))
{
jimport('joomla.html.pagination');

$limitstart = $this->getState('limitstart');
$limit = $this->getState('limit');
$total = $this->getTotal();

$this->_pagination = new JPagination( $total, $limitstart,


$limit );
}

return $this->_pagination;
}

The magic of creating the actual JPagination-object just involves including the library-file through
jimport() and creating the object with the right arguments.
 

Das könnte Ihnen auch gefallen