SlideShare a Scribd company logo
1 of 40
Checkout
demystified
Spryker User Group
Berlin
27.01.2020
Damijan Ćavar
About me
2
− 20+ years of experience
− 3+ years at Spryker
− Project experience with various stack
− Project experience with multiple industries
− ...
What will we learn?
3
− How to place an Order?
− What is a step engine?
− Why is do we need step engine?
− How to implements a new step?
− Where do we modify the Quote?
− What happens it something goes wrong?
− ...
Quote transfer lifetime
4
What is a checkout?
5
− Step is a class that implements the StepInterface and handles the data.
What is a step?
6
StepInterface
7
public function preCondition(AbstractTransfer $quoteTransfer);
public function requireInput(AbstractTransfer $dataTransfer);
public function execute(Request $request, AbstractTransfer $dataTransfer);
public function postCondition(AbstractTransfer $dataTransfer);
public function getStepRoute();
public function getEscapeRoute();
public function getTemplateVariables(AbstractTransfer $dataTransfer);
preCondition method
8
Preconditions are called before each step. If the condition is met then it will return true and the process
will continue. If it returns false, the customer will be redirected to the escape route defined for this step.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function preCondition(AbstractTransfer $quoteTransfer)
{
if ($this->isCartEmpty($quoteTransfer)) {
return false;
}
if (!$quoteTransfer->getCheckoutConfirmed()) {
$this->escapeRoute = CheckoutPageControllerProvider::CHECKOUT_SUMMARY;
return false;
}
return true;
}
requireInput method
9
In this method we determine if step requires user input. If input methods return true we will render the
form and wait for user input.
/**
* Require input for customer authentication if the customer is not logged in already, or haven't authenticated yet.
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function requireInput(AbstractTransfer $quoteTransfer)
{
if ($this->isCustomerLoggedIn()) {
return false;
}
return true;
}
execute method
10
If the form is valid, the updated QuoteTransfer is passed to Step::execute() method where you can
modify it further or apply custom logic (call a client or Zed). Also, there is Symfony Request object
passed if additional/manual data mapping is required.
/**
* Update QuoteTransfer with customer step handler plugin.
*
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function execute(Request $request, AbstractTransfer $quoteTransfer)
{
return $this->customerStepHandler->addToDataClass($request, $quoteTransfer);
}
postCondition method
11
Post condition is an essential part of the step Processing. It indicates if a step has all the data that it
needs and if its requirements are satisfied.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function postCondition(AbstractTransfer $quoteTransfer)
{
if ($this->hasOnlyGiftCardItems($quoteTransfer)) {
return true;
}
if (!$this->isShipmentSet($quoteTransfer)) {
return false;
}
return true;
}
Do not modify the Quote in postCondition!!!
getTemplateVariables method
12
With this method we can provide additional parameters that we might want to render on the template.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getTemplateVariables(AbstractTransfer $quoteTransfer)
{
return [
'quoteTransfer' => $quoteTransfer,
'cartItems' => $this->productBundleClient->getGroupedBundleItems(
$quoteTransfer->getItems(),
$quoteTransfer->getBundleItems()
),
];
}
getStepRoute and getEscapeRoute methods
13
Step route is the route to the step and
escape route is where we redirect in case of an error.
/**
* @return string
*/
public function getStepRoute()
{
return $this->stepRoute;
}
/**
* @return string
*/
public function getEscapeRoute()
{
return $this->escapeRoute;
}
Step collection
14
interface StepCollectionInterface extends IteratorAggregate
{
public function addStep(StepInterface $step);
public function canAccessStep(StepInterface $step, Request $request, AbstractTransfer $dataTransfer);
public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer);
public function getNextStep(StepInterface $currentStep);
public function getPreviousStep(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null);
public function getCurrentUrl(StepInterface $currentStep);
public function getNextUrl(StepInterface $currentStep, AbstractTransfer $dataTransfer);
public function getPreviousUrl(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null);
public function getEscapeUrl(StepInterface $currentStep);
}
Step collection
15
Step engine accesses step through step engine. Order of steps is also defined by collection.
canAccessStep method
16
With this method we determine if we can access a step or not. We can access it only if previous steps
were completed successfully.
/**
* @param SprykerYvesStepEngineDependencyStepStepInterface $currentStep
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $dataTransfer
*
* @return bool
*/
public function canAccessStep(StepInterface $currentStep, Request $request, AbstractTransfer $dataTransfer)
{
if ($request->get('_route') === $currentStep->getStepRoute()) {
return true;
}
foreach ($this->getCompletedSteps($dataTransfer) as $step) {
if ($step->getStepRoute() === $request->get('_route')) {
return true;
}
}
return false;
}
getCurrentStep method
17
This method will return the last not completed step by checking the post condition of steps.
/**
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $dataTransfer
*
* @return SprykerYvesStepEngineDependencyStepStepInterface
*/
public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer)
{
foreach ($this->steps as $step) {
if (!$step->postCondition($dataTransfer) || $request->get('_route') === $step->getStepRoute()) {
return $step;
}
$this->completedSteps[] = $step;
}
return end($this->completedSteps);
}
Form collection
18
Form collection
19
This class is responsible for forms rendering and data binding.
interface FormCollectionHandlerInterface
{
public function getForms(AbstractTransfer $dataTransfer);
public function hasSubmittedForm(Request $request, AbstractTransfer $dataTransfer);
public function handleRequest(Request $request, AbstractTransfer $dataTransfer);
public function provideDefaultFormData(AbstractTransfer $dataTransfer);
}
handleRequest method
20
After form has been submitted we validate the input and populate the underlying data object.
public function handleRequest(Request $request, AbstractTransfer $dataTransfer)
{
foreach ($this->getForms($dataTransfer) as $form) {
if ($request->request->has($form->getName())) {
$form->setData($dataTransfer);
return $form->handleRequest($request);
}
}
throw new InvalidFormHandleRequest('Form to handle not found in Request.');
}
data Providers
21
If we need to provide additional data to the form we use dataProviders
interface StepEngineFormDataProviderInterface
{
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function getData(AbstractTransfer $quoteTransfer);
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getOptions(AbstractTransfer $quoteTransfer);
}
getData method
22
In this method we can do a some business logic before setting values to quote.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return SprykerSharedKernelTransferAbstractTransfer
*/
public function getData(AbstractTransfer $quoteTransfer)
{
$quoteTransfer->setShippingAddress($this->getShippingAddress($quoteTransfer));
$quoteTransfer->setBillingAddress($this->getBillingAddress($quoteTransfer));
$quoteTransfer->setBillingSameAsShipping(
$this->isSameAddress($quoteTransfer->getShippingAddress(), $quoteTransfer->getBillingAddress())
);
return $quoteTransfer;
}
getOptions
23
If we need to populate dropdowns (call Zed) or have business rules that we need to apply then we do it
in getOptions
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getOptions(AbstractTransfer $quoteTransfer)
{
return [
CheckoutAddressCollectionForm::OPTION_ADDRESS_CHOICES => $this->getAddressChoices(),
CheckoutAddressCollectionForm::OPTION_COUNTRY_CHOICES => $this->getAvailableCountries(),
];
}
Data container
24
dataContainer
25
DataContainer is a simple wrapper around quote persistence. Depending on the selected strategy it
can be either Redis or DB (or you can have your own custom implementation)
interface DataContainerInterface
{
/**
* @return GeneratedSharedTransferQuoteTransfer
*/
public function get();
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return void
*/
public function set(AbstractTransfer $quoteTransfer);
}
Step engine
26
interface StepEngineInterface
{
/**
* @param SymfonyComponentHttpFoundationRequest $request
* @param SprykerYvesStepEngineFormFormCollectionHandlerInterface|null $formCollection
*
* @return array|SymfonyComponentHttpFoundationRedirectResponse
*/
public function process(Request $request, ?FormCollectionHandlerInterface $formCollection = null);
}
Step engine
27
Step engine
28
Workflow
29
Code
30
https://github.com/spryker/step-
engine/blob/master/src/Spryker/Yves/StepEn
gine/Process/StepEngine.php#L73
Placing the order
31
Checkout workflow
32
interface CheckoutWorkflowInterface
{
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferCheckoutResponseTransfer
*/
public function placeOrder(QuoteTransfer $quoteTransfer);
}
After we are through the checkout we still need to place the order. We need to transform Quote into Order
and store it into database. That is done in Checkout workflow on Zed.
Place the order
33
public function placeOrder(QuoteTransfer $quoteTransfer)
{
$checkoutResponseTransfer = $this->createCheckoutResponseTransfer();
if (!$this->checkPreConditions($quoteTransfer, $checkoutResponseTransfer)) {
return $checkoutResponseTransfer;
}
$quoteTransfer = $this->doPreSave($quoteTransfer, $checkoutResponseTransfer);
$quoteTransfer = $this->doSaveOrder($quoteTransfer, $checkoutResponseTransfer);
$this->runStateMachine($checkoutResponseTransfer->getSaveOrder());
$this->doPostSave($quoteTransfer, $checkoutResponseTransfer);
return $checkoutResponseTransfer;
}
− check preconditions (is quote still valid)
− presave (any additional info)
− saving the order
− post save
You only have 30s !!!
checkCondition method
34
interface CheckoutPreConditionPluginInterface
{
/**
* Specification:
* - Checks a condition before the order is saved.
* - Returns "false" and adds error to response transfer when condition failso.
* - Returns "true" when condition passed. Can add errors to response transfer.
* - Does not change Quote transfer.
* - Does not write to Persistence.
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponseTransfer
*
* @return bool
*/
public function checkCondition(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer
$checkoutResponseTransfer);
}
check if Quote is still valid
preSave method
35
interface CheckoutPreSaveInterface
{
/**
* Specification:
* - Do something before orderTransfer save
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function preSave(QuoteTransfer $quoteTransfer);
}
expand the quote with additional info
saveOrder method
36
interface CheckoutDoSaveOrderInterface
{
/**
* Specification:
* - Retrieves (its) data from the quote object and saves it to the database.
* - These plugins are already enveloped into a transaction.
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferSaveOrderTransfer $saveOrderTransfer
*
* @return void
*/
public function saveOrder(QuoteTransfer $quoteTransfer, SaveOrderTransfer $saveOrderTransfer);
}
persist checked and expanded Quote to database - place an order.
postSave method
37
interface CheckoutPostSaveHookInterface
{
/**
* Specification:
* - This plugin is called after the order is placed.
* - Set the success flag to false, if redirect should be headed to an error page afterwords
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponse
*
* @return void
*/
public function executeHook(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer
$checkoutResponse);
}
if we need to make an action after order is placed.
questions?
38
39
The Spryker Commerce
OS is a “beyond shop -
beyond desktop”
commerce technology,
enabling transactional
use cases at every
touchpoint today and in
future.
Contact us
spryker.com
hello@spryker.com
@sprysys
+49 (30) 2084983 53

More Related Content

What's hot

What's hot (10)

Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
 
Java script advance-auroskills (2)
Java script advance-auroskills (2)Java script advance-auroskills (2)
Java script advance-auroskills (2)
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
Angular 2 NgModule
Angular 2 NgModuleAngular 2 NgModule
Angular 2 NgModule
 
No internet? No Problem!
No internet? No Problem!No internet? No Problem!
No internet? No Problem!
 
Introduction to AJAX and DWR
Introduction to AJAX and DWRIntroduction to AJAX and DWR
Introduction to AJAX and DWR
 
Template syntax in Angular 2.0
Template syntax in Angular 2.0Template syntax in Angular 2.0
Template syntax in Angular 2.0
 
Relay Modern: architecture and workflow
Relay Modern: architecture and workflowRelay Modern: architecture and workflow
Relay Modern: architecture and workflow
 
Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017Intro to GraphQL on Android with Apollo DroidconNYC 2017
Intro to GraphQL on Android with Apollo DroidconNYC 2017
 
Why I Love JSX!
Why I Love JSX!Why I Love JSX!
Why I Love JSX!
 

Similar to Chekout demistified

CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)
brian d foy
 

Similar to Chekout demistified (20)

Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w LaraveluLaravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
 
Wykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w LaraveluWykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w Laravelu
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
What's new in jQuery 1.5
What's new in jQuery 1.5What's new in jQuery 1.5
What's new in jQuery 1.5
 
Mashing up JavaScript
Mashing up JavaScriptMashing up JavaScript
Mashing up JavaScript
 
Spring MVC Annotations
Spring MVC AnnotationsSpring MVC Annotations
Spring MVC Annotations
 
CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
 
Key Insights into Development Design Patterns for Magento 2 - Magento Live UK
Key Insights into Development Design Patterns for Magento 2 - Magento Live UKKey Insights into Development Design Patterns for Magento 2 - Magento Live UK
Key Insights into Development Design Patterns for Magento 2 - Magento Live UK
 
Php Enums
Php EnumsPhp Enums
Php Enums
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 

Recently uploaded

Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptxChiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
raffaeleoman
 
Uncommon Grace The Autobiography of Isaac Folorunso
Uncommon Grace The Autobiography of Isaac FolorunsoUncommon Grace The Autobiography of Isaac Folorunso
Uncommon Grace The Autobiography of Isaac Folorunso
Kayode Fayemi
 
If this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New NigeriaIf this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New Nigeria
Kayode Fayemi
 
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
amilabibi1
 

Recently uploaded (18)

Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptxChiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
 
Uncommon Grace The Autobiography of Isaac Folorunso
Uncommon Grace The Autobiography of Isaac FolorunsoUncommon Grace The Autobiography of Isaac Folorunso
Uncommon Grace The Autobiography of Isaac Folorunso
 
If this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New NigeriaIf this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New Nigeria
 
Sector 62, Noida Call girls :8448380779 Noida Escorts | 100% verified
Sector 62, Noida Call girls :8448380779 Noida Escorts | 100% verifiedSector 62, Noida Call girls :8448380779 Noida Escorts | 100% verified
Sector 62, Noida Call girls :8448380779 Noida Escorts | 100% verified
 
Causes of poverty in France presentation.pptx
Causes of poverty in France presentation.pptxCauses of poverty in France presentation.pptx
Causes of poverty in France presentation.pptx
 
Digital collaboration with Microsoft 365 as extension of Drupal
Digital collaboration with Microsoft 365 as extension of DrupalDigital collaboration with Microsoft 365 as extension of Drupal
Digital collaboration with Microsoft 365 as extension of Drupal
 
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
Bring back lost lover in USA, Canada ,Uk ,Australia ,London Lost Love Spell C...
 
Aesthetic Colaba Mumbai Cst Call girls 📞 7738631006 Grant road Call Girls ❤️-...
Aesthetic Colaba Mumbai Cst Call girls 📞 7738631006 Grant road Call Girls ❤️-...Aesthetic Colaba Mumbai Cst Call girls 📞 7738631006 Grant road Call Girls ❤️-...
Aesthetic Colaba Mumbai Cst Call girls 📞 7738631006 Grant road Call Girls ❤️-...
 
Thirunelveli call girls Tamil escorts 7877702510
Thirunelveli call girls Tamil escorts 7877702510Thirunelveli call girls Tamil escorts 7877702510
Thirunelveli call girls Tamil escorts 7877702510
 
Dreaming Music Video Treatment _ Project & Portfolio III
Dreaming Music Video Treatment _ Project & Portfolio IIIDreaming Music Video Treatment _ Project & Portfolio III
Dreaming Music Video Treatment _ Project & Portfolio III
 
lONG QUESTION ANSWER PAKISTAN STUDIES10.
lONG QUESTION ANSWER PAKISTAN STUDIES10.lONG QUESTION ANSWER PAKISTAN STUDIES10.
lONG QUESTION ANSWER PAKISTAN STUDIES10.
 
Busty Desi⚡Call Girls in Sector 51 Noida Escorts >༒8448380779 Escort Service-...
Busty Desi⚡Call Girls in Sector 51 Noida Escorts >༒8448380779 Escort Service-...Busty Desi⚡Call Girls in Sector 51 Noida Escorts >༒8448380779 Escort Service-...
Busty Desi⚡Call Girls in Sector 51 Noida Escorts >༒8448380779 Escort Service-...
 
My Presentation "In Your Hands" by Halle Bailey
My Presentation "In Your Hands" by Halle BaileyMy Presentation "In Your Hands" by Halle Bailey
My Presentation "In Your Hands" by Halle Bailey
 
ICT role in 21st century education and it's challenges.pdf
ICT role in 21st century education and it's challenges.pdfICT role in 21st century education and it's challenges.pdf
ICT role in 21st century education and it's challenges.pdf
 
Report Writing Webinar Training
Report Writing Webinar TrainingReport Writing Webinar Training
Report Writing Webinar Training
 
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdfThe workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
 
Dreaming Marissa Sánchez Music Video Treatment
Dreaming Marissa Sánchez Music Video TreatmentDreaming Marissa Sánchez Music Video Treatment
Dreaming Marissa Sánchez Music Video Treatment
 
AWS Data Engineer Associate (DEA-C01) Exam Dumps 2024.pdf
AWS Data Engineer Associate (DEA-C01) Exam Dumps 2024.pdfAWS Data Engineer Associate (DEA-C01) Exam Dumps 2024.pdf
AWS Data Engineer Associate (DEA-C01) Exam Dumps 2024.pdf
 

Chekout demistified

  • 2. About me 2 − 20+ years of experience − 3+ years at Spryker − Project experience with various stack − Project experience with multiple industries − ...
  • 3. What will we learn? 3 − How to place an Order? − What is a step engine? − Why is do we need step engine? − How to implements a new step? − Where do we modify the Quote? − What happens it something goes wrong? − ...
  • 5. What is a checkout? 5
  • 6. − Step is a class that implements the StepInterface and handles the data. What is a step? 6
  • 7. StepInterface 7 public function preCondition(AbstractTransfer $quoteTransfer); public function requireInput(AbstractTransfer $dataTransfer); public function execute(Request $request, AbstractTransfer $dataTransfer); public function postCondition(AbstractTransfer $dataTransfer); public function getStepRoute(); public function getEscapeRoute(); public function getTemplateVariables(AbstractTransfer $dataTransfer);
  • 8. preCondition method 8 Preconditions are called before each step. If the condition is met then it will return true and the process will continue. If it returns false, the customer will be redirected to the escape route defined for this step. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function preCondition(AbstractTransfer $quoteTransfer) { if ($this->isCartEmpty($quoteTransfer)) { return false; } if (!$quoteTransfer->getCheckoutConfirmed()) { $this->escapeRoute = CheckoutPageControllerProvider::CHECKOUT_SUMMARY; return false; } return true; }
  • 9. requireInput method 9 In this method we determine if step requires user input. If input methods return true we will render the form and wait for user input. /** * Require input for customer authentication if the customer is not logged in already, or haven't authenticated yet. * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function requireInput(AbstractTransfer $quoteTransfer) { if ($this->isCustomerLoggedIn()) { return false; } return true; }
  • 10. execute method 10 If the form is valid, the updated QuoteTransfer is passed to Step::execute() method where you can modify it further or apply custom logic (call a client or Zed). Also, there is Symfony Request object passed if additional/manual data mapping is required. /** * Update QuoteTransfer with customer step handler plugin. * * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function execute(Request $request, AbstractTransfer $quoteTransfer) { return $this->customerStepHandler->addToDataClass($request, $quoteTransfer); }
  • 11. postCondition method 11 Post condition is an essential part of the step Processing. It indicates if a step has all the data that it needs and if its requirements are satisfied. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function postCondition(AbstractTransfer $quoteTransfer) { if ($this->hasOnlyGiftCardItems($quoteTransfer)) { return true; } if (!$this->isShipmentSet($quoteTransfer)) { return false; } return true; } Do not modify the Quote in postCondition!!!
  • 12. getTemplateVariables method 12 With this method we can provide additional parameters that we might want to render on the template. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getTemplateVariables(AbstractTransfer $quoteTransfer) { return [ 'quoteTransfer' => $quoteTransfer, 'cartItems' => $this->productBundleClient->getGroupedBundleItems( $quoteTransfer->getItems(), $quoteTransfer->getBundleItems() ), ]; }
  • 13. getStepRoute and getEscapeRoute methods 13 Step route is the route to the step and escape route is where we redirect in case of an error. /** * @return string */ public function getStepRoute() { return $this->stepRoute; } /** * @return string */ public function getEscapeRoute() { return $this->escapeRoute; }
  • 15. interface StepCollectionInterface extends IteratorAggregate { public function addStep(StepInterface $step); public function canAccessStep(StepInterface $step, Request $request, AbstractTransfer $dataTransfer); public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer); public function getNextStep(StepInterface $currentStep); public function getPreviousStep(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null); public function getCurrentUrl(StepInterface $currentStep); public function getNextUrl(StepInterface $currentStep, AbstractTransfer $dataTransfer); public function getPreviousUrl(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null); public function getEscapeUrl(StepInterface $currentStep); } Step collection 15 Step engine accesses step through step engine. Order of steps is also defined by collection.
  • 16. canAccessStep method 16 With this method we determine if we can access a step or not. We can access it only if previous steps were completed successfully. /** * @param SprykerYvesStepEngineDependencyStepStepInterface $currentStep * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $dataTransfer * * @return bool */ public function canAccessStep(StepInterface $currentStep, Request $request, AbstractTransfer $dataTransfer) { if ($request->get('_route') === $currentStep->getStepRoute()) { return true; } foreach ($this->getCompletedSteps($dataTransfer) as $step) { if ($step->getStepRoute() === $request->get('_route')) { return true; } } return false; }
  • 17. getCurrentStep method 17 This method will return the last not completed step by checking the post condition of steps. /** * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $dataTransfer * * @return SprykerYvesStepEngineDependencyStepStepInterface */ public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer) { foreach ($this->steps as $step) { if (!$step->postCondition($dataTransfer) || $request->get('_route') === $step->getStepRoute()) { return $step; } $this->completedSteps[] = $step; } return end($this->completedSteps); }
  • 19. Form collection 19 This class is responsible for forms rendering and data binding. interface FormCollectionHandlerInterface { public function getForms(AbstractTransfer $dataTransfer); public function hasSubmittedForm(Request $request, AbstractTransfer $dataTransfer); public function handleRequest(Request $request, AbstractTransfer $dataTransfer); public function provideDefaultFormData(AbstractTransfer $dataTransfer); }
  • 20. handleRequest method 20 After form has been submitted we validate the input and populate the underlying data object. public function handleRequest(Request $request, AbstractTransfer $dataTransfer) { foreach ($this->getForms($dataTransfer) as $form) { if ($request->request->has($form->getName())) { $form->setData($dataTransfer); return $form->handleRequest($request); } } throw new InvalidFormHandleRequest('Form to handle not found in Request.'); }
  • 21. data Providers 21 If we need to provide additional data to the form we use dataProviders interface StepEngineFormDataProviderInterface { /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function getData(AbstractTransfer $quoteTransfer); /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getOptions(AbstractTransfer $quoteTransfer); }
  • 22. getData method 22 In this method we can do a some business logic before setting values to quote. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return SprykerSharedKernelTransferAbstractTransfer */ public function getData(AbstractTransfer $quoteTransfer) { $quoteTransfer->setShippingAddress($this->getShippingAddress($quoteTransfer)); $quoteTransfer->setBillingAddress($this->getBillingAddress($quoteTransfer)); $quoteTransfer->setBillingSameAsShipping( $this->isSameAddress($quoteTransfer->getShippingAddress(), $quoteTransfer->getBillingAddress()) ); return $quoteTransfer; }
  • 23. getOptions 23 If we need to populate dropdowns (call Zed) or have business rules that we need to apply then we do it in getOptions /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getOptions(AbstractTransfer $quoteTransfer) { return [ CheckoutAddressCollectionForm::OPTION_ADDRESS_CHOICES => $this->getAddressChoices(), CheckoutAddressCollectionForm::OPTION_COUNTRY_CHOICES => $this->getAvailableCountries(), ]; }
  • 25. dataContainer 25 DataContainer is a simple wrapper around quote persistence. Depending on the selected strategy it can be either Redis or DB (or you can have your own custom implementation) interface DataContainerInterface { /** * @return GeneratedSharedTransferQuoteTransfer */ public function get(); /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return void */ public function set(AbstractTransfer $quoteTransfer); }
  • 27. interface StepEngineInterface { /** * @param SymfonyComponentHttpFoundationRequest $request * @param SprykerYvesStepEngineFormFormCollectionHandlerInterface|null $formCollection * * @return array|SymfonyComponentHttpFoundationRedirectResponse */ public function process(Request $request, ?FormCollectionHandlerInterface $formCollection = null); } Step engine 27
  • 32. Checkout workflow 32 interface CheckoutWorkflowInterface { /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferCheckoutResponseTransfer */ public function placeOrder(QuoteTransfer $quoteTransfer); } After we are through the checkout we still need to place the order. We need to transform Quote into Order and store it into database. That is done in Checkout workflow on Zed.
  • 33. Place the order 33 public function placeOrder(QuoteTransfer $quoteTransfer) { $checkoutResponseTransfer = $this->createCheckoutResponseTransfer(); if (!$this->checkPreConditions($quoteTransfer, $checkoutResponseTransfer)) { return $checkoutResponseTransfer; } $quoteTransfer = $this->doPreSave($quoteTransfer, $checkoutResponseTransfer); $quoteTransfer = $this->doSaveOrder($quoteTransfer, $checkoutResponseTransfer); $this->runStateMachine($checkoutResponseTransfer->getSaveOrder()); $this->doPostSave($quoteTransfer, $checkoutResponseTransfer); return $checkoutResponseTransfer; } − check preconditions (is quote still valid) − presave (any additional info) − saving the order − post save You only have 30s !!!
  • 34. checkCondition method 34 interface CheckoutPreConditionPluginInterface { /** * Specification: * - Checks a condition before the order is saved. * - Returns "false" and adds error to response transfer when condition failso. * - Returns "true" when condition passed. Can add errors to response transfer. * - Does not change Quote transfer. * - Does not write to Persistence. * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponseTransfer * * @return bool */ public function checkCondition(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer $checkoutResponseTransfer); } check if Quote is still valid
  • 35. preSave method 35 interface CheckoutPreSaveInterface { /** * Specification: * - Do something before orderTransfer save * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function preSave(QuoteTransfer $quoteTransfer); } expand the quote with additional info
  • 36. saveOrder method 36 interface CheckoutDoSaveOrderInterface { /** * Specification: * - Retrieves (its) data from the quote object and saves it to the database. * - These plugins are already enveloped into a transaction. * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferSaveOrderTransfer $saveOrderTransfer * * @return void */ public function saveOrder(QuoteTransfer $quoteTransfer, SaveOrderTransfer $saveOrderTransfer); } persist checked and expanded Quote to database - place an order.
  • 37. postSave method 37 interface CheckoutPostSaveHookInterface { /** * Specification: * - This plugin is called after the order is placed. * - Set the success flag to false, if redirect should be headed to an error page afterwords * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponse * * @return void */ public function executeHook(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer $checkoutResponse); } if we need to make an action after order is placed.
  • 39. 39 The Spryker Commerce OS is a “beyond shop - beyond desktop” commerce technology, enabling transactional use cases at every touchpoint today and in future.