commerce_api-8.x-1.x-dev/src/Resource/ShippingMethodsResource.php
src/Resource/ShippingMethodsResource.php
<?php
declare(strict_types=1);
namespace Drupal\commerce_api\Resource;
use Drupal\commerce_api\Plugin\DataType\ShippingRate as ShippingRateDataType;
use Drupal\commerce_api\ResourceType\RenamableResourceType;
use Drupal\commerce_api\TypedData\ShippingRateDefinition;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\commerce_shipping\ShipmentManagerInterface;
use Drupal\commerce_shipping\ShippingOrderManagerInterface;
use Drupal\commerce_shipping\ShippingRate;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\TypedData\TypedDataTrait;
use Drupal\jsonapi\JsonApiResource\LinkCollection;
use Drupal\jsonapi\JsonApiResource\ResourceObject;
use Drupal\jsonapi\JsonApiResource\ResourceObjectData;
use Drupal\jsonapi\ResourceResponse;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\ResourceType\ResourceTypeAttribute;
use Drupal\jsonapi_resources\Resource\ResourceBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
final class ShippingMethodsResource extends ResourceBase implements ContainerInjectionInterface {
use TypedDataTrait;
/**
* Constructs a new ShippingMethodsResource object.
*
* @param \Drupal\commerce_shipping\ShipmentManagerInterface $shipmentManager
* The shipment manager.
* @param \Drupal\commerce_shipping\ShippingOrderManagerInterface $shippingOrderManager
* The shipping order manager.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
*/
public function __construct(private ShipmentManagerInterface $shipmentManager, private ShippingOrderManagerInterface $shippingOrderManager, private RendererInterface $renderer) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$instance = new self(
$container->get('commerce_shipping.shipment_manager'),
$container->get('commerce_shipping.order_manager'),
$container->get('renderer')
);
$instance->setTypedDataManager($container->get('typed_data_manager'));
return $instance;
}
/**
* Process the resource request.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
* @param array $resource_types
* The resource types for this resource.
* @param \Drupal\commerce_order\Entity\OrderInterface $commerce_order
* The order.
*
* @return \Drupal\jsonapi\ResourceResponse
* The response.
*/
public function process(Request $request, array $resource_types, OrderInterface $commerce_order): ResourceResponse {
$shipments = $commerce_order->get('shipments')->referencedEntities();
if (empty($shipments)) {
$shipping_profile = $commerce_order->get('shipping_information')->entity;
$shipments = $this->shippingOrderManager->pack($commerce_order, $shipping_profile);
}
$resource_type = reset($resource_types);
$render_context = new RenderContext();
$options = $this->renderer->executeInRenderContext($render_context, function () use ($shipments, $resource_type) {
$options = [];
foreach ($shipments as $shipment) {
assert($shipment instanceof ShipmentInterface);
$shipping_rate_data_definition = ShippingRateDefinition::create();
$options[] = array_map(function (ShippingRate $rate) use ($resource_type, $shipping_rate_data_definition) {
$data = $this->getTypedDataManager()->create($shipping_rate_data_definition, $rate->toArray());
assert($data instanceof ShippingRateDataType);
$resource_object_data = $data->getProperties();
unset($resource_object_data['id']);
return new ResourceObject(
new CacheableMetadata(),
$resource_type,
$rate->getId(),
NULL,
$resource_object_data,
new LinkCollection([])
);
}, $this->shipmentManager->calculateRates($shipment));
}
return array_merge([], ...$options);
});
$response = $this->createJsonapiResponse(new ResourceObjectData($options), $request);
if ($response instanceof CacheableResponseInterface) {
$response->addCacheableDependency($commerce_order);
if (!$render_context->isEmpty()) {
$response->addCacheableDependency($render_context->pop());
}
}
return $response;
}
/**
* {@inheritdoc}
*/
public function getRouteResourceTypes(Route $route, string $route_name): array {
return [$this->getShippingRateOptionResourceType()];
}
/**
* Get the shipping rate option resource type.
*
* @return \Drupal\jsonapi\ResourceType\ResourceType
* The resource type.
*/
private function getShippingRateOptionResourceType(): ResourceType {
$resource_type = new RenamableResourceType(
'shipping_rate_option',
'shipping_rate_option',
NULL,
'shipping-rate-option',
FALSE,
FALSE,
FALSE,
FALSE,
[
'optionId' => new ResourceTypeAttribute('optionId', 'optionId'),
'label' => new ResourceTypeAttribute('label', 'label'),
'methodId' => new ResourceTypeAttribute('methodId', 'methodId'),
'rate' => new ResourceTypeAttribute('rate', 'rate'),
]
);
$resource_type->setRelatableResourceTypes([]);
return $resource_type;
}
}
