As Matthew kindly requested in Slack thread here is an example of ValidatorManager
not calling custom validator factory.
Same goes for FormElementManager
not calling form factory.
Simply comment out any (or both) of two defined delegators.
Just a few initial comments, as I had to dive a bit further into code to understand what’s being wired and where.
- In
config/config.php
, add entries for each of theConfigProvider
classes of the ZF components installed (e.g.,Zend\Filter\ConfigProvider::class
), instead of addingconfig/autoload/<component>.global.php
files that import and invoke them. It’s simpler to see which components are registered, plays nicer with zend-component-installer, and follows the conventions of default Expressive applications. - One problem highlighted is that
App\Form\Form
composesApp\InputFilter\InputFilter
, and the latter is not being injected with the custom validatorApp\Validator\Validator
, which is provided viavalidators
configuration inApp\ConfigProvider
.
I have update the example to reflect your suggestion and slightly modified Form
and FormFactory
so that commenting out FormElementDelegator
will cause an exception to be thrown because FormFactory
is not called
I’ve done the following:
- Cloned your repository
- Run
composer install
. When I did, it prompted me to inject the ConfigProvider from zend-filter, which I did. - I then ran
php -S 0:8080 -t public/ public/index.php
to initialize a web server. - I navigated to
https://localhost:8080/test
to test the form.
As expected, this worked fine.
I then did as you suggested, and commented out first the FormElementManager
delegator in App\ConfigProvider
, and then the ValidatorManager
delegator. This continued to work.
And then I remembered to enable development mode, to ensure the configuration cache was cleared: composer development-enable
. Once I did this, I repeated the steps above, refreshing the page at each step. At the step where I commented out the FormElementManager
delegator, I ran into the problem.
whoops reports that the issue is within App\Form\Form::init()
, at the line that tests if !$this->something
, which triggers an exception. This demonstrates that the App\Form\FormFactory
is not being used to instantiate the form instance.
If I instead comment out the ValidatorManager
entry, I do not see an error until after submission, at which point App\Validator\Validator::isValid()
raises an exception because its first argument, assigned to the property $test
, is null — indicating that its factory was not invoked.
So, at this point, I have something reproducible. I’ll see what I can find from here.
Okay, I figured out the issue, and it affects pretty much all of these AbstractPluginManager
implementations.
In zend-mvc applications, we tie into zend-modulemanager, and have integration in the Module
class of each that informs Zend\ModuleManager\Listener\ServiceListener
of configuration keys associated with each plugin manager. Once bootstrap is over, it merges configuration under that key in order to configure the associated plugin manager.
What this means is that the various keys such as validators
, form_elements
, etc. have meaning in zend-mvc applications, but not currently in Expressive applications.
This is clearly a serious issue, and I’m not 100% sure how to manage it. I think we may be able to do it via the factory for each plugin manager, however. They could look for the config service and relevant config key, and, if found use the value to configure the plugin manager before returning it.
To be on the safe side, we’d check to see if the ServiceListener
service is present before doing so, as we would not want to double-inject. (That said, this approach may also mean we no longer need to use that functionality, which could be fantastic.)
I’ll keep this post updated with links to pull requests as I make them.
So glad you could reproduce the problem! Really looking forward to the bugfix. Thanks for the patience for understanding the problem and your time looking into this case - I’m sure Expressive will profit a lot in sense of ZF component usage.
First patch is for zend-validator: https://github.com/zendframework/zend-validator/pull/168
Second patch is for zend-form: https://github.com/zendframework/zend-form/pull/164
Third patch is for zend-filter: https://github.com/zendframework/zend-filter/pull/56
Fourth patch is for zend-inputfilter: https://github.com/zendframework/zend-inputfilter/pull/137
Fifth patch is for zend-hydrator: https://github.com/zendframework/zend-hydrator/pull/59
Sixth patch is for zend-i18n: https://github.com/zendframework/zend-i18n/pull/74
Seventh and final patch is for zend-log: https://github.com/zendframework/zend-log/pull/74
All releases are done!
- zend-log 2.9.2
- zend-i18n 2.7.4
- zend-hydrator 2.2.2
- zend-filter 2.7.2
- zend-validator 2.9.1
- zend-inputfilter 2.7.4
- zend-form 2.10.2
Pin to ^<version>
in your composer.json
files (or run composer require "zendframework/<component>:^<version>"
; alternately, just run composer update
), and you should now have something working!
I’ve just tried that with the sample app you provided, commenting out the two delegator factories you provided, and all is working now!
Works like a charm
Great job guys! Looking forward to test that myself…
Quite curious if this addresses some of the issues you’ve raised in the past, @RalfEggert!
Now I just need to work on the navigation stuff with @froschdesign sometime in the near future so we can get that sorted!
Yes, it does solve my issues. My /config/container.php file looked like this before the update:
use Zend\Filter\FilterPluginManager;
use Zend\Form\FormElementManager\FormElementManagerV3Polyfill;
use Zend\Hydrator\HydratorPluginManager;
use Zend\InputFilter\InputFilterPluginManager;
use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;
use Zend\Validator\ValidatorPluginManager;
// Load configuration
$config = require __DIR__ . '/config.php';
// Build container
$container = new ServiceManager();
(new Config($config['dependencies']))->configureServiceManager($container);
// Inject config
$container->setService('config', $config);
/** @var HydratorPluginManager $hydratorManager */
$hydratorManager = $container->get('HydratorManager');
$hydratorManager->configure($config['hydrators']);
/** @var FilterPluginManager $filterManager */
$filterManager = $container->get('FilterManager');
$filterManager->configure($config['filters']);
/** @var ValidatorPluginManager $validatorManager */
$validatorManager = $container->get('ValidatorManager');
$validatorManager->configure($config['validators']);
/** @var InputFilterPluginManager $inputFilterManager */
$inputFilterManager = $container->get('InputFilterManager');
$inputFilterManager->configure($config['input_filters']);
/** @var FormElementManagerV3Polyfill $formElementManager */
$formElementManager = $container->get('FormElementManager');
$formElementManager->configure($config['form_elements']);
return $container;
Now I can shorten it to this:
use Zend\Filter\FilterPluginManager;
use Zend\Form\FormElementManager\FormElementManagerV3Polyfill;
use Zend\Hydrator\HydratorPluginManager;
use Zend\InputFilter\InputFilterPluginManager;
use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;
use Zend\Validator\ValidatorPluginManager;
// Load configuration
$config = require __DIR__ . '/config.php';
// Build container
$container = new ServiceManager();
(new Config($config['dependencies']))->configureServiceManager($container);
// Inject config
$container->setService('config', $config);
return $container;
Without these extra lines all custom form elements, validators, and stuff weren’t found. After upgrading, they are.
little late, but wanted to reply on this again. Updated packages, removed my workaround and it worked like expected for custom filters and validators. Really great!
I think this was a huge step forward for using these packages inside Expressive context and I’m really happy to see the benefits Matthew pointed out in his blog post about this. From a question inside slack to a complex series of releases, that fix the problem. And many people being involved to get the problem solved.
So let me thank you @matthew for working on the patches/release, @metalinspired for providing the example and all others I missed that were part of this.
Working now ~10 years with ZF. ZF2 and ModuleManager was a huge step forward, but all the work @matthew did in relation to standards and Expressive - it feels just right. Working now 4 weeks with Expressive2 and there was no situation I didn’t liked it. No magic needed, so flexible to use - v2 just nailed it.