Service Processor
The Service Processor is responsible for handling place order requests. It matches the given payment method code to an optional corresponding Place Order Service.
If no match is found, it falls back to the default service provided by the PlaceOrderServiceProvider which can be found at \Hyva\Checkout\Model\Magewire\Payment\PlaceOrderServiceProvider
.
Happy Flow
The high-level happy flow when the Place Order button is pressed is as follows:
- A request is made to the method
\Hyva\Checkout\Magewire\Main::placeOrder()
. - Since version 1.1.13, the
placeOrder()
method accepts hyva_checkout session data, which is automatically passed through to the Place Order Service asHyva\Checkout\Model\Magewire\Payment\AbstractOrderData
. - The processors, if permitted by the Place Order Service
canPlaceOrder()
method, attempt to convert the session data and run the Place Order Service'splaceOrder()
method, catching any exceptions that are thrown. - When the order is placed successfully, an
order:place:success
window event is pushed into the Evaluation batch, which is then dispatched on the frontend immediately after. - If the Place Order Service permits the processor to redirect afterward, a Redirect evaluation result is added to the
Evaluation Batch. This result includes the redirect URL provided by the Place Order Service's
getRedirectUrl()
method.
Since 1.1.13, the \Hyva\Checkout\Model\Magewire\Payment\PlaceOrderServiceProvider
has been marked as @internal
which means this object should not be used by any other than the Main checkout component.
Register a Place Order Service
Ensuring that a specific place order service is used for a certain payment method requires registration and can be achieved as follows.
<!-- File: etc/frontend/di.xml -->
<type name="Hyva\Checkout\Model\Magewire\Payment\PlaceOrderServiceProvider">
<arguments>
<argument name="placeOrderServiceList" xsi:type="array">
<item name="foo" xsi:type="object">
My\Example\Model\Payment\PlaceOrderService\FooPlaceOrderService
</item>
</argument>
</arguments>
</type>
For more details, please refer to Place Order Service API - Example scenario.
Exception Handling
The service processor automatically dispatches an order:place:error
and order:place:{payment_method_code}:error
window event which by default is not being listened to by any default frontend components.
Accordingly, if the handleException method of the used order place service re-throws the exception, the processor will
set a default message: "Something went wrong while processing your order. Please try again." This message can be
customized by allowing the handleException()
method to throw an exception of type \Magento\Framework\Exception\LocalizedException
.
Additionally, the exception message is logged. Subsequently, an error message Evaluation result is added to the batch, which will be automatically dispatched and displayed on the frontend, notifying the customer that something went wrong.
For more details, please refer to Abstract Layer - Handle Exception.
Example scenario
You have bound a custom Place Order Service to a specific payment method with the code foo
. This method attempts to
place the order via a custom placeOrder()
method, but throws an exception due to an API call to an external service
returning a 403 response.
In this scenario, we assume the quote has not yet been transferred into an order object. Therefore, we need to catch the error on the frontend within the payment method template itself.
Using the Messenger component
The messenger component is a template used for a messenger block. This template automatically turns the block into a messenger listening component responsible for displaying error messages in a unified manner, without requiring you to handle any business logic or specific styling.
The messenger needs to be injected manually via layout XML, as the platform cannot determine where you want these messages to be displayed.
<block name="checkout.shipping.method.foo" as="foo_foo">
<block name="component-messenger-guest-details"
template="Hyva_Checkout::page/messenger.phtml"
>
<arguments>
<argument name="event_prefix" xsi:type="string">
order:place
</argument>
</arguments>
</block>
</block>
The event_prefix
makes the messenger automatically listen for any {event_prefix}:error
events, which, as previously
mentioned, will be automatically dispatched on the window by the order place service processor.
Next we need to show a message which shows a bit more specific what went wrong. We'll do this via our custom place order service
including our own handleException()
.
<?php
public function handleException(\Exception $exception, \Magewirephp\Magewire\Component $component, \Magento\Quote\Model\Quote $quote): void
{
if ($exception instanceof \My\Example\Exceptions\AuthenticationFailureException) {
throw new \Magento\Framework\Exception\LocalizedException(
__('Unable to authenticate to the payment gateway. Please try again.')
);
}
// Use the default behaviour.
parent::handleException($exception, $component, $quote);
}
Now imagine you want to add custom data. You could either include it in the message or use an evaluation result, which provides more flexibility to meet your specific needs.
This is done by adding another result to the Main component batch, which can hold an unlimited number of results.
<?php
public function handleException(\Exception $exception, \Magewirephp\Magewire\Component $component, \Magento\Quote\Model\Quote $quote): void
{
if ($exception instanceof \My\Example\Exceptions\AuthenticationFailureException) {
$component->getEvaluationResultBatch()
->push($component->getEvaluationResultBatch()->getFactory()
->createEvent('my:custom:event')
->withDetails([
'code' => $exception->getCode(),
'gateway' => $exception->getGateway()
])
);
throw new \Magento\Framework\Exception\LocalizedException(
__('Unable to authenticate to the payment gateway. Please try again.')
);
}
parent::handleException($exception, $component, $quote);
}
In this case, my:custom:event
will be dispatched onto the window
with custom details to work with.
Using a custom event listener
Even though the Messenger component is our best practice for displaying error and warning messages in a unified manner, it is still possible to build more customized solutions.
This can help clarify the situation for your customers and provide guidance on how they can potentially resolve the issue.
Using other evaluation results
The Evaluation API is as flexible as you need it to be. You can inject custom results or use existing ones, which we continually improve and expand to handle various situations.
Using these results is identical to how you would use them in a custom component. The only difference is that you need
to add them to a pre-created batch that resides on the $component
.
Additionally, the batch object has a getFactory()
method that can be used to create result objects.
<?php
public function handleException(\Exception $exception, \Magewirephp\Magewire\Component $component, \Magento\Quote\Model\Quote $quote): void
{
// Get the factory.
$factory = $component->getEvaluationResultBatch()->getFactory();
// Create the required result.
$executable = $factory->createExecutable('foo_exception');
// Push it onto the stack.
$component->getEvaluationResultBatch()->push($executable);
//...
}
For more details, please refer to Evaluation API - Evaluation result types.