FOF 4 is a major version, breaking backwards compatibility. The first goal was to remove features which have become obsolete in the four or so years since FOF 3's release. The second goal was to add features which are useful but might break the way FOF renders components, thus requiring a major version update. The third objective is to move towards Joomla! 4 compatibility. The third goal is something which will happen over the course of FOF 4's lifetime as it's nowhere near stable by the time we started writing FOF 4.
FOF 4 uses a different library path and namespace than its predecessor. This allows you to run both versions of the framework side by side and perform upgrades to your components at your own pace.
This document discusses the differences between FOF 3 and FOF 4 and gives you useful information for migrating your extensions from FOF 3 to FOF 4. There is no migration path from FOF 2 to FOF 4.
You need to replace the FOF30
namespace with FOF40
. This should be a fairly straightforward search and replace, as
long as you do it case-sensitive.
The other obvious change is that the code to include FOF 4.x to your extension has changed. You should use something like this instead:
if (!defined('FOF40_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof40/include.php'))
{
die('You need to have the Akeeba Framework-on-Framework (FOF) version 4 package installed on your site to use this
component. Please visit https://www.akeeba.com/download/fof4.html to download it and install it on your site.');
return;
}
The Utils package has grown over the lifetime of FOF 3 into an unwieldy mess of unrelated features. In an attempt to restore sanity the Utils package is being refactored to only include helper classes used internally by FOF. The remaining, very useful features are being refactored into their own, semantically coherent packages.
The following classes did NOT move:
- FOF40\Utils\ArrayHelper
- FOF40\Utils\Buffer
- FOF40\Utils\Collection
- FOF40\Utils\FilesCheck
- FOF40\Utils\ModelTypeHints
- FOF40\Utils\PhpFunc
The following classes have been removed from the Utils package.
- FOF40\Utils\StringHelper. Use the function fofStringToBool() instead of StringHelper::toBool().
- FOF40\Utils\FEFHelper\Html. Use FOF40\Html\FEFHelper\BrowseView instead (your code might need rewriting).
- FOF40\Utils\InstallScript. Use FOF40\InstallScript\Component instead.
The following classes have been moved out of the Utils package and into existing or new packages. The following table helps you understand what moved where.
From | To |
---|---|
FOF40\Utils\CacheCleaner | FOF40\JoomlaAbstraction\CacheCleaner |
FOF40\Utils\ComponentVersion | FOF40\JoomlaAbstraction\ComponentVersion |
FOF40\Utils\DynamicGroups | FOF40\JoomlaAbstraction\DynamicGroups |
FOF40\Utils\FEFHelper\BrowseView | FOF40\Html\FEFHelper\BrowseView |
FOF40\Utils\FEFHelper\Html | (removed) |
FOF40\Utils\InstallScript\BaseInstaller | FOF40\InstallScript\BaseInstaller |
FOF40\Utils\InstallScript\Component | FOF40\InstallScript\Component |
FOF40\Utils\InstallScript\Module | FOF40\InstallScript\Module |
FOF40\Utils\InstallScript\Plugin | FOF40\InstallScript\Plugin |
FOF40\Utils\InstallScript | FOF40\InstallScript\Component |
FOF40\Utils\Ip | FOF40\IP\IPHelper |
FOF40\Utils\SelectOptions | FOF40\Html\SelectOptions |
FOF40\Utils\TimezoneWrangler | FOF40\Date\TimezoneWrangler |
The FOF Autoloader adds class aliases for the moved classes. The aliases are a temporary measure and WILL be removed in FOF 5. We strongly recommend you to refactor your code using the new class names (in the "To" column) to ensure future compatibility.
Use the InstallScript
class shipped with FOF 4. During
extension installation/upgrade it will remove your extension from the list of FOF 3 dependent extensions and will add
it to the list of FOF 4 dependent extensions. Likewise, on uninstallation, it will remove your extensions from the lists
of FOF 3 and FOF 4 dependent extensions.
Moreover, during installation/upgrade, it will check if there are any more extensions depending on FOF 3. If not, it will try to uninstall it.
DO NOT directly copy or remove the FOF files from JPATH_LIBRARIES/lib_fof40
.
DO NOT try to manually uninstall or remove FOF 3.
DO include FOF 4 in your package
type extension and DO NOT list it in the package manifest. You need to follow
the example of our extensions. Otherwise, when you are trying to install an outdated version of FOF Joomla! will see the
package failing to install and will stop installing your extension, throwing an error. DO NOT try to circumvent this by
copying files directly. Doing so will put you permanently on a public Hall of Shame.
A lot of the work done on FOF 3.4 and 4.0 revolves around using Akeeba Frontend Framework (FEF). You are not required to use it, and we do not have public documentation for it. If you do choose to use it please make sure that you are installing it the same way as FOF 4 (see above).
FOF 4 accepts the following directories under the component area's root folder for the view templates of a view named Example
and they are searched in this order:
tmpl/Example
Joomla 4 compatible — recommended, has priorityViewTemplates/Example
FOF 3 compatible. No longer recommended.
View template files will NOT be located in the following directories (b/c break):
views/Example/tmpl
Joomla 1.x, 2.x, 3.x compatible. Already removed in FOF 3.View/Example/tmpl
FOF 3 legacy. Removed in FOF 4.
The view template overrides in all cases are located in <TEMPLATE FOLDER>/html/Example
, following the standard Joomla 1.5 or later convention. Template overrides have priority over extension files.
The view template files can either be Blade (extension .blade.php
, recommended) or pure PHP view templates (extension .php
).
Creating frontend and backend menus in Joomla 3 and 4 requires a view metadata XML. In Joomla 3 it's supposed to be located in views/Example/tmpl
whereas in Joomla 4 it can be located either there or in tmpl/Example
. However, the folder views/Example/tmpl
creates a problem with Joomla 4's view template overrides feature in its template manager.
As a solution we propose putting your view metadata XML files in the tmpl/Example
folder. When your component is installed on Joomla 3 these will copied into the view/Example/tmpl
folders as needed. Moreover, when installing your component in Joomla 4 the entire views
folder will be automatically removed to avoid problems. This behavior is controlled by the migrateJoomla4MenuXMLFiles
and removeLegacyViewsFolder
properties of the component post-installation script.
FOF 4 ships with a ViewTemplates folder which contains common view templates. They use per-renderer extensions (see
below) to provide the same view template for different frontend framework requirements. These are used as wrappers in
browse and edit views and implement picking and displaying users (the latter two being necessary after the removal of
XML forms, see below). These can be included by using any:lib_fof40/Common/templateName
and can be overridden in two
ways:
- Globally, in the
templates/YOUR_TEMPLATE/html/lib_fof40/Common
folder - Per component, in the
View/Common/tmpl
,views/Common/tmpl
orViewTemplates/Common
folder per standard FOF convention.
If you are not using FEF, you can simply skip these common FEF View Templates.
The common Blade templates are implemented as a last resort fallback in FOF's ViewTemplateFinder. This means that FOF
will look for view template files in the following order: template overrides for your component, your component, the
other side of your component (only if you're using a magic Factory), common Blade view template's overrides in
<template Folder>/html/lib_fof40/Common
and finally FOF itself (libraries/fof40/ViewTemplates/Common
).
Unlike regular view templates, FOF will only look for .blade.php
overrides for common Blade view templates. This is on
purpose. You are meant to @include
them in your own Blade templates and override their sections as you see fit.
One of the major changes in FOF 4 is the removal of the Form package, a.k.a. XML forms. When we first introduced this
feature, Joomla had a limited number of form fields. There was a very well-defined HTML output, created in the PHP classes implementing the form fields. In the following years, Joomla! went on to using JLayout
to try to abstract the output of form fields, allowing templates to override them.
The problem with that approach is that we had two features not present in Joomla's forms: header fields and using XML forms for browse views. Each of these features required us to provide our own HTML output. This was produced inside the PHP classes implementing the fields because that's what Joomla! itself did at that point. Moreover, because of the way class hierarchies in Joomla's JForm package worked we had to literally extend each and every field class and add the extra functionality we needed. When Joomla transitioned to JLayouts, our fields would no longer render correctly in some templates. Even if we rewrote the entire feature to use JLayouts, there was no incentive for template developers to provide overrides for our JLayouts so we still had the same issue.
On top of that, using XML forms in real world software proved that they are limited and cumbersome. Very quickly you end up writing hordes of custom fields which are very difficult (if not impossible) to override. This makes output customisation very painful.
PHP view templates, introduced in Joomla! 1.5 back in 2007, are a much more versatile approach. They do, however, have a fundamental issue: they are very verbose and make it difficult for frontend developers to understand what is going on.
The best alternative is templates using the Blade syntax. They are far less verbose, make much more sense to frontend developers, and they are transpiled to PHP. The latter means that you can still use PHP code where needed. The downside is that displaying them requires the tokenizer
PHP extension. However, we have a solution to that in the form of precompiled templates (placed in your component's PrecompiledTemplates folder, following the same structure as the ViewTemplates folder). If the tokenizer is not available you will fall back to PrecompiledTemplates. The downside is that template overrides in this case must be pure PHP templates, not Blade. If you are on a bad host which doesn't allow you to use the tokenizer just switch hosts. There is absolutely no security reason whatsoever to disable the tokenizer extension. The only real reason is that your host doesn't understand how PHP works -- which in itself is a security threat!!!
Scaffolding in FOF 3 let you create Controllers, Models, Views and XML forms based on your database schema. This was a quick way to start hashing out a component. However, most of that functionality has been superseded by other FOF features, making this feature obsolete.
Creating a Controller, Model or View class file is not actually necessary. If you want to quickly whip out a component you have two options. One, create empty class files extending the base Controller/DataController, Model/DataModel and View/Html/Json/Csv classes respectively. This is the recommended method. Two, use the Magic factory to have FOF fill in the gaps for you.
This leaves us with view templates. Scaffolding was only really useful in creating XML forms which could kinda sorta be used to represent your data but suffered from all the problems plaguing XML forms, outlined above. We consider using Blade and the built-in common Blade view templates the best way to create a quick interface for your component. Moreover, you get to choose the CSS framework you'd like to implement instead of being forced to use Bootstrap 2 as was the case with XML forms. You win something, you lose something. In our experience the end result is far more flexible without too much additional time spent designing the interface.
The third party LESS compiler we were using in FOF had not been updated in ages. This made us rather nervous as to whether it still works correctly. Moreover, LESS seems to have been gradually abandoned for Sass/SCSS or completely ditched for modern CSS which allows variable replacements. Moreover, we have seen that an increasing number of developers introduce a step of precompilation and / or minification of their CSS in their build and release workflow. Finally, compiling LESS on the fly was slow and had several challenges regarding making the compiled file available to the browser.
With that in mind we completely removed LESS support from FOF 4. You are advised to compile and minify your CSS before releasing your extension.
A goal of FOF 4 is the easier implementation of component which work across substantially different Joomla! versions (e.g. Joomla! 3 and Joomla! 4). The biggest challenge with that is that the HTML you need to output in each case is probably radically different. For this reason we add automatic suffixes to view templates based on the Joomla! version and FOF renderer used.
For example, consider that you are trying to load the view template default.php
on a Joomla! 3.9 site using the FEF
renderer. FOF will try to file a view template file from most to least specific:
- default.j39.fef.php
- default.j39.php
- default.j3.fef.php
- default.j3.php
- default.fef.php
- default.php
First one to be found is used.
When trying to understand which view template will be loaded also keep in mind that the suffixes do not override the
path priority. What we mean is that FOF will first look for template overrides in the site's template, then view
templates in the component (in the order ViewTemplates/view_name/default.php
, View/view_name/tmpl/default.php
,
views/view_name/tmpl/default.php
). If you are using a Magic factory the same will be repeated on the other side of the
application (e.g. the backend if you are accessing the component from the site's frontend).
In simple terms, if your client has created a template override for default.php
it will be loaded instead of the
default.j39.fef.php
inside your component. This is on purpose. The idea being that a template override is always
most specific as it's done for a specific site which runs a specific Joomla! version and for a specific component whose
renderer you already know.
The following changes have taken places in FOF's renderers:
- AkeebaStrapper has been removed. This was a transitional renderer which backported Bootstrap 2 styling in Joomla! 2.5. Joomla! 2.5 is no longer supported and Akeeba Strapper (the library with the custom, namespaced Boostrap 2 distribution) is obsolete. Therefore this renderer has no reason of existence.
- Joomla has been added. This is the new default renderer (if the FEF renderer is unavailable) and works in all Joomla! versions supported by FOF (3.x and 4.x).
- Joomla3 no longer outputs the wrapper DIV id
akeeba-renderjoomla
. Instead, it outputs the wrapper DIV classakeeba-renderer-joomla
andakeeba-renderer-joomla3
. Moreover, it will only enable itself on Joomla! 3.x; it will be disabled on Joomla! 4.x. - Joomla4 has been added. This is currently a tentative renderer since Joomla! 4 has not reached a beta stage and
its template is still under development. It outputs the wrapper DIV class
akeeba-renderer-joomla
andakeeba-renderer-joomla4
. Moreover, it will only enable itself on Joomla! 4.x; it will be disabled on Joomla! 3.x. - FEF no longer outputs the wrapper DIV id
akeeba-renderer-fef
. Instead, it only outputs the wrapper DIV classakeeba-renderer-fef
. It extends theJoomla
renderer, but it will NOT output theakeeba-renderer-joomla
wrapper DIV class; this class is forcibly added to theremove_wrapper_classes
renderer option.
All renderers support the remove_wrapper_classes
and add_wrapper_classes
renderer options. These options now allow
you to also remove the wrapper classes (e.g. akeeba-renderer-joomla
and akeeba-renderer-fef
) if you so wish. Just
remember that removing the wrapper class from the FEF renderer will result in unstyled content unless you wrap the
output yourself in a DIV with the class akeeba-renderer-fef
.
If you wrote a custom renderer extending the now defunct AkeebaStrapper
renderer please extend the Joomla
renderer
OR the RenderBase
class instead.
Finally, keep in mind that the default renderer is automatically detected using the information provided by FOF's Render
classes. If FEF is installed on your site, FOF will automatically prefer the FEF renderer instead of the Joomla!
renderer. This many NOT be what you want. Always set up the desired renderer in your fof.xml
file to prevent nasty
surprises.
StringHelper::toSlug
was removed. Replace calls to it with \Joomla\CMS\Application\ApplicationHelper::stringURLSafe()
StringHelper::toASCII
was removed. Replace calls to it with \Joomla\CMS\Factory::getLanguage()->transliterate()
The following protected properties have been renamed, dropping their underscore prefix:
- _trackAssets to trackAssets
- _has_tags to has_tags
- _rules to rules
- _behaviorParams to behaviorParams
- _assetKey to assetKey
The mcrypt PHP extension has been declared deprecated since PHP 7.1. Moreover, it's not been maintained since 2003, making it unsuitable for production. PHP recommends replacing it with OpenSSL. To this end we had modified our Encrypt package to work with both mcrypt and OpenSSL since FOF 3.0.13 released in August 2016. In FOF 4 we are completely removing mcrypt support. This change is transparent as long as you use the Encrypt\Aes class. If you were instantiating Encrypt\AesAdapter\Mcrypt directly your code will break.
AES encryption used to allow an optional strength. This behaved differently in mcrypt and OpenSSL implementation so it was deprecated. Support for the strength has been removed.
Key expansion had also been modified in FOF 3. The very old method (renamed to Legacy Mode) was using an insecure key expansion and was deprecated. The new method is much more secure. We removed the legacy method.
As a result of the above we changed the following methods:
- Encrypt\Aes::__construct. The deprecated $key and $strength parameters have been removed.
- Encrypt\Aes::setPassword. The $legacy option has been removed.
- Encrypt\AesAdapter\AdapterInterface::setEncryptionMode. The $strength parameter has been removed.
Moreover, we have removed the unused $strength parameter from Encrypt\Aes and also modified Encrypt\AesAdapter\AdapterInterface::setEncryptionMode accordingly.
In FOF 3 the EncryptService (the crypto
service in the container) used a very bad key expansion policy. It would take
your long password, calculate its SHA-256, throw half of it away(!) and use the remainder as the AES-128 key. This was
not very secure.
In FOF 4 we use PBKDF2 using 1000 rounds of SHA-256 for key expansion, i.e. convert a password to a usable key for AES-128 encryption. However, this is incompatible with the old way and your data cannot be decrypted as-is.
The crypto
service's decrypt() method accepts a second parameter which allows you to decrypt legacy data. We recommend
using it like this, e.g. for JSON-encoded data:
// Try decrypting using the modern method first
$decrypted = @json_decode($this->container->crypto->decrypt($encrypted), true);
// Try decrypting with the legacy method if the previous attempt failed
if (!is_array($decrypted))
{
$decrypted = @json_decode($this->container->crypto->decrypt($encrypted, true), true);
}
// Check for failure to decrypt the data as you'd always do, consume the decrypted data if it's valid.
Since the minimum version has been raised to PHP 7.2 we are also changing the method declarations to include parameter type hints for scalar types and method return values including nullable types and the special type "void". When this is not possible (e.g. a method parameter accepts a string and an array) type checking is implemented in the method, throwing an InvalidArgumentException when the type constraints are violated.
These changes imply that any overrides of the methods need to conform to the new, typed declaration. This may cause backwards incompatible breaks in your code.
Furthermore, some methods have changed their return type for sanity's sake, again causing backwards incompatible
changes. Typically, methods which returned some less-than-sane types (e.g. string or boolean false) have had their
return type converted to a nullable type (e.g. string or null, denoted by ?string
).
The following methods have had their return type changed:
- FOF40\Platform\FilesystemInterface::pathFind() -- FROM string|bool TO string|null
- FOF40\Download\Download::getFromURL() -- FROM string|bool TO string|null
- FOF40\View\DataView\Raw::hasAjaxOrderingSupport() -- FROM array|bool TO array|null
In FOF 3 you could set the useHypermedia property to true to automatically inject HAL metadata to the JSON output. However, the HAL specification has not been updated since 2013. We don't really see it being much used in the wild or supported by frameworks consuming JSON data. A better suited replacement would be JSON-LD (JSON for Linking Data, a W3C standard) but it's not possible to automatically derive the context the format calls for. In fact, writing a FOF wrapper around it would make it far more complicated to use than if we just let you override the JSON output through a Json View class and / or a suitable JSON view template!
As a result we removed the HAL support from FOF and ask you to implement whichever JSON metadata scheme you want yourself.
FOF 3 has a set of handy FEF helpers, acessible through Joomla's HTMLHelper with the FEFHelper.
prefix. The prefix has been changed to FEFHelp.
to allow FOF 3 and FOF 4 to run side by side.
You must upgrade your code to use the new prefix. The old one will call the FOF 3 helpers (if FOF 3 is loaded) or fail to load any helper at all. In both cases your extensions break.