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

Commit

Permalink
Merge branch 'hotfix/16'
Browse files Browse the repository at this point in the history
Close #16
  • Loading branch information
weierophinney committed Oct 11, 2016
2 parents 9b6b18a + 054df0e commit 80fa351
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 49 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ All notable changes to this project will be documented in this file, in reverse
a `ConfigInjectorChain`, which allows injecting a module or component into
multiple configuration sources. The stated use is for injection into
development configuration.
- [#16](https://github.com/zendframework/zend-component-installer/pull/16) adds
support for defining both a module and a component in the same package,
ensuring that they are both injected, and at the appropriate positions in the
module list.

### Deprecated

Expand Down
81 changes: 32 additions & 49 deletions src/ComponentInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,12 @@ public function onPostPackageInstall(PackageEvent $event)
})
// Create injectors
->reduce(function ($injectors, $module) use ($options, $packageTypes) {
$injectors[$module] = $this->promptForConfigOption($module, $options, $packageTypes);
$injectors[$module] = $this->promptForConfigOption($module, $options, $packageTypes[$module]);
return $injectors;
}, new Collection([]))
// Inject modules into configuration
->each(function ($injector, $module) use ($name, $packageTypes) {
$this->injectModuleIntoConfig($name, $module, $injector, $packageTypes);
$this->injectModuleIntoConfig($name, $module, $injector, $packageTypes[$module]);
});
}

Expand Down Expand Up @@ -254,18 +254,22 @@ private function getExtraMetadata(array $extra)
* exposes in the extra configuration.
*
* @param string[] $extra
* @return int[] Array of Injector\InjectorInterface::TYPE_* constants.
* @return Collection Collection of Injector\InjectorInterface::TYPE_* constants.
*/
private function discoverPackageTypes(array $extra)
{
$packageTypes = array_flip($this->packageTypes);
$knownTypes = array_keys($packageTypes);
return Collection::create(array_keys($extra))
->filter(function ($type) use ($knownTypes) {
return Collection::create($extra)
->filter(function ($packages, $type) use ($knownTypes) {
return in_array($type, $knownTypes, true);
})
->reduce(function ($discoveredTypes, $type) use ($packageTypes) {
$discoveredTypes[] = $packageTypes[$type];
->reduce(function ($discoveredTypes, $packages, $type) use ($packageTypes) {
$packages = is_array($packages) ? $packages : [$packages];

foreach ($packages as $package) {
$discoveredTypes[$package] = $packageTypes[$type];
}
return $discoveredTypes;
}, new Collection([]));
}
Expand Down Expand Up @@ -337,12 +341,12 @@ private function marshalInstallableModules(array $extra, Collection $options)
*
* @param string $name
* @param Collection $options
* @param Collection $packageTypes
* @param int $packageType
* @return Injector\InjectorInterface
*/
private function promptForConfigOption($name, Collection $options, Collection $packageTypes)
private function promptForConfigOption($name, Collection $options, $packageType)
{
if ($cachedInjector = $this->getCachedInjector($packageTypes)) {
if ($cachedInjector = $this->getCachedInjector($packageType)) {
return $cachedInjector;
}

Expand All @@ -366,7 +370,7 @@ private function promptForConfigOption($name, Collection $options, Collection $p

if (is_numeric($answer) && isset($options[(int) $answer])) {
$injector = $options[(int) $answer]->getInjector();
$this->promptToRememberOption($injector);
$this->promptToRememberOption($injector, $packageType);
return $injector;
}

Expand All @@ -379,9 +383,10 @@ private function promptForConfigOption($name, Collection $options, Collection $p
*
* @todo Will need to store selection in filesystem and remove when all packages are complete
* @param Injector\InjectorInterface $injector
* @param int $packageType
* return void
*/
private function promptToRememberOption(Injector\InjectorInterface $injector)
private function promptToRememberOption(Injector\InjectorInterface $injector, $packageType)
{
$ask = ["\n <question>Remember this option for other packages of the same type? (y/N)</question>"];

Expand All @@ -390,7 +395,7 @@ private function promptToRememberOption(Injector\InjectorInterface $injector)

switch ($answer) {
case 'y':
$this->cacheInjector($injector);
$this->cacheInjector($injector, $packageType);
return;
case 'n':
// intentionally fall-through
Expand All @@ -406,28 +411,13 @@ private function promptToRememberOption(Injector\InjectorInterface $injector)
* @param string $package Package name
* @param string $module Module to install in configuration
* @param Injector\InjectorInterface $injector Injector to use.
* @param Collection $packageTypes
* @param int $packageType
* @return void
*/
private function injectModuleIntoConfig(
$package,
$module,
Injector\InjectorInterface $injector,
Collection $packageTypes
) {
// Find the first package type the injector can handle.
$type = $packageTypes
->reduce(function ($discovered, $type) use ($injector) {
if ($discovered) {
return $discovered;
}

$discovered = $injector->registersType($type) ? $type : $discovered;
return $discovered;
}, false);

private function injectModuleIntoConfig($package, $module, Injector\InjectorInterface $injector, $packageType)
{
$this->io->write(sprintf('<info>Installing %s from package %s</info>', $module, $package));
$injector->inject($module, $type, $this->io);
$injector->inject($module, $packageType, $this->io);
}

/**
Expand Down Expand Up @@ -522,36 +512,29 @@ private function metadataForKeyIsValid($key, array $metadata)
}

/**
* Attempt to retrieve a cached injector, based on the current package types.
* Attempt to retrieve a cached injector for the current package type.
*
* @param Collection $packageTypes
* @param int $packageType
* @return null|Injector\InjectorInterface
*/
private function getCachedInjector(Collection $packageTypes)
private function getCachedInjector($packageType)
{
return $packageTypes->reduce(function ($injector, $type) {
if (null !== $injector || ! isset($this->cachedInjectors[$type])) {
return $injector;
}
if (isset($this->cachedInjectors[$packageType])) {
return $this->cachedInjectors[$packageType];
}

return $this->cachedInjectors[$type];
}, null);
return null;
}

/**
* Cache an injector for later use.
*
* @param Injector\InjectorInterface $injector
* @param int $packageType
* @return void
*/
private function cacheInjector(Injector\InjectorInterface $injector)
private function cacheInjector(Injector\InjectorInterface $injector, $packageType)
{
Collection::create($injector->getTypesAllowed())
->reject(function ($type) {
return isset($this->cachedInjectors[$type]);
})
->each(function ($type) use ($injector) {
$this->cachedInjectors[$type] = $injector;
});
$this->cachedInjectors[$packageType] = $injector;
}
}
178 changes: 178 additions & 0 deletions test/ComponentInstallerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -634,4 +634,182 @@ public function testModuleIsAppended()
'Some\Module'
], $modules);
}

public function testAppendModuleAndPrependComponent()
{
$this->createApplicationConfig(
'<' . "?php\nreturn [\n 'modules' => [\n 'SomeApplication',\n ]\n];"
);

$package = $this->prophesize(PackageInterface::class);
$package->getName()->willReturn('some/package');
$package->getExtra()->willReturn(['zf' => [
'module' => 'Some\\Module',
'component' => 'Some\\Component',
]]);

$operation = $this->prophesize(InstallOperation::class);
$operation->getPackage()->willReturn($package->reveal());

$event = $this->prophesize(PackageEvent::class);
$event->isDevMode()->willReturn(true);
$event->getOperation()->willReturn($operation->reveal());

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}

if (! strstr($argument[0], "Please select which config file you wish to inject 'Some\Module' into")) {
return false;
}

if (! strstr($argument[1], 'Do not inject')) {
return false;
}

if (! strstr($argument[2], 'application.config.php')) {
return false;
}

return true;
}), 0)->willReturn(1);

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}

if (! strstr($argument[0], "Please select which config file you wish to inject 'Some\Component' into")) {
return false;
}

if (! strstr($argument[1], 'Do not inject')) {
return false;
}

if (! strstr($argument[2], 'application.config.php')) {
return false;
}

return true;
}), 0)->willReturn(1);

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}
if (! strstr($argument[0], 'Remember')) {
return false;
}

return true;
}), 'n')->willReturn('n');

$this->io->write(Argument::that(function ($argument) {
return strstr($argument, 'Installing Some\Module from package some/package');
}))->shouldBeCalled();

$this->io->write(Argument::that(function ($argument) {
return strstr($argument, 'Installing Some\Component from package some/package');
}))->shouldBeCalled();

$this->assertNull($this->installer->onPostPackageInstall($event->reveal()));
$config = include(vfsStream::url('project/config/application.config.php'));
$modules = $config['modules'];
$this->assertEquals([
'Some\Component',
'SomeApplication',
'Some\Module',
], $modules);
}

public function testPrependComponentAndAppendModule()
{
$this->createApplicationConfig(
'<' . "?php\nreturn [\n 'modules' => [\n 'SomeApplication',\n ]\n];"
);

$package = $this->prophesize(PackageInterface::class);
$package->getName()->willReturn('some/package');
$package->getExtra()->willReturn(['zf' => [
'component' => 'Some\\Component',
'module' => 'Some\\Module',
]]);

$operation = $this->prophesize(InstallOperation::class);
$operation->getPackage()->willReturn($package->reveal());

$event = $this->prophesize(PackageEvent::class);
$event->isDevMode()->willReturn(true);
$event->getOperation()->willReturn($operation->reveal());

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}

if (! strstr($argument[0], "Please select which config file you wish to inject 'Some\Module' into")) {
return false;
}

if (! strstr($argument[1], 'Do not inject')) {
return false;
}

if (! strstr($argument[2], 'application.config.php')) {
return false;
}

return true;
}), 0)->willReturn(1);

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}

if (! strstr($argument[0], "Please select which config file you wish to inject 'Some\Component' into")) {
return false;
}

if (! strstr($argument[1], 'Do not inject')) {
return false;
}

if (! strstr($argument[2], 'application.config.php')) {
return false;
}

return true;
}), 0)->willReturn(1);

$this->io->ask(Argument::that(function ($argument) {
if (! is_array($argument)) {
return false;
}
if (! strstr($argument[0], 'Remember')) {
return false;
}

return true;
}), 'n')->willReturn('n');

$this->io->write(Argument::that(function ($argument) {
return strstr($argument, 'Installing Some\Module from package some/package');
}))->shouldBeCalled();

$this->io->write(Argument::that(function ($argument) {
return strstr($argument, 'Installing Some\Component from package some/package');
}))->shouldBeCalled();

$this->assertNull($this->installer->onPostPackageInstall($event->reveal()));
$config = include(vfsStream::url('project/config/application.config.php'));
$modules = $config['modules'];
$this->assertEquals([
'Some\Component',
'SomeApplication',
'Some\Module',
], $modules);
}
}

0 comments on commit 80fa351

Please sign in to comment.