1

I am building a onepagecheckout for craft commerce 3. I created a custom controller to submit cart and payment info in one form submit. I'll call the default updateCart action with a curl request and send the formdata with it. This works but create a new cart eachtime instead of update the current cart in the current session. How i'll update the current cart instead of create a new one?

this is my custom action

<?php

namespace modules\modulename\controllers;

use Craft;
use craft\web\Controller;
use craft\helpers\UrlHelper;

class CheckoutController extends Controller
{

    protected $allowAnonymous = true;

    public function actionCheckout(){
        // Require POST request
        $this->requirePostRequest();
        // Get params
        $data = $this->request->post();

        try {
            $url = UrlHelper::siteUrl() . "actions/commerce/cart/update-cart";
            $curl = curl_init($url);
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Accept: application/json'));
            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
            $resp = curl_exec($curl);
            $jsonResponse = \json_decode($resp);

            // Show error if fails
            if(!empty($jsonResponse)) {
                if($jsonResponse->success){
                    Craft::$app->session->setError($jsonResponse->message);
                } else {
                    Craft::$app->session->setError($jsonResponse->error);
                }
            } else{
                Craft::$app->session->setError('mis');
            }
            curl_close($curl);
        } catch (\Throwable $th) {
            throw $th;
        }


        $redirect = UrlHelper::siteUrl() . "webshop/checkout/onepagecheckout";
        $this->redirect($redirect);

        Craft::$app->end();
    }
}

1 Answer 1

2

You don't want to use a separate web request to call the controller action of Craft Commerce. This has numerous downsides beyond your current problem with the missing session. It will negatively impact performance, double the roundtrip time and increase the server load.

Instead, if you want to call a controller action of Craft or another plugin from one of your own controllers, you can simply do so using the craft\web\Application::runAction method. Put this in your controller:

$response = \Craft::$app->runAction('commerce/cart/update-cart');

$response will be a Response object that you can inspect to check if the action executed successfully. Or return it from your controller action to return whatever the given action returned to the client.

5
  • 1
    That sounds nice, was not aware of this function! I'm going to try Commented Jun 24, 2022 at 11:39
  • The 'commerce/cart/update-cart' returns the cart if action submit is successfully. But runAction returns a response object and the data and content in that response object are empty (error and success). How get te return data of the action (cart)? Commented Jun 26, 2022 at 14:01
  • @MaartenHeideman Looks like the controller only returns a Response object with model data if the request accepts JSON: github.com/craftcms/cms/blob/main/src/web/…
    – MoritzLost
    Commented Jun 27, 2022 at 7:30
  • Craft::$app->runAction('commerce/cart/update-cart', $this->asJson($postData)); Send the post data as json like this makes that the response returns some data (the original posted data). But this action should return the cart data. That I'll need for proper messages for example. The curl request did return the cart but missing the session info. Any suggestions? Commented Jun 27, 2022 at 19:16
  • @MarteenHeidemann The controller action sets the cart as a route parameter. So you should be able to access the updated cart object through the URL manager – Craft::$app->getUrlManager()->getRouteParams()
    – MoritzLost
    Commented Jun 28, 2022 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.