Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #17722 #18032

Merged
merged 29 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a128748
Fixes #17722
SamMousa May 6, 2020
2705854
Use class name when retrieving from DI
SamMousa May 6, 2020
1665411
Use className() for PHP5.4 support
SamMousa May 6, 2020
fd78e31
Use different class to test DI injection
SamMousa May 6, 2020
6118917
Added test for optional and nullable injections. Improved descriptions
SamMousa May 6, 2020
03b7c84
Injection using the DI container will now only work for classes with …
SamMousa May 6, 2020
8279e32
Don't use action injection php < 7
SamMousa May 6, 2020
4734e7e
Disable action injection for php7.0 as well
SamMousa May 6, 2020
3f1f472
Introduce php7.1 test controller
SamMousa May 6, 2020
208276c
Fixed assertion
SamMousa May 6, 2020
44bbbef
Added more tests for unknown / missing DI definitions
SamMousa May 7, 2020
6a361af
Fixed tests
SamMousa May 7, 2020
a8a81b7
Fixed php 5.4 syntax error
SamMousa May 7, 2020
3fa769c
Another 5.4 fix
SamMousa May 7, 2020
f359ef9
Refactor to reduce npath complexity
SamMousa May 7, 2020
58ab02b
Merge branch 'master' into action-injection
samdark May 7, 2020
969d228
Merge branch 'master' into action-injection
samdark May 24, 2020
f2df145
Update version, remove unused imports
samdark May 31, 2020
16d5ee3
Update version
samdark May 31, 2020
76d0d03
Fix phpdoc
samdark May 31, 2020
cc2c245
Add info about the feature to the guide
samdark May 31, 2020
e0737d9
Add CHANGELOG
samdark May 31, 2020
bf65d79
Merge branch 'master' into action-injection
samdark May 31, 2020
58faa57
Merge branch 'master' into action-injection
samdark Jun 10, 2020
5f6a782
Implement console action injection
samdark Jun 10, 2020
cff428c
Add tests for console controller, implement named params binding
samdark Jun 10, 2020
86c988c
Merge branch 'master' into action-injection
samdark Jun 10, 2020
debd294
Mention console controllers in docs
samdark Jun 10, 2020
5bb82f4
Update CHANGELOG.md
samdark Jun 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions framework/web/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public function bindActionParams($action, $params)
$args = [];
$missing = [];
$actionParams = [];
$requestedParams = [];
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
Expand Down Expand Up @@ -162,6 +163,19 @@ public function bindActionParams($action, $params)
}
$args[] = $actionParams[$name] = $params[$name];
unset($params[$name]);
} elseif (PHP_VERSION_ID >= 70100 && ($type = $param->getType()) !== null && !$type->isBuiltin()) {
samdark marked this conversation as resolved.
Show resolved Hide resolved
// Since it is not a builtin type it must be DI injection.
$typeName = $type->getName();
if (($component = $this->module->get($name, false)) instanceof $typeName) {
$args[] = $component;
$requestedParams[$name] = "Component: " . get_class($component) . " \$$name";
} elseif (\Yii::$container->has($typeName) && ($service = \Yii::$container->get($typeName)) instanceof $typeName) {
$args[] = $service;
$requestedParams[$name] = "DI: $typeName \$$name";
} elseif ($type->allowsNull()) {
$args[] = null;
$requestedParams[$name] = "Unavailable service: $name";
}
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $actionParams[$name] = $param->getDefaultValue();
} else {
Expand All @@ -177,6 +191,11 @@ public function bindActionParams($action, $params)

$this->actionParams = $actionParams;

// We use a different array here, specifically one that doesn't contain service instances but descriptions instead.
if (\Yii::$app->requestedParams === null) {
\Yii::$app->requestedParams = array_merge($actionParams, $requestedParams);
}

return $args;
}

Expand Down
66 changes: 66 additions & 0 deletions tests/framework/web/ControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
use Yii;
use yii\base\InlineAction;
use yii\web\Response;
use yiiunit\framework\web\stubs\VendorImage;
use yiiunit\TestCase;

/**
* @group web
*/
class ControllerTest extends TestCase
{
/** @var FakeController */
private $controller;
public function testBindActionParams()
{
$aksi1 = new InlineAction('aksi1', $this->controller, 'actionAksi1');
Expand All @@ -32,6 +35,69 @@ public function testBindActionParams()
$this->assertEquals('avaliable', $other);
}

public function testNullableInjectedActionParams()
{
if (PHP_VERSION_ID < 70100) {
$this->markTestSkipped('Can not be tested on PHP < 7.1');
return;
}

// Use the PHP71 controller for this test
$this->controller = new FakePhp71Controller('fake', new \yii\web\Application([
'id' => 'app',
'basePath' => __DIR__,

'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
],
],
]));
$this->mockWebApplication(['controller' => $this->controller]);

$injectionAction = new InlineAction('injection', $this->controller, 'actionNullableInjection');
$params = [];
$args = $this->controller->bindActionParams($injectionAction, $params);
$this->assertEquals(\Yii::$app->request, $args[0]);
$this->assertNull($args[1]);
}

public function testInjectedActionParams()
{
if (PHP_VERSION_ID < 70100) {
$this->markTestSkipped('Can not be tested on PHP < 7.1');
return;
}
// Use the PHP71 controller for this test
$this->controller = new FakePhp71Controller('fake', new \yii\web\Application([
'id' => 'app',
'basePath' => __DIR__,

'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
],
],
]));
$this->mockWebApplication(['controller' => $this->controller]);

$injectionAction = new InlineAction('injection', $this->controller, 'actionInjection');
$params = ['between' => 'test', 'after' => 'another', 'before' => 'test'];
$args = $this->controller->bindActionParams($injectionAction, $params);
$this->assertEquals($params['before'], $args[0]);
$this->assertEquals(\Yii::$app->request, $args[1]);
$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->assertNull($args[4]);
$this->assertEquals('Unavailable service: $post', \Yii::$app->requestedParams['post']);
$this->assertEquals($params['after'], $args[5]);
}
/**
* @see https://github.com/yiisoft/yii2/issues/17701
*/
Expand Down
2 changes: 2 additions & 0 deletions tests/framework/web/FakeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
namespace yiiunit\framework\web;

use yii\web\Controller;
use yii\web\Request;
use yiiunit\framework\web\stubs\VendorImage;

/**
* @author Misbahul D Munir <[email protected]>
Expand Down
30 changes: 30 additions & 0 deletions tests/framework/web/FakePhp71Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/

namespace yiiunit\framework\web;

use yii\web\Controller;
use yii\web\Request;
use yiiunit\framework\web\stubs\VendorImage;

/**
* @author Sam Mousa<[email protected]>
* @since 2.0.35
*/
class FakePhp71Controller extends Controller
{
public $enableCsrfValidation = false;

public function actionInjection($before, Request $request, $between, VendorImage $vendorImage, Post $post = null, $after)
{

}

public function actionNullableInjection(?Request $request, ?Post $post)
{
}
}