Closed maximal closed 2 years ago
Hi @maximal,
Take a look at the tests
directory, and verify you're using a compatible PSR-7/15 Dispatcher. php-fpm
isn't a PSR dispatcher so you'll need to use something like RoadRunner, Diactoros,
A working example is there:
config: https://github.com/charlesportwoodii/yii2-psr7-bridge/blob/master/tests/config/config.php
return [
// Other flags
'components' => [
'request' => [
'class' => \yii\Psr7\web\Request::class,
],
'response' => [
'class' => \yii\Psr7\web\Response::class
],
// Other components
]
];
https://github.com/charlesportwoodii/yii2-psr7-bridge/blob/master/tests/ApplicationTest.php#L80
@charlesportwoodii, thanks for the reply!
I’m running the app through RoadRunner (FPM variant is just for comparison). My web.php
config is:
'components' => [
'request' => [
'cookieValidationKey' => 'secret_key',
'csrfParam' => '_myCsrf',
// PSR7 compatible class for RoadRunner support
'class' => \yii\Psr7\web\Request::class,
],
'response' => [
// PSR7 compatible class for RoadRunner support
'class' => \yii\Psr7\web\Response::class
],
// ... ... ...
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'' => 'site/index',
'news/<type:\w+>' => 'admin/news/index',
],
],
],
var_dump(Yii::$app->request::class)
gives \yii\Psr7\web\Request
, so I guess class replacement is done right.
Related Composer packages are:
"yiisoft/yii2": "^2.0.14",
"spiral/roadrunner": "dev-master",
"nyholm/psr7": "^1.5",
"charlesportwoodii/yii2-psr7-bridge": "dev-master",
I haven't touched this repo in a few years. Last I checked Road Runner 1.8 worked, and there was a MR added for 2.5 that worked as well. Maybe try locking spiral/roadrunner
package to one of those instead of their development branch? spiral/roadrunner
gets pulled in by this repo already.
I just spun up the yii2-app-basic
app using road-runner and it worked. Here's my configuration an the resulting screenshot. I pulled all this from either rr's documentation or the docs from this one.
.rr.yaml
---
http:
address: "0.0.0.0:8081"
pool.debug: true
middleware: [ "static" ]
static:
dir: "./web"
rpc:
enable: true
server:
command: ./web/roadrunner
env:
YII_ALIAS_WEB: "http://127.0.0.1:8081"
YII_ALIAS_WEBROOT: ./web
web/roadrunner
#!/usr/bin/env php
<?php
ini_set('display_errors', 'stderr');
// Set your normal YII_ definitions
defined('YII_DEBUG') or define('YII_DEBUG', true);
// Alternatives set this in your rr.yaml file
//defined('YII_DEBUG') or define('YII_DEBUG', \getenv('YII_DEBUG'));
defined('YII_ENV') or define('YII_ENV', 'dev');
// Alternatives set this in your rr.yaml file
//defined('YII_ENV') or define('YII_ENV', \getenv('YII_ENV'));
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
$worker = Spiral\RoadRunner\Worker::create();
$psrServerFactory = new Laminas\Diactoros\ServerRequestFactory();
$psrStreamFactory = new Laminas\Diactoros\StreamFactory();
$psrUploadFileFactory = new Laminas\Diactoros\UploadedFileFactory();
$psr7 = new Spiral\RoadRunner\Http\PSR7Worker($worker, $psrServerFactory, $psrStreamFactory, $psrUploadFileFactory);
$config = require __DIR__ . '/../config/web.php';
$application = (new \yii\Psr7\web\Application($config));
// Handle each request in a loop
try {
while ($request = $psr7->waitRequest()) {
if (($request instanceof Psr\Http\Message\ServerRequestInterface)) {
try {
$response = $application->handle($request);
$psr7->respond($response);
} catch (\Throwable $e) {
$psr7->getWorker()->error((string)$e);
}
if ($application->clean()) {
$psr7->getWorker()->stop();
return;
}
}
}
} catch (\Throwable $e) {
$psr7->getWorker()->error((string)$e);
}
composer.json
"require": {
"php": ">=5.6.0",
"yidas/yii2-bower-asset": "2.0.13.1",
"yiisoft/yii2": "~2.0.14",
"yiisoft/yii2-bootstrap4": "~2.0.0",
"yiisoft/yii2-swiftmailer": "~2.0.0 || ~2.1.0",
"charlesportwoodii/yii2-psr7-bridge": "dev-master",
"spiral/roadrunner": "^2.9"
}
web/config.php
[
'aliases' => [
'@bower' => '@vendor/yidas/yii2-bower-asset/bower',
'@npm' => '@vendor/npm-asset',
],
'request' => [
'class' => \yii\Psr7\web\Request::class,
'enableCookieValidation' => false,
'enableCsrfValidation' => false,
'enableCsrfCookie' => false,
'cookieValidationKey' => 'foo',
'parsers' => [
'application/json' => \yii\web\JsonParser::class,
]
],
'response' => [
'class' => \yii\Psr7\web\Response::class,
'charset' => 'UTF-8'
],
]
This is also the latest spiral/roadrunner.
Double check your configuration. Start with the basic app, then port things over to your custom app.
@charlesportwoodii, I cannot see Laminas\Diactoros
dependency in your composer.json
. Which version do you use?
I’m using a different implementation (nyholm/psr7
), maybe the problem is here.
It's pulled in: https://github.com/charlesportwoodii/yii2-psr7-bridge/blob/master/composer.json#L17.
The example implementation uses it. You don't have to use Diactoros you can use any PSR dispatcher you want - the example provided is just as an example implementation.
Tried both (nyholm/psr7
and laminas/laminas-diactoros
) PSR-7 implementations. Couldn’t get standard Yii2 paging widgets working, they’re using ->get()
actively.
If we have parameters in URL and simultaneously using paging, then URLs in paging links are broken.
/news/index?dp-39-page=2
or something instead of /news/type_name?page=2
.
This bridge’s Yii::$app->request->get('type')
for parameters in URLs returns null
. Standard Yii2 Request
implementation returns type_name
.
You're using the runner and configuration I provided, correct? The example Dispatcher/rr worker is very tied to laminas/laminas-diactoros
so if you aren't using that exact Dispatcher and folder structure you'll need to make your own. The examples are provided for illustrative purposes only, but they do work -
I can also verify that the request object works just fine with both pretty URLs. See the following gif and code blocks. As you can see the URL parameters change and this works just fine with enablePrettyUrls set and the script name hidden.
// SiteController.php
public function actionPager()
{
$provider = new \yii\data\ArrayDataProvider([
'allModels' => [
[ 1, "test1", "test1@example.com"],
[ 2, "test2", "test2@example.com"],
[ 3, "test3", "test3@example.com"],
[ 4, "test4", "test4@example.com"],
[ 5, "test5", "test5@example.com"],
[ 6, "test6", "test6@example.com"],
[ 7, "test7", "test7@example.com"],
[ 8, "test8", "test8@example.com"],
[ 9, "test9", "test9@example.com"],
],
'sort' => [
'attributes' => ['id', 'username', 'email'],
],
'pagination' => [
'pageSize' => 10,
],
]);
$provider->pagination->pageSize=2;
return $this->render('pager', [
'dataProvider' => $provider
]);
}
// views/pager.php
<?php
/** @var yii\web\View $this */
$this->title = 'My Yii Application';
echo \yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
]);
echo \yii\widgets\LinkPager::widget([
'pagination' => $dataProvider->pagination,
]);
All yii/psr7/web/Request
does is translate the PSR7 request object into the appropriate Yii2 models, so if it's not doing that, then something is wrong with your runner/dispatcher. Have you tried the code I provided?
A few things I recommend you try:
yii-web-basic
application to see how it behaves and it get working there.Yii::$app->request->getPsr7Request()
) and verify that the PSR7 object has your request parameters. If it doesn't then something isn't quite right with your dispatcher.Try these first, especially just testing this in the yii-web-basic
app and verify it meets your needs before trying it in your other app. This is alpha software but it does work I use it rather extensively in several private projects.
Regarding:
This bridge’s Yii::$app->request->get('type') for parameters in URLs returns null. Standard Yii2 Request implementation returns type_name.
I don't think yii\web\Request::get()
has ever returned named parameters, I believe the standard way to achieve this is to pass them as action arguments, like so
public function actionIndex($type) {}
maps to
'news/<type:\s+>' => 'admin/news/index'
yii\web\Request::get()
is only documented to return $_GET
parameters.
I recommend reviewing the Yii2 documentation, and making sure you've actually go thing setup correctly. Sounds like there's other issues you need to address first before getting into this.
Seems like the problem is in yii\widgets\ListView
. For some reason I don’t understand it doesn’t initiate its ->pager->pagination
properties with the params I passed.
My view:
<?= ListView::widget([
'options' => ['tag' => null],
'itemOptions' => ['tag' => null],
'layout' => "<div>{items}</div>\n<div>{pager}</div>",
'dataProvider' => $dataProvider,
'itemView' => 'item',
'pager' => [
'pagination' => [
'params' => ['alias' => $model->url, '#' => 'asdf'],
// Should fail due to setting unknown property, but it won’t
'any_string' => 'dummy',
],
// Fails as expected if uncommented
//'any_string' => 'dummy',
],
]) ?>
Pagination::createUrl()
method:
public function createUrl($page, $pageSize = null, $absolute = false)
{
$page = (int) $page;
$pageSize = (int) $pageSize;
//
// Here it doesn’t see my URL params passed to `widget()` initiation method.
// It doesn’t see them in both cases (`yii\web\Request` and `yii\Psr7\web\Request`),
// but `yii\web\Request::getQueryParams()` gets them, so the app works fine in this case
// and won’t work in `yii\Psr7\web\Request` case.
//
if (($params = $this->params) === null) {
$request = Yii::$app->getRequest();
$params = $request instanceof Request ? $request->getQueryParams() : [];
}
if ($page > 0 || $page == 0 && $this->forcePageParam) {
$params[$this->pageParam] = $page + 1;
} else {
unset($params[$this->pageParam]);
}
if ($pageSize <= 0) {
$pageSize = $this->getPageSize();
}
if ($pageSize != $this->defaultPageSize) {
$params[$this->pageSizeParam] = $pageSize;
} else {
unset($params[$this->pageSizeParam]);
}
$params[0] = $this->route === null ? Yii::$app->controller->getRoute() : $this->route;
$urlManager = $this->urlManager === null ? Yii::$app->getUrlManager() : $this->urlManager;
if ($absolute) {
return $urlManager->createAbsoluteUrl($params);
}
return $urlManager->createUrl($params);
}
Investigating further.
Maybe @samdark could take a look?
I am not a member ofthe Yii2 team, and samdark is not affiliated with this project in any way.
Please re-view the instructions I previously provided, your runner configuration is not setup correctly. yii\widgets\ListView
will work once you configure your runner as outlined here: https://github.com/charlesportwoodii/yii2-psr7-bridge/issues/9#issuecomment-1098250099
I can confirm that yii\widgets\ListView
works with that configuration. If you are using a custom configuration, dispatcher, or anything beyond what I have provided I'm afraid I'm not really able to provide any support as the examples I have provided work.
The example listed here is using the exact same configuration as I've provided above, and the relevant controller, and view files are listed as follows.
//controllers/SiteController.php
public function actionPager()
{
$provider = new \yii\data\ArrayDataProvider([
'allModels' => [
[ 1, "test1", "test1@example.com"],
[ 2, "test2", "test2@example.com"],
[ 3, "test3", "test3@example.com"],
[ 4, "test4", "test4@example.com"],
[ 5, "test5", "test5@example.com"],
[ 6, "test6", "test6@example.com"],
[ 7, "test7", "test7@example.com"],
[ 8, "test8", "test8@example.com"],
[ 9, "test9", "test9@example.com"],
],
'sort' => [
'attributes' => ['id', 'username', 'email'],
],
'pagination' => [
'pageSize' => 1,
'defaultPageSize' => 1
],
]);
return $this->render('pager', [
'dataProvider' => $provider
]);
}
//views/pager.php
<h2>This is a \yii\widgets\ListView instance</h2>
<?php
echo \yii\widgets\ListView::widget([
'layout' => "<div>{items}</div><br /><br /><div>{pager}</div>",
'dataProvider' => $dataProvider,
'itemView' => 'item'
]);
//views/item.php
<h4>This is an item view item.php for <?php echo $model[1]; ?></h4>
<?php var_dump($model);
I must re-iterate that you please try the examples I have provided, exactly as they are provided, before adapting things to ensure it meets you requirements. As I have verified this works with yii\widgets\ListView
(and the test suite that is attached verifies it work as well), I will be closing and locking this issue for further discussion. If you have specific issues after testing with the yii2-app-basic and implementing the runner exactly as I have outlined in the linked comment I'll be happy to review them, however as it stands I am neither able to reproduce this or verify this as an issue.
@maximal Please review #10 and see if it resolves your issue and thanks for your patience. I didn't understand the issue you were reporting as the URL Parameters != Query Parameters but Yii2 does some (imo bad) weird mapping resulting in them being returned with yii\web\Request::getQueryParameters()
.
I've updated the issue title to make that more clear, but please review the MR to see if it covers your needs.
Sorry for being not accurate in my description of this issue.
With #10 it works fine, thank you!
I have
'enablePrettyUrl' => true, 'showScriptName' => false
, and'news/<type:\w+>' => 'news/index'
rule in myurlManager
config. While using FPM approach, I can gettype
param (when accessing/news/some-type
URL) by callingYii::$app->request->get('type')
. When usingyii\Psr7\web\Request
and your bridge, I get nulls on everyget()
orpost()
call.Could you please describe how to get it working?