laminas-validator icon indicating copy to clipboard operation
laminas-validator copied to clipboard

Validator plugin manager requires a `MvcTranslator` for translation - in any context

Open froschdesign opened this issue 2 years ago • 2 comments

Bug Report

Q A
Version(s) 2.33.0

Summary

The validator plugin manager tries to inject a translator with name MvcTranslator but outside of a laminas-mvc based application there is no MvcTranslator. This means it will fail in a Mezzio based application or any other context.

Current behavior

The validator plugin manager searches for a service with name MvcTranslator:

https://github.com/laminas/laminas-validator/blob/1d82b5c0ede9316263e14d11e9284dfb3130f158/src/ValidatorPluginManager.php#L590-L594

A registered service with name Laminas\I18n\Translator\TranslatorInterface::class will not be used and an alias can not be used because the AbstractValidator expected an implementation of Laminas\Validator\Translator\TranslatorInterface:

https://github.com/laminas/laminas-validator/blob/1d82b5c0ede9316263e14d11e9284dfb3130f158/src/Translator/TranslatorInterface.php#L5-L14

https://github.com/laminas/laminas-validator/blob/1d82b5c0ede9316263e14d11e9284dfb3130f158/src/AbstractValidator.php#L441

How to reproduce

// Service manager
$serviceManager = new Laminas\ServiceManager\ServiceManager();
$serviceManager->setService('config', []); // for translator factory
$serviceManager->configure(
    (new Laminas\I18n\ConfigProvider())->getDependencyConfig()
);

// Translator
/** @var Laminas\I18n\Translator\TranslatorInterface $translator */
$translator = $serviceManager->get(
    Laminas\I18n\Translator\TranslatorInterface::class
);
$translator->addTranslationFilePattern(
    Laminas\I18n\Translator\Loader\PhpArray::class,
    Laminas\I18n\Translator\Resources::getBasePath(),
    Laminas\I18n\Translator\Resources::getPatternForValidator()
);
Locale::setDefault('de');

// Test
$validatorManager = new Laminas\Validator\ValidatorPluginManager(
    $serviceManager
);
$validator = $validatorManager->get(Laminas\Validator\NotEmpty::class);
$validator->isValid('');

// Is not translated!
echo $validator->getMessages()['isEmpty']; // Value is required and can't be empty

A service must be added manually:

$serviceManager->setService(
    'MvcTranslator',
    new class ($translator)
        implements Laminas\Validator\Translator\TranslatorInterface {
        public function __construct(
            private readonly Laminas\I18n\Translator\TranslatorInterface $translator
        ) {
        }

        public function translate(
            $message,
            $textDomain = 'default',
            $locale = null
        ) {
            return $this->translator->translate($message, $textDomain, $locale);
        }
    }
);

Or laminas-mvc-i18n must be used:

$serviceManager->configure(
    (new Laminas\Mvc\I18n\ConfigProvider())->getDependencyConfig()
);
echo $validator->getMessages()['isEmpty']; // Es wird eine Eingabe benötigt

Expected behavior

Seamless integration should also be available outside of laminas-mvc based application without the user having to write anything manually or have to use an MVC package in a Mezzio application.

froschdesign avatar Jun 23 '23 10:06 froschdesign

Yah, laminas-mvc actually does the whole wiring stuff. mainly due to the modulemanager as it provides those provider interfaces. Not sure if @Xerkus wanted to drop modulemanager in some way, but these provider interfaces are actually the source of the problem. But I do not see issues with having additional provider features in MVC but as you say, the config key should be handled by each component on its own imho.

boesing avatar Jun 23 '23 11:06 boesing

Related pull requests:

  • https://github.com/zendframework/zendframework/pull/4391
  • https://github.com/zendframework/zendframework/pull/4410

froschdesign avatar Jun 23 '23 11:06 froschdesign