Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion modules/checkout/commerce_checkout.services.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
services:
commerce_checkout.chain_checkout_flow_resolver:
class: Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolver
tags:
- { name: service_collector, call: addResolver, tag: commerce_checkout.checkout_flow_resolver }

commerce_checkout.default_checkout_flow_resolver:
class: Drupal\commerce_checkout\Resolver\DefaultCheckoutFlowResolver
arguments: ['@entity_type.manager']
tags:
- { name: commerce_checkout.checkout_flow_resolver, priority: -100 }

commerce_checkout.checkout_order_manager:
class: Drupal\commerce_checkout\CheckoutOrderManager
arguments: ['@entity_type.manager']
arguments: ['@commerce_checkout.chain_checkout_flow_resolver']

plugin.manager.commerce_checkout_flow:
class: Drupal\commerce_checkout\CheckoutFlowManager
Expand Down
25 changes: 12 additions & 13 deletions modules/checkout/src/CheckoutOrderManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,37 @@

namespace Drupal\commerce_checkout;

use Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolverInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
* Manages checkout flows for orders.
*/
class CheckoutOrderManager implements CheckoutOrderManagerInterface {

/**
* The entity type manager.
* The chain checkout flow resolver.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
* @var \Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolverInterface
*/
protected $entityTypeManager;
protected $chainCheckoutFlowResolver;

/**
* Constructs a new CheckoutOrderManager object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\commerce_checkout\Resolver\ChainCheckoutFlowResolverInterface $chain_checkout_flow_resolver
* The chain checkout flow resolver.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
public function __construct(ChainCheckoutFlowResolverInterface $chain_checkout_flow_resolver) {
$this->chainCheckoutFlowResolver = $chain_checkout_flow_resolver;
}

/**
* {@inheritdoc}
*/
public function getCheckoutFlow(OrderInterface $order) {
if ($order->checkout_flow->isEmpty()) {
/** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
$order_type = $this->entityTypeManager->getStorage('commerce_order_type')->load($order->bundle());
$checkout_flow = $order_type->getThirdPartySetting('commerce_checkout', 'checkout_flow', 'default');
// @todo Allow other modules to add their own resolving logic.
$order->checkout_flow->target_id = $checkout_flow;
$order->checkout_flow = $this->chainCheckoutFlowResolver->resolve($order);
$order->save();
}

Expand Down
58 changes: 58 additions & 0 deletions modules/checkout/src/Resolver/ChainCheckoutFlowResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace Drupal\commerce_checkout\Resolver;

use Drupal\commerce_checkout\Entity\CheckoutFlowInterface;
use Drupal\commerce_order\Entity\OrderInterface;

/**
* Default implementation of the chain checkout flow resolver.
*/
class ChainCheckoutFlowResolver implements ChainCheckoutFlowResolverInterface {

/**
* The resolvers.
*
* @var \Drupal\commerce_checkout\Resolver\CheckoutFlowResolverInterface[]
*/
protected $resolvers = [];

/**
* Constructs a new ChainCheckoutFlowResolver object.
*
* @param \Drupal\commerce_checkout\Resolver\CheckoutFlowResolverInterface[] $resolvers
* The resolvers.
*/
public function __construct(array $resolvers = []) {
$this->resolvers = $resolvers;
}

/**
* {@inheritdoc}
*/
public function addResolver(CheckoutFlowResolverInterface $resolver) {
$this->resolvers[] = $resolver;
}

/**
* {@inheritdoc}
*/
public function getResolvers() {
return $this->resolvers;
}

/**
* {@inheritdoc}
*/
public function resolve(OrderInterface $order) {
foreach ($this->resolvers as $resolver) {
$result = $resolver->resolve($order);
if ($result instanceof CheckoutFlowInterface) {
return $result;
}
}

return NULL;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Drupal\commerce_checkout\Resolver;

/**
* Runs the added resolvers one by one until one of them returns the checkout flow.
*
* Each resolver in the chain can be another chain, which is why this interface
* extends the checkout flow resolver one.
*/
interface ChainCheckoutFlowResolverInterface extends CheckoutFlowResolverInterface {

/**
* Adds a resolver.
*
* @param \Drupal\commerce_checkout\Resolver\CheckoutFlowResolverInterface $resolver
* The resolver.
*/
public function addResolver(CheckoutFlowResolverInterface $resolver);

/**
* Gets all added resolvers.
*
* @return \Drupal\commerce_checkout\Resolver\CheckoutFlowResolverInterface[]
* The resolvers.
*/
public function getResolvers();

}
24 changes: 24 additions & 0 deletions modules/checkout/src/Resolver/CheckoutFlowResolverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Drupal\commerce_checkout\Resolver;

use Drupal\commerce_order\Entity\OrderInterface;

/**
* Defines the interface for checkout flow resolvers.
*/
interface CheckoutFlowResolverInterface {

/**
* Resolves the checkout flow.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The order that is being checked out.
*
* @return \Drupal\commerce_checkout\Entity\CheckoutFlowInterface
* The checkout flow, if resolved. Otherwise NULL, indicating that
* the next resolver in the chain should be called.
*/
public function resolve(OrderInterface $order);

}
41 changes: 41 additions & 0 deletions modules/checkout/src/Resolver/DefaultCheckoutFlowResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Drupal\commerce_checkout\Resolver;

use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
* Returns the order type's default checkout flow.
*/
class DefaultCheckoutFlowResolver implements CheckoutFlowResolverInterface {

/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* Constructs a new DefaultCheckoutFlowResolver object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}

/**
* {@inheritdoc}
*/
public function resolve(OrderInterface $order) {
/** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
$order_type = $this->entityTypeManager->getStorage('commerce_order_type')->load($order->bundle());
$checkout_flow_id = $order_type->getThirdPartySetting('commerce_checkout', 'checkout_flow', 'default');
$checkout_flow = $this->entityTypeManager->getStorage('commerce_checkout_flow')->load($checkout_flow_id);
return $checkout_flow;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Drupal\Tests\commerce_checkout\Kernel;

use Drupal\commerce_order\Entity\Order;
use Drupal\Tests\commerce\Kernel\CommerceKernelTestBase;

/**
* Tests the chain checkout flow resolver.
*
* @group commerce
*/
class ChainCheckoutFlowResolverTest extends CommerceKernelTestBase {

/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'path',
'options',
'entity',
'entity_reference_revisions',
'views',
'address',
'profile',
'state_machine',
'inline_entity_form',
'commerce',
'commerce_price',
'commerce_store',
'commerce_product',
'commerce_order',
'commerce_checkout',
];

/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('commerce_order');
$this->installConfig('commerce_order');
$this->installConfig('commerce_product');
$this->installConfig('commerce_checkout');
}

/**
* Tests resolving the checkout flow.
*/
public function testCheckoutFlowResolution() {
$user = $this->createUser(['mail' => $this->randomString() . '@example.com']);
$order = Order::create([
'type' => 'default',
'mail' => $user->getEmail(),
'uid' => $user->id(),
'store_id' => $this->store->id(),
]);
$order->save();

$resolver = $this->container->get('commerce_checkout.chain_checkout_flow_resolver');
/** @var \Drupal\commerce_checkout\Entity\CheckoutFlowInterface $checkout_flow */
$checkout_flow = $resolver->resolve($order);

$this->assertEquals('default', $checkout_flow->id());
}

}