Fix #18115: Allow to load action-injected services from module's container

This commit is contained in:
ErickSkrauch
2020-06-22 23:49:02 +03:00
committed by GitHub
parent d755004c41
commit 2e21a8275c
6 changed files with 72 additions and 4 deletions

View File

@ -9,7 +9,7 @@ Yii Framework 2 Change Log
- Bug #18026: Fix `ArrayHelper::getValue()` did not work with `ArrayAccess` objects (mikk150)
- Enh #18048: Use `Instance::ensure()` to set `User::$accessChecker` (lav45)
- Bug #18051: Fix missing support for custom validation method in EachValidator (bizley)
- Enh #17722: Add action injection support (SamMousa, samdark)
- Enh #17722: Add action injection support (SamMousa, samdark, erickskrauch)
- Bug #18041: Fix RBAC migration for MSSQL (darkdef)
- Bug #18081: Fix for PDO_DBLIB/MSSQL. Set flag ANSI_NULL_DFLT_ON to ON for current connect to DB (darkdef)
- Bug #13828: Fix retrieving inserted data for a primary key of type uniqueidentifier for SQL Server 2005 or later (darkdef)

View File

@ -565,9 +565,12 @@ class Controller extends Component implements ViewContextInterface
if (($component = $this->module->get($name, false)) instanceof $typeName) {
$args[] = $component;
$requestedParams[$name] = "Component: " . get_class($component) . " \$$name";
} elseif ($this->module->has($typeName) && ($service = $this->module->get($typeName)) instanceof $typeName) {
$args[] = $service;
$requestedParams[$name] = 'Module ' . get_class($this->module) . " DI: $typeName \$$name";
} elseif (\Yii::$container->has($typeName) && ($service = \Yii::$container->get($typeName)) instanceof $typeName) {
$args[] = $service;
$requestedParams[$name] = "DI: $typeName \$$name";
$requestedParams[$name] = "Container DI: $typeName \$$name";
} elseif ($type->allowsNull()) {
$args[] = null;
$requestedParams[$name] = "Unavailable service: $name";

View File

@ -170,12 +170,35 @@ class ControllerTest extends TestCase
$this->assertEquals('Component: yii\console\Request $request', \Yii::$app->requestedParams['request']);
$this->assertEquals($params['between'], $args[2]);
$this->assertInstanceOf(DummyService::className(), $args[3]);
$this->assertEquals('DI: yiiunit\framework\console\stubs\DummyService $dummyService', \Yii::$app->requestedParams['dummyService']);
$this->assertEquals('Container DI: yiiunit\framework\console\stubs\DummyService $dummyService', \Yii::$app->requestedParams['dummyService']);
$this->assertNull($args[4]);
$this->assertEquals('Unavailable service: post', \Yii::$app->requestedParams['post']);
$this->assertEquals($params['after'], $args[5]);
}
public function testInjectedActionParamsFromModule()
{
if (PHP_VERSION_ID < 70100) {
$this->markTestSkipped('Can not be tested on PHP < 7.1');
return;
}
$module = new \yii\base\Module('fake', new Application([
'id' => 'app',
'basePath' => __DIR__,
]));
$module->set('yii\data\DataProviderInterface', [
'class' => \yii\data\ArrayDataProvider::className(),
]);
// Use the PHP71 controller for this test
$this->controller = new FakePhp71Controller('fake', $module);
$this->mockWebApplication(['controller' => $this->controller]);
$injectionAction = new InlineAction('injection', $this->controller, 'actionModuleServiceInjection');
$args = $this->controller->bindActionParams($injectionAction, []);
$this->assertInstanceOf(\yii\data\ArrayDataProvider::className(), $args[0]);
$this->assertEquals('Module yii\base\Module DI: yii\data\DataProviderInterface $dataProvider', \Yii::$app->requestedParams['dataProvider']);
}
public function assertResponseStatus($status, $response)
{
$this->assertInstanceOf('yii\console\Response', $response);

View File

@ -7,6 +7,7 @@
namespace yiiunit\framework\console;
use yii\data\DataProviderInterface;
use yiiunit\framework\console\stubs\DummyService;
use yii\console\Controller;
use yii\console\Request;
@ -21,4 +22,8 @@ class FakePhp71Controller extends Controller
public function actionNullableInjection(?Request $request, ?Post $post)
{
}
public function actionModuleServiceInjection(DataProviderInterface $dataProvider)
{
}
}

View File

@ -155,11 +155,43 @@ class ControllerTest extends TestCase
$this->assertEquals('Component: yii\web\Request $request', \Yii::$app->requestedParams['request']);
$this->assertEquals($params['between'], $args[2]);
$this->assertInstanceOf(VendorImage::className(), $args[3]);
$this->assertEquals('DI: yiiunit\framework\web\stubs\VendorImage $vendorImage', \Yii::$app->requestedParams['vendorImage']);
$this->assertEquals('Container DI: yiiunit\framework\web\stubs\VendorImage $vendorImage', \Yii::$app->requestedParams['vendorImage']);
$this->assertNull($args[4]);
$this->assertEquals('Unavailable service: post', \Yii::$app->requestedParams['post']);
$this->assertEquals($params['after'], $args[5]);
}
public function testInjectedActionParamsFromModule()
{
if (PHP_VERSION_ID < 70100) {
$this->markTestSkipped('Can not be tested on PHP < 7.1');
return;
}
$module = new \yii\base\Module('fake', new \yii\web\Application([
'id' => 'app',
'basePath' => __DIR__,
'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
],
],
]));
$module->set('yii\data\DataProviderInterface', [
'class' => \yii\data\ArrayDataProvider::className(),
]);
// Use the PHP71 controller for this test
$this->controller = new FakePhp71Controller('fake', $module);
$this->mockWebApplication(['controller' => $this->controller]);
$injectionAction = new InlineAction('injection', $this->controller, 'actionModuleServiceInjection');
$args = $this->controller->bindActionParams($injectionAction, []);
$this->assertInstanceOf(\yii\data\ArrayDataProvider::className(), $args[0]);
$this->assertEquals('Module yii\base\Module DI: yii\data\DataProviderInterface $dataProvider', \Yii::$app->requestedParams['dataProvider']);
}
/**
* @see https://github.com/yiisoft/yii2/issues/17701
*/

View File

@ -7,6 +7,7 @@
namespace yiiunit\framework\web;
use yii\data\DataProviderInterface;
use yii\web\Controller;
use yii\web\Request;
use yiiunit\framework\web\stubs\VendorImage;
@ -27,4 +28,8 @@ class FakePhp71Controller extends Controller
public function actionNullableInjection(?Request $request, ?Post $post)
{
}
public function actionModuleServiceInjection(DataProviderInterface $dataProvider)
{
}
}