Skip to content
Merged
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
68 changes: 16 additions & 52 deletions src/Controller/MagewireUpdateRoute.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?php

/**
* Copyright © Willem Poortman 2021-present. All rights reserved.
*
Expand All @@ -12,28 +11,22 @@
namespace Magewirephp\Magewire\Controller;

use Exception;
use Magewirephp\Magewire\Mechanisms\HandleComponents\Checksum;
use Magento\Framework\App\Action\Forward;
use Magento\Framework\App\ActionFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\PhpEnvironment\Request;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\Webapi\ServiceInputProcessor;
use Magewirephp\Magento\App\Router\MagewireRouteValidator;
use Magewirephp\Magewire\Enums\RequestMode;
use Magewirephp\Magewire\MagewireServiceProvider;
use Magewirephp\Magewire\Mechanisms\HandleComponents\Checksum;
use Magewirephp\Magewire\Mechanisms\HandleComponents\CorruptComponentPayloadException;
use Magewirephp\Magewire\Mechanisms\HandleComponents\SnapshotFactory;
use Magewirephp\Magewire\Mechanisms\HandleRequests\ComponentRequestContextFactory;
use Magewirephp\Magewire\Mechanisms\HandleRequests\ComponentRequestContext;
use Psr\Log\LoggerInterface;
use RuntimeException;

use function Magewirephp\Magewire\trigger;

/**
* Handles routing for Magewire component update requests.
*/
abstract class MagewireUpdateRoute extends MagewireRoute
{
public const PARAM_IS_SUBSEQUENT = 'is_magewire_subsequent';
Expand All @@ -42,8 +35,7 @@ abstract class MagewireUpdateRoute extends MagewireRoute

public function __construct(
private readonly SerializerInterface $serializer,
private readonly SnapshotFactory $snapshotFactory,
private readonly ComponentRequestContextFactory $componentRequestContextFactory,
private readonly ServiceInputProcessor $serviceInputProcessor,
private readonly MagewireServiceProvider $magewireServiceProvider,
private readonly ActionFactory $actionFactory,
private readonly LoggerInterface $logger,
Expand All @@ -53,13 +45,6 @@ public function __construct(
parent::__construct($this->actionFactory, $this->logger, $this->magewireRouteValidator);
}

/**
* Matches and processes Magewire update requests.
*
* Validates the request, boots Magewire in subsequent mode, and parses
* component data. Returns a forward action on failure or the matched
* action on success.
*/
public function match(RequestInterface $request): ActionInterface|null
{
$match = parent::match($request);
Expand All @@ -68,42 +53,30 @@ public function match(RequestInterface $request): ActionInterface|null
return null;
}

// Mark the request as a subsequent Magewire request.
$request->setParam(self::PARAM_IS_SUBSEQUENT, true);

/**
* Boot Magewire and initialize the request context.
*
* Magewire has two trigger points for initialization:
* 1. During component updates (the only feasible location after confirming an update request)
* 2. During page load via the view block observer
*
* This call marks the request as "subsequent" to distinguish between initial page loads
* and subsequent update requests, allowing system-wide determination of Magewire's state.
* Magewire has two trigger points for booting itself. One occurs during the updating of components.
* This is the only feasible location, after confirming we are on an update request,
* where we should attempt to boot. [2/2]
*
* @see \Magewirephp\Magewire\Observer\ViewBlockAbstractToHtmlBefore
*/
$this->magewireServiceProvider->boot(RequestMode::SUBSEQUENT);
$this->magewireServiceProvider->boot();

try {
$request->setParams($this->parseRequest($request));
} catch (Exception $exception) {
$this->logger->critical($exception->getMessage(), ['exception' => $exception]);

return null;
return $this->actionFactory->create(Forward::class);
}

return $match;
}


/**
* Parses and validates the component update request payload.
*
* Deserializes component data from the request body, verifies checksums,
* validates component prerequisites (resolver/handle), and converts
* component data to service contract objects.
*
* @throws LocalizedException
* @throws FileSystemException
* @throws \Magento\Framework\Exception\RuntimeException
* @throws CorruptComponentPayloadException
*/
protected function parseRequest(RequestInterface $request): array
{
Expand All @@ -130,17 +103,8 @@ protected function parseRequest(RequestInterface $request): array
throw new RuntimeException('Base component prerequisites not satisfied.');
}

$snapshot = $this->snapshotFactory->create([
'data' => $component['snapshot']['data'] ?? [],
'memo' => $component['snapshot']['memo'] ?? [],
'checksum' => $component['snapshot']['checksum'] ?? '',
]);

$input[self::PARAM_COMPONENTS][$key] = $this->componentRequestContextFactory->create([
'snapshot' => $snapshot,
'calls' => $component['calls'] ?? [],
'updates' => $component['updates'] ?? [],
]);
// Each component request context must conform to the service contract requirements.
$input[self::PARAM_COMPONENTS][$key] = $this->serviceInputProcessor->convertValue($component, ComponentRequestContext::class);
}

/** @var Request $request */
Expand Down
Loading