The checkout session is an object, which stores a set of data associated with checkout, like quote, customer, shipping, billing addresses, and else. Instead of relying on PHP’s $_SESSION
object, which in turn, relies on phpsessid
cookie, we pass the needed information, in our example, quoteId
into the resolver’s arguments which allows us to set checkoutSession
manually before configProvider
get’s to read from it.
Let’s have a look at the typical config provider from some arbitrary magento extension:
namespace ExampleVendor\\ExampleExtension;
class ExtensionConfigProvider implements ConfigProviderInterface {
...
public function getConfig() {
return [
'payment' => [
self::DIRECT_CODE =>
'code' => self::DIRECT_CODE,
'icons' => $this->getIcons(),
],
],
];
}
...
private function getIcons() {
$quoteId = '';
if ($this->checkoutSession->getQuote()) {
$quoteId = $this->checkoutSession->getQuote()->get('id')['entity_id'];
}
...
}
...
}
This config provider returns certain information in getConfig
method, like icons using getIcons
method. Note, that getIcons
method actually uses checkoutSession
to access quoteId
which it might use for certain conditions in the logic.
Typically you would write a resolver for exposing config data to the ScandiPWA front end by dependency-injecting the configProvider
model into the resolver’s constructor and returning needed values from it.
<aside> 💡 How to create a Resolver?
</aside>
Example resolver file which returns config values from original configProvider
:
namespace Scandiweb\\MyExtension\\Model\\Resolver;
use ExampleExtension\\Model\\ExtensionConfigProvider;
class MyConfigResolver implements ResolverInterface {
protected ExtensionConfigProvider extensionConfigProvider;
public function __construct(
// vvv Dependency injection of extension's config provider object
ExtensionConfigProvider extensionConfigProvider
) {
$this->extensionConfigProvider = $extensionConfigProvider;
}
public function resolve([...]) {
// vvv Getting the config object's result
$result = $this->extensionConfigProvider->getConfig();
if (!isset($result['payment'])) {
return [];
}
return [
'code' => $resultConfig['code'],
'icons' => $resultConfig['icons']
];
}
}
But, let’s now try querying the resolver to see the result:
"errors": [
{
"debugMessage": "Warning: Undefined array key \\"entity_id\\" in ExtensionConfigProvider.php on line 91",
"message": "Internal server error",
"extensions": {
"category": "internal"
},
...
And, looks like entity_id
is an undefined key which causes program to throw error. Let’s see where entity_id
is used in ExtensionConfigProvider.php
:
...
private function getIcons() {
$quoteId = '';
if ($this->checkoutSession->getQuote()) {
-> $quoteId = $this->checkoutSession->getQuote()->get('id')['entity_id'];
}
...
}
...
As we see, entity_id
should be accessed from the quote object which we should get from checkoutSession
, but for some reason, checkoutSession->getQuote
didn’t return us a valid value when called it inside the resolver, even though it returned a correct value in luma theme.
The checkout session is a service that manages customer session data during the checkout process. It is responsible for storing and retrieving information such as customer, quote, customer shipping and billing addresses, selected shipping and payment methods, and items in the customer's shopping cart.
Specifically, it’s a model located in the following namespace: Magento\\Checkout\\Model\\Session
.
Further on, we can find that the checkout session model actually extends certain Magento\\Framework\\Session\\SessionManager
class which is some sort of abstraction for working with session.
And SessionManager
itself is using php’s global $_SESSION
to control the session data:
In php, $_SESSION
get’s associated using phpsessid
cookie stored in user’s browser.
<aside> 💡 Read more about $_SESSION global in php
</aside>
Sometimes though, due to varnish cache or other reasons, the cookie is not correct which returns checkoutSession
with outdated data on server side.
Checkout session data wouldn’t be empty if it was set manually in the resolver before executing config provider methods. In our case, we need to set quote
data into the checkoutSession
.
By setting the quote Id manually in the checkout session, we can ensure that the correct quote is being used in the config provider, because Magento\\Checkout\\Model\\Session
’s getQuote
method will attempt to resolve cart using it’s id:
Modified resolver to set cart id before accessing config provider:
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
// ↓↓ Get cartId from the query's arguments
$maskedCartId = $args['cartId'];
$currentUserId = $context->getUserId();
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
$cart = $this->getCartForUser->execute($maskedCartId, $currentUserId, $storeId);
// ↓↓ Update checkout session with the cartId before calling getConfig()
$this->checkoutSession->setQuoteId($cart->getId());
$result = $this->configProvider->getConfig();
if (!isset($result['payment'])) {
return [];
}
return [
'code' => $resultConfig['code'],
'icons' => $resultConfig['icons']
];
}
That’s it! Now we should get correct values from configProvider.