In Yii2, we are using \Stripe\Charge::create following the site's documentation example:
https://stripe.com/docs/payments/accept-a-payment-charges
Everything works great as long we use straight HTML in the views, but when we embed the card-element in an ActiveForm, the stripe.js returns:
XMLHttpRequest cannot load https://api.stripe.com/v1/tokens due to
access control checks.
We would like to use ActiveForm to simplify the validation and handling of other fields on the form. Any help?
Best,
Joe
The error is CORS related, see CORS. Use the appropriate Access-Control as described there.
You can use Yii's build in behavior yii\filters\Cors in your controller.
Try first without any restriction:
public function behaviors()
{
return [
'corsFilter' => [
'class' => \yii\filters\Cors::className(),
],
];
}
If it works, than you can restrict the access by parametrising the behavior, something like that:
public function behaviors()
{
return [
'corsFilter' => [
'class' => \yii\filters\Cors::className(),
'cors' => [
'Origin' => [https://api.stripe.com'],
'Access-Control-Request-Method' => ['POST', 'PUT'],
],
],
];
}
So, for anyone landing here, the only way I can get this to work is to remove the ActiveForm scaffolding. Real bummer because I've had to validate the non-Stripe input fields with Javascript, which is lot more work.
I do challenge anyone to post working code in Yii using ActiveForm that will return a token. I don't think it can be done...but I would love to be wrong.
Best,
Joe
Related
I want to add some api to my Yii2 site. Api must be only in json. I don't want to set Accept: application/json headers for each request. I can set 'response' => ['format' => \yii\web\Response::FORMAT_JSON] in application configuration but it breaks all pages. Also my api function returns data in xml.
I tried to use rest\ActiveRecord for my purposes. Maybe I do it's wrong. What I want.
To have my Yii2 based site with some api acсessed through https://example.com/api/controller/action. In project I want to see folder controllers/api which contains my controllers. Controllers must use standard \yii\db\ActiveRecord based models. Also controllers input paramaters only in json body or as part url and output data only in json.
You may need to set the following code in the controller's action somewhere before return or in beforeAction() method:
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
also since Yii 2.0.11 there is a dedicated asJson() method to return a response in JSON format:
return $this->asJson($array);
The more elegant solution is to use yii\filters\ContentNegotiator.
When the Accept header is missing ContentNegotiator assumes it allows any type and send response in first format defined in its $formats property. If the requested format is not among accepted formats the content negotiator will throw yii\web\NotAcceptableHttpException and app will respond with http status 406 Not Acceptable.
You can add it in your controller in behaviors() method like this:
public function behaviors()
{
return [
[
'class' => 'yii\filters\ContentNegotiator',
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
],
];
}
If your controller extends yii\rest\Controller it already has the ContentNegotiator filter added among its behaviors. You only need to limit allowed formats like this:
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats'] = [
'application/json' => \yii\web\Response::FORMAT_JSON,
];
return $behaviors;
}
Using ContentNegotiator instead of explicitly forcing the JSON format in beforeAction() will allow for easier addition of other formats if they are needed in future.
My slugs looks like this:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<lang>/<p_page>/<p_category>/<p_product>' => 'splitter/manage-request',
'<lang>/<p_page>/<p_category>' => 'splitter/manage-request',
'<lang>/<p_page>' => 'splitter/manage-request',
'<lang>/' => 'splitter/manage-request',
'<lang>' => 'splitter/manage-request',
'' => 'splitter/manage-request',
],
],
I am sending all the requests to that SplitterController where I am parsing them. But I don't want the AJAXs to be send to it. Is it possible to give them some default route? To redirect them backend for example. I couldn't find information about it in the documentation? Appreciating links also is I missed it. Thank you!
According to my experience, there are probably the following options for your reference:
the first: The easiest way is to add a beforeAction() to your SplitterController, determine if it is an ajax request in beforeAction(), and redirect to your target address, for example:
public function beforeAction()
{
if (\Yii::$app->request->isAjax) {
return \Yii::$app->response->redirect($targetUrl);
}
return parent::beforeAction($action);
}
second: You can check if the request is an ajax request in the nginx configuration and then redirect to your target address
third: If you can't set up additional routing rules and configure the ajax request address, then you can consider implementing it by customizing UrlManager::parseRequest(), just check if it is an ajax request before it starts parsing the request, then redirect to your target. address
This answer is translated from Google Translate
A customer has requested to have the exact same endpoints available through web interface as well as through REST API.
The same endpoint should be visible using web browser only when being logged in. When accessing it via REST API, a valid access token must be submitted.
The rule for this specific endpoint is defined as follows:
[
'class' => 'yii\rest\UrlRule',
'controller' => 'site',
'pluralize' => false,
'extraPatterns' => [
'POST upload-raw-data' => 'uploadRawData'
],
]
Now, when I try to access this endpoint, I've got these results:
Browser: no problem
Postman / POST: 404 error
Postman / GET: no problem
When trying the same with enableStrictParsing enabled, I've got 404 errors all around.
If I need to provide other parts of the code, I'll happily provide them.
I think I found the solution for my issue. The problem seems to have been the CSRF validation.
By disabling it for this specific action in beforeAction(), the POST call behaves as intended.
public function beforeAction($action) {
if ($action->id == 'upload-raw-data')
Yii::$app->controller->enableCsrfValidation = false;
return parent::beforeAction($action);
}
source: https://gist.github.com/guerreiro/9e9cb3154b9047f5d2a0
Is it possible to run action of frontend controller from backend?
this code works if called action is in backend too. can i specify in runAction that controller/action is in frontend?
Yii::$app->runAction('controller/action')
Also i' m tried something like
$c=new controller();
$s->action();
too but it seems it not working too. //new controller() need some parameters and i have no idea what it is.
The yii\base\Application object has a public property controllerNamespace, which defaults to app\\controllers. You need to change it accordingly to changing default controller namespace.
Change namespace in action:
Yii::$app->controllerNamespace = 'frontend\controllers' and use runAction
A way could be this .
In your backend application config you could create an additional 'UrlManager' component
name eg: urlManagerFrontEnd
return [
'components' => [
'urlManager' => [
// here is your backend URL rules
],
'urlManagerFrontEnd' => [
'class' => 'yii\web\urlManager',
'baseUrl' => 'http://your_path/frontend/web/index.php',
'enablePrettyUrl' => true,
'showScriptName' => false,
],
],
];
Then you should invoke following to compose front-end URL:
Yii::$app->urlManagerFrontEnd->createUrl();
and add the controller/action you prefer
remeber that
runAction()
Runs an action within this controller with the specified action ID and
parameters.
http://www.yiiframework.com/doc-2.0/yii-base-controller.html#runAction()-detail
this mean that cannot run an action of another controller or of another application ..
If you need a service then you must configure a RESTFull or you simply need a redirection you can use redirect
In console application when I used Yii::$app->user->isGuest it is giving the below exception:
Exception 'yii\base\UnknownPropertyException' with message 'Getting unknown prop
erty: yii\console\Application::user'
I even tried adding the user in components array in config file. But it didn't worked. Any idea what am I doing wrong?
In Console application Yii->$app->user does not exist. So, you need to configure user component in config\console.php.
like as,
config\console.php
'components' => [
.........
......
'user' => [
'class' => 'yii\web\User',
'identityClass' => 'app\models\User',
//'enableAutoLogin' => true,
],
'session' => [ // for use session in console application
'class' => 'yii\web\Session'
],
.......
]
To check it works or not using below code.
public function actionIndex($message = 'hello world')
{
echo $message . "\n";
$session = \Yii::$app->session->set('name', 'ASG');
if(\Yii::$app->session) // to check session works or not
echo \Yii::$app->session->get('name')."\n";
print_R(\Yii::$app->user);
}
More info about your problem : Link
Note : There's no session in console.
The reason is simple. Guide says about application components (user is a component):
user: represents the user authentication information. This component
is only available in Web applications Please refer to the
Authentication section for more details.
So Yii::$app->user it not available in console applications.
As a consequence you have to consider using this component in model classes that are also used by console applications.
Extra note: it is internally used by BlameableBehavior, however, this makes no problems since user will be null if a model gets saved/created and no user is available.