1

I've been struggling with the following scenario: i have a custom API endpoint to process the guest to customer login. This endpoint basically does the same thing as /integration/customer/token with one exception. During the authentication it merges any products the visitor had as a guest into the customer cart of the account they are logging in to.

Problem is that any which way i try, i keep running into the same error: "Invalid state change requested" when i try to save the updated customer quote.

Some investigation led me to the class \Quote\Model\QuoteRepository\Plugin\AccessChangeQuoteControl in the Magento_Quote module. This class is a plugin that is triggered before the save() method of the QuoteRepository. Turns out that as a guest you are not allowed to save a quote that has customer id. And during the authentication procedure you apparently are still a guest, even after authenticating.

Is there any way to make the backend system aware of the fact that the customer is logged in properly without having to do a second API call that contains the Authorization header with the new token? Somehow i have to make sure $this->userContext->getUserType() in the AccessChangeQuoteControl plugin returns UserContextInterface::USER_TYPE_CUSTOMER in stead of UserContextInterface::USER_TYPE_GUEST but i have no clue on how to make this happen.

Thanks!

  • UserContextInterface will give you customer id and it will work. – Aditya Shah Aug 30 '18 at 5:04
  • Well, that's the whole thing. I'd expect it to return a customer id as the authentication process is done just before. Unfortunately the UserContext will still return a guest type an no customer id – Tijs van Raaij Aug 31 '18 at 2:48
  • Actually i faced the same issue and but when i pass Auth of customer token i am getting customer token. – Aditya Shah Aug 31 '18 at 5:04
  • Have you tried the solution ? – Aditya Shah Aug 31 '18 at 9:33
  • Other priorities in this project atm, what else is new. I don't think this solution doesn't fit my case exactly but i think it has everything i need in order to get things going. I will let you know (and update my answer) as soon as i've been able to tinker around with it. Either way, already thanks for your extended answer! – Tijs van Raaij Sep 3 '18 at 8:14
1

Magento gets the customer data with passing anything except token value in API call.

In between magento calls some API related controllers for the same

vendor/magento/module-customer/etc/webapi.xml

<route url="/V1/customers/me" method="GET">
        <service class="Magento\Customer\Api\CustomerRepositoryInterface" method="getById"/>
        <resources>
            <resource ref="self"/>
        </resources>
        <data>
            <parameter name="customerId" force="true">%customer_id%</parameter>
        </data>
 </route>

in this API call magento get customer data based on token.

Based on API url url="/V1/customers/me" magento calls function from

Magento calls In-between call of dispatch function.

vendor/magento/module-webapi/Controller/Rest.php

 public function dispatch(\Magento\Framework\App\RequestInterface $request)
 {
     /** In between code **/
     // In the same file
     $this->processApiRequest();

 }
 protected function processApiRequest()
 {
      $inputParams = $this->getInputParamsResolver()->resolve();
 }

And this resolve() function calls override() function

vendor/magento/module-webapi/Controller/Rest/InputParamsResolver.php

 public function resolve()
 {
      $inputData = $this->paramsOverrider->override($inputData, $route->getParameters());
 }

and overide() function calls getOverriddenValue() function

vendor/magento/module-webapi/Controller/Rest/ParamsOverrider.php

 public function override(array $inputData, array $parameters)
 {
      $value = $this->paramOverriders[$paramValue]->getOverriddenValue();
 }

getOverriddenValue() calls ParamOverriderInterface

vendor/magento/framework/Webapi/Rest/Request/ParamOverriderInterface.php

  • To Override parameter values
  • Parameters in the webapi.xml can be forced. This ensures that on specific routes, a specific value is always used.
  • For instance, if there is a ".../me/..." route, the route should use only user information specific to the
  • currently logged in user. More specifically, if there was a "/customers/me/addresses" route, the service method
  • invoked could have a signature of "getAddresses($customerId)", but in the webapi.xml, the $customerId parameter
  • would be forced to be the customer id of the current authenticated user.
  • The forced override parameter configuration is in the webapi.

   <data>
     <parameter name="customer.id" force="true">%customer_id%</parameter>
   </data>

and for business logic of this function is in file -

vendor/magento/module-webapi/Controller/Rest/ParamOverriderCustomerId.php

   /**
    * {@inheritDoc}
    */
   public function getOverriddenValue()
   {
       if ($this->userContext->getUserType() === UserContextInterface::USER_TYPE_CUSTOMER) {
           return $this->userContext->getUserId();
   }
   return null;
   }

So this is how Magento get Customer Id between API calls !!

solution 1

public function __construct(
   \Magento\Authorization\Model\UserContextInterface $userContext
){
   $this->userContext = $userContext;
}

$customerId = $this->userContext->getUserId();

solution 2

$ch = curl_init('dev.magento2.com/rest/V1/customers/me');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json'
));
curl_setopt($ch, CURLOPT_COOKIE, 'PHPSESSID=' . $_COOKIE['PHPSESSID']);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

//execute post
$result = curl_exec($ch);

//close connection
curl_close($ch);

$json = json_decode($result);
echo $json->id;
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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