Update J3 component to J4

From Joomla! Documentation


Helpful Notes[edit]

Joomla 4 has been out long enough that I'm feeling guilty about not upgrading my (in-house) component. These are the notes I wish I'd had as I work through this project.

My context is a primarily administrator screens only component. Data structures are fairly complex, by comparison with core data at least. The component consists of about ten lists of structures, with view or edit forms behind that. The installation file is currently just my own code and is around 130kB. This will increase as there are still some functions to include, primarily providing end points of an associated mobile app.

In general, I found many things remain the same and the upgrade process isn't too hard, nor is there much that really got me scratching my head, once I'd worked out a couple of small points. Of course, before I sorted it out, it was incredibly frustrating.

Feel free (in fact, feel obliged) to let me know, or simply edit, if there are errors, omissions, or anything else that can be helpfully changed. I've been developing in Joomla for a long time, but I'm only just starting with J4.

General Points[edit]

It appears you can get away with making very minimal changes (eg see the JCE installed structure). I tried to go the whole way, making the component fully compliant to J4 standards.

Judging by the disparity between the documents I've found and what's actually in the released (core) code, it seems that things are still evolving, so a) it’s sometimes not clear what the current recommended usage is and b) this may become outdated as J4 evolves.

Again, let me know if something is (perhaps "no longer") correct.


Namespacing is very central to the new philosophy.

While it can be a little tedious, particularly during conversion, this is really helpful and "A Good Thing"TM. If you need to know more details than I've got here, look at the docs.

Every file that declares a class should be namespaced. Put very simply, it allows us to ensure the correct classes are loaded, even if there are several that have the same name. We just specify the full path to pick the one we want. With our own code, it means we can use the same names that are in other places and still get the right one.

Allowing the same names to be used in different contexts means that you have to specify the name space that you want. That then means that whenever you want to use classes in your code that aren’t in the current namespace, you have to use its full name.

You can either write out its whole path at each point in the code that you use it, which makes for long code, or you can employ the “use” statement. At some point, normally at the top of your code, you write a use statement for the class you want and then whenever you refer to it you simply use the class name. For example to use the Factory class, at the head of your code include

use Joomla\CMS\Factory;

and then you can write Factory::{whatever-you-want} without needing to include the full path. This is equivalent to the previous use of JLoader, but simpler.

If you use two (or more) classes that have the same name but are from different namespaces, you can still use them by setting up aliases. For example

use Joomla\CMS\Factory as CoreFactory;
use myCompany\Component\MyComponent\Administrator\Helper\MyFactory;

They got rid of “J”![edit]

Lots of J3 core classes were called “J”-something, for example “JFactory”. This is no longer true, this one thus becomes simply “Factory”. This doesn’t (seem to) hold for core language string naming though.

Flip it![edit]

The previous rule for naming core entities often went (J){Type}{Client}, for example JControllerAdmin. For the new name, according to the previous note remove the J, and then flip the remaining two elements, so we have AdminController.


The new structure for an admin component is : (fill this in)

Most source code files are now named {unit}{type}, where previously they were {mything}{type}{unit}. For example what was MythingControllerMyunit is now MyunitController.

On case sensitive platforms (?), the case of file names needs to reflect the case of the class name. A spin off of this is that table classes and their files cannot have upper case letters anywhere except the first letter, so you can’t have a table class named CompoundTableNameTable, it has to be CompoundtablenameTable.


getModel $prefix now needs to reflect the “client” for this controller, either “Administrator” or “Site”(?)

Form controllers (as opposed to list controllers) now extend the core class FormController rather than JcontrollerAdmin.

Having the form controller name the same as model helps. This tends to imply that tables should be named in the singular. You don't have to, of course, but it makes things easier.


Form models now extend the AdminModel class.

The getTable method is no longer required (or valid).

Field (code implementing form field types used (eg) in form xml definitions)

Class naming is brought in line with other classes, ie it doesn’t need to be preceded by “JformField”, simply followed by “Field”. Ie the old JformFieldMyType becomes MyTypeField.

Extending the core class “ListField” means that JformHelper::loadFieldClass('list'); is now redundant. (?)


Class naming[edit]

Previous setup {UnitRef}{fill this in}. It’s now HtmlView!

Convert the previous

“JerrorRaiseError(500, implode('<br />', $errors); return false”


throw new GenericDataException(implode("\n", $errors), 500);

There’s that ol’ “switcheroo” thang again, although in s alightly different context. Here the parameters have changed position.

The sidebar thing is gone[edit]

Toolbar code structure is now different. The ToolbarHelper still exists, without its previous J prefix of course, but it’s used for many fewer things, typically now just the title. Create a toolbar (actually get an instance of it) and use its methods to set it up. There are specific methods now rather than passing multiple parameters to the helper.

Creating your own toolbar buttons is now “regular” not “custom”.

Creating a modal is now a popupButton and not in “customButton”


New filesystem position – to facilitate moving code away from the webserver root in future.

Changes due to new style / standard[edit]


Remove the message that goes with the ubiquitous “defined('_JEXEC') or die()”

Debugging notes[edit]

The error “Call to a member function getGroup() on null” may mean the xml filter definition file is not present.

Custom field types don’t work? Need to add the namespace prefix in the form definition file. For example, change the xml "form" tag to

<form addfieldprefix="myCompany\Component\MyComponent\Administrator\Field">

provided, of course, that you've used the standard file structure and namespaced your code accordingly.

Specific changes[edit]

Class naming[edit]

Core classes to overload
Type Old New
List controller JControllerAdmin AdminController
List model JmodelAdmin ListModel
List view (html) JViewLegacy (?) HtmlView
Form controller JControllerForm FormController
Form model JModelAdmin FormModel
Form view (html) JViewLegacy (?) HtmlView