Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Controller, view and layout

A component page is produced by three files. The controller receives the request and picks a view. The view prepares the data. The layout turns it into HTML. Let us make the first site page — a list of blog posts.

Files

Create three files in the site part by hand:

components/com_hello/
├── src/
│   ├── Controller/
│   │   └── DisplayController.php
│   └── View/
│       └── Posts/
│           └── HtmlView.php
└── tmpl/
    └── posts/
        └── default.php

The controller

// components/com_hello/src/Controller/DisplayController.php
namespace My\Component\Hello\Site\Controller;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\Controller\BaseController;
 
class DisplayController extends BaseController
{
    protected $default_view = 'posts';
}

DisplayController is the controller Joomla calls when the request names no other action. Its display() method is already written in the parent class: it reads the view parameter from the address and renders the view with that name. Without the parameter, $default_view is used.

The view

// components/com_hello/src/View/Posts/HtmlView.php
namespace My\Component\Hello\Site\View\Posts;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
 
class HtmlView extends BaseHtmlView
{
    public array $posts = [];
 
    public function display($tpl = null): void
    {
        $this->posts = ['First post', 'Second post'];
 
        parent::display($tpl);
    }
}

The view puts data into its properties and calls parent::display(), which includes the layout. For now the posts are hard-coded; in the next lesson a model supplies them.

The layout

<?php
// components/com_hello/tmpl/posts/default.php
 
defined('_JEXEC') or die;
?>
<h1>Blog</h1>
 
<ul>
    <?php foreach ($this->posts as $title) : ?>
        <li><?php echo $this->escape($title); ?></li>
    <?php endforeach; ?>
</ul>

In a component layout $this is the view object: its properties are available as $this->posts. The escape() method escapes output.

The result

Open this address on the site:

http://joomla.test/index.php?option=com_hello&view=posts

Inside the site template you see the heading "Blog" and a list of two posts. The address without view — index.php?option=com_hello — shows the same page thanks to $default_view.

How the address maps to files

In the addressWhat Joomla looks for
option=com_helloThe component and its provider
view=postsThe class View\Posts\HtmlView
layout=default (the default)The layout tmpl/posts/default.php
format=html (the default)The HtmlView class; for format=json it is JsonView
task=post.saveThe save() method of the Controller\PostController class

To add a second page, create one more folder in View and one more in tmpl. No new controller is needed for that.

Controller actions

The task parameter calls a controller method. Everything that changes data is done this way: saving, deleting, publishing. task=post.save means "the PostController controller, the save method". When done, such a method does not render a page but redirects to one with $this->setRedirect(). Ready-made controllers with actions appear in the lesson on saving data.

The control panel

The administrator part is built exactly the same way; only the paths and one word of the namespace change:

File on the siteFile in the panel
components/com_hello/src/...administrator/components/com_hello/src/...
My\Component\Hello\Site\...My\Component\Hello\Administrator\...

Common mistake

Class and folder names are tied together strictly: the posts view is the View/Posts folder and the tmpl/posts/default.php layout. On a mismatch Joomla reports "View not found". On Windows the letter case of folder names does not matter, but on a Linux server View/posts and View/Posts are different folders: use a capital letter in src and lowercase in tmpl.

Thanks for reading!

Donate to the site — we work hard for you.