Skip to content
Open
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
1,616 changes: 108 additions & 1,508 deletions core/components/minishop3/src/Controllers/Api/Manager/OrdersController.php

Large diffs are not rendered by default.

161 changes: 40 additions & 121 deletions core/components/minishop3/src/ServiceRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class ServiceRegistry
'class' => \MiniShop3\Services\ExtraFields\RepeaterFieldService::class,
'interface' => null,
],
'ms3_extra_fields' => [
'class' => \MiniShop3\Services\ExtraFieldsService::class,
'interface' => null,
],
'ms3_product_image' => [
'class' => \MiniShop3\Services\Product\ProductImageService::class,
'interface' => null,
Expand Down Expand Up @@ -125,6 +129,26 @@ class ServiceRegistry
'class' => \MiniShop3\Services\Order\OrderFinalizeService::class,
'interface' => null,
],
'ms3_manager_order_presenter' => [
'class' => \MiniShop3\Services\Order\ManagerOrderPresenter::class,
'interface' => null,
],
'ms3_manager_order_list' => [
'class' => \MiniShop3\Services\Order\ManagerOrderListService::class,
'interface' => null,
],
'ms3_manager_order_mutation' => [
'class' => \MiniShop3\Services\Order\ManagerOrderMutationService::class,
'interface' => null,
],
'ms3_manager_order_products' => [
'class' => \MiniShop3\Services\Order\ManagerOrderProductsService::class,
'interface' => null,
],
'ms3_manager_order_cost_recalculator' => [
'class' => \MiniShop3\Services\Order\ManagerOrderCostRecalculator::class,
'interface' => null,
],
// Cart services
'ms3_cart_item_manager' => [
'class' => \MiniShop3\Services\Cart\CartItemManager::class,
Expand Down Expand Up @@ -444,131 +468,25 @@ protected function registerService(string $serviceKey, array $config): bool

$validatedClass = $this->validateClass($className, $fallbackClass, $requiredInterface);

$modx = $this->modx;
$factories = ServiceRegistryFactories::map();
if (!isset($factories[$serviceKey])) {
$this->modx->log(
modX::LOG_LEVEL_ERROR,
"[MiniShop3 ServiceRegistry] No factory registered for service '{$serviceKey}'"
);

// Controllers requiring only MiniShop3 instance: __construct(MiniShop3 $ms3)
$controllersWithMs3Only = ['ms3_cart', 'ms3_order', 'ms3_customer'];

// Services requiring both modX and MiniShop3: __construct(modX $modx, MiniShop3 $ms3)
$servicesWithModxAndMs3 = [
'ms3_order_draft_manager',
'ms3_order_cost_calculator',
'ms3_order_user_resolver',
'ms3_order_log',
'ms3_cart_item_manager',
'ms3_customer_address_manager',
];

// Services with complex dependencies (resolved via DI)
$servicesWithDependencies = [
'ms3_order_field_manager',
'ms3_order_address_manager',
'ms3_order_submit_handler',
'ms3_order_status',
'ms3_order_finalize',
];

if (in_array($serviceKey, $controllersWithMs3Only)) {
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
return new $validatedClass($ms3);
});
} elseif (in_array($serviceKey, $servicesWithModxAndMs3)) {
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
return new $validatedClass($modx, $ms3);
});
} elseif (in_array($serviceKey, $servicesWithDependencies)) {
// Services with dependencies - resolve them from DI
$this->registerServiceWithDependencies($serviceKey, $validatedClass);
} else {
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
return new $validatedClass($modx);
});
return false;
}

return true;
}

/**
* Register service with complex dependencies
*
* Dependencies are resolved from DI container (lazy loading).
* This allows overriding any dependency via config.
*
* @param string $serviceKey Service key
* @param string $validatedClass Validated class name
* @return void
*/
protected function registerServiceWithDependencies(string $serviceKey, string $validatedClass): void
{
$factory = $factories[$serviceKey];
$modx = $this->modx;
$services = $this->modx->services;

switch ($serviceKey) {
case 'ms3_order_field_manager':
// OrderFieldManager(modX, MiniShop3, OrderDraftManager)
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
$draftManager = $modx->services->get('ms3_order_draft_manager');
return new $validatedClass($modx, $ms3, $draftManager);
});
break;

case 'ms3_order_address_manager':
// OrderAddressManager(modX, MiniShop3, OrderDraftManager, OrderFieldManager)
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
$draftManager = $modx->services->get('ms3_order_draft_manager');
$fieldManager = $modx->services->get('ms3_order_field_manager');
return new $validatedClass($modx, $ms3, $draftManager, $fieldManager);
});
break;

case 'ms3_order_submit_handler':
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
$draftManager = $modx->services->get('ms3_order_draft_manager');
$costCalculator = $modx->services->get('ms3_order_cost_calculator');
$fieldManager = $modx->services->get('ms3_order_field_manager');
$addressManager = $modx->services->get('ms3_order_address_manager');
$userResolver = $modx->services->get('ms3_order_user_resolver');
$numberGenerator = $modx->services->get('ms3_order_number_generator');
return new $validatedClass(
$modx,
$ms3,
$draftManager,
$costCalculator,
$fieldManager,
$addressManager,
$userResolver,
$numberGenerator
);
});
break;

case 'ms3_order_finalize':
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
$numberGenerator = $modx->services->get('ms3_order_number_generator');
return new $validatedClass($modx, $ms3, $numberGenerator);
});
break;

case 'ms3_order_status':
// OrderStatusService(modX, MiniShop3, OrderLogService)
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
$ms3 = $modx->getService('MiniShop3', \MiniShop3\MiniShop3::class);
$orderLog = $modx->services->get('ms3_order_log');
return new $validatedClass($modx, $ms3, $orderLog);
});
break;

default:
// Fallback: create with modX only
$this->modx->services->add($serviceKey, function () use ($validatedClass, $modx) {
return new $validatedClass($modx);
});
}
$this->modx->services->add($serviceKey, function () use ($factory, $validatedClass, $modx, $services) {
return $factory($modx, $services, $validatedClass);
});

return true;
}

/**
Expand Down Expand Up @@ -608,7 +526,8 @@ protected function validateClass(
if (!in_array($requiredInterface, $interfaces ?: [])) {
$this->modx->log(
modX::LOG_LEVEL_ERROR,
"[MiniShop3 ServiceRegistry] Class '{$className}' must implement {$requiredInterface}, using fallback"
"[MiniShop3 ServiceRegistry] Class '{$className}' must implement {$requiredInterface}, "
. 'using fallback'
);
return $fallbackClass;
}
Expand Down
156 changes: 156 additions & 0 deletions core/components/minishop3/src/ServiceRegistryFactories.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php

namespace MiniShop3;

use MODX\Revolution\modX;

/**
* Explicit DI factory map for ServiceRegistry (#345).
*
* Each entry: serviceKey => callable(modX $modx, object $services, string $class): object
*
* @internal
*/
class ServiceRegistryFactories
{
/**
* @return array<string, callable(modX, object, string): object>
*/
public static function map(): array
{
$modxOnly = static fn (): callable => static function (modX $modx, object $services, string $class): object {
return new $class($modx);
};

$ms3Only = static fn (): callable => static function (modX $modx, object $services, string $class): object {
return new $class(self::ms3($modx));
};

$modxAndMs3 = static fn (): callable => static function (modX $modx, object $services, string $class): object {
return new $class($modx, self::ms3($modx));
};

return [
'ms3_field_config_manager' => $modxOnly(),
'ms3_config_service' => $modxOnly(),
'ms3_product_service' => $modxOnly(),
'ms3_product_data_service' => $modxOnly(),
'ms3_repeater_field' => $modxOnly(),
'ms3_extra_fields' => $modxOnly(),
'ms3_product_image' => $modxOnly(),
'ms3_vendor_service' => $modxOnly(),
'ms3_delivery_service' => $modxOnly(),
'ms3_payment_service' => $modxOnly(),
'ms3_order_service' => $modxOnly(),
'ms3_order_number_generator' => $modxOnly(),
'ms3_manager_order_presenter' => $modxOnly(),
'ms3_token_service' => $modxOnly(),
'ms3_category_service' => $modxOnly(),
'ms3_category_option_service' => $modxOnly(),
'ms3_image' => $modxOnly(),
'ms3_option_service' => $modxOnly(),
'ms3_auth_manager' => $modxOnly(),
'ms3_register_service' => $modxOnly(),
'ms3_email_verification_service' => $modxOnly(),
'ms3_sms_verification_service' => $modxOnly(),
'ms3_rate_limiter' => $modxOnly(),
'ms3_grid_config' => $modxOnly(),
'ms3_category_products_list' => $modxOnly(),
'ms3_category_product_scope' => $modxOnly(),
'ms3_category_tree' => $modxOnly(),
'ms3_filter_config' => $modxOnly(),
'ms3_notifications' => $modxOnly(),
'ms3_notification_config' => $modxOnly(),
'ms3_customer_duplicate_checker' => $modxOnly(),
'ms3_customer_factory' => $modxOnly(),

'ms3_cart' => $ms3Only(),
'ms3_order' => $ms3Only(),
'ms3_customer' => $ms3Only(),

'ms3_order_draft_manager' => $modxAndMs3(),
'ms3_order_cost_calculator' => $modxAndMs3(),
'ms3_order_user_resolver' => $modxAndMs3(),
'ms3_order_log' => $modxAndMs3(),
'ms3_manager_order_cost_recalculator' => $modxAndMs3(),
'ms3_cart_item_manager' => $modxAndMs3(),
'ms3_customer_address_manager' => $modxAndMs3(),

'ms3_order_field_manager' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
self::ms3($modx),
$services->get('ms3_order_draft_manager')
);
},

'ms3_order_address_manager' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
self::ms3($modx),
$services->get('ms3_order_draft_manager'),
$services->get('ms3_order_field_manager')
);
},

'ms3_order_submit_handler' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
self::ms3($modx),
$services->get('ms3_order_draft_manager'),
$services->get('ms3_order_cost_calculator'),
$services->get('ms3_order_field_manager'),
$services->get('ms3_order_address_manager'),
$services->get('ms3_order_user_resolver'),
$services->get('ms3_order_number_generator')
);
},

'ms3_order_finalize' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
self::ms3($modx),
$services->get('ms3_order_number_generator')
);
},

'ms3_order_status' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
self::ms3($modx),
$services->get('ms3_order_log')
);
},

'ms3_manager_order_list' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
$services->get('ms3_manager_order_presenter')
);
},

'ms3_manager_order_mutation' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
$services->get('ms3_manager_order_presenter'),
$services->get('ms3_order_log')
);
},

'ms3_manager_order_products' => static function (modX $modx, object $services, string $class): object {
return new $class(
$modx,
$services->get('ms3_order_log')
);
},
];
}

private static function ms3(modX $modx): MiniShop3
{
/** @var MiniShop3 $ms3 */
$ms3 = $modx->services->get('ms3');

return $ms3;
}
}
Loading