Add branding feature with form, route, and object implementations

Introduced a new branding functionality, including a `branding_o` object, `create_branding_f` form, and associated routes in `BrandingRoute`. Refactored the forms directory for better organization and added support for branding in departments. Extended validation, object handling, and response handling to accommodate this new feature.
This commit is contained in:
Jepp9350
2025-03-26 11:04:12 +01:00
parent 6f36dc230a
commit 4deef9dc09
11 changed files with 495 additions and 24 deletions
+8 -7
View File
@@ -9,16 +9,17 @@ require_once WD . '/traits/form_t.php';
require_once WD . '/modules/forms/form_helper_c.php';
use Exception;
use forms\book_interior_wash_f;
use forms\book_wash_f;
use forms\form_helper_c;
use forms\generate_booking_wash_certificate_f;
use forms\objects\book_interior_wash_f;
use forms\objects\book_wash_f;
use forms\objects\generate_booking_wash_certificate_f;
use traits\form_t;
/** Require the forms */
require_once WD . '/modules/forms/book_wash_f.php';
require_once WD . '/modules/forms/book_interior_wash_f.php';
require_once WD . '/modules/forms/generate_booking_wash_certificate_f.php';
/** Require the forms using glob */
foreach ( glob(WD . '/modules/forms/objects/*.php') as $filename ) {
require_once $filename;
}
class form
{
+7 -1
View File
@@ -31,7 +31,13 @@ class response implements response_i
}
// If the data isn't an array, convert it to an array
if (!is_array($data) && !is_object($data)) {
$data = ['message' => $data];
// Check if the variable is a valid JSON string
if (is_string($data) && json_decode($data) !== null) {
$data = json_decode($data, true);
} else {
// If the variable is not a valid JSON string, convert it to an array
$data = ['message' => $data];
}
}
// If the debug mode is enabled, add the debug data to the response
if ($DEBUG) {
@@ -1,8 +1,9 @@
<?php
namespace forms;
namespace forms\objects;
use classes\email;
use forms\form_helper_c;
use objects\departments_o;
use objects\users_o;
use traits\form_t;
@@ -1,8 +1,9 @@
<?php
namespace forms;
namespace forms\objects;
use classes\email;
use forms\form_helper_c;
use objects\bookings_new_o;
use objects\departments_o;
use objects\users_o;
@@ -0,0 +1,132 @@
<?php
namespace forms\objects;
use Exception;
use forms\form_helper_c;
use objects\branding_o;
use objects\departments_o;
use traits\form_t;
class create_branding_f extends form_helper_c
{
use form_t;
/**
* @inheritDoc
*/
public function sanitize(): void
{
foreach ( $this->form_unsanitized_data as $key => $value ) {
// Sanitize the input TODO: Implement the sanitization logic
$this->form_unsanitized_data[$key] = $value;
}
// Set the sanitized data
$this->form_sanitized_data = $this->form_unsanitized_data;
}
/**
* @inheritDoc
*/
public function validateInput(): void
{
}
/**
* @inheritDoc
*/
public function beforeSave(): void
{
// Check if the user has access to the booking
self::restrictAccessDepartment(
self::getSanitizedData('department_id'),
);
self::setDepartmentId(
self::getSanitizedData('department_id'),
);
// Check if the user has access to add branding options
self::requirePermission(
'add_branding_option',
'User does not have access to add branding option',
);
// Check if the user has access to add branding options
$department = (new departments_o())->select(self::getDepartmentId());
if ($department->branding->value() !== null) {
throw new Exception('Branding already exists for this department');
}
}
/**
* @inheritDoc
* @throws Exception If the creation of the branding object fails
*/
public function afterSubmit(): void
{
// Add the branding object
$branding = new branding_o();
$branding->add(
[
'name' => (string)self::getSanitizedData('name'),
'description' => (string)self::getSanitizedData('description'),
'cvr' => (int)self::getSanitizedData('cvr'),
],
);
// Set the departments branding id to the newly created branding id
$department = (new departments_o())->select(self::getDepartmentId());
$department->branding->set((int)$branding->id);
}
/**
* @inheritDoc
*/
public function setup(): void
{
self::setFormIdentifier('CREATE_BRANDING');
self::setFormName('Opret brand');
self::setFormDescription('Du kan oprette et unikt brand til afdelingen.');
self::setSubmitButtonText('Opret brand');
// Set the form fields
self::defineInputFieldsAdvanced([
'department_id' => [
'description' => 'Vælg den afdeling, som brandet skal tilknyttes.',
'required' => true,
'placeholder' => 'Vælg afdeling',
'label' => 'Afdeling',
'help' => 'Dette er afdelingen, som brandet skal tilknyttes.',
'error' => 'Du skal vælge en afdeling.',
'validation_method' => 'validateDepartmentId',
],
'name' => [
'description' => 'Dette navn bruges til at identificere brandet. Det ville være bedst at vælge et navn, der er let at huske og relaterer til brandet.',
'required' => true,
'placeholder' => 'Indtast brand navn',
'label' => 'Brand navn',
'help' => 'Dette er brand navnet, der bruges til at identificere brandet.',
'error' => 'Du skal indtaste et gyldigt brand navn.',
'validation_method' => 'validateString',
],
'description' => [
'description' => 'En beskrivelse af brandet, der forklarer, hvad det handler om. Dette kan være nyttigt for andre brugere.',
'required' => true,
'placeholder' => 'Indtast brand beskrivelse',
'label' => 'Brand beskrivelse',
'help' => 'Dette er brand beskrivelsen, der bruges til at forklare brandet.',
'error' => 'Du skal indtaste en gyldig brand beskrivelse.',
'validation_method' => 'validateString',
'default' => '',
],
'cvr' => [
'description' => 'CVR nummeret er et unikt identifikationsnummer for virksomheder i Danmark. Det er vigtigt at indtaste det korrekte CVR nummer, da det bruges til at identificere brandet.',
'required' => true,
'placeholder' => 'Indtast brand CVR nummer',
'label' => 'Brand CVR nummer',
'help' => 'Dette er brand CVR nummeret, der bruges til at identificere brandet.',
'error' => 'Du skal indtaste et gyldigt brand CVR nummer.',
'validation_method' => 'validateInt',
],
]);
}
}
@@ -1,7 +1,8 @@
<?php
namespace forms;
namespace forms\objects;
use forms\form_helper_c;
use objects\bookings_new_o;
use traits\form_t;
+136
View File
@@ -0,0 +1,136 @@
<?php
namespace objects;
use classes\db;
use classes\object_property;
use Exception;
use traits\db_object_t;
class branding_o extends db
{
use db_object_t;
public object_property $name;
public object_property $description;
public object_property $cvr;
public object_property $address;
public object_property $phone_country_code;
public object_property $phone;
public object_property $email;
public object_property $website;
public object_property $banner;
public object_property $logo;
public object_property $favicon;
public object_property $signature;
public function structure(): void
{
$this->setTable('branding');
}
/**
* Add a branding object
* @param array $data The additional data of the branding (e.g. ["key" => "value"])
* @return void
* @throws Exception If the object was not created successfully
*/
public function add(
array $data,
): void
{
global /** @var db $db */
$db;
// Define the default values
$default_values = [
'name' => null,
'description' => null,
'cvr' => null,
'address' => null,
'phone_country_code' => null,
'phone' => null,
'email' => null,
'website' => null,
'banner' => null,
'logo' => null,
'favicon' => null,
'signature' => null,
];
// Sanitize the input
$sanitized_data = [];
foreach ( $data as $key => $value ) {
// Sanitize the input
if (array_key_exists($key, $default_values)) {
// If the value is null, skip it
if (is_null($value)) {
continue;
} elseif (is_string($value)) {
$sanitized_data[$key] = $db->escape_string($value);
} elseif (is_int($value)) {
$sanitized_data[$key] = (int)$value;
} elseif (is_array($value)) {
$sanitized_data[$key] = json_encode($value);
} else {
throw new Exception("Invalid value type for key: $key");
}
} else {
throw new Exception("Invalid key: $key");
}
}
// Define the actual object values
$new_object = array_merge(
$default_values,
$sanitized_data
);
// Remove null values
$new_object = array_filter($new_object, function ($value) {
return !is_null($value);
});
// Add the object to the database
$new_id = self::add_object($new_object);
self::select($new_id);
}
public function getObjectProperties(): void
{
$this->name = new object_property($this->table, $this->id, 'name', 'string', false);
$this->description = new object_property($this->table, $this->id, 'description', 'string', false);
$this->cvr = new object_property($this->table, $this->id, 'cvr', 'int', false);
$this->address = new object_property($this->table, $this->id, 'address', 'string', false);
$this->phone_country_code = new object_property($this->table, $this->id, 'phone_country_code', 'int', false);
$this->phone = new object_property($this->table, $this->id, 'phone', 'int', false);
$this->email = new object_property($this->table, $this->id, 'email', 'string', false);
$this->website = new object_property($this->table, $this->id, 'website', 'string', false);
$this->banner = new object_property($this->table, $this->id, 'banner', 'string', false);
$this->logo = new object_property($this->table, $this->id, 'logo', 'string', false);
$this->favicon = new object_property($this->table, $this->id, 'favicon', 'string', false);
$this->signature = new object_property($this->table, $this->id, 'signature', 'string', false);
}
public function objectChanged(): void
{
//TODO: Add cache invalidation
}
public function asArray(): array
{
return [
'id' => (int)$this->id,
'name' => $this->name->value(),
'description' => $this->description->value(),
'cvr' => $this->cvr->value(),
'address' => $this->address->value(),
'phone_country_code' => $this->phone_country_code->value(),
'phone' => $this->phone->value(),
'email' => $this->email->value(),
'website' => $this->website->value(),
'banner' => $this->banner->value(),
'logo' => $this->logo->value(),
'favicon' => $this->favicon->value(),
'signature' => $this->signature->value(),
];
}
}
+2 -1
View File
@@ -18,6 +18,7 @@ class departments_o extends db
public object_property $slack_webhook; // The slack webhook for the department
public department_variables_o $variables; // The department variables object
public object_property $dimension; // The dimension of the department
public object_property $branding; // The branding of the department
public object_property $created_at;
public object_property $updated_at;
@@ -71,7 +72,7 @@ class departments_o extends db
$this->slack_webhook = new object_property($this->table, $this->id, 'slack_webhook', 'string', false);
$this->variables = (new department_variables_o())->selectDepartment($this->id);
$this->dimension = new object_property($this->table, $this->id, 'dimension', 'int', false);
$this->branding = new object_property($this->table, $this->id, 'branding', 'int', false);
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
}
+175
View File
@@ -0,0 +1,175 @@
<?php
namespace routes;
use classes\authentication;
use objects\branding_o;
use objects\logs_o;
use traits\route_t;
class BrandingRoute
{
use route_t;
public function run(): void
{
$this->get('/branding', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('list_branding_options');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Log the incident
(new logs_o())->add('branding', 'global', 1, $user->id, 'LIST_BRANDING_OPTIONS', 'User listed branding options');
// Check the user has specified the branding id
if (self::isParametersSet(['id'])) {
// Check if the parameters are of the correct type
self::requireType(self::getParameter('id'), self::TYPE_INT());
// Select the object
$branding = (new branding_o())->select(self::getParameter('id'));
// Check if the object exists
if ($branding->exists()) {
// Return the object as an array
$response->success(
(new branding_o())->select(self::getParameter('id'))->__toString()
);
} else {
// Log the incident
(new logs_o())->add('branding', 'global', 1, $user->id, 'LIST_BRANDING_OPTIONS', 'User tried to list branding options with an invalid id');
// Return an error
$response->error('Invalid id', 400);
}
}
// Return the list of departments
$response->success(
(new branding_o())
->listObjectsWithPaginationIfSet(
function ($branding) use ($user) {
// Return the object as an array
$tmp_branding = (new branding_o())->select($branding['id']);
return $tmp_branding->asArray();
}
)
);
} else {
// Log the incident
(new logs_o())->add('branding', 'global', 1, 0, 'LIST_BRANDING_OPTIONS', 'User tried to list branding options without being logged in');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'list_branding_options' => 'List all product options'
]
);
$this->post('/branding', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('add_branding_option');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Check if the required parameters are set
self::requireParameters(['name', 'description', 'cvr']);
// Check if the parameters are of the correct type
self::requireType(self::getParameter('name'), self::TYPE_STRING());
self::requireType(self::getParameter('description'), self::TYPE_STRING());
self::requireType(self::getParameter('cvr'), self::TYPE_INT());
// Create the object
$branding = new branding_o();
// Add the object
$branding->add(
[
'name' => self::getParameter('name'),
'description' => self::getParameter('description'),
'cvr' => self::getParameter('cvr')
]
);
// Log the incident
(new logs_o())->add('branding', 'global', 1, $user->id, 'ADD_BRANDING_OPTION', 'User added a branding option');
// Return the object
$response->success(
$branding->__toString()
);
} else {
// Log the incident
(new logs_o())->add('branding', 'global', 1, 0, 'ADD_BRANDING_OPTION', 'User tried to add a branding option without being logged in');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'add_branding_option' => 'Add a branding option'
]
);
$this->put('/branding', function () {
// Require the user to be logged in
global $response;
$this->requirePermission('edit_branding_option');
// Get the user object
$user = (new authentication())->get_user();
// Check if the request was successful
if ($user) {
// Check if the required parameters are set
self::requireParameters(['id']);
// Check if the parameters are of the correct type
self::requireType(self::getParameter('id'), self::TYPE_INT());
// Create the object
$branding = new branding_o();
// Select the object
$branding->select(self::getParameter('id'));
// Check what the user wants to edit
// Option name
if (self::isParametersSet(['name'])) {
// Check if the parameters are of the correct type
self::requireType(self::getParameter('name'), self::TYPE_STRING());
// Set the name
$branding->name->set(
(string)self::getParameter('name')
);
}
// Option description
if (self::isParametersSet(['description'])) {
// Check if the parameters are of the correct type
self::requireType(self::getParameter('description'), self::TYPE_STRING());
// Set the description
$branding->description->set(
(string)self::getParameter('description')
);
}
// Option cvr
if (self::isParametersSet(['cvr'])) {
// Check if the parameters are of the correct type
self::requireType(self::getParameter('cvr'), self::TYPE_INT());
// Set the cvr value
$branding->cvr->set(
(int)self::getParameter('cvr')
);
}
// Log the incident
(new logs_o())->add('branding', 'global', 1, $user->id, 'EDIT_BRANDING_OPTION', 'User edited a branding option');
// Return the object
$response->success(
$branding->__toString()
);
} else {
// Log the incident
(new logs_o())->add('branding', 'global', 1, 0, 'EDIT_BRANDING_OPTION', 'User tried to edit a branding option without being logged in');
// Return an error
$response->error('Invalid session', 400);
}
},
[
'edit_branding_option' => 'Edit a branding option'
]
);
}
}
+17 -11
View File
@@ -106,10 +106,27 @@ trait db_object_t
public function __toString(): string
{
self::requireSelected();
// Return the object as a string
// Check if the asArray function is set, if not, return the object row directly
if (method_exists($this, 'asArray')) {
return json_encode($this->asArray());
}
// If the asArray function is not set, return the object row directly
return json_encode($this->getArray());
}
/**
* Require selected object.
* Will throw an exception if object is not selected.
*/
public function requireSelected(): void
{
if (!$this->id) {
throw new Exception('Object not selected or does not exist in ' . $this->table);
}
}
/**
* Get current object row as an array
* @return array The current object row as an array
@@ -651,17 +668,6 @@ trait db_object_t
self::objectChanged();
}
/**
* Require selected object.
* Will throw an exception if object is not selected.
*/
public function requireSelected(): void
{
if (!$this->id) {
throw new Exception('Object not selected or does not exist in ' . $this->table);
}
}
/**
* Columns exist
* Check if all the columns in the array exist in the table
+12 -1
View File
@@ -4,7 +4,7 @@ namespace traits;
use classes\response;
use Exception;
use forms\book_wash_f;
use forms\objects\book_wash_f;
use objects\departments_o;
use objects\form_submissions_o;
use objects\users_o;
@@ -577,6 +577,17 @@ trait form_t
return preg_match('/^[1-9][0-9]*$/', $int) === 1;
}
/**
* Validation method for department ids
* @param int $int The integer to validate
* @return bool True if the integer is valid, false otherwise
*/
public function validateDepartmentId(int $int): bool
{
// Check if the department id is valid (A positive integer)
return preg_match('/^[1-9][0-9]*$/', $int) === 1;
}
/**
* Validation method for strings
* @param string $string The string to validate