name: fantastico-api-method
description: Adds a new public method to src/Fantastico.php following the SOAP call pattern used by addIp/editIp/deactivateIp. Use when user says 'add method', 'new API call', 'add function', or needs to expose a new Fantastico API operation. Key capabilities: SOAP call wiring, StatisticClient instrumentation, cache management, PHPDoc blocks, and a matching test stub. Do NOT use for modifying the constructor, connect(), or soapIpFunction() internals.
fantastico-api-method
Critical
- Use tabs for indentation (not spaces) — enforced by
.scrutinizer.yml - Every public method must have a PHPDoc block with
@paramand@returntags - Constants must be
UPPERCASE; method/property names must becamelCase - No short open tags (
<?is forbidden; use<?php) - Every new method requires a corresponding
test*method intests/FantasticoTest.php - Do not modify
connect(),__construct(), orsoapIpFunction()
Instructions
Determine the SOAP call pattern based on what parameters the new method needs:
- Single
$ipAddressparam, no extra args → delegate to$this->soapIpFunction('methodName', $ipAddress)(same pattern asdeactivateIp,reactivateIp,deleteIp) - Multiple params or custom response handling → implement inline (same pattern as
addIporeditIp) - Read-only list/query with caching needed → use the
getIpList/getIpDetailscache pattern - Verify the SOAP method name matches what Netenberg's WSDL exposes before proceeding.
- Single
Write the method in
src/Fantastico.phpinside theDetain\Fantastico\Fantasticoclass, before the closing}.For a single-IP-param method (delegate pattern):
/** * Fantastico::newMethodName() * One-line description of what it does. * * Output Success * Array * ( * [key] => value * ) * * Output Error * Array * ( * [faultcode] => 1801 * [fault ] => "The IP Address that you have specified does not exist." * ) * * @param string $ipAddress ip address to operate on * @return array response array with result keys or faultcode/fault on error */ public function newMethodName($ipAddress) { return $this->soapIpFunction('newMethodName', $ipAddress); }For a multi-param method (inline pattern, modelled on
addIp):/** * Fantastico::newMethodName() * One-line description. * * @param string $ipAddress ip address * @param integer $param2 description of second param * @return array response array containing faultcode/fault on error, or result keys on success */ public function newMethodName($ipAddress, $param2) { if (!$this->validIp($ipAddress)) { $response = ['faultcode' => 1, 'fault' => 'Invalid IP Address '.$ipAddress]; } else { $this->connect(); if (class_exists(\StatisticClient::class, false)) { \StatisticClient::tick('Fantastico', 'newMethodName'); } $response = json_decode($this->soapClient->newMethodName($this->getHash(), $ipAddress, $param2), true); if ($response === false) { if (class_exists(\StatisticClient::class, false)) { \StatisticClient::report('Fantastico', 'newMethodName', false, 1, 'Soap Client Error', STATISTICS_SERVER); } } else { if (class_exists(\StatisticClient::class, false)) { \StatisticClient::report('Fantastico', 'newMethodName', true, 0, '', STATISTICS_SERVER); } } myadmin_log('fantastico', 'debug', json_encode($response), __LINE__, __FILE__); if (isset($response['fault '])) { $response['fault'] = $response['fault ']; unset($response['fault ']); } } $this->cache = []; return $response; }Add a test stub in
tests/FantasticoTest.phpinsideFantasticoTest, following the existing pattern:/** * @covers Detain\Fantastico\Fantastico::newMethodName * @todo Implement testNewMethodName(). */ public function testNewMethodName() { // Remove the following lines when you implement this test. $this->markTestIncomplete( 'This test has not been implemented yet.' ); }Run the test suite to confirm no syntax errors and existing tests still pass:
vendor/bin/phpunit tests/ -vVerify no test regressions appear beyond the expected
markTestIncompleteskips.
Examples
User says: "Add a suspendIp method that suspends a license by IP"
Actions taken:
- Single IP param, mutating operation → use delegate pattern via
soapIpFunction - Add to
src/Fantastico.php:/** * Fantastico::suspendIp() * Suspends a Fantastico IP License * * Output Success * Array * ( * [ipAddress] => 130.253.175.32 * [status] => Inactive * ) * * Output Error * Array * ( * [faultcode] => 1801 * [fault ] => "The IP Address that you have specified does not exist." * ) * * @param string $ipAddress ip address to suspend * @return array response array with status or faultcode/fault on error */ public function suspendIp($ipAddress) { return $this->soapIpFunction('suspendIp', $ipAddress); } - Add to
tests/FantasticoTest.php:/** * @covers Detain\Fantastico\Fantastico::suspendIp * @todo Implement testSuspendIp(). */ public function testSuspendIp() { $this->markTestIncomplete( 'This test has not been implemented yet.' ); }
Result: PHPUnit reports the new test as skipped (incomplete), all prior tests unchanged.
Common Issues
Fatal error: Call to undefined method SoapClient::newMethodName()— the SOAP method name passed tosoapIpFunction()or$this->soapClient->does not match the WSDL. Check the exact method name athttps://netenberg.com/api/netenberg.wsdl.json_decode() returns nullinstead of array — the SOAP response is not valid JSON. Addvar_dump($this->soapClient->newMethodName(...))temporarily to inspect the raw response before decoding.- Scrutinizer fails with
parameter_doc_comments— a@paramtag is missing or its type/name doesn't match the actual parameter. Every parameter in the signature needs a@param type $name descriptionline. - Scrutinizer fails with
use_tabs— spaces were used for indentation. Rununexpand --first-only -t 4 src/Fantastico.phpto convert or manually replace leading spaces with tabs. - Cache not cleared after mutation — mutating methods (
add,edit,delete,deactivate,reactivate) must end with$this->cache = [];. Read-only methods should populate$this->cache['key']and return from it on repeat calls.