feat: auto-create custom fields, add try/catch coverage, PHPDoc, and Pint formatting
All checks were successful
Publish Release / release (push) Successful in 10s

- Auto-create 'Initial Operating System' and 'Initial SSH Key' custom fields
  via Database::ensureCustomFields() on module load, eliminating the manual
  modify.sql step
- Delete modify.sql (no longer needed)
- Add try/catch blocks around every DB operation and API call across all PHP
  files per CLAUDE.md error handling rules
- Add comprehensive PHPDoc to all classes, methods, and properties
- Set up Laravel Pint (laravel/pint) with Laravel-style preset for consistent
  code formatting across the codebase
- Add git pre-commit hook (hooks/pre-commit) that runs Pint on staged PHP
  files, auto-installed via Composer post-install/post-update scripts
- Simplify README installation to a single copy-paste command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Prophet731
2026-03-19 15:03:17 -05:00
parent 1ab2ef42a5
commit d253bd44e6
22 changed files with 2384 additions and 1474 deletions

View File

@@ -4,13 +4,28 @@ namespace WHMCS\Module\Server\VirtFusionDirect;
use WHMCS\Database\Capsule as DB;
/**
* Handles all database operations for the module's custom table (mod_virtfusion_direct)
* and queries against core WHMCS tables (tblhosting, tblclients, tblservers, etc.).
*/
class Database
{
const SYSTEM_TABLE = 'mod_virtfusion_direct';
/** @var bool Tracks whether custom field existence has already been verified this request. */
private static $fieldsChecked = false;
/**
* Creates or migrates the module table schema and ensures custom fields exist.
*
* Creates mod_virtfusion_direct with service_id and server_id columns if absent,
* adds the server_object column if missing, then calls ensureCustomFields().
*
* @return void
*/
public static function schema()
{
if (!DB::schema()->hasTable(self::SYSTEM_TABLE)) {
if (! DB::schema()->hasTable(self::SYSTEM_TABLE)) {
try {
DB::schema()->create(self::SYSTEM_TABLE, function ($table) {
$table->unsignedBigInteger('service_id')->nullable()->default(null)->index();
@@ -22,7 +37,7 @@ class Database
}
}
if (!DB::schema()->hasColumn(self::SYSTEM_TABLE, 'server_object')) {
if (! DB::schema()->hasColumn(self::SYSTEM_TABLE, 'server_object')) {
try {
DB::schema()->table(self::SYSTEM_TABLE, function ($table) {
$table->longText('server_object')->nullable()->default(null);
@@ -31,92 +46,283 @@ class Database
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
self::ensureCustomFields();
}
/**
* Ensures the "Initial Operating System" and "Initial SSH Key" custom fields exist
* for every VirtFusionDirect product, creating them via upsert if absent.
*
* @return void
*/
public static function ensureCustomFields()
{
if (self::$fieldsChecked) {
return;
}
self::$fieldsChecked = true;
try {
$productIds = DB::table('tblproducts')
->where('servertype', 'VirtFusionDirect')
->pluck('id');
foreach ($productIds as $productId) {
foreach (['Initial Operating System', 'Initial SSH Key'] as $fieldName) {
DB::table('tblcustomfields')->updateOrInsert(
['type' => 'product', 'relid' => $productId, 'fieldname' => $fieldName],
[
'fieldtype' => 'text',
'description' => '',
'fieldoptions' => '',
'regexpr' => '',
'adminonly' => '',
'required' => '',
'showorder' => 'on',
'showinvoice' => '',
'sortorder' => 0,
'updated_at' => DB::raw('UTC_TIMESTAMP()'),
],
);
}
}
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
/**
* Fetches a VirtFusionDirect server record from tblservers.
*
* When $server is non-zero, returns the matching server by ID.
* When $any is true and $server is 0, returns the first enabled server.
*
* @param int $server WHMCS server ID to look up (0 to skip ID filter).
* @param bool $any If true, fall back to the first active server.
* @return object|false Row object on success, false on failure or not found.
*/
public static function getWhmcsServer(int $server, $any = false)
{
if ($server) {
return DB::table('tblservers')->where('type', 'VirtFusionDirect')->where('id', $server)->first();
}
try {
if ($server) {
return DB::table('tblservers')->where('type', 'VirtFusionDirect')->where('id', $server)->first();
}
if ($any) {
return DB::table('tblservers')->where('type', 'VirtFusionDirect')->where('disabled', 0)->first();
if ($any) {
return DB::table('tblservers')->where('type', 'VirtFusionDirect')->where('disabled', 0)->first();
}
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
return false;
}
/**
* Checks whether a WHMCS service belongs to the given client.
*
* @param int $serviceId WHMCS hosting service ID.
* @param int $userId WHMCS client ID.
* @return bool True if the service is owned by the client, false otherwise.
*/
public static function userWhmcsService(int $serviceId, int $userId)
{
return DB::table('tblhosting')->where('id', $serviceId)->where('userid', $userId)->exists();
try {
return DB::table('tblhosting')->where('id', $serviceId)->where('userid', $userId)->exists();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
return false;
}
}
/**
* Returns the WHMCS system URL from tblconfiguration.
*
* @return string The system URL, or an empty string if not found or on error.
*/
public static function getSystemUrl()
{
$url = DB::table('tblconfiguration')->where('setting', '=', 'SystemURL')->first();
if (!$url) return '';
return $url->value;
try {
$url = DB::table('tblconfiguration')->where('setting', '=', 'SystemURL')->first();
if (! $url) {
return '';
}
return $url->value;
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
return '';
}
}
/**
* Fetches a WHMCS client record by ID.
*
* @param int $id WHMCS client ID.
* @return object|null Row object on success, null on failure or not found.
*/
public static function getUser(int $id)
{
return DB::table('tblclients')->where('id', $id)->first();
try {
return DB::table('tblclients')->where('id', $id)->first();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
return null;
}
}
/**
* Fetches a WHMCS hosting service record by ID.
*
* @param int $serviceId WHMCS hosting service ID.
* @return object|null Row object on success, null on failure or not found.
*/
public static function getWhmcsService(int $serviceId)
{
return DB::table('tblhosting')->where('id', $serviceId)->first();
try {
return DB::table('tblhosting')->where('id', $serviceId)->first();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
return null;
}
}
/**
* Upserts the VirtFusion server ID for a given WHMCS service in the module table.
*
* @param int $serviceId WHMCS hosting service ID.
* @param int $serverId VirtFusion server ID.
* @return void
*/
public static function updateSystemServiceServerId(int $serviceId, int $serverId)
{
DB::table(self::SYSTEM_TABLE)->updateOrInsert(
[
"service_id" => $serviceId
],
[
'server_id' => $serverId
]
);
try {
DB::table(self::SYSTEM_TABLE)->updateOrInsert(
[
'service_id' => $serviceId,
],
[
'server_id' => $serverId,
],
);
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
/**
* Updates one or more WHMCS tables with the provided data for a given service ID.
*
* $data is keyed by table name; each value is an associative array of column => value
* pairs passed to an update() WHERE id = $serviceId.
*
* @param int $serviceId WHMCS hosting service ID.
* @param array $data Map of table name to column-value pairs to update.
* @return void
*/
public static function updateWhmcsServiceParams(int $serviceId, $data)
{
if (count($data)) {
foreach ($data as $key => $items) {
DB::table($key)->where('id', $serviceId)->update($items);
try {
if (count($data)) {
foreach ($data as $key => $items) {
DB::table($key)->where('id', $serviceId)->update($items);
}
}
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
/**
* Checks whether a module table record exists for the given service.
*
* @param int $serviceId WHMCS hosting service ID.
* @return bool True if a record exists, false otherwise.
*/
public static function checkSystemService(int $serviceId)
{
return DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->exists();
}
try {
return DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->exists();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
public static function deleteSystemService(int $serviceId)
{
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->delete();
}
public static function updateSystemServiceServerObject(int $serviceId, $data)
{
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->update(['server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
}
public static function systemOnServerCreate(int $serviceId, $data)
{
if (DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->exists()) {
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->update(['server_id' => $data->data->id, 'server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
} else {
DB::table(self::SYSTEM_TABLE)->insert(['service_id' => $serviceId, 'server_id' => $data->data->id, 'server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
return false;
}
}
public static function getSystemService(int $serviceId)
/**
* Deletes the module table record for the given service.
*
* @param int $serviceId WHMCS hosting service ID.
* @return void
*/
public static function deleteSystemService(int $serviceId)
{
return DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->first();
try {
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->delete();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
}
/**
* Persists the raw VirtFusion server API response as JSON in the module table.
*
* @param int $serviceId WHMCS hosting service ID.
* @param mixed $data Server object from the VirtFusion API (will be JSON-encoded).
* @return void
*/
public static function updateSystemServiceServerObject(int $serviceId, $data)
{
try {
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->update(['server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
/**
* Inserts or updates the module table record immediately after a VirtFusion server is created.
*
* Stores both the VirtFusion server ID (from $data->data->id) and the full server
* object JSON. Uses update if a record already exists, otherwise inserts.
*
* @param int $serviceId WHMCS hosting service ID.
* @param mixed $data Full API response object from the VirtFusion server creation call.
* @return void
*/
public static function systemOnServerCreate(int $serviceId, $data)
{
try {
if (DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->exists()) {
DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->update(['server_id' => $data->data->id, 'server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
} else {
DB::table(self::SYSTEM_TABLE)->insert(['service_id' => $serviceId, 'server_id' => $data->data->id, 'server_object' => json_encode($data, JSON_PRETTY_PRINT)]);
}
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
}
}
/**
* Fetches the module table record for the given service.
*
* @param int $serviceId WHMCS hosting service ID.
* @return object|null Row object on success, null on failure or not found.
*/
public static function getSystemService(int $serviceId)
{
try {
return DB::table(self::SYSTEM_TABLE)->where('service_id', $serviceId)->first();
} catch (\Exception $e) {
Log::insert(__FUNCTION__, [], $e->getMessage());
return null;
}
}
}