Is there any way to apply a function to all requests and queries in Yii2?
I want to replace specific characters for all of them.
I am using Yii2 advanced app
Thanks.
This is the config file:
$config = [
'language' => 'en',
'components' => [
'request' => [
'cookieValidationKey' => 'something',
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
'defaultRoles' => ['guest'],
],
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
],
],
];
return $config;
Without extending custom code on each request can be exexuted like so (add this to your application config):
return [
'on beforeRequest' => function () {
if (!Yii::$app->get('user', false)) {
return;
}
$user = User::getCurrent();
if ($user) {
Yii::$app->setTimeZone($user->time_zone);
}
},
'on afterRequest' => function () {
...
},
];
Depending on when you need to execute code (before or after the request) use 'on beforeRequest' or 'on afterRequest' accordingly.
yii2 have a request component. You can extend yii\web\request and define your custom implementation.
[
...
'components' =>
'request' => [
'class' => '\common\MyRequest',
'addGeoLocationForExample' => true,
]
...
Related
I've found a lot of answers on how to create Access Control that requires login to all controllers and actions.
The following post shows how I did all controllers require login:
Yii2 require all Controller and Action to login
I've used the code below under my components:
'as beforeRequest' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
[
'allow' => true,
'actions' => ['login', 'error'],
],
[
'allow' => true,
'roles' => ['#'],
],
]
],
But, I want to add some exceptions to it. Some controllers need to have some actions visible to Guest.
I've tried to use this code inside my behaviors on ReportsController:
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['share'],
'roles' => ['?'],
],
],
]
Still get redirected to login.
I'm trying to to make actionShare($param) {} public to guests.
What am I missing?
Thanks for all your help!
First execute
yii migrate --migrationPath=#yii/rbac/migrations
from command prompt to create RBAC table in data base.
Then create RbacController in component folder
namespace app\components;
use yii;
use yii\web\Controller;
use yii\filters\AccessControl;
class RbacController extends Controller
{
public function RbacRule($modules = false)
{
$rules = false;
if ($modules){
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$module/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}else{
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
//$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}
return $rules;
// return true;
}
}
then extend to your controller using this RbacController instead of controller.
use app\components\RbacController;
class AdminController extends RbacController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
// [
// 'actions' => ['login', 'logout'],
// 'allow' => true,
// 'roles' => ['?'],
// ],
parent::RbacRule(),
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
'bulk-delete' => ['post'],
],
],
];
}
.......
}
If your controller is inside Modules folder then you have to use
parent::RbacRule(TRUE) instead of parent::RbacRule(),
I am currently using the following lines of code on every controller in the API module in order to return JSON response/data.
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
It works well. But how can i achieve the same using main configuration file?
I tried the following on my frontend/config/main.php
'api' => [
'class' => 'app\modules\api\Module',
'components' => [
'user' => [
'class' => 'yii\web\User',
'identityClass' => 'common\models\User',
'enableSession' => false,
'loginUrl' => null,
],
'response' => [
'class' => \yii\filters\ContentNegotiator::className(),
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
]
],// Module component
],
above configuration still returns XML response only. What is the correct configuration to set all the controllers in the API module to return JSON data.Thanks
Configure your response component as follows:
'response' => [
'format' => yii\web\Response::FORMAT_JSON,
// ...
]
formats is an array containing the available formats. format is the actual output format.
Add this is your config/main-local.php
use yii\web\Response;
$config['bootstrap'][]=
[
'class' => '\yii\filters\ContentNegotiator',
'formats' => [
'text/html' => Response::FORMAT_JSON,
]
];
When I try to post using Postman,I get this error {"name":"Bad Request","message":"Invalid JSON data in request body: Syntax error.","code":0,"status":400,"type":"yii\\web\\BadRequestHttpException"}
My controller is
`class CountryController extends ActiveController
{
public $modelClass = 'app\models\Country';
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['index', 'view','create'],
'formats' => ['application/json' => Response::FORMAT_JSON,],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['put'],
'delete' => ['delete'],
'deleteall'=>['post'],
],
],
];
}
}`
added
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
in api/config.php file.
Where I am wrong??
Try this
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'only' => ['index', 'view','create'],
'formats' => ['application/json' => Response::FORMAT_JSON]
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'index'=>['get'],
'view'=>['get'],
'create'=>['post'],
'update'=>['post'],
'delete' => ['delete'],
'deleteall'=>['post'],
]
]
];
}
I am using wordpress 4.7 on php 7, also getting problems with the empty request body.
My Controller :
add_action('rest_api_init', function()
{
register_rest_route('v0', '/accounts/(?P<slug>[a-z0-9_\-]+)/accounts', array(
'methods' => 'GET',
'callback' => function($request)
{
try {
return 'hello';
}
catch (Exception $e) {
$error = json_decode($e->getMessage(), true);
return new WP_Error($error['status_code'], $error['message'], "");
}
}
));
});
Response Error :
{"code":"rest_invalid_json","message":"Invalid JSON body passed.","data":{"status":400,"json_error_code":4,"json_error_message":"Syntax error"}}
I did not found any solution rather than changing in WP core : wp-includes/rest-api/class-wp-rest-request.php and chaning line 672 for conditional check for empty body or not.
$params = json_decode( $this->get_body(), true );
I'm implementing RESTFUL API with Yii2. The thing is I don't use models at all. My API just gets the request and performs some calculations (or passes request as a proxy to somewhere else) and outputs the response.
I have following controllers in app\modules\api\v1\controllers:
namespace app\modules\api\v1\controllers;
class CarController extends \yii\rest\Controller
{
// GET /v1/car/:id
public function actionIndex()
{
$carId = \Yii::$app->request->get('id');
// Forwarding request to other API
return ['some_reponse'];
}
// DELETE /v1/car/:id
public function actionDelete()
{
$carId = \Yii::$app->request->get('id');
// Forwarding request to other API
return ['some_reponse'];
}
public function behaviors()
{
return [
'verbs' => [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'create' => ['post'],
'delete' => ['delete']
],
],
];
}
}
// ===============================
namespace app\modules\api\v1\controllers;
class CarsController extends \yii\rest\Controller
{
// POST /v1/cars
public function actionCreate()
{
$carData = \Yii::$app->request->post;
// Forwarding data to other API
return ['some_reponse'];
}
public function behaviors()
{
return [
'verbs' => [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'create' => ['post']
],
],
];
}
}
// ===============================
namespace app\modules\api\v1\controllers;
class NotificationsController extends \yii\rest\Controller
{
// POST /v1/notifications
public function actionCreate()
{
$noticicationsData = \Yii::$app->request->post;
// Perform some additinal actions here
return ['some_reponse'];
}
public function behaviors()
{
return [
'verbs' => [
'class' => \yii\filters\VerbFilter::className(),
'actions' => [
'create' => ['post']
],
],
];
}
}
Url manager configuration:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/cars' ],
'extraPatterns' => [ 'POST cars' => 'create' ]
],
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/car' ],
'extraPatterns' => [ 'GET car' => 'index', 'DELETE car' => 'delete' ]
],
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/notifications' ],
'extraPatterns' => [ 'POST notifications' => 'create' ]
]
]
]
Cars endpoint works fine. But other endoints return 404 error. Error response example:
{
"name": "Not Found",
"message": "Page not found.",
"code": 0,
"status": 404,
"type": "yii\web\NotFoundHttpException",
"previous": {
"name": "Invalid Route",
"message": "Unable to resolve the request: v1/car/options",
"code": 0,
"type": "yii\base\InvalidRouteException"
}
}
Any ideas whats wrong here? I guess something is wrong with my rules.
The problem was with urlManager rules configuration. For e.g. if I create CarController it treats like CarsController. So I have to set pluralize to false. Also modified extraPatterns section as well:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/cars' ],
'extraPatterns' => [ 'POST' => 'create' ],
],
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/car' ],
'extraPatterns' => [ 'GET' => 'index', 'DELETE' => 'delete' ],
'pluralize' => false
],
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/notifications' ],
'extraPatterns' => [ 'POST' => 'create' ]
]
]
]
Problem with yii\rest\Controller::actions(), this method already have actions index , options,view etc. You need disabled action to use your action:
public function actions()
{
$actions = parent::actions();
unset($actions['view'], $actions['index']);
return $actions;
}
We've been working on a project with Yii2 Advanced App, with a custom bootstrap template. I've generated the crud using gii. All other CRUDs work fine. But the User crud displays Yii2 User Module not the CRUD.
I've gone through amnah's complete documentations and couldn't find any solutions in any other places either. I even tried Yii2 documentations and it wasn't any help either.
This is my backend config
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
use \yii\web\Request;
$baseUrl = str_replace('/frontend/web', '', (new Request)->getBaseUrl());
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'defaultRoute' => 'sahasa/index',
'bootstrap' => ['log'],
'components' => [
'urlManager' => [
'class' => 'yii\web\UrlManager',
// Disable index.php
'showScriptName' => false,
// Disable r= routes
'enablePrettyUrl' => true,
'rules' => array(
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
),
],
'request' => [
'baseUrl' => $baseUrl,
],
'user' => [
'class' => 'amnah\yii2\user\components\User',
],
// 'user' => [
// 'identityClass' => 'common\models\User',
// 'enableAutoLogin' => true,
// ],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
],
'params' => $params,
'modules' => [
'user' => [
'class' => 'amnah\yii2\user\Module',
// set custom module properties here ...
],
'debug' => [
'class' => 'yii\debug\Module',
],
],
];
This is what I get when I goto localhost/app/backend/web/index.php?r=user
I want it to display a CRUD similar to this
I'm stuck there. Without the CRUD it'll be difficult to manage the USERS.
Any help is appreciated.
Thanks in advance.
I think you need to redefine the controller too. You need a new controller derived form the original controller for correctly addressing the new CRUD element.
I suppose your controller is in backend and is named user otherwise change properly the following example (part of config/main.php):
'user' => [
...
'controllerMap' => [
'user' => 'backend\controllers\user',
],
],
You can add this code to Controller in backend
public function init()
{
$user_id = Yii::$app->getUser()->id;
if($user_id){
$user = \amnah\yii2\user\models\User::findOne($user_id);
if ($user->can("admin")) {
// do something
}else{
throw new HttpException(403, 'You are not allowed to perform this action.');
}
}else{
throw new HttpException(403, 'You are not allowed to perform this action.');
}
parent::init();
}
Just click the link /user/admin
You'll get CRUD for users.