Skip to content

Commit

Permalink
Merge branch '2.x' of github.com:ray-di/Ray.Di into 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
koriym committed Jul 23, 2017
2 parents 783a5d9 + 903eb9a commit 34f5e41
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
@@ -1,5 +1,6 @@
language: php
sudo: false
sudo: required
dist: trusty
php:
- 5.6
- 7
Expand Down
73 changes: 59 additions & 14 deletions README.ja.md
Expand Up @@ -372,33 +372,78 @@ protected function configure()

## コンストラクタ束縛

`@Inject`アノテーションのないサードパーティーのクラスに特定の束縛を指定するのに`toConstructor`を使うことができます。クラス名と`Named Binding`を指定して束縛します。
`@Inject`アノテーションのないサードパーティーのクラスやアノテーションを使いたくない時には`Provider`束縛を使うこともできますが、その場合インスタンスをユーザーコードが作成する事になりAOPが利用できません。

この問題は`toConstructor()`束縛で解決できます。インターフェイスにクラスを束縛するのは`to()`と同じですが、`@Named`やセッターメソッドの`@Inject`の指定をアノテートする事なしに指定できます。

```php
<?php
class Car
{
public function __construct(EngineInterface $engine, $carName)
{
// ...
```
```php
<?php
protected function configure()
{
$this->bind(EngineInterface::class)->annotatedWith('na')->to(NaturalAspirationEngine::class);
$this->bind()->annotatedWith('car_name')->toInstance('Eunos Roadster');
$this
->bind(CarInterface::class)
->toConstructor(
Car::class,
'engine=na,carName=car_name' // varName=BindName,...
Car::class, // $class_name
[
['enginne' => 'na'], // $name
['number' => 'registrtion_number']
],
(new InjectionPoints) // $setter_injection
->addMethod('setWheel', "right")
->addOptionalMethod('setTurboCharger'),
'initialize' // $postCosntruct
);
}
```

この例では`Car`クラスでは`EngineInterface $engine, $carName`と二つの引数が必要ですが、それぞれの変数名に`Named binding`束縛を行い依存解決をしています。

### Parameter

**class_name**

クラス名

**name**

名前束縛。配列か文字列で`引数名``束縛名の名前`をペアにして指定します。

array `[[$parame_name => $binding_name],...]` or string `"param_name=binding_name&..."`

**setter_injection**

セッターインジェクションのメソッド名と`束縛名の名前`を指定したインジェクとポイントオブジェクト

**postCosntruct**

`@postCosntruct`と同じく全てのインジェクションが終わった後に呼ばれる初期化メソッド名。

## PDO Example

[PDO](http://php.net/manual/ja/pdo.construct.php)クラスの束縛の例です.

```php
public PDO::__construct ( string $dsn [, string $username [, string $password [, array $options ]]] )
```

```php
protected function configure()
{
$this->bind(\PDO::class)->toConstructor(
\PDO::class,
[
['pdo' => 'pdo_dsn'],
['username' => 'pdo_username'],
['password' => 'pdo_password']
]
)->in(Scope::SINGLETON);
$this->bind()->annotatedWith('pdo_dsn')->toInstance($dsn);
$this->bind()->annotatedWith('pdo_username')->toInstance($username);
$this->bind()->annotatedWith('pdo_password')->toInstance($password);
}
```

PDOのどのインターフェイスがないので`toConstructor()`メソッドの二番目の引数の名前束縛でP束縛しています

## スコープ

デフォルトでは、Rayは毎回新しいインスタンスを生成しますが、これはスコープの設定で変更することができます。
Expand Down
66 changes: 57 additions & 9 deletions README.md
Expand Up @@ -538,9 +538,9 @@ To address this, Ray.Di has `toConstructor` bindings.
class Car implements CarInerface
{
/**
* @Named("na")
* @Named("engine=na,number=registrtion_number")
*/
public function __construct(EngineInterface $engine)
public function __construct(EngineInterface $engine, $numer, $passowrd)
{
// ...
}
Expand Down Expand Up @@ -577,16 +577,64 @@ protected function configure()
$this
->bind(CarInterface::class)
->toConstructor(
Car::class,
'na', // constructor injection
(new InjectionPoints)
->addMethod('setWheel', "right") // setter injection
->addOptionalMethod('setTurboCharger'), // optional setter injection
'initialize' // @PostCosntruct
Car::class, // $class_name
[
['enginne' => 'na'], // $name
['number' => 'registrtion_number']
],
(new InjectionPoints) // $setter_injection
->addMethod('setWheel', "right")
->addOptionalMethod('setTurboCharger'),
'initialize' // $postCosntruct
);
}
```
Ray.Di will invoke that constructor and setter method to satisfy the binding and invoke in `initialize` method after all dependencies are injected.
### Parameter

**class_name**

Class Name

**name**

Parameter name binding.

array `[[$parame_name => $binding_name],...]` or string `"param_name=binding_name&..."`

**setter_injection**

Setter Injection

**postCosntruct**

Ray.Di will invoke that constructor and setter method to satisfy the binding and invoke in `$postCosntruct` method after all dependencies are injected.

## PDO Example

Here is the example for the native [PDO](http://php.net/manual/ja/pdo.construct.php) class.

```php
public PDO::__construct ( string $dsn [, string $username [, string $password [, array $options ]]] )
```

```php
protected function configure()
{
$this->bind(\PDO::class)->toConstructor(
\PDO::class,
[
['pdo' => 'pdo_dsn'],
['username' => 'pdo_username'],
['password' => 'pdo_password']
]
)->in(Scope::SINGLETON);
$this->bind()->annotatedWith('pdo_dsn')->toInstance($dsn);
$this->bind()->annotatedWith('pdo_username')->toInstance($username);
$this->bind()->annotatedWith('pdo_password')->toInstance($password);
}
```

Since no argument of PDO has a type, it binds with the `Name Binding` of the second argument of the `toConstructor()` method.

## Scopes ##

Expand Down
27 changes: 26 additions & 1 deletion src/Bind.php
Expand Up @@ -105,14 +105,17 @@ public function to($class)

/**
* @param string $class class name
* @param string $name varName=bindName,...
* @param string | array $name "varName=bindName,..." or [[varName=>bindName],...]
* @param InjectionPoints $injectionPoints injection points
* @param null $postConstruct method name of initialization after all dependencies are injected
*
* @return $this
*/
public function toConstructor($class, $name, InjectionPoints $injectionPoints = null, $postConstruct = null)
{
if (is_array($name)) {
$name = $this->getStringName($name);
}
$this->untarget = null;
$postConstruct = $postConstruct ? new \ReflectionMethod($class, $postConstruct) : null;
$this->bound = (new DependencyFactory)->newToConstructor(new \ReflectionClass($class), $name, $injectionPoints, $postConstruct);
Expand Down Expand Up @@ -200,4 +203,26 @@ private function hasNotRegistered($interface)

return $hasNotRegistered;
}

/**
* Return string
*
* input: [['varA' => 'nameA'], ['varB' => 'nameB']]
* output: "varA=nameA,varB=nameB"
*
* @param array $name
*
* @return string
*/
private function getStringName(array $name)
{
$names = array_reduce(array_keys($name), function ($carry, $key) use ($name) {
$carry[] .= $key . '=' . $name[$key];

return $carry;
}, []);
$string = implode(',', $names);

return $string;
}
}
15 changes: 13 additions & 2 deletions tests/BindTest.php
Expand Up @@ -67,12 +67,23 @@ public function testUntargetedBindSingleton()
$this->assertSame(spl_object_hash($dependency1), spl_object_hash($dependency2));
}

public function testToConstructor()
public function nameProvider()
{
return [
['tmpDir=tmp_dir,leg=left'],
[['tmpDir' => 'tmp_dir','leg' => 'left']]
];
}

/**
* @dataProvider nameProvider
*/
public function testToConstructor($name)
{
$container = new Container;
$container->add((new Bind($container, ''))->annotatedWith('tmp_dir')->toInstance('/tmp'));
$container->add((new Bind($container, FakeLegInterface::class))->annotatedWith('left')->to(FakeLeftLeg::class));
$container->add((new Bind($container, FakeRobotInterface::class))->toConstructor(FakeToConstructorRobot::class, 'tmpDir=tmp_dir,leg=left'));
$container->add((new Bind($container, FakeRobotInterface::class))->toConstructor(FakeToConstructorRobot::class, $name));
$instance = $container->getInstance(FakeRobotInterface::class, Name::ANY);
/* @var $instance FakeToConstructorRobot */
$this->assertInstanceOf(FakeLeftLeg::class, $instance->leg);
Expand Down

0 comments on commit 34f5e41

Please sign in to comment.