Can I overwrite a factory in getViewHelperConfig() of ConfigProvider.php?

Hi.

I want to overwrite a factory for FormElementErrors in Laminas\Form\ConfigProvider.php.

Refering to getViewHelperConfig in ConfigureProvider.php, I added factory to getViewHelperConfig in my Module.php as follow.

(In Modue.php)
    public function getViewHelperConfig(): array
    {
        return[
            'aliases' =>[
                'form_element_errors'        => \Laminas\Form\View\Helper\FormElementErrors::class,
                'formelementerrors'          => \Laminas\Form\View\Helper\FormElementErrors::class,
                'formElementErrors'          => \Laminas\Form\View\Helper\FormElementErrors::class,
                'FormElementErrors'          => \Laminas\Form\View\Helper\FormElementErrors::class,
            ],

            'factories'=>[
                \Laminas\Form\View\Helper\FormElementErrors::class => function($sm)
                {
                    $fee = $sm->get("\Laminas\Form\View\Helper\FormElementErrors::class");
                    $fee->setAttributes(['class' => 'alert-warning']);
                    return $fee;
                }
            ]
        ];
    }

But when I see [A] in SerivceManager by debbger,


private function doCreate($resolvedName, array $options = null)
{
    try {
        if (! isset($this->delegators[$resolvedName])) {
            // Let's create the service by fetching the factory
            $factory = $this->getFactory($resolvedName); [A]
            $object  = $factory($this->creationContext, $resolvedName, $options);
        } else {

it sitll shows ā€œLaminas\ServiceManager\Factory\InvokableFattoryā€, and
the result of webpate is not change.

Is there any way to overwrite factory of getViewHelperConfig() in ConfigProvider.php?

You can omit most of it because the aliases already registered.

Config

return [
    'view_helpers'    => [
        'factories' => [
            Laminas\Form\View\Helper\FormElementErrors::class => MyModule\View\FormElementErrorsFactory::class,
        ],
    ],
    'view_helper_config' => [
        'form_element_errors' => [
            'message_open_format' => '<div>',
            'message_separator_string' => '</br>',
            'message_close_string' => '</div>',
        ],
    ],
];

Factory

namespace MyModule\View;

use Laminas\Form\View\Helper\FormElementErrors;
use Psr\Container\ContainerInterface;

class FormElementErrorsFactory
{
    public function __invoke(ContainerInterface $container): FormElementErrors
    {
        $helper = new FormElementErrors();

        $config = $container->get('config');
        if (isset($config['view_helper_config']['form_element_errors'])) {
            $configHelper = $config['view_helper_config']['form_element_errors'];
            if (isset($configHelper['message_open_format'])) {
                $helper->setMessageOpenFormat(
                    $configHelper['message_open_format']
                );
            }
            if (isset($configHelper['message_separator_string'])) {
                $helper->setMessageSeparatorString(
                    $configHelper['message_separator_string']
                );
            }
            if (isset($configHelper['message_close_string'])) {
                $helper->setMessageCloseString(
                    $configHelper['message_close_string']
                );
            }
        }

        return $helper;
    }
}
1 Like

Iā€™m sorry to make bother you to write complete code.

I understand it is not enough to write a simple closer but need to write a ā€œ__invokeā€ class in my module.

I must study harder. Thank you.

You can because the problem is not the closure but this line:

You create a factory for this object and have registered in the service manager. But then you will fetch this object from the service manager in the factory itself.

1 Like

I seeā€¦ Iā€™ll read the reference around ServiceManager and configureation again.
Thank you for your advice.

I also find a workaround. After Advanced Configuration Tricks - tutorials - Laminas Docs, we can steal merged configuration and rewrite it. I add the code in my Module.php as follows.

public function init(ModuleManager $moduleManager)
{
    $events = $moduleManager->getEventManager();
    $events->attach(ModuleEvent::EVENT_MERGE_CONFIG, [$this, 'onMergeConfig']);
}

public function onMergeConfig(ModuleEvent $e)
{
    $configListener = $e->getConfigListener();
    $config         = $configListener->getMergedConfig(false);

    $config["view_helpers"]["factories"]["Laminas\Form\View\Helper\FormElementErrors"]
        =function ($sm) {
            $fee = new FormElementErrors();
            $fee->setAttributes(['class' => 'alert-warning']);
            return $fee;
        };
    
    // Pass the changed configuration back to the listener:
    $configListener->setMergedConfig($config);
}

Using that code, I can change the format of FormElementErrorsā€™s <ul>.

I think you have badly misunderstood something about my example.

You donā€™t need a workaround! You can use this factory in all your projects and add an individual configuration for the view helper. And you can extend it, for example to set the attributes:

namespace MyModule\View;

use Laminas\Form\View\Helper\FormElementErrors;
use Psr\Container\ContainerInterface;

class FormElementErrorsFactory
{
    public function __invoke(ContainerInterface $container): FormElementErrors
    {
        $helper = new FormElementErrors();

        $config = $container->get('config');
        if (isset($config['view_helper_config']['form_element_errors'])) {
            $configHelper = $config['view_helper_config']['form_element_errors'];
            if (isset($configHelper['message_open_format'])) {
                $helper->setMessageOpenFormat(
                    $configHelper['message_open_format']
                );
            }
            if (isset($configHelper['message_separator_string'])) {
                $helper->setMessageSeparatorString(
                    $configHelper['message_separator_string']
                );
            }
            if (isset($configHelper['message_close_string'])) {
                $helper->setMessageCloseString(
                    $configHelper['message_close_string']
                );
            }
            // Attributes
            if (isset($configHelper['attributes']) && is_array($configHelper['attributes'])) {
                $helper->setAttributes($configHelper['attributes']);
            }
        }

        return $helper;
    }
}

And the related config:

return [
    'view_helpers'    => [
        'factories' => [
            Laminas\Form\View\Helper\FormElementErrors::class => MyModule\View\FormElementErrorsFactory::class,
        ],
    ],
    'view_helper_config' => [
        'form_element_errors' => [
            'attributes' => ['class' => 'alert-warning'],
        ],
    ],
];
1 Like

Ok. I understand this is the right way when I change some property to a view helper.

Thank you!

Btw. I will create a pull request to add this factory to laminas-form.

1 Like

I was very surprised to get a direct suggestion from a core member of Lmainas project.
Thank you so lot.

I try to answer wherever I can help and when I find the time.
But there are also other Laminas members around here.

@smj320
The factory is coming with version 3 of laminas-form:

1 Like

Thank you for your information. :grinning: