|
| 1 | +--- |
| 2 | +name: inc-function |
| 3 | +description: Adds a new procedural function to `src/parallels.inc.php` wrapping a `\Detain\Parallels\Parallels` KA API method with the standard `myadmin_log` + `request_log` + try/catch pattern. Use when user says 'add function', 'new API call', 'call parallels method', or needs to expose a KA API method. Do NOT use for Plugin.php static event handlers or bin/ scripts. |
| 4 | +--- |
| 5 | +# inc-function |
| 6 | + |
| 7 | +## Critical |
| 8 | + |
| 9 | +- **No type hints on parameters, no return type declarations** — existing functions are untyped legacy PHP style; `ReflectionFunction` tests enforce this. |
| 10 | +- **No PHP namespace declaration** in `src/parallels.inc.php` — it is a plain procedural include file. |
| 11 | +- **Always catch `\XML_RPC2_CurlException`** (not `\Exception`) and return `false` on failure — this is the only exception the KA API client throws. |
| 12 | +- **Always call `request_log()`** for both success and failure paths with identical `'licenses'` module and `'parallels'` service arguments. |
| 13 | +- The `use \Detain\Parallels\Parallels;` statement already exists at the top of the file — do not add a second one. |
| 14 | + |
| 15 | +## Instructions |
| 16 | + |
| 17 | +1. **Identify the KA API method** to wrap. Check `\Detain\Parallels\Parallels` for the exact method name and signature (e.g., `getKeyInfo($keyNumber)`, `retrieveKey($keyNumber)`, `getAvailableUpgrades($keyNumber)`). |
| 18 | + |
| 19 | +2. **Add the PHPDoc block** immediately before the function: |
| 20 | + ```php |
| 21 | + /** |
| 22 | + * parallels_<action>() |
| 23 | + * @param mixed $param1 |
| 24 | + * @return mixed |
| 25 | + */ |
| 26 | + ``` |
| 27 | + Use `@param mixed` — no concrete types. Verify the block is present before proceeding. |
| 28 | + |
| 29 | +3. **Write the function signature** — no type hints, no return type: |
| 30 | + ```php |
| 31 | + function parallels_<action>($param1) |
| 32 | + ``` |
| 33 | + Name must be `parallels_` prefixed + snake_case action (e.g., `parallels_get_key_info`). |
| 34 | + |
| 35 | +4. **Open with `myadmin_log`** describing the call: |
| 36 | + ```php |
| 37 | + myadmin_log('licenses', 'info', "Parallels <Action> ({$param1})", __LINE__, __FILE__); |
| 38 | + ``` |
| 39 | + |
| 40 | +5. **Instantiate the client and build `$request`:** |
| 41 | + ```php |
| 42 | + $parallels = new \Detain\Parallels\Parallels(); |
| 43 | + $request = [$param1]; // mirror the args passed to the API method |
| 44 | + ``` |
| 45 | + |
| 46 | +6. **Wrap the API call in try/catch:** |
| 47 | + ```php |
| 48 | + try { |
| 49 | + $response = $parallels->apiMethodName($param1); |
| 50 | + request_log('licenses', false, __FUNCTION__, 'parallels', 'apiMethodName', $request, $response); |
| 51 | + myadmin_log('licenses', 'info', "parallels_<action>({$param1}) Response: ".json_encode($response), __LINE__, __FILE__); |
| 52 | + } catch (\XML_RPC2_CurlException $e) { |
| 53 | + request_log('licenses', false, __FUNCTION__, 'parallels', 'apiMethodName', $request, $e->getMessage()); |
| 54 | + return false; |
| 55 | + } |
| 56 | + return $response; |
| 57 | + ``` |
| 58 | + Verify `request_log()` is called in **both** the try and catch blocks before proceeding. |
| 59 | + |
| 60 | +7. **Register the function in `tests/bootstrap.php`** only if the function calls any new MyAdmin globals not already stubbed. Check existing stubs: `myadmin_log`, `get_service_define`, `function_requirements`, `request_log`, `get_module_settings`. |
| 61 | + |
| 62 | +8. **Add a test** in `tests/ParallelsIncTest.php` following the existing `testActivateParallelsFunctionExists` pattern — at minimum assert `function_exists('parallels_<action>')`. |
| 63 | + |
| 64 | +9. **Run tests** to confirm nothing broke: |
| 65 | + ```bash |
| 66 | + vendor/bin/phpunit tests/ParallelsIncTest.php |
| 67 | + ``` |
| 68 | + |
| 69 | +## Examples |
| 70 | + |
| 71 | +**User says:** "Add a function that calls `getKeyInfo` on a key number" |
| 72 | + |
| 73 | +**Actions taken:** |
| 74 | +1. Confirm `\Detain\Parallels\Parallels::getKeyInfo($keyNumber)` exists in the client. |
| 75 | +2. Append to `src/parallels.inc.php`: |
| 76 | + |
| 77 | +```php |
| 78 | +/** |
| 79 | + * parallels_get_key_info() |
| 80 | + * @param mixed $keyNumber |
| 81 | + * @return mixed |
| 82 | + */ |
| 83 | +function parallels_get_key_info($keyNumber) |
| 84 | +{ |
| 85 | + myadmin_log('licenses', 'info', "Parallels Get Key Info ({$keyNumber})", __LINE__, __FILE__); |
| 86 | + $parallels = new \Detain\Parallels\Parallels(); |
| 87 | + $request = [$keyNumber]; |
| 88 | + try { |
| 89 | + $response = $parallels->getKeyInfo($keyNumber); |
| 90 | + request_log('licenses', false, __FUNCTION__, 'parallels', 'getKeyInfo', $request, $response); |
| 91 | + myadmin_log('licenses', 'info', "parallels_get_key_info({$keyNumber}) Response: ".json_encode($response), __LINE__, __FILE__); |
| 92 | + } catch (\XML_RPC2_CurlException $e) { |
| 93 | + request_log('licenses', false, __FUNCTION__, 'parallels', 'getKeyInfo', $request, $e->getMessage()); |
| 94 | + return false; |
| 95 | + } |
| 96 | + return $response; |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +3. Add `testParallelsGetKeyInfoFunctionExists` to `tests/ParallelsIncTest.php`. |
| 101 | +4. Run `vendor/bin/phpunit tests/ParallelsIncTest.php` — all green. |
| 102 | + |
| 103 | +**Result:** New function appears in `src/parallels.inc.php`, test passes. |
| 104 | + |
| 105 | +## Common Issues |
| 106 | + |
| 107 | +- **`Call to undefined function myadmin_log()`** during tests: add `function myadmin_log() {}` stub to `tests/bootstrap.php` — it must be defined before `require_once` of the inc file. |
| 108 | +- **`Call to undefined function request_log()`** during tests: same fix — add `function request_log() {}` to `tests/bootstrap.php`. |
| 109 | +- **`Class 'XML_RPC2_CurlException' not found`** at runtime: the class lives in the `detain/parallels-licensing` package; run `composer install` to ensure it is present. |
| 110 | +- **Test fails with `Function parallels_<action>() should be defined`**: the function name in the `function_exists()` assertion must exactly match the PHP function name including the `parallels_` prefix. |
| 111 | +- **Duplicate `use` statement error**: `use \Detain\Parallels\Parallels;` is already at line 10 of `src/parallels.inc.php`; never add it again. |
0 commit comments