Skip to content

Commit

Permalink
perf(admin): only save product settings once per request
Browse files Browse the repository at this point in the history
  • Loading branch information
EdieLemoine committed Oct 23, 2024
1 parent c4dccd1 commit 5e7b425
Showing 1 changed file with 74 additions and 26 deletions.
100 changes: 74 additions & 26 deletions src/Hooks/HasPdkProductHooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,33 @@
use MyParcelNL\Pdk\Base\Support\Arr;
use MyParcelNL\Pdk\Facade\Actions;
use MyParcelNL\Pdk\Facade\Frontend;
use MyParcelNL\Pdk\Facade\Logger;
use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\PrestaShop\Facade\EntityManager;
use MyParcelNL\Sdk\src\Support\Str;
use Symfony\Component\HttpFoundation\Request;
use Throwable;
use Tools;

trait HasPdkProductHooks
{
/**
* Saves the MyParcel product settings when a product is updated.
*
* @param array $params
*
* @return void
*/
public function hookActionProductUpdate(array $params): void
{
$this->saveProductSettings((int) $params['id_product']);
try {
$this->saveProductSettings((int) $params['id_product']);
} catch (Throwable $e) {
Logger::error(sprintf('Failed to save product settings for product %d', (int) $params['id_product']), [
'error' => $e->getMessage(),
'trace' => $e->getTrace(),
]);
}
}

/**
Expand All @@ -39,6 +50,60 @@ public function hookDisplayAdminProductsExtra(array $params): string
return $this->renderProductSettings((int) $params['id_product']);
}

/**
* @param int $productId
* @param array $productSettings
*
* @return \Symfony\Component\HttpFoundation\Request
* @throws \JsonException
*/
private function createRequest(int $productId, array $productSettings): Request
{
$parameters = [
'action' => PdkBackendActions::UPDATE_PRODUCT_SETTINGS,
'productId' => $productId,
];

$requestBody = [];

foreach ($productSettings as $key => $value) {
$trimmedKey = Arr::last(explode('-', $key));
$requestBody[$trimmedKey] = $value;
}

$content = json_encode(['data' => ['product_settings' => $requestBody]], JSON_THROW_ON_ERROR);

return new Request($parameters, [], [], [], [], [], $content);
}

/**
* The product update hook is called multiple (about 8) times by PrestaShop. This method checks if the product
* settings are already saved by comparing a checksum of the settings with the checksum we add to $_POST.
*
* @see https://www.prestashop.com/forums/topic/591295-ps17-hookactionproductupdate-gets-multiple-called-and-no-image-uploaded/
*
* @param int $idProduct
* @param array $productSettings
*
* @return bool
* @throws \JsonException
*/
private function isAlreadySaved(int $idProduct, array $productSettings): bool

Check notice on line 91 in src/Hooks/HasPdkProductHooks.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Hooks/HasPdkProductHooks.php#L91

isAlreadySaved accesses the super-global variable $_POST.
{
$appInfo = Pdk::getAppInfo();
$checksumKey = "_$appInfo->name-product-save-checksum-$idProduct";
$existingChecksum = $_POST[$checksumKey] ?? null;

Check failure on line 95 in src/Hooks/HasPdkProductHooks.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Hooks/HasPdkProductHooks.php#L95

$_POST[$checksumKey] not unslashed before sanitization. Use wp_unslash() or similar

Check failure on line 95 in src/Hooks/HasPdkProductHooks.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Hooks/HasPdkProductHooks.php#L95

Direct use of $_POST Superglobal detected.

Check notice on line 95 in src/Hooks/HasPdkProductHooks.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Hooks/HasPdkProductHooks.php#L95

Processing form data without nonce verification.
$checksum = md5(json_encode($productSettings, JSON_THROW_ON_ERROR));

if ($existingChecksum === $checksum) {
return true;
}

$_POST[$checksumKey] = $checksum;

Check failure on line 102 in src/Hooks/HasPdkProductHooks.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Hooks/HasPdkProductHooks.php#L102

Direct use of $_POST Superglobal detected.

return false;
}

/**
* @param int $idProduct
*
Expand All @@ -54,42 +119,25 @@ private function renderProductSettings(int $idProduct): string
}

/**
* @param int $idProduct
* @param int $productId
*
* @return void
* @throws \JsonException
*/
private function saveProductSettings(int $idProduct): void
private function saveProductSettings(int $productId): void
{
$postValues = Tools::getAllValues();
$name = Pdk::getAppInfo()->name;

$productSettings = array_filter($postValues, static function ($key) use ($name) {
$name = Pdk::getAppInfo()->name;
$productSettings = array_filter(Tools::getAllValues(), static function ($key) use ($name) {
return Str::startsWith((string) $key, $name);
}, ARRAY_FILTER_USE_KEY);

if (empty($productSettings)) {
if (empty($productSettings) || $this->isAlreadySaved($productId, $productSettings)) {
return;
}

$requestBody = [];

foreach ($productSettings as $key => $value) {
$trimmedKey = Arr::last(explode('-', $key));
$requestBody[$trimmedKey] = $value;
}
$request = $this->createRequest($productId, $productSettings);

$request = new Request(
[
'action' => PdkBackendActions::UPDATE_PRODUCT_SETTINGS,
'productId' => $idProduct,
],
[],
[],
[],
[],
[],
json_encode(['data' => ['product_settings' => $requestBody]])
);
Logger::debug(sprintf('Saving product settings for product %d', $productId), ['settings' => $productSettings]);

Actions::execute($request);

Expand Down

0 comments on commit 5e7b425

Please sign in to comment.