|
| 1 | +--- |
| 2 | +name: addon-handler-setup |
| 3 | +description: Creates a new AddonHandler registration block inside a `getAddon` method. Use when user says 'add addon', 'register addon', 'new webhosting addon', or adds a new `load_addons` hook handler. Generates `function_requirements('class.AddonHandler')`, fluent `->set_text()`, `->set_cost()`, `->setEnable()`, `->setDisable()`, `->register()` chain followed by `$service->addAddon()`. Do NOT use for editing existing addons or for non-addon hook handlers. |
| 4 | +--- |
| 5 | +# Addon Handler Setup |
| 6 | + |
| 7 | +## Critical |
| 8 | + |
| 9 | +- `function_requirements('class.AddonHandler')` MUST be called before `new \AddonHandler()` — the class is lazy-loaded. |
| 10 | +- `$service->addAddon($addon)` MUST be the last line in `getAddon()` — omitting it silently drops the addon. |
| 11 | +- The `getAddon` method signature MUST accept `GenericEvent $event` and extract `$service` via `$event->getSubject()`. |
| 12 | +- Register the hook in `getHooks()` using `self::$module.'.load_addons'` as the key — never hardcode the module string. |
| 13 | +- `doEnable` and `doDisable` MUST have the signature: `(\ServiceHandler $serviceOrder, $repeatInvoiceId, $regexMatch = false)`. |
| 14 | + |
| 15 | +## Instructions |
| 16 | + |
| 17 | +1. **Add the hook to `getHooks()`** in `src/Plugin.php`. The key is `self::$module.'.load_addons'`, value is `[__CLASS__, 'getAddon']`. |
| 18 | + ```php |
| 19 | + public static function getHooks(): array { |
| 20 | + return [ |
| 21 | + self::$module.'.load_addons' => [__CLASS__, 'getAddon'], |
| 22 | + self::$module.'.settings' => [__CLASS__, 'getSettings'], |
| 23 | + ]; |
| 24 | + } |
| 25 | + ``` |
| 26 | + Verify `getHooks()` returns this key before proceeding. |
| 27 | + |
| 28 | +2. **Write the `getAddon` method** immediately after `getHooks()`. Extract `$service` from the event, call `function_requirements`, instantiate `\AddonHandler`, chain all setters, call `register()`, then call `$service->addAddon($addon)`. |
| 29 | + ```php |
| 30 | + public static function getAddon(GenericEvent $event) |
| 31 | + { |
| 32 | + /** @var \ServiceHandler $service */ |
| 33 | + $service = $event->getSubject(); |
| 34 | + function_requirements('class.AddonHandler'); |
| 35 | + $addon = new \AddonHandler(); |
| 36 | + $addon->setModule(self::$module) |
| 37 | + ->set_text('Your Addon Name') |
| 38 | + ->set_text_match('Your Addon Name (.*)') |
| 39 | + ->set_cost(YOUR_COST_CONSTANT) |
| 40 | + ->setEnable([__CLASS__, 'doEnable']) |
| 41 | + ->setDisable([__CLASS__, 'doDisable']) |
| 42 | + ->register(); |
| 43 | + $service->addAddon($addon); |
| 44 | + } |
| 45 | + ``` |
| 46 | + `set_text_match` must be a regex where `(.*)` captures the variable part (e.g., IP or plan name). |
| 47 | + |
| 48 | +3. **Write `doEnable`**. It receives `\ServiceHandler $serviceOrder`. Retrieve service info and settings first. Skip WHM calls for `WEB_DIRECTADMIN` and `WEB_STORAGE` types. Log every WHM response before acting on it. |
| 49 | + ```php |
| 50 | + public static function doEnable(\ServiceHandler $serviceOrder, $repeatInvoiceId, $regexMatch = false) |
| 51 | + { |
| 52 | + $serviceInfo = $serviceOrder->getServiceInfo(); |
| 53 | + $settings = get_module_settings(self::$module); |
| 54 | + if ($regexMatch === false) { |
| 55 | + function_requirements('get_service_master'); |
| 56 | + $serverdata = get_service_master($serviceInfo[$settings['PREFIX'].'_server'], self::$module); |
| 57 | + if (in_array($serviceInfo[$settings['PREFIX'].'_type'], [get_service_define('WEB_DIRECTADMIN'), get_service_define('WEB_STORAGE')])) { |
| 58 | + // skip — unsupported type |
| 59 | + } else { |
| 60 | + // perform enable logic |
| 61 | + myadmin_log(self::$module, 'info', 'Enabling addon for '.$serviceInfo[$settings['PREFIX'].'_id'], __LINE__, __FILE__, self::$module, $serviceInfo[$settings['PREFIX'].'_id']); |
| 62 | + } |
| 63 | + } |
| 64 | + } |
| 65 | + ``` |
| 66 | + |
| 67 | +4. **Write `doDisable`**. Same signature as `doEnable`. Always call `add_output('...')` and send an admin cancellation email via `(new \MyAdmin\Mail())->adminMail()`. |
| 68 | + ```php |
| 69 | + public static function doDisable(\ServiceHandler $serviceOrder, $repeatInvoiceId, $regexMatch = false) |
| 70 | + { |
| 71 | + $serviceInfo = $serviceOrder->getServiceInfo(); |
| 72 | + $settings = get_module_settings(self::$module); |
| 73 | + $db = get_module_db(self::$module); |
| 74 | + // disable logic here |
| 75 | + add_output('Your Addon Order Canceled'); |
| 76 | + $subject = $settings['TBLNAME'].' '.$serviceInfo[$settings['PREFIX'].'_id'].' Canceled Your Addon'; |
| 77 | + $email = $settings['TBLNAME'].' ID: '.$serviceInfo[$settings['PREFIX'].'_id'].'<br>Description: '.self::$name.'<br>'; |
| 78 | + (new \MyAdmin\Mail())->adminMail($subject, $email, false, 'admin/website_ip_canceled.tpl'); |
| 79 | + } |
| 80 | + ``` |
| 81 | + |
| 82 | +5. **Run tests** to verify hook registration and addon wiring: |
| 83 | + ```bash |
| 84 | + vendor/bin/phpunit tests/ -v |
| 85 | + ``` |
| 86 | + |
| 87 | +## Examples |
| 88 | + |
| 89 | +**User says:** "Add a new addon for SSL certificates" |
| 90 | + |
| 91 | +**Actions taken:** |
| 92 | +1. Add `self::$module.'.load_addons' => [__CLASS__, 'getAddon']` to `getHooks()` in `src/Plugin.php`. |
| 93 | +2. Create `getAddon(GenericEvent $event)` with `set_text('SSL Certificate')`, `set_text_match('SSL Certificate (.*)')`, `set_cost(SSL_CERT_COST)`. |
| 94 | +3. Create `doEnable` skipping WHM for DirectAdmin/Storage, logging all API calls. |
| 95 | +4. Create `doDisable` calling `add_output('SSL Certificate Canceled')` and `adminMail()`. |
| 96 | + |
| 97 | +**Result:** Addon appears in `webhosting.load_addons` event, is purchasable at `SSL_CERT_COST`, enable/disable callbacks are wired. |
| 98 | + |
| 99 | +## Common Issues |
| 100 | + |
| 101 | +- **`Class 'AddonHandler' not found`**: `function_requirements('class.AddonHandler')` was not called before `new \AddonHandler()`. Add it as the first line inside `getAddon()`. |
| 102 | +- **Addon silently missing from the service**: `$service->addAddon($addon)` was omitted. It must follow `->register()` — `register()` alone does not attach the addon to the service. |
| 103 | +- **`doEnable` never fires for DirectAdmin accounts**: This is expected — the `in_array(...WEB_DIRECTADMIN...)` guard intentionally skips those. Do not remove it. |
| 104 | +- **`set_text_match` not matching on invoice**: The regex passed to `set_text_match` must include `(.*)` and match the exact invoice line text. Test with the literal string from a real invoice. |
| 105 | +- **WHM API returns null response**: `function_requirements('whm_api')` was skipped. Always call it before `new \xmlapi()`; always `myadmin_log` the raw response string before `json_decode()`. |
0 commit comments