User tests: Successful: Unsuccessful:
Pull Request for Issue #30297 .
Add new Joomla4 categories classes for easier Joomla 3-4 extension development.
Apply patch, see that nothing category-related is changed.
No result.
No changes.
No.
Status | New | ⇒ | Pending |
Category | ⇒ | Libraries |
Please keep in mind that we promise a 3.10 extension will work in 4.0. We don't promise a 4.0 extension will work in 3.10 (it wont).
So we should only backport what is really needed into 3.10. To my knowledge categories work just fine in 4.0 also with old code. We already have that B/C layer in 4.0. If you're writing extensons that work in 3.10 and 4.0, there are some compromises you will have to do.
There are no plans to increase the php minimum version in 3.10.
Labels |
Added:
?
|
@laoneo The code actually used in the core is compatible with PHP 5.3, there are no issues here.
The only real change is that Categories
class now implements CategoryInterface
.
The other added classes are for the 3rd-party extensions which require PHP 7.x as min.
Please remember that the aim of backporting these classes is to be able to start using and maintaining the J4 code with optional J3 support: J3 classes of 3rd-party extensions will be actually emulated from existing J4 code. It really helps with the J3+J4 supporting period of extension lifecycle.
I know about compromises, but these files help to have new J4 categories code + J3 compatibility layer for the custom extensions. And this compatibility layer is not a completely separate code but utilizes J4 code.
Object return types are not compatible on PHP 5.3...
The other added classes are for the 3rd-party extensions which require PHP 7.x as min.
From my view it doesn't matter if a class shipped with core is used by core or not, it has to meet the PHP minimum requirement anyway.
Otherwise 3rd parties would need to manually check each class for its minimum requirements before using it - which is absolutely not acceptable.
As said the B/C layer we have is not meant to be able to use J4 code in J3. It's the other way around. And only some rare code is backported where it wasn't possible otherwise.
If you as 3rd party dev want to maintain only one codebase for your extensions which support both J3 and J4, you either don't use J4 features or you add a bunch of switches. Imho the better approach is to have the J3 codebase put on "security only releases" following the CMS. Users wanting new features will be forced to upgrade to J4.
How to restart AppVeyor job? It's finished unexpectedly.
It's absolutely fine to backport features, no problem with, but it needs to fit the requirements if 3.10.
Also traits are php 5.4+ only, it's really unlikely that this pr get merged.
Traits removed, at least we can support CategoryFactory-related + CategoryInterface code.
Any news?
I have tested this item
Done.
I have now taken a closer look into the latest code here. Right now this PR here seems to backport the classnames + one method. And that method (createCategory)
will always return SectionNotFoundException in 3.10 as we have not backported the service stuff to 3.10.
So where does that help as you still have todo version detection to fallback to JCategories::getInstance for 3.x or do i miss something?
In J4 the component uses the factory mainly internally from the container. So I'm wondering why you want to backport it as well, beside the valid points from @zero-24. I guess the interface makes sense to backport even when it is of little use as no code is done against the interface in J3 anyway.
Having all these files helps to use J4 Category service for J3: J3's category helper is emulated via class_alias of existing J4 category service.
The code is reduced to support both J3 and J4, the code is based on J4 version and it's easy to drop J3 compatibility.
J3's category helper is emulated via class_alias of existing J4 category service.
I'm curious how does that look like?
@laoneo @HLeithner to me this is ok to be shipped even without the service stuff as it does not break the existing stuff but seems to help 3rd party extensions? Any objections?
@laoneo example for com_foo
site part:
/components/com_foo/src/Service/Category.php
- the J4 category service - native J4 code:
<?php
namespace Joomla\Component\Foo\Site\Service;
defined('_JEXEC') or die;
use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Categories\CategoryInterface;
class Category extends Categories implements CategoryInterface
{
/**
* @inheritDoc
*
* @since 1.0.0
*/
public function __construct($options = array())
{
$options['table'] = '#__foo_items';
$options['extension'] = 'com_foo';
parent::__construct($options);
}
}
J3 uses FooCategories
helper from /components/com_foo/helpers/category.php
:
<?php
defined('_JEXEC') or die('Restricted access');
require_once __DIR__ . '/../src/Service/Category.php';
class_alias(\Joomla\Component\Foo\Site\Service\Category::class, 'FooCategories');
See that we have native J4 class, ported and usable in J3.
We really need only CategoryInterface
here, but CategoryFactory
and CategoryFactoryInterface
are required in J4 router which can be used as J3 router in the same way - we have J4 Joomla\Component\Foo\Site\Service\Router
class which is aliased in /components/com_foo/router.php
easily.
So you are namespacing only the categories class or do you plan to namespace your whole extension and then work with class alias?
So models, fields, views, controllers are all namespaced?
@laoneo Yes, we have the usual J4 namespaced code + minimal code for J3 which actually uses J4 code base. Only layouts are different (/views
and /tmpl
folders for J3/J4 accordingly).
The idea is not to adopt J3 code for J4, but to adopt the J4 code for J3. In this case we can continue developing J4 code and easily drop J3 support later.
Ok So the only thing left here for me would be an seccond successful test that categories are not broken here with that change. And Im happy to merge it into 3.10
I have tested this item
Opened the back end article categories and saved one. Works as expected.
Merging thanks!
Status | Pending | ⇒ | Fixed in Code Base |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2020-09-02 11:26:32 |
Closed_By | ⇒ | zero-24 |
@HLeithner Unfortunately, not yet, need to recode the current extension for 3.10. I am using the approach above but the classes added in this PR were bundled with extension and registered via JLoader in J3 code.
Now the classes are in Joomla and the final code will look like above.
Adding sample example for router:
/components/com_foo/src/Service/Router.php
- the J4 native code
<?php
namespace Joomla\Component\Foo\Site\Service;
defined('_JEXEC') or die;
use Joomla\CMS\Application\SiteApplication;
// todo enable once 3.9 is finished.
//use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Categories\CategoryFactory;
use Joomla\CMS\Categories\CategoryFactoryInterface;
use Joomla\CMS\Categories\CategoryInterface;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Component\Router\RouterView;
use Joomla\CMS\Component\Router\RouterViewConfiguration;
use Joomla\CMS\Component\Router\Rules\MenuRules;
use Joomla\CMS\Component\Router\Rules\NomenuRules;
use Joomla\CMS\Component\Router\Rules\StandardRules;
use Joomla\CMS\Factory;
use Joomla\CMS\Menu\AbstractMenu;
use Joomla\CMS\Router\Route;
use Joomla\Component\Foo\Site\Helper\RouteHelper;
// todo enable once 3.9 is finished.
//use Joomla\Database\DatabaseInterface;
/**
* @since 1.0
*/
class Router extends RouterView
{
protected $noIDs = false;
/**
* The category factory
*
* @var CategoryFactoryInterface
*
* @since 4.0.0
*/
private $categoryFactory;
/**
* The category cache
*
* @var array
*
* @since 2.0
*/
private $categoryCache = [];
/**
* The db
*
* @var2 DatabaseInterface
* @var \JDatabaseDriver
* @todo - convert to DatabaseInterface once 3.9 is finished.
*
* @since 4.0.0
*/
private $db;
/**
* Required for 3.9 compat, todo - remove once once 3.9 is finished.
* @var string
* @since 2.0
*/
protected $name = 'foo';
/**
* @inheritdoc
* @since 2.0
*/
/*public function __construct(SiteApplication $app, AbstractMenu $menu, CategoryFactoryInterface $categoryFactory, DatabaseInterface $db)
{
public function __construct(SiteApplication $app, AbstractMenu $menu, $categoryFactory = null, $db = null)
{
// todo - enable once 3.9 is finished
// $this->categoryFactory = $categoryFactory;
// $this->db = $db;
$this->categoryFactory = $categoryFactory ?? new CategoryFactory('Joomla\Component\Foo');
$this->db = $db ?? Factory::getDbo();
...
And here is the J3 /components/com_foo/router.php
:
<?php
// Joomla 3.9 compat, todo - remove once 3.9 is finished.
require_once __DIR__ . '/src/Service/Router.php';
class_alias(Joomla\Component\Foo\Site\Service\Router::class, 'FooRouter');
Sample /components/com_foo.php
file executed in J3:
<?php
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Factory;
// Register component namespaces.
JLoader::registerNamespace('Joomla\Component\Foo\Site', JPATH_SITE . '/components/com_foo/src', false, false, 'psr4');
JLoader::registerNamespace('Joomla\Component\Foo\Administrator', JPATH_ADMINISTRATOR . '/components/com_foo/src', false, false, 'psr4');
// Register legacy helpers
JLoader::register('FooHelperRoute', JPATH_SITE . '/components/com_foo/helpers/route.php');
JLoader::register('FooCategories', JPATH_SITE . '/components/com_foo/helpers/category.php');
// Joomla 3 workaround for Joomla 4 controllers.
/** @noinspection PhpUnhandledExceptionInspection */
$command = Factory::getApplication()->input->get('task', 'display');
if (strpos($command, '.') !== false)
{
list($controller, $task) = explode('.', $command);
/** @noinspection PhpUnhandledExceptionInspection */
Factory::getApplication()->input->set('task', $task);
}
elseif ($command)
{
$controller = $command;
}
else
{
$controller = 'display';
}
$classname = 'Joomla\Component\Foo\Site\Controller\\' . ucfirst($controller) . 'Controller';
/** @var \Joomla\Component\Foo\Site\Controller\DisplayController $controller */
$controller = new $classname();
/** @noinspection PhpUnhandledExceptionInspection */
$controller->execute(Factory::getApplication()->input->get('task'));
$controller->redirect();
etc.
If you have a final component it would be great if you write some blog post or tutorial how you did it.
This has been documented here: https://docs.joomla.org/J3.x:Joomla_3.10_Backports But I'm happy to textend this doc with the demo component when you have something to share.
Code must be compatible with PHP 5.3.10.