Add module action handling and license plate lookup logging
Implemented `module_action_t` trait to standardize module actions with validation, logging, and execution. Added `module_action_logs_o` for logging module actions and integrated `license_plate_lookup_a` in motorapi for license plate lookup requests. Enhanced error handling to log failed actions and provide detailed feedback.
This commit is contained in:
@@ -4,9 +4,12 @@ namespace classes;
|
||||
|
||||
require_once WD . '/modules/motorapi/motorapi_c.php';
|
||||
require_once WD . '/modules/motorapi/helpers/motorapi_vehicle_types.php';
|
||||
/** Actions */
|
||||
require_once WD . '/modules/motorapi/actions/license_plate_lookup_a.php';
|
||||
|
||||
use Exception;
|
||||
use interfaces\motorapi_i;
|
||||
use motorapi\actions\license_plate_lookup_a;
|
||||
use motorapi\helpers\motorapi_vehicle_types;
|
||||
use motorapi\motorapi_c;
|
||||
use objects\motorapi_lookups_o;
|
||||
@@ -30,10 +33,20 @@ class motorapi implements motorapi_i
|
||||
*/
|
||||
private string $api_url = 'https://v1.motorapi.dk/';
|
||||
|
||||
/**
|
||||
* ACTION: LICENSE_PLATE_LOOKUP
|
||||
* @see license_plate_lookup_a
|
||||
* @notation This action is when a license plate lookup request is made, and logs the request in the database
|
||||
* @var license_plate_lookup_a
|
||||
*/
|
||||
private license_plate_lookup_a $license_plate_lookup;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new motorapi_c();
|
||||
$this->vehicle_types = new motorapi_vehicle_types();
|
||||
/** Actions */
|
||||
$this->license_plate_lookup = new license_plate_lookup_a();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,8 +130,12 @@ class motorapi implements motorapi_i
|
||||
*/
|
||||
function getCachedResult(string $licensePlate): object
|
||||
{
|
||||
global /** @var response $response */
|
||||
$response;
|
||||
// Get the cached result from the log/local database/cache
|
||||
$motorapi_lookups = new motorapi_lookups_o();
|
||||
// Add the cached value to the meta
|
||||
$response->add_meta('cached', true);
|
||||
return json_decode($motorapi_lookups->getCachedResult($licensePlate)->result->value());
|
||||
}
|
||||
|
||||
@@ -142,7 +159,18 @@ class motorapi implements motorapi_i
|
||||
'POST' => self::sendPostRequest($licensePlate, $endpoint, $data),
|
||||
'PUT' => self::sendPutRequest($licensePlate, $endpoint, $data),
|
||||
'DELETE' => self::sendDeleteRequest($licensePlate, $endpoint, $data),
|
||||
default => throw new Exception('Invalid method'),
|
||||
default => self::exception(
|
||||
$licensePlate, [
|
||||
'method' => $method,
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => 400,
|
||||
'error' => 'Invalid request method',
|
||||
],
|
||||
500
|
||||
),
|
||||
};
|
||||
// Add the request to the log
|
||||
self::addRequestToLog($licensePlate, $endpoint, $response);
|
||||
@@ -179,10 +207,27 @@ class motorapi implements motorapi_i
|
||||
{
|
||||
// Check if the secret key is valid
|
||||
if ($this->config->secret_key->getVariableValue() === null) {
|
||||
throw new Exception('Invalid secret key');
|
||||
self::exception(
|
||||
'',
|
||||
[
|
||||
'status_code' => 500,
|
||||
'error' => 'Invalid secret key defined in the config (motorapi_secret_key_c)',
|
||||
],
|
||||
500
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
function exception(string $licensePlate, array $data = [], int $status_code = 500): exception
|
||||
{
|
||||
// Add the request to the log
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, $data, $status_code);
|
||||
return throw new Exception($data['error'] ?? 'An error occurred while processing the request, in ' . $this->config->getModuleName() . ' module');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception
|
||||
@@ -210,7 +255,18 @@ class motorapi implements motorapi_i
|
||||
|
||||
// Check for errors
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('cURL error: ' . curl_error($ch));
|
||||
self::exception(
|
||||
$licensePlate, [
|
||||
'method' => 'GET',
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => 500,
|
||||
'error' => curl_error($ch),
|
||||
],
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
// Get the status code
|
||||
@@ -225,8 +281,20 @@ class motorapi implements motorapi_i
|
||||
429 => 'Too many requests',
|
||||
default => 'Invalid response',
|
||||
};
|
||||
throw new Exception($exception_message);
|
||||
self::exception(
|
||||
$licensePlate, [
|
||||
'method' => 'GET',
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => $status_code,
|
||||
'error' => $exception_message,
|
||||
],
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), $status_code);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -243,6 +311,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -259,6 +328,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -275,6 +345,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace motorapi\actions;
|
||||
|
||||
use Exception;
|
||||
use traits\module_action_t;
|
||||
|
||||
class license_plate_lookup_a
|
||||
{
|
||||
use module_action_t;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module name is invalid
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
self::set_module_name('MOTORAPI');
|
||||
|
||||
/** Add the action to the list of valid actions */
|
||||
// LICENSE_PLATE_LOOKUP
|
||||
self::add_action(
|
||||
'LICENSE_PLATE_LOOKUP',
|
||||
'This action is when a license plate lookup request is made',
|
||||
// Method to call
|
||||
self::class . '::license_plate_lookup',
|
||||
[
|
||||
'license_plate' => 'The license plate that was looked up',
|
||||
'data' => 'The data returned from the lookup (If any)',
|
||||
'status_code' => 'The status code of the action',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* License plate lookup action
|
||||
* @param string $license_plate The license plate that was looked up
|
||||
* @param array|object $data The data returned from the lookup (If any)
|
||||
* @param int $status_code The status code of the action
|
||||
* @throws Exception If the action name is invalid
|
||||
* @throws Exception If the action data is invalid
|
||||
* @throws Exception If the action status code is invalid
|
||||
* @throws Exception If the action is not valid
|
||||
*/
|
||||
public function license_plate_lookup(string $license_plate, array|object $data = [], int $status_code = 0): void
|
||||
{
|
||||
self::set_action('LICENSE_PLATE_LOOKUP');
|
||||
// If the data is an object, convert it to an array
|
||||
if (is_object($data)) {
|
||||
$data = (array)$data;
|
||||
}
|
||||
// Validate the action data
|
||||
if (!is_array($data)) {
|
||||
throw new Exception('Action data is invalid');
|
||||
}
|
||||
// Validate the action status code
|
||||
self::set_data([
|
||||
'license_plate' => $license_plate,
|
||||
'data' => $data,
|
||||
]);
|
||||
self::set_status($status_code);
|
||||
// Add the action to the log
|
||||
self::add_action_log(
|
||||
self::get_action_name(),
|
||||
(int)self::get_status(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class module_action_logs_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
/**
|
||||
* The module name
|
||||
* @var object_property $module The module name
|
||||
*/
|
||||
public object_property $module;
|
||||
/**
|
||||
* The action name
|
||||
* @var object_property $action The action name
|
||||
*/
|
||||
public object_property $action;
|
||||
/**
|
||||
* The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
* @var object_property $status_code The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
*/
|
||||
public object_property $status_code;
|
||||
/**
|
||||
* The action data
|
||||
* @var object_property $data The data JSON encoded
|
||||
*/
|
||||
public object_property $data;
|
||||
/**
|
||||
* The action created at
|
||||
* @var object_property $created_at The action created at
|
||||
*/
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('module_usage_logs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a module action log
|
||||
* @param string $module The module name
|
||||
* @param string $action The action name
|
||||
* @param int $status_code The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
* @param array $data The action data
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $module, string $action, int $status_code, array $data): void
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$module = $db->escape_string($module);
|
||||
$action = $db->escape_string($action);
|
||||
$status_code = (int)$status_code;
|
||||
// JSON encode the data
|
||||
$encoded_data = $db->escape_string(json_encode($data));
|
||||
// Add the object
|
||||
$tmp_id = self::add_object([
|
||||
'module' => $module,
|
||||
'action' => $action,
|
||||
'status_code' => $status_code,
|
||||
'data' => $encoded_data,
|
||||
]);
|
||||
if (!$tmp_id) {
|
||||
throw new Exception('The object was not created successfully.');
|
||||
}
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->module = new object_property($this->table, $this->id, 'module', 'string', false);
|
||||
$this->action = new object_property($this->table, $this->id, 'action', 'string', false);
|
||||
$this->status_code = new object_property($this->table, $this->id, 'status_code', 'int', false);
|
||||
$this->data = new object_property($this->table, $this->id, 'data', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'datetime', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object as an array
|
||||
* @return array The object as an array
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'module' => (string)$this->module->value(),
|
||||
'action' => (string)$this->action->value(),
|
||||
'status_code' => (int)$this->status_code->value(),
|
||||
'data' => self::decodeData((string)$this->data->value()),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the data
|
||||
* @param string $data The data JSON encoded
|
||||
* @return array The data
|
||||
*/
|
||||
public static function decodeData(string $data): array
|
||||
{
|
||||
return json_decode($data, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace traits;
|
||||
|
||||
use Exception;
|
||||
use motorapi\actions\license_plate_lookup_a;
|
||||
use objects\module_action_logs_o;
|
||||
|
||||
trait module_action_t
|
||||
{
|
||||
/**
|
||||
* The module name
|
||||
* @var string The module name
|
||||
*/
|
||||
private string $module = '';
|
||||
/**
|
||||
* The modules valid actions
|
||||
* @var array The modules valid actions
|
||||
*/
|
||||
private array $actions = [];
|
||||
/**
|
||||
* The relevant data for the action (Only set when the action is called)
|
||||
* @var array Data for the action
|
||||
*/
|
||||
private array $data = [];
|
||||
/**
|
||||
* The HTTP status code, if not set, defaults to 0
|
||||
* @var int HTTP status code
|
||||
*/
|
||||
private int $status = 0;
|
||||
/**
|
||||
* The action name (Only set when the action is called)
|
||||
* @var string The action name
|
||||
* @see set_action() - Sets the action name
|
||||
* @see get_action() - Gets the action name
|
||||
*/
|
||||
private string $action = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @throws Exception If the module name is invalid
|
||||
* @throws Exception If the action name is invalid
|
||||
* @throws Exception If the action is not valid
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Run the run method
|
||||
self::run();
|
||||
}
|
||||
|
||||
/**
|
||||
* The run method, to be implemented by the module
|
||||
* This should be used to define the following:
|
||||
* - The module name
|
||||
* - The actions
|
||||
* @return void
|
||||
*/
|
||||
abstract public function run(): void;
|
||||
|
||||
/**
|
||||
* Set the action name
|
||||
* @param string $action The action name
|
||||
* @return module_action_t|license_plate_lookup_a
|
||||
* @throws Exception If the action name is invalid
|
||||
*/
|
||||
public function set_action(string $action): self
|
||||
{
|
||||
self::validate_action_name($action);
|
||||
$this->action = strtoupper($action);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the action name
|
||||
* @param string $action The action name
|
||||
* @return void
|
||||
* @throws Exception If the action name is empty
|
||||
* @throws Exception If the action name is invalid (only letters, numbers and underscores are allowed)
|
||||
* @throws Exception If the action name is longer than 50 characters
|
||||
* @throws Exception If the action name is shorter than 3 characters
|
||||
*/
|
||||
private static function validate_action_name(string $action): void
|
||||
{
|
||||
// Action name cannot be empty
|
||||
if (empty($action)) {
|
||||
throw new Exception('Action name cannot be empty');
|
||||
}
|
||||
// Action name can only contain letters, numbers and underscores
|
||||
if (!preg_match('/^[a-zA-Z0-9_]+$/', $action)) {
|
||||
throw new Exception('Action name can only contain letters, numbers and underscores');
|
||||
}
|
||||
// Action name cannot be longer than 50 characters
|
||||
if (strlen($action) > 50) {
|
||||
throw new Exception('Action name cannot be longer than 50 characters');
|
||||
}
|
||||
// Action name cannot be shorter than 3 characters
|
||||
if (strlen($action) < 3) {
|
||||
throw new Exception('Action name cannot be shorter than 3 characters');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the module name
|
||||
* @param string $module The module name
|
||||
* @return module_action_t|license_plate_lookup_a
|
||||
* @throws Exception If the module name is invalid
|
||||
*/
|
||||
public function set_module_name(string $module): self
|
||||
{
|
||||
self::validate_module_name($module);
|
||||
$this->module = strtoupper($module);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the module name
|
||||
* @param string $module The module name
|
||||
* @return void
|
||||
* @throws Exception If the module name is empty
|
||||
* @throws Exception If the module name is invalid (only letters, numbers and underscores are allowed)
|
||||
* @throws Exception If the module name is longer than 50 characters
|
||||
* @throws Exception If the module name is shorter than 3 characters
|
||||
*/
|
||||
private static function validate_module_name(string $module): void
|
||||
{
|
||||
// Module name cannot be empty
|
||||
if (empty($module)) {
|
||||
throw new Exception('Module name cannot be empty');
|
||||
}
|
||||
// Module name can only contain letters, numbers and underscores
|
||||
if (!preg_match('/^[a-zA-Z0-9_]+$/', $module)) {
|
||||
throw new Exception('Module name can only contain letters, numbers and underscores');
|
||||
}
|
||||
// Module name cannot be longer than 50 characters
|
||||
if (strlen($module) > 50) {
|
||||
throw new Exception('Module name cannot be longer than 50 characters');
|
||||
}
|
||||
// Module name cannot be shorter than 3 characters
|
||||
if (strlen($module) < 3) {
|
||||
throw new Exception('Module name cannot be shorter than 3 characters');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an action to the module
|
||||
* @param string $action The action name
|
||||
* @param string $description The action description
|
||||
* @param callable $callback The action callback function
|
||||
* @param array $parameters The action parameters
|
||||
* @return module_action_t|license_plate_lookup_a
|
||||
* @throws Exception If the action name is invalid
|
||||
*/
|
||||
public function add_action(string $action, string $description, callable $callback, array $parameters = []): self
|
||||
{
|
||||
// Validate the action name
|
||||
self::validate_action_name($action);
|
||||
// Check if the action name is already set
|
||||
if (isset($this->actions[$action])) {
|
||||
throw new Exception('Action name is already set');
|
||||
}
|
||||
// Check if the action callback function is callable
|
||||
if (!is_callable($callback)) {
|
||||
throw new Exception('Action callback function is not callable');
|
||||
}
|
||||
// Check if the action parameters are an array
|
||||
if (!is_array($parameters)) {
|
||||
throw new Exception('Action parameters are not an array');
|
||||
}
|
||||
// Add the action to the module
|
||||
$this->actions[$action] = [
|
||||
'description' => $description,
|
||||
'callback' => $callback,
|
||||
'parameters' => $parameters
|
||||
];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action name
|
||||
* @return string The action name
|
||||
*/
|
||||
public function get_action_name(): string
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions
|
||||
* @return array The actions
|
||||
*/
|
||||
public function get_actions(): array
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to the action
|
||||
* @param array $data The data to be added
|
||||
* @return self
|
||||
*/
|
||||
public function add_data(array $data): self
|
||||
{
|
||||
$this->data = array_merge($this->data, $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP status code
|
||||
* @return int The HTTP status code
|
||||
*/
|
||||
public function get_status(): int
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP status code
|
||||
* @param int $status The HTTP status code
|
||||
* @return self
|
||||
*/
|
||||
public function set_status(int $status): self
|
||||
{
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add action log to the database
|
||||
* @param string $action The action name
|
||||
* @param int $status The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
* @return self
|
||||
* @throws Exception If the action name is empty
|
||||
* @throws Exception If the action status code is empty
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add_action_log(string $action, int $status = 0): self
|
||||
{
|
||||
// Validate the action name
|
||||
if (empty($action)) {
|
||||
throw new Exception('Action name cannot be empty');
|
||||
}
|
||||
// Validate the action status code
|
||||
if (empty($status)) {
|
||||
throw new Exception('Action status code cannot be empty');
|
||||
}
|
||||
|
||||
// Add action log to the database
|
||||
$module_action_log = new module_action_logs_o();
|
||||
$module_action_log->add(self::get_module_name(), (string)$action, (int)$status, self::get_data());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module name
|
||||
* @return string The module name
|
||||
* @throws Exception If the module name isn't set
|
||||
*/
|
||||
public function get_module_name(): string
|
||||
{
|
||||
if (empty($this->module)) {
|
||||
throw new Exception('Module name is not set');
|
||||
}
|
||||
return $this->module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data
|
||||
* @return array The data
|
||||
*/
|
||||
public function get_data(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data
|
||||
* @param array $data The data to be returned
|
||||
* @return self
|
||||
*/
|
||||
public function set_data(array $data): self
|
||||
{
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user