?
avatar SharkyKZ
SharkyKZ
3 Feb 2020

In J3 we have Joomla\CMS\HTML\HTMLHelper::register() method but in J4 it's deprecated in favor of Joomla\CMS\HTML\Registry but that one seems to handle only classes, not specific methods.

avatar SharkyKZ SharkyKZ - open - 3 Feb 2020
avatar joomla-cms-bot joomla-cms-bot - change - 3 Feb 2020
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 3 Feb 2020
avatar mbabker
mbabker - comment - 3 Feb 2020

Use the registry for services, subclass the class whose method(s) you want to extend, and treat it as any other PHP class going forward.

avatar SharkyKZ
SharkyKZ - comment - 3 Feb 2020

So no more granular control over methods? In J3 it was possible for different plugins to override different methods of the same service.

avatar SharkyKZ
SharkyKZ - comment - 3 Feb 2020

Not only to override but now it's not possible for different plugins to add new methods. So this code is going to break completely:

<?php if (HTMLHelper::isRegistered('users.' . $field->id)) : ?>
<?php echo HTMLHelper::_('users.' . $field->id, $field->value); ?>
<?php elseif (HTMLHelper::isRegistered('users.' . $field->fieldname)) : ?>
<?php echo HTMLHelper::_('users.' . $field->fieldname, $field->value); ?>
<?php elseif (HTMLHelper::isRegistered('users.' . $field->type)) : ?>
<?php echo HTMLHelper::_('users.' . $field->type, $field->value); ?>
<?php else : ?>
<?php echo HTMLHelper::_('users.value', $field->value); ?>
<?php endif; ?>

avatar mbabker
mbabker - comment - 3 Feb 2020

That example gets harder to deal with, but there are different ways to deal with it.

/**
 * Extended JHtmlUsers instance using inheritance
 */
class MyHtmlUsers extends JHtmlUsers
{
    // New methods or extended methods here
}

/**
 * Extended JHtmlUsers instance using the decorator pattern
 */
class MyHtmlUsers
{
    /**
     * Decorated HTML helper.
     *
     * This can't be typehinted to a specific object type due to there not being interfaces for HTML helper classes and breaking use of the decorator pattern.
     *
     * @var object
     */
    private object $decoratedHelper;

    public function __construct(object $decoratedHelper)
    {
        $this->decoratedHelper = $decoratedHelper;
    }

    // New methods or extended methods here

    public function __call(string $name, array $arguments)
    {
        if (!method_exists($this->decoratedHelper, $name)) {
            throw new BadMethodCallException(sprintf('Method "%s" does not exist in "%s".', $name, self::class));
        }

        return $this->decoratedHelper->$name(...$arguments);
    }
}

Granular control on a per method basis only works if you are only using the API design from when Joomla 1.6 was released when this feature was added (all methods must be static methods inside a class, i.e. no support for class instances with dependency injection which makes automated testing of any of these helper methods more complex). The service registry is a bit more technically complex to manage overrides on, but it also adds another layer of feature support to the API as well.

(FWIW this same type of design flaw, a lack of a central registry of known types that can be overridden programatically, exists in other APIs such as the form API with its resolution of form entities (fields, rules, etc.) and the log API (and supporting different logger instances); I made a similar registry type thing for the log API but in the form API they instead chose to replace the addfieldpath bit with addfieldprefix (or whatever it was to specify a namespace) instead of opting for the registry approach)

avatar korenevskiy
korenevskiy - comment - 4 Feb 2020

Fully support. For example, you can create a plugin that changes the methods for the Joomshopping component. Thus, Joomshopping can be updated via the update server. However, Joomshopping can use a modified plugin method.
This is a very important point.
.
For example, the store component uses the add material or contact function: ContentModelContent:: save($data);
Thus, you cannot override the method in the CMS, and you cannot modify the store component. But now this can't be done in the PLUGIN.
Dear developers, explain how to do it then?

avatar infograf768 infograf768 - change - 8 Feb 2020
Status New Discussion
avatar SharkyKZ SharkyKZ - change - 25 Mar 2021
Status Discussion Closed
Closed_Date 0000-00-00 00:00:00 2021-03-25 17:42:05
Closed_By SharkyKZ
avatar SharkyKZ SharkyKZ - close - 25 Mar 2021

Add a Comment

Login with GitHub to post a comment