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

Commit

Permalink
Merge branch 'hotfix/176' into develop
Browse files Browse the repository at this point in the history
Forward port #176
  • Loading branch information
weierophinney committed Feb 15, 2017
2 parents 2dcc55a + 309dc00 commit cb84e72
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 32 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- Nothing.
- [#176](https://github.com/zendframework/zend-servicemanager/pull/176) adds
the options `-i` or `--ignore-unresolved` to the shipped
`generate-deps-for-config-factory` command. This flag allows it to build
configuration for classes resolved by the `ConfigAbstractFactory` that
typehint on interfaces, which was previously unsupported.

### Deprecated

Expand Down
25 changes: 17 additions & 8 deletions doc/book/console-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ document details each.
$ ./vendor/bin/generate-deps-for-config-factory
Usage:

generate-deps-for-config-factory [-h|--help|help] <configFile> <className>
generate-deps-for-config-factory [-h|--help|help] [-i|--ignore-unresolved] <configFile> <className>

Arguments:

-h|--help|help This usage message
<configFile> Path to a config file for which to generate configuration.
If the file does not exist, it will be created. If it does
exist, it must return an array, and the file will be
updated with new configuration.
<className> Name of the class to reflect and for which to generate
dependency configuration.
-h|--help|help This usage message
-i|--ignore-unresolved Ignore classes with unresolved direct dependencies.
<configFile> Path to a config file for which to generate
configuration. If the file does not exist, it will
be created. If it does exist, it must return an
array, and the file will be updated with new
configuration.
<className> Name of the class to reflect and for which to
generate dependency configuration.


Reads the provided configuration file (creating it if it does not exist),
Expand All @@ -33,6 +35,13 @@ will read the named configuration file (creating it if it does not exist), and
merge any configuration it generates with the return values of that file,
writing the changes back to the original file.
Since 3.2.1, the tool also supports the `-i` or `--ignore-unresolved` flag.
Use these flags when you have typehints to classes that cannot be resolved.
When you omit the flag, such classes will cause the tool to fail with an
exception message. By adding the flag, you can have it continue and produce
configuration. This option is particularly useful when typehints are on
interfaces or resolve to services served by other abstract factories.
## generate-factory-for-class
```bash
Expand Down
35 changes: 30 additions & 5 deletions src/Tool/ConfigDumper.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<?php
/**
* @link http://github.com/zendframework/zend-servicemanager for the canonical source repository
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2016-2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\ServiceManager\Tool;

use Interop\Container\ContainerInterface;
use ReflectionClass;
use ReflectionParameter;
use Traversable;
Expand All @@ -25,13 +26,27 @@ class ConfigDumper
return %s;
EOC;

/**
* @var ContainerInterface
*/
private $container;

/**
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container = null)
{
$this->container = $container;
}

/**
* @param array $config
* @param string $className
* @param bool $ignoreUnresolved
* @return array
* @throws InvalidArgumentException for invalid $className
*/
public function createDependencyConfig(array $config, $className)
public function createDependencyConfig(array $config, $className, $ignoreUnresolved = false)
{
$this->validateClassName($className);

Expand Down Expand Up @@ -60,22 +75,32 @@ function (ReflectionParameter $argument) {
return $this->createInvokable($config, $className);
}

$config[ConfigAbstractFactory::class][$className] = [];
$classConfig = [];

foreach ($constructorArguments as $constructorArgument) {
$argumentType = $constructorArgument->getClass();
if (is_null($argumentType)) {
if ($ignoreUnresolved) {
// don't throw an exception, just return the previous config
return $config;
}
// don't throw an exception if the class is an already defined service
if ($this->container && $this->container->has($className)) {
return $config;
}
throw new InvalidArgumentException(sprintf(
'Cannot create config for constructor argument "%s", '
. 'it has no type hint, or non-class/interface type hint',
$constructorArgument->getName()
));
}
$argumentName = $argumentType->getName();
$config = $this->createDependencyConfig($config, $argumentName);
$config[ConfigAbstractFactory::class][$className][] = $argumentName;
$config = $this->createDependencyConfig($config, $argumentName, $ignoreUnresolved);
$classConfig[] = $argumentName;
}

$config[ConfigAbstractFactory::class][$className] = $classConfig;

return $config;
}

Expand Down
46 changes: 30 additions & 16 deletions src/Tool/ConfigDumperCommand.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* @link http://github.com/zendframework/zend-servicemanager for the canonical source repository
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2016-2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

Expand All @@ -21,17 +21,19 @@ class ConfigDumperCommand
const HELP_TEMPLATE = <<< EOH
<info>Usage:</info>
%s [-h|--help|help] <configFile> <className>
%s [-h|--help|help] [-i|--ignore-unresolved] <configFile> <className>
<info>Arguments:</info>
<info>-h|--help|help</info> This usage message
<info><configFile></info> Path to a config file for which to generate configuration.
If the file does not exist, it will be created. If it does
exist, it must return an array, and the file will be
updated with new configuration.
<info><className></info> Name of the class to reflect and for which to generate
dependency configuration.
<info>-h|--help|help</info> This usage message
<info>-i|--ignore-unresolved</info> Ignore classes with unresolved direct dependencies.
<info><configFile></info> Path to a config file for which to generate
configuration. If the file does not exist, it will
be created. If it does exist, it must return an
array, and the file will be updated with new
configuration.
<info><className></info> Name of the class to reflect and for which to
generate dependency configuration.
Reads the provided configuration file (creating it if it does not exist),
and injects it with ConfigAbstractFactory dependency configuration for
Expand Down Expand Up @@ -81,7 +83,11 @@ public function __invoke(array $args)

$dumper = new ConfigDumper();
try {
$config = $dumper->createDependencyConfig($arguments->config, $arguments->class);
$config = $dumper->createDependencyConfig(
$arguments->config,
$arguments->class,
$arguments->ignoreUnresolved
);
} catch (Exception\InvalidArgumentException $e) {
$this->helper->writeErrorMessage(sprintf(
'Unable to create config for "%s": %s',
Expand Down Expand Up @@ -117,6 +123,12 @@ private function parseArgs(array $args)
return $this->createHelpArgument();
}

$ignoreUnresolved = false;
if (in_array($arg1, ['-i', '--ignore-unresolved'], true)) {
$ignoreUnresolved = true;
$arg1 = array_shift($args);
}

if (! count($args)) {
return $this->createErrorArgument('Missing class name');
}
Expand Down Expand Up @@ -157,7 +169,7 @@ private function parseArgs(array $args)
));
}

return $this->createArguments(self::COMMAND_DUMP, $configFile, $config, $class);
return $this->createArguments(self::COMMAND_DUMP, $configFile, $config, $class, $ignoreUnresolved);
}

/**
Expand All @@ -178,15 +190,17 @@ private function help($resource = STDOUT)
* which it will be written.
* @param array $config Parsed configuration.
* @param string $class Name of class to reflect.
* @param bool $ignoreUnresolved If to ignore classes with unresolved direct dependencies.
* @return \stdClass
*/
private function createArguments($command, $configFile, $config, $class)
private function createArguments($command, $configFile, $config, $class, $ignoreUnresolved)
{
return (object) [
'command' => $command,
'configFile' => $configFile,
'config' => $config,
'class' => $class,
'command' => $command,
'configFile' => $configFile,
'config' => $config,
'class' => $class,
'ignoreUnresolved' => $ignoreUnresolved,
];
}

Expand Down
15 changes: 15 additions & 0 deletions test/TestAsset/ObjectWithObjectScalarDependency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
/**
* @link http://github.com/zendframework/zend-servicemanager for the canonical source repository
* @copyright Copyright (c) 2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\ServiceManager\TestAsset;

class ObjectWithObjectScalarDependency
{
public function __construct(SimpleDependencyObject $simpleDependencyObject, ObjectWithScalarDependency $dependency)
{
}
}
46 changes: 45 additions & 1 deletion test/Tool/ConfigDumperCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* @link http://github.com/zendframework/zend-servicemanager for the canonical source repository
* @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2016-2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

Expand All @@ -15,6 +15,7 @@
use Zend\ServiceManager\Tool\ConfigDumperCommand;
use Zend\Stdlib\ConsoleHelper;
use ZendTest\ServiceManager\TestAsset\InvokableObject;
use ZendTest\ServiceManager\TestAsset\ObjectWithObjectScalarDependency;
use ZendTest\ServiceManager\TestAsset\ObjectWithScalarDependency;
use ZendTest\ServiceManager\TestAsset\SimpleDependencyObject;

Expand Down Expand Up @@ -59,6 +60,14 @@ public function helpArguments()
];
}

public function ignoreUnresolvedArguments()
{
return [
'short' => ['-i'],
'long' => ['--ignore-unresolved'],
];
}

/**
* @dataProvider helpArguments
*/
Expand Down Expand Up @@ -110,6 +119,41 @@ public function testGeneratesConfigFileWhenProvidedConfigurationFileNotFound()
$this->assertEquals([], $factoryConfig[InvokableObject::class]);
}

/**
* @dataProvider ignoreUnresolvedArguments
*/
public function testGeneratesConfigFileIgnoringUnresolved($argument)
{
$command = $this->command;
vfsStream::newDirectory('config', 0775)
->at($this->configDir);
$config = vfsStream::url('project/config/test.config.php');

$this->helper->writeLine('<info>[DONE]</info> Changes written to ' . $config)->shouldBeCalled();

$this->assertEquals(0, $command([$argument, $config, ObjectWithObjectScalarDependency::class]));

$generated = include $config;
$this->assertInternalType('array', $generated);
$this->assertArrayHasKey(ConfigAbstractFactory::class, $generated);
$factoryConfig = $generated[ConfigAbstractFactory::class];
$this->assertInternalType('array', $factoryConfig);
$this->assertArrayHasKey(SimpleDependencyObject::class, $factoryConfig);
$this->assertArrayHasKey(InvokableObject::class, $factoryConfig);
$this->assertContains(InvokableObject::class, $factoryConfig[SimpleDependencyObject::class]);
$this->assertEquals([], $factoryConfig[InvokableObject::class]);

$this->assertArrayHasKey(ObjectWithObjectScalarDependency::class, $factoryConfig);
$this->assertContains(
SimpleDependencyObject::class,
$factoryConfig[ObjectWithObjectScalarDependency::class]
);
$this->assertContains(
ObjectWithScalarDependency::class,
$factoryConfig[ObjectWithObjectScalarDependency::class]
);
}

public function testEmitsErrorWhenConfigurationFileDoesNotReturnArray()
{
$command = $this->command;
Expand Down
Loading

0 comments on commit cb84e72

Please sign in to comment.