-
Notifications
You must be signed in to change notification settings - Fork 0
Core Services ConfigOptionSetupService
**Referenced Files in This Document** - [ConfigOptionSetupService.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/Services/ConfigOptionSetupService.php) - [SliderConfigReaderService.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/Services/SliderConfigReaderService.php) - [AuditsExtensionActions.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/Services/Concerns/AuditsExtensionActions.php) - [PricingController.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/Http/Controllers/Api/PricingController.php) - [StoreReservationRequest.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/Http/Requests/StoreReservationRequest.php) - [2025_01_01_000002_create_ptero_pricing_configs_table.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/database/migrations/2025_01_01_000002_create_ptero_pricing_configs_table.php) - [2025_01_01_000005_drop_ptero_pricing_configs_table.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/database/migrations/2025_01_01_000005_drop_ptero_pricing_configs_table.php) - [ConfigOptionSetupServiceTest.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/tests/Unit/ConfigOptionSetupServiceTest.php) - [SetupWizardValidationTest.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/tests/Feature/SetupWizardValidationTest.php) - [LaravelTestCase.php](https://github.com/ObsidianNetwork/dynamic-pterodactyl/blob/6b7f83bda6f7c3fe014d52428b31af1638daa6cc/tests/LaravelTestCase.php)Preserved Qoder snapshot. This deep-dive page is retained so the earlier Wiki work and its source trail are not lost. For the reconciled implementation, Architecture Overview is canonical; references below to retired controllers, listeners, services, or API shapes are historical.
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document explains the ConfigOptionSetupService, which creates and configures dynamic slider options for Paymenter products. It focuses on how the service builds slider metadata (ranges, steps, defaults), validates pricing configuration, integrates with Paymenter’s pricing engine by storing metadata consumed by core pricing methods, and manages optional location options. It also covers migration procedures that moved slider configuration from a dedicated table to native ConfigOption metadata, common configuration patterns, and troubleshooting invalid setups.
The extension is a nested Paymenter “Other” extension. Slider setup lives under Services, with supporting services for reading slider configurations and auditing actions. The service interacts with Paymenter’s core models (ConfigOption, Product) and uses database transactions to ensure atomicity when creating or updating multiple slider options.
graph TB
A["Admin Setup Wizard"] --> B["ConfigOptionSetupService"]
B --> C["Paymenter Core: ConfigOption"]
B --> D["Database Transaction"]
B --> E["AuditsExtensionActions"]
F["SliderConfigReaderService"] --> C
G["PricingController"] --> C
H["StoreReservationRequest"] --> C
Diagram sources
- ConfigOptionSetupService.php:44-77
- SliderConfigReaderService.php:14-53
- PricingController.php:38-76
- StoreReservationRequest.php:75-140
Section sources
- ConfigOptionSetupService: Creates/updates dynamic_slider ConfigOptions for memory, CPU, disk, and optionally Location; validates pricing metadata; audits setup runs.
- SliderConfigReaderService: Reads configured sliders per product for API/frontend consumption.
- AuditsExtensionActions: Safely logs setup actions even if audit logging fails.
Key responsibilities:
- Build resource metadata with min/max/step/default values and display units.
- Validate pricing model parameters via Paymenter’s rule.
- Upsert existing slider options to avoid duplication.
- Create location dropdown options as child entries under a parent “Location” option.
- Provide helpers to detect existing slider options and count products with sliders.
Section sources
- ConfigOptionSetupService.php:14-42
- ConfigOptionSetupService.php:44-77
- ConfigOptionSetupService.php:79-146
- ConfigOptionSetupService.php:148-171
- ConfigOptionSetupService.php:173-206
- ConfigOptionSetupService.php:208-258
- SliderConfigReaderService.php:14-53
- AuditsExtensionActions.php:10-32
The service orchestrates slider creation within a single transaction. For each enabled resource type, it either updates an existing dynamic_slider option or creates a new one, attaching it to the product. Pricing metadata is validated before persisting. If locations are provided, a Location select option and its child options are created. After success, an audit entry is recorded.
sequenceDiagram
participant Admin as "Setup Wizard"
participant Svc as "ConfigOptionSetupService"
participant DB as "Database"
participant Core as "Paymenter Core : ConfigOption"
participant Audit as "AuditLogService"
Admin->>Svc : createDynamicSliderOptions(productId, config, locations)
Svc->>DB : beginTransaction()
loop For each resource (memory, cpu, disk)
Svc->>Core : findExistingOption(productId, resourceType)
alt exists
Svc->>Core : update(type=dynamic_slider, metadata)
else not exists
Svc->>Core : create(name, type=dynamic_slider, env_variable, sort, metadata)
Svc->>Core : attach to product
end
end
opt locations provided
Svc->>Core : create/update Location parent + children
end
Svc->>DB : commit()
Svc->>Audit : log setup_run with summary
Svc-->>Admin : created options map
Diagram sources
- ConfigOptionSetupService.php:44-77
- ConfigOptionSetupService.php:79-146
- ConfigOptionSetupService.php:173-206
- AuditsExtensionActions.php:10-32
- Entry point: createDynamicSliderOptions accepts productId, configuration array, and optional locations.
- Iterates over memory, cpu, disk; skips any resource whose enable flag is false.
- Builds metadata using defaults and user-provided values, then validates pricing metadata through Paymenter’s rule.
- Upserts ConfigOption with type dynamic_slider and attaches to the product.
- Optionally creates a Location select option and child options for each location.
- Wraps all writes in a transaction; rolls back on any failure.
- Audits successful runs with a summary of configured sliders.
Common configuration inputs:
- Base price and pricing_model (linear, tiered, base_addon).
- Per-resource min, max, step, default values.
- Per-resource rate or tiers depending on model.
- Optional locations list with id, short, long identifiers.
Output:
- Map of resource types to created/updated ConfigOption instances, plus location if created.
Section sources
- ConfigOptionSetupService.php:44-77
- ConfigOptionSetupService.php:79-146
- ConfigOptionSetupService.php:148-171
- ConfigOptionSetupService.php:173-206
- Pricing metadata validation is delegated to Paymenter’s DynamicSliderPricingRule during buildResourceMetadata.
- Validation errors are collected and thrown as an InvalidArgumentException with concatenated messages.
- Range and step normalization applies divisor scaling to align internal vs display units.
Validation rules enforced at setup time include:
- Non-negative base_price and rates.
- Tier ordering and final tier handling for tiered models.
- Included amounts non-negative for base_addon model.
These rules mirror those used elsewhere in the system to ensure consistency between setup and runtime.
Section sources
- The service does not calculate prices. It stores metadata consumed by Paymenter core pricing methods:
- Plan::dynamicSliderBasePrice() for shared base charge per plan/product.
- ConfigOption::calculateDynamicPriceDelta() for marginal charges per slider value.
- SliderConfigReaderService exposes slider metadata for frontend/API consumption.
- PricingController reads configured sliders and validates request values against slider ranges and steps.
- StoreReservationRequest enforces slider range and step constraints at reservation submission.
flowchart TD
Start(["Setup Wizard"]) --> BuildMeta["Build metadata<br/>min/max/step/default/display"]
BuildMeta --> ValidatePricing["Validate pricing metadata"]
ValidatePricing --> Persist["Persist ConfigOption(s)<br/>attach to product"]
Persist --> ReadCfg["SliderConfigReaderService.getConfig()"]
ReadCfg --> Api["PricingController preview"]
Api --> Submit["StoreReservationRequest validate"]
Submit --> End(["Checkout/Reservation"])
Diagram sources
- ConfigOptionSetupService.php:117-146
- SliderConfigReaderService.php:14-53
- PricingController.php:38-76
- StoreReservationRequest.php:75-140
Section sources
- Each dynamic_slider ConfigOption is linked to a product via the pivot table.
- Existing options are identified by name or metadata.resource_type to support idempotent re-runs.
- Sorting order ensures consistent UI presentation (memory first, then cpu, then disk).
- Location options are hierarchical: a parent “Location” option with child options representing available locations.
Section sources
- ConfigOptionSetupService.php:79-115
- ConfigOptionSetupService.php:173-206
- ConfigOptionSetupService.php:235-248
- Historical ptero_pricing_configs table was removed; slider configuration now lives in ConfigOption metadata.
- To migrate or reconfigure:
- Run the Setup Wizard to create dynamic_slider ConfigOptions for the target product.
- Re-run is safe due to upsert logic that updates existing options rather than duplicating them.
- Use checkExistingOptions to inspect current slider presence and IDs.
- Audit logs record setup runs for traceability.
Migration notes:
- The drop migration removes the legacy table and documents data loss on rollback; reconfiguration should be done via the Setup Wizard after rollback.
Section sources
- 2025_01_01_000005_drop_ptero_pricing_configs_table.php:12-27
- ConfigOptionSetupService.php:208-233
- ConfigOptionSetupService.php:235-248
- Linear pricing: set base_price and per-resource rates (e.g., memory_rate, cpu_rate, disk_rate).
- Tiered pricing: define tiers per resource with ascending up_to boundaries and a final tier with null upper bound.
- Base + addon: specify included units and overage rate per resource.
- Location selection: provide a list of locations to generate a dropdown under the Location option.
Examples validated by tests:
- Full happy path creating memory, cpu, disk, and location sliders.
- Rollback behavior when tiered pricing contains invalid tiers.
- Audit logging of setup runs with correct payload.
Section sources
- ConfigOptionSetupServiceTest.php:25-51
- ConfigOptionSetupServiceTest.php:53-76
- ConfigOptionSetupServiceTest.php:78-106
- SetupWizardValidationTest.php:75-93
Symptoms and causes:
- Invalid tiered pricing (non-ascending or missing final open-ended tier) triggers an InvalidArgumentException during setup.
- Mismatched slider values at checkout/reservation time fail validation if they violate min/max or step constraints.
- Missing required slider fields in requests produce field-specific errors indicating required resources.
Resolution steps:
- Fix pricing model parameters to satisfy validation rules.
- Ensure slider values respect configured min, max, and step.
- Confirm all required slider fields are present in the request for the product.
Recovery:
- Re-run the Setup Wizard with corrected configuration; the service will update existing options atomically.
- Inspect audit logs to confirm successful setup runs.
Section sources
- ConfigOptionSetupService.php:117-146
- StoreReservationRequest.php:75-140
- ConfigOptionSetupServiceTest.php:25-51
- External dependencies:
- Paymenter core models: ConfigOption, Product.
- Paymenter core pricing rules: DynamicSliderPricingRule.
- Database transactions for atomicity.
- AuditLogService via AuditsExtensionActions.
- Internal dependencies:
- SliderConfigReaderService for reading slider metadata.
- HTTP layer components rely on slider metadata for validation and pricing previews.
classDiagram
class ConfigOptionSetupService {
+createDynamicSliderOptions(productId, config, locations) array
+checkExistingOptions(productId) array
+getProductsWithSlidersCount() int
-createResourceOption(productId, resourceType, config) ConfigOption
-buildResourceMetadata(resourceType, config, defaults) array
-buildPricingMetadata(resourceType, pricingModel, config) array
-createLocationOption(productId, locations) ConfigOption
-findExistingOption(productId, name) ConfigOption?
}
class SliderConfigReaderService {
+getConfig(productId) array
-getDynamicSliderOptions(productId) Collection
}
class AuditsExtensionActions {
+safeAudit(action, entityType, entityId, newValues) void
}
ConfigOptionSetupService ..> AuditsExtensionActions : "uses trait"
ConfigOptionSetupService --> SliderConfigReaderService : "conceptual read path"
Diagram sources
- ConfigOptionSetupService.php:10-258
- SliderConfigReaderService.php:7-66
- AuditsExtensionActions.php:8-32
Section sources
- ConfigOptionSetupService.php:10-258
- SliderConfigReaderService.php:7-66
- AuditsExtensionActions.php:8-32
- All slider creations/updates occur within a single database transaction to minimize partial writes and simplify rollback.
- Option lookup uses direct joins and JSON extraction to efficiently identify existing sliders by name or resource_type.
- Avoids redundant storage by leveraging native ConfigOption metadata instead of a separate pricing configs table.
- Real-time availability decisions are outside this service; however, the design avoids caching Pterodactyl responses elsewhere in the extension.
[No sources needed since this section provides general guidance]
- Validation failures during setup:
- Check pricing model parameters (base_price, rates, tiers, included units).
- Ensure tiered pricing has ascending up_to values and a final tier with null upper bound.
- Review error messages thrown by the pricing rule validator.
- Checkout/reservation validation failures:
- Verify slider values fall within configured min/max and adhere to step increments.
- Ensure all required slider fields are present in the request.
- Re-running setup:
- Use the Setup Wizard again; the service will update existing sliders without duplication.
- Confirm audit logs show a successful setup_run action.
Section sources
- ConfigOptionSetupService.php:117-146
- StoreReservationRequest.php:75-140
- ConfigOptionSetupServiceTest.php:25-51
ConfigOptionSetupService centralizes the creation and validation of dynamic slider options for Paymenter products. It standardizes slider metadata, enforces pricing constraints via core rules, and integrates seamlessly with downstream components that read slider configuration and perform pricing previews and validations. The migration to native ConfigOption metadata simplifies the architecture and improves maintainability. Administrators can safely re-run setup to update configurations while preserving data integrity through transactions and robust validation.
[No sources needed since this section summarizes without analyzing specific files]
sequenceDiagram
participant Admin as "Admin"
participant Wizard as "Setup Wizard"
participant Service as "ConfigOptionSetupService"
participant Core as "ConfigOption"
participant Reader as "SliderConfigReaderService"
participant API as "PricingController"
participant Req as "StoreReservationRequest"
Admin->>Wizard : Configure sliders
Wizard->>Service : createDynamicSliderOptions(...)
Service->>Core : Upsert dynamic_slider options
Note over Service,Core : Metadata includes ranges, steps, pricing
API->>Reader : getConfig(productId)
Reader-->>API : Slider metadata
API-->>Admin : Pricing preview
Admin->>Req : Submit reservation with slider values
Req->>Req : Validate min/max/step
Req-->>Admin : Success or validation errors
Diagram sources
DynamicPterodactyl · Dynamic Resource Sliders for Paymenter × Pterodactyl · Reviewed code checkpoint · Publication commits intentionally pin their latest code-bearing predecessor because a Git commit cannot self-reference its unknown object ID.
DynamicPterodactyl
Guides
Architecture
- Architecture Overview
Core Services
API Reference
Database
System