Integrate Virkdata module with new routes, helpers, and configurations

- Added `virkdata` class to handle API operations for company information retrieval and config validation.
- Introduced `virkdata_i` interface and supporting helpers: `virkdata_request_parameters`, `virkdata_response`, and enums for formats, countries, and error codes.
- Implemented new routes: `/worker/debug`, `/worker/licenseplates`, `/cvr/lookup`, and `/economic/doesCustomerExist`.
- Added module `Virkdata` route for searching company data and fetching/updating configurations (`moduleVirkDataRoute`).
- Created `virkdata` module configurations: `enabled`, `secret_key`, and `monthly_limit`.
- Integrated virkdata initialization in `index.php`.
This commit is contained in:
Jeppe Bundgaard
2025-10-12 12:50:57 +02:00
parent 6f68713c7a
commit ca29ded6be
16 changed files with 841 additions and 0 deletions
+208
View File
@@ -0,0 +1,208 @@
<?php
namespace classes;
require_once WD . '/modules/virkdata/virkdata_c.php';
/** Actions */
require_once WD . '/modules/virkdata/actions/virkdata_search_a.php';
use Exception;
use modules\virkdata\helpers\virkdata_response;
use virkdata\actions\virkdata_search_a;
use virkdata\virkdata_c;
use interfaces\virkdata_i;
class virkdata implements virkdata_i
{
/**
* Configuration of the virkdata module
* @var virkdata_c
*/
public virkdata_c $config;
/**
* API URL
* @var string
*/
private string $api_url = 'https://api.virkdata.com/';
/**
* ACTION: VIRKDATA_SEARCH
* @see virkdata_search_a
* @notation This action is when a company search request is made, and logs the request in the database
* @var virkdata_search_a $virkdata_search
*/
private virkdata_search_a $virkdata_search;
public function __construct()
{
$this->config = new virkdata_c();
/** Actions */
$this->virkdata_search = new virkdata_search_a();
}
/**
* @inheritDoc
* @throws Exception If the base or target currency is invalid
* @throws Exception If the endpoint is invalid
* @throws Exception If the response is invalid
* @throws Exception If the response is not valid JSON
* @throws Exception If the request fails
*/
function getCompanyInformation(string $search, string $endpoint, array $data): \modules\virkdata\helpers\virkdata_response
{
// Send the request
// Return the conversion rate
return self::sendRequest($search, $endpoint, $data);
}
/**
* @inheritDoc
* @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
*/
function sendRequest(
string $search,
string $endpoint,
array $data = [],
string $method = 'GET'
): object
{
// Validate the module is enabled
self::requireModuleEnabled();
// Validate the secret key
self::requireValidSecretKey();
// Send the request
$response = match ($method) {
'GET' => self::sendGetRequest($search, $endpoint, $data),
//'POST' => self::sendPostRequest($search, $endpoint, $data),
//'PUT' => self::sendPutRequest($search, $endpoint, $data),
//'DELETE' => self::sendDeleteRequest($search, $endpoint, $data),
default => self::exception(
$search,
[
'method' => $method,
'endpoint' => $endpoint,
'data' => $data,
'search' => $search,
'response' => null,
'status_code' => 400,
'error' => 'Invalid request method',
],
500
),
};
// Add the usage to the request log
$this->virkdata_search->virkdata_search($search, $response, 200);
// Return the response
return $response;
}
/**
* @inheritDoc
*/
function requireModuleEnabled(): void
{
// Check if the module is enabled
if (!$this->config->enabled->isTrue()) {
throw new Exception('The virkdata module is not enabled');
}
}
/**
* @inheritDoc
*/
function requireValidSecretKey(): void
{
// Check if the secret key is valid
if ($this->config->secret_key->getVariableValue() === null) {
self::exception(
'',
[
'status_code' => 500,
'error' => 'Invalid secret key defined in the config (virkdata_secret_key_c)',
],
500
);
}
}
/**
* @throws Exception
*/
function exception(string $search, array $data, int $status_code = 500): object
{
// Check if the response is valid JSON
if (!json_decode($data['response'])) {
throw new Exception('Invalid response');
}
// Add the request to the log
$this->virkdata_search->virkdata_search($search, $data, $status_code);;
return throw new Exception($data['error'] ?? 'An error occurred while processing the request, in ' . $this->config->getModuleName() . ' module');
}
/**
* @inheritDoc
* @throws Exception
*/
function sendGetRequest(string $search, string $endpoint, array $data): virkdata_response
{
if (!empty($data)) {
$query_string = '?' . http_build_query($data);
} else {
$query_string = '';
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://virkdata.dk/api/?search={$search}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: {$this->config->secret_key->getVariableValue()}"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
}
// Get the status code
$status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// Check if the response is valid JSON
if (!json_decode($response)) {
$exception_message = match ($status_code) {
401 => 'Unauthorized',
404 => 'Not found',
429 => 'Too many requests',
default => 'Invalid response',
};
self::exception(
$search,
[
'method' => 'GET',
'endpoint' => $endpoint,
'data' => $data,
'response' => null,
'status_code' => $status_code,
'error' => $exception_message,
],
$status_code
);
}
return (new virkdata_response())->populate(json_decode($response, true));
}
}