? Pending

User tests: Successful: Unsuccessful:

avatar Denitz
Denitz
12 Aug 2020

Pull Request for Issue #30297 .

Summary of Changes

Add new Joomla4 categories classes for easier Joomla 3-4 extension development.

Testing Instructions

Apply patch, see that nothing category-related is changed.

Actual result BEFORE applying this Pull Request

No result.

Expected result AFTER applying this Pull Request

No changes.

Documentation Changes Required

No.

Votes

# of Users Experiencing Issue
1/1
Average Importance Score
2.00

avatar Denitz Denitz - open - 12 Aug 2020
avatar Denitz Denitz - change - 12 Aug 2020
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 12 Aug 2020
Category Libraries
avatar SharkyKZ
SharkyKZ - comment - 12 Aug 2020

Code must be compatible with PHP 5.3.10.

avatar Bakual
Bakual - comment - 12 Aug 2020

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.

avatar Denitz
Denitz - comment - 12 Aug 2020

@Bakual Yes, sure, but these files really help to have the single code base for both Joomla 3 and 4 with the future easy removal of Joomla 3 part.

avatar laoneo
laoneo - comment - 12 Aug 2020

This code is not compatible with PHP 5.3. So @zero-24 has to decide if Joomla 3.10 increases the PHP min version up to the one for Joomla 4 or we leave the one for Joomla 3 which is 5.3.

avatar zero-24
zero-24 - comment - 13 Aug 2020

There are no plans to increase the php minimum version in 3.10.

avatar Denitz Denitz - change - 13 Aug 2020
Labels Added: ?
avatar Denitz
Denitz - comment - 13 Aug 2020

@Bakual I updated @SInCE tags

@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.

avatar laoneo
laoneo - comment - 13 Aug 2020

Object return types are not compatible on PHP 5.3...

avatar Bakual
Bakual - comment - 14 Aug 2020

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.

avatar Denitz
Denitz - comment - 14 Aug 2020

How to restart AppVeyor job? It's finished unexpectedly.

avatar laoneo
laoneo - comment - 14 Aug 2020

It's absolutely fine to backport features, no problem with, but it needs to fit the requirements if 3.10.

avatar HLeithner
HLeithner - comment - 14 Aug 2020

Also traits are php 5.4+ only, it's really unlikely that this pr get merged.

avatar Denitz
Denitz - comment - 18 Aug 2020

Traits removed, at least we can support CategoryFactory-related + CategoryInterface code.

avatar Denitz
Denitz - comment - 25 Aug 2020

Any news?

avatar adj9 adj9 - test_item - 29 Aug 2020 - Tested successfully
avatar adj9
adj9 - comment - 29 Aug 2020

I have tested this item successfully on f0c42e0

Done.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/30346.

avatar zero-24
zero-24 - comment - 30 Aug 2020

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?

avatar laoneo
laoneo - comment - 31 Aug 2020

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.

avatar Denitz
Denitz - comment - 31 Aug 2020

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.

avatar zero-24
zero-24 - comment - 1 Sep 2020

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?

avatar laoneo
laoneo - comment - 1 Sep 2020

I see no use case why it should help 3rd party dev, perhaps @Denitz can show us an example. But you are right, nothing breaks with this pr. But honestly I see no point in porting the factory back, the interface CategoryInterface would be enough I guess.

avatar Denitz
Denitz - comment - 2 Sep 2020

@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.

avatar laoneo
laoneo - comment - 2 Sep 2020

So you are namespacing only the categories class or do you plan to namespace your whole extension and then work with class alias?

avatar Denitz
Denitz - comment - 2 Sep 2020

@laoneo The main code in /src is namespaced (pure J4 style) but we also keep files required for J3 which are not namespaced (J3 style).

avatar laoneo
laoneo - comment - 2 Sep 2020

So models, fields, views, controllers are all namespaced?

avatar Denitz
Denitz - comment - 2 Sep 2020

@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.

avatar zero-24
zero-24 - comment - 2 Sep 2020

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

avatar Denitz
Denitz - comment - 2 Sep 2020

@zero-24 Great!

avatar HLeithner
HLeithner - comment - 2 Sep 2020

@Denitz do you have the extension ready and can share it? So maybe we can comment on it or other extension developer can be inspired?

avatar laoneo laoneo - test_item - 2 Sep 2020 - Tested successfully
avatar laoneo
laoneo - comment - 2 Sep 2020

I have tested this item successfully on bc4b54b

Opened the back end article categories and saved one. Works as expected.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/30346.

avatar zero-24
zero-24 - comment - 2 Sep 2020

Merging thanks!

avatar zero-24 zero-24 - change - 2 Sep 2020
Status Pending Fixed in Code Base
Closed_Date 0000-00-00 00:00:00 2020-09-02 11:26:32
Closed_By zero-24
avatar zero-24 zero-24 - close - 2 Sep 2020
avatar zero-24 zero-24 - merge - 2 Sep 2020
avatar zero-24
zero-24 - comment - 2 Sep 2020

@Denitz please feel free to follow up with other things we can do to support that use case in 3.10

avatar Denitz
Denitz - comment - 2 Sep 2020

@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.

avatar HLeithner
HLeithner - comment - 2 Sep 2020

If you have a final component it would be great if you write some blog post or tutorial how you did it.

avatar zero-24
zero-24 - comment - 29 Sep 2020

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.

Add a Comment

Login with GitHub to post a comment