Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit 93b9919

Browse files
committed
Merge branch 'hotfix/117'
Close #119 Close #117 Fixes #100
2 parents bb2938d + 778df73 commit 93b9919

File tree

5 files changed

+217
-20
lines changed

5 files changed

+217
-20
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ All notable changes to this project will be documented in this file, in reverse
1818

1919
### Fixed
2020

21-
- Nothing.
21+
- [#119](https://github.com/zendframework/zend-form/pull/119) fixes the order in
22+
which the default initializers are injected into the `FormElementManager`,
23+
ensuring that the initializer injecting a factory into a `FormFactoryAware`
24+
instance is triggered before the initializer that calls `init()`, and also
25+
that the initializer calling `init()` is always triggered last.
2226

2327
## 2.9.0 - 2016-06-07
2428

src/FormElementManager/FormElementManagerV2Polyfill.php

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,11 @@ class FormElementManagerV2Polyfill extends AbstractPluginManager
175175
*/
176176
public function __construct($configInstanceOrParentLocator = null, array $v3config = [])
177177
{
178-
parent::__construct($configInstanceOrParentLocator, $v3config);
178+
// Provide default initializers, ensuring correct order
179+
array_unshift($this->initializers, [$this, 'injectFactory']);
180+
array_push($this->initializers, [$this, 'callElementInit']);
179181

180-
$this->addInitializer([$this, 'injectFactory']);
181-
$this->addInitializer([$this, 'callElementInit'], false);
182+
parent::__construct($configInstanceOrParentLocator, $v3config);
182183
}
183184

184185
/**
@@ -261,4 +262,32 @@ public function validatePlugin($plugin)
261262
));
262263
}
263264
}
265+
266+
/**
267+
* Overrides parent::addInitializer in order to ensure default initializers are in expected positions.
268+
*
269+
* Always pushes `injectFactory` to top of initializer stack, and
270+
* `callElementInit` to the bottom.
271+
*
272+
* {@inheritDoc}
273+
*/
274+
public function addInitializer($initializer, $topOfStack = true)
275+
{
276+
$firstInitializer = [$this, 'injectFactory'];
277+
$lastInitializer = [$this, 'callElementInit'];
278+
279+
foreach ([$firstInitializer, $lastInitializer] as $default) {
280+
if (false === ($index = array_search($default, $this->initializers))) {
281+
continue;
282+
}
283+
unset($this->initializers[$index]);
284+
}
285+
286+
parent::addInitializer($initializer, $topOfStack);
287+
288+
array_unshift($this->initializers, $firstInitializer);
289+
array_push($this->initializers, $lastInitializer);
290+
291+
return $this;
292+
}
264293
}

src/FormElementManager/FormElementManagerV3Polyfill.php

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,6 @@ class FormElementManagerV3Polyfill extends AbstractPluginManager
202202
*/
203203
protected $instanceOf = ElementInterface::class;
204204

205-
/**
206-
* Constructor
207-
*
208-
* Overrides parent constructor in order to add the initializer methods injectFactory()
209-
* and callElementInit().
210-
*
211-
* @param ContainerInterface $parentLocator
212-
* @param null|array $config
213-
*/
214-
public function __construct(ContainerInterface $parentLocator = null, array $config = [])
215-
{
216-
$this->addInitializer([$this, 'injectFactory']);
217-
parent::__construct($parentLocator, $config);
218-
$this->addInitializer([$this, 'callElementInit']);
219-
}
220-
221205
/**
222206
* Inject the factory to any element that implements FormFactoryAwareInterface
223207
*
@@ -299,4 +283,32 @@ public function validate($plugin)
299283
));
300284
}
301285
}
286+
287+
/**
288+
* Overrides parent::configure in order to ensure default initializers are in expected positions.
289+
*
290+
* Always pushes `injectFactory` to top of initializer stack, and
291+
* `callElementInit` to the bottom.
292+
*
293+
* {@inheritDoc}
294+
*/
295+
public function configure(array $config)
296+
{
297+
$firstInitializer = [$this, 'injectFactory'];
298+
$lastInitializer = [$this, 'callElementInit'];
299+
300+
foreach ([$firstInitializer, $lastInitializer] as $default) {
301+
if (false === ($index = array_search($default, $this->initializers))) {
302+
continue;
303+
}
304+
unset($this->initializers[$index]);
305+
}
306+
307+
parent::configure($config);
308+
309+
array_unshift($this->initializers, $firstInitializer);
310+
array_push($this->initializers, $lastInitializer);
311+
312+
return $this;
313+
}
302314
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
/**
3+
* @link http://github.com/zendframework/zend-form for the canonical source repository
4+
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license http://framework.zend.com/license/new-bsd New BSD License
6+
*/
7+
8+
namespace ZendTest\Form\Integration;
9+
10+
use PHPUnit_Framework_TestCase as TestCase;
11+
use Prophecy\Argument;
12+
use Zend\Form\Element;
13+
use Zend\Form\Form;
14+
use Zend\Form\FormElementManager;
15+
use Zend\Form\FormElementManagerFactory;
16+
use Zend\ServiceManager\Config;
17+
use Zend\ServiceManager\InitializerInterface;
18+
use Zend\ServiceManager\ServiceManager;
19+
20+
class ServiceManagerTest extends TestCase
21+
{
22+
public function testInitInitializerShouldBeCalledAfterAllOtherInitializers()
23+
{
24+
// Reproducing the behaviour of a full stack MVC + ModuleManager
25+
$serviceManagerConfig = new Config([
26+
'factories' => [
27+
'FormElementManager' => FormElementManagerFactory::class,
28+
],
29+
]);
30+
31+
$serviceManager = new ServiceManager();
32+
$serviceManagerConfig->configureServiceManager($serviceManager);
33+
34+
$formElementManager = $serviceManager->get('FormElementManager');
35+
36+
$test = 0;
37+
$spy = function () use (&$test) {
38+
TestCase::assertEquals(1, $test);
39+
};
40+
41+
$element = $this->prophesize(Element::class);
42+
$element->init()->will($spy);
43+
44+
$initializer = $this->prophesize(InitializerInterface::class);
45+
$incrementTest = function () use (&$test) {
46+
$test += 1;
47+
};
48+
49+
if (method_exists($serviceManager, 'configure')) {
50+
$initializer->__invoke(
51+
$serviceManager,
52+
$element->reveal()
53+
)->will($incrementTest)->shouldBeCalled();
54+
} else {
55+
$initializer->initialize(
56+
$element->reveal(),
57+
$formElementManager
58+
)->will($incrementTest)->shouldBeCalled();
59+
}
60+
61+
$formElementManagerConfig = new Config([
62+
'factories' => [
63+
'InitializableElement' => function () use ($element) {
64+
return $element->reveal();
65+
},
66+
],
67+
'initializers' => [
68+
$initializer->reveal(),
69+
],
70+
]);
71+
72+
$formElementManagerConfig->configureServiceManager($formElementManager);
73+
74+
$formElementManager->get('InitializableElement');
75+
}
76+
77+
public function testInjectFactoryInitializerShouldTriggerBeforeInitInitializer()
78+
{
79+
// Reproducing the behaviour of a full stack MVC + ModuleManager
80+
$serviceManagerConfig = new Config([
81+
'factories' => [
82+
'FormElementManager' => FormElementManagerFactory::class,
83+
],
84+
]);
85+
86+
$serviceManager = new ServiceManager();
87+
$serviceManagerConfig->configureServiceManager($serviceManager);
88+
89+
$formElementManager = $serviceManager->get('FormElementManager');
90+
91+
$initializer = $this->prophesize(InitializerInterface::class);
92+
$formElementManagerAssertion = function ($form) use ($formElementManager) {
93+
TestCase::assertInstanceOf(Form::class, $form);
94+
TestCase::assertSame($formElementManager, $form->getFormFactory()->getFormElementManager());
95+
return true;
96+
};
97+
if (method_exists($serviceManager, 'configure')) {
98+
$initializer->__invoke(
99+
$serviceManager,
100+
Argument::that($formElementManagerAssertion)
101+
)->shouldBeCalled();
102+
} else {
103+
$initializer->initialize(
104+
Argument::that($formElementManagerAssertion),
105+
$formElementManager
106+
)->shouldBeCalled();
107+
}
108+
109+
$formElementManagerConfig = new Config([
110+
'factories' => [
111+
'MyForm' => function () {
112+
return new TestAsset\Form();
113+
},
114+
],
115+
'initializers' => [
116+
$initializer->reveal(),
117+
],
118+
]);
119+
120+
$formElementManagerConfig->configureServiceManager($formElementManager);
121+
122+
/** @var TestAsset\Form */
123+
$form = $formElementManager->get('MyForm');
124+
$this->assertSame($formElementManager, $form->elementManagerAtInit);
125+
}
126+
}

test/Integration/TestAsset/Form.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
/**
3+
* @link http://github.com/zendframework/zend-form for the canonical source repository
4+
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license http://framework.zend.com/license/new-bsd New BSD License
6+
*/
7+
8+
namespace ZendTest\Form\Integration\TestAsset;
9+
10+
use Zend\Form\Form as BaseForm;
11+
12+
class Form extends BaseForm
13+
{
14+
/**
15+
* @param null|\Zend\Form\FormElementManager
16+
*/
17+
public $elementManagerAtInit;
18+
19+
/**
20+
* {@inheritDoc}
21+
*/
22+
public function init()
23+
{
24+
$this->elementManagerAtInit = $this->getFormFactory()->getFormElementManager();
25+
}
26+
}

0 commit comments

Comments
 (0)