iflrandevu/application/models/Unavailabilities_model.php

446 lines
15 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php defined('BASEPATH') or exit('No direct script access allowed');
/* ----------------------------------------------------------------------------
* IFLRandevu - İzmir Fen Lisesi Randevu Portalı
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) Alex Tselegidis
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyunavailabilities.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* Unavailabilities model.
*
* @package Models
*/
class Unavailabilities_model extends EA_Model
{
/**
* @var array
*/
protected array $casts = [
'id' => 'integer',
'is_unavailability' => 'boolean',
'id_users_provider' => 'integer',
'id_users_customer' => 'integer',
'id_services' => 'integer',
];
/**
* @var array
*/
protected array $api_resource = [
'id' => 'id',
'book' => 'book_datetime',
'start' => 'start_datetime',
'end' => 'end_datetime',
'location' => 'location',
'color' => 'color',
'status' => 'status',
'notes' => 'notes',
'hash' => 'hash',
'providerId' => 'id_users_provider',
'googleCalendarId' => 'id_google_calendar',
];
/**
* Save (insert or update) an unavailability.
*
* @param array $unavailability Associative array with the unavailability data.
*
* @return int Returns the unavailability ID.
*
* @throws InvalidArgumentException
*/
public function save(array $unavailability): int
{
$this->validate($unavailability);
if (empty($unavailability['id'])) {
return $this->insert($unavailability);
} else {
return $this->update($unavailability);
}
}
/**
* Validate the unavailability data.
*
* @param array $unavailability Associative array with the unavailability data.
*
* @throws InvalidArgumentException
*/
public function validate(array $unavailability)
{
// If an unavailability ID is provided then check whether the record really exists in the database.
if (!empty($unavailability['id'])) {
$count = $this->db->get_where('appointments', ['id' => $unavailability['id']])->num_rows();
if (!$count) {
throw new InvalidArgumentException(
'The provided unavailability ID does not exist in the database: ' . $unavailability['id'],
);
}
}
// Make sure all required fields are provided.
if (
empty($unavailability['start_datetime']) ||
empty($unavailability['end_datetime']) ||
empty($unavailability['id_users_provider'])
) {
throw new InvalidArgumentException(
'Not all required fields are provided: ' . print_r($unavailability, true),
);
}
// Make sure that the provided unavailability date time values are valid.
if (!validate_datetime($unavailability['start_datetime'])) {
throw new InvalidArgumentException('The unavailability start date time is invalid.');
}
if (!validate_datetime($unavailability['end_datetime'])) {
throw new InvalidArgumentException('The unavailability end date time is invalid.');
}
// Make the unavailability lasts longer than the minimum duration (in minutes).
$diff = (strtotime($unavailability['end_datetime']) - strtotime($unavailability['start_datetime'])) / 60;
if ($diff < EVENT_MINIMUM_DURATION) {
throw new InvalidArgumentException(
'The unavailability duration cannot be less than ' . EVENT_MINIMUM_DURATION . ' minutes.',
);
}
// Make sure the provider ID really exists in the database.
$count = $this->db
->select()
->from('users')
->join('roles', 'roles.id = users.id_roles', 'inner')
->where('users.id', $unavailability['id_users_provider'])
->where('roles.slug', DB_SLUG_PROVIDER)
->get()
->num_rows();
if (!$count) {
throw new InvalidArgumentException(
'The unavailability provider ID was not found in the database: ' . $unavailability['id_users_provider'],
);
}
}
/**
* Get all unavailabilities that match the provided criteria.
*
* @param array|string|null $where Where conditions.
* @param int|null $limit Record limit.
* @param int|null $offset Record offset.
* @param string|null $order_by Order by.
*
* @return array Returns an array of unavailabilities.
*/
public function get(
array|string $where = null,
int $limit = null,
int $offset = null,
string $order_by = null,
): array {
if ($where !== null) {
$this->db->where($where);
}
if ($order_by) {
$this->db->order_by($order_by);
}
$unavailabilities = $this->db
->get_where('appointments', ['is_unavailability' => true], $limit, $offset)
->result_array();
foreach ($unavailabilities as &$unavailability) {
$this->cast($unavailability);
}
return $unavailabilities;
}
/**
* Insert a new unavailability into the database.
*
* @param array $unavailability Associative array with the unavailability data.
*
* @return int Returns the unavailability ID.
*
* @throws RuntimeException
*/
protected function insert(array $unavailability): int
{
$unavailability['book_datetime'] = date('Y-m-d H:i:s');
$unavailability['create_datetime'] = date('Y-m-d H:i:s');
$unavailability['update_datetime'] = date('Y-m-d H:i:s');
$unavailability['hash'] = random_string('alnum', 12);
$unavailability['is_unavailability'] = true;
if (!$this->db->insert('appointments', $unavailability)) {
throw new RuntimeException('Could not insert unavailability.');
}
return $this->db->insert_id();
}
/**
* Update an existing unavailability.
*
* @param array $unavailability Associative array with the unavailability data.
*
* @return int Returns the unavailability ID.
*
* @throws RuntimeException
*/
protected function update(array $unavailability): int
{
$unavailability['update_datetime'] = date('Y-m-d H:i:s');
if (!$this->db->update('appointments', $unavailability, ['id' => $unavailability['id']])) {
throw new RuntimeException('Could not update unavailability record.');
}
return $unavailability['id'];
}
/**
* Remove an existing unavailability from the database.
*
* @param int $unavailability_id Unavailability ID.
*
* @throws RuntimeException
*/
public function delete(int $unavailability_id): void
{
$this->db->delete('appointments', ['id' => $unavailability_id]);
}
/**
* Get a specific unavailability from the database.
*
* @param int $unavailability_id The ID of the record to be returned.
*
* @return array Returns an array with the unavailability data.
*
* @throws InvalidArgumentException
*/
public function find(int $unavailability_id): array
{
$unavailability = $this->db->get_where('appointments', ['id' => $unavailability_id])->row_array();
if (!$unavailability) {
throw new InvalidArgumentException(
'The provided unavailability ID was not found in the database: ' . $unavailability_id,
);
}
$this->cast($unavailability);
return $unavailability;
}
/**
* Get a specific field value from the database.
*
* @param int $unavailability_id Unavailability ID.
* @param string $field Name of the value to be returned.
*
* @return mixed Returns the selected unavailability value from the database.
*
* @throws InvalidArgumentException
*/
public function value(int $unavailability_id, string $field): mixed
{
if (empty($field)) {
throw new InvalidArgumentException('The field argument is cannot be empty.');
}
if (empty($unavailability_id)) {
throw new InvalidArgumentException('The unavailability ID argument cannot be empty.');
}
// Check whether the unavailability exists.
$query = $this->db->get_where('appointments', ['id' => $unavailability_id]);
if (!$query->num_rows()) {
throw new InvalidArgumentException(
'The provided unavailability ID was not found in the database: ' . $unavailability_id,
);
}
// Check if the required field is part of the unavailability data.
$unavailability = $query->row_array();
$this->cast($unavailability);
if (!array_key_exists($field, $unavailability)) {
throw new InvalidArgumentException(
'The requested field was not found in the unavailability data: ' . $field,
);
}
return $unavailability[$field];
}
/**
* Get the query builder interface, configured for use with the unavailabilities table.
*
* @return CI_DB_query_builder
*/
public function query(): CI_DB_query_builder
{
return $this->db->from('appointments');
}
/**
* Search unavailabilities by the provided keyword.
*
* @param string $keyword Search keyword.
* @param int|null $limit Record limit.
* @param int|null $offset Record offset.
* @param string|null $order_by Order by.
*
* @return array Returns an array of unavailabilities.
*/
public function search(string $keyword, int $limit = null, int $offset = null, string $order_by = null): array
{
$unavailabilities = $this->db
->select()
->from('appointments')
->join('users AS providers', 'providers.id = appointments.id_users_provider', 'inner')
->where('is_unavailability', true)
->group_start()
->like('appointments.start_datetime', $keyword)
->or_like('appointments.end_datetime', $keyword)
->or_like('appointments.location', $keyword)
->or_like('appointments.hash', $keyword)
->or_like('appointments.notes', $keyword)
->or_like('providers.first_name', $keyword)
->or_like('providers.last_name', $keyword)
->or_like('providers.email', $keyword)
->or_like('providers.phone_number', $keyword)
->group_end()
->limit($limit)
->offset($offset)
->order_by($order_by)
->get()
->result_array();
foreach ($unavailabilities as &$unavailability) {
$this->cast($unavailability);
}
return $unavailabilities;
}
/**
* Load related resources to an unavailability.
*
* @param array $unavailability Associative array with the unavailability data.
* @param array $resources Resource names to be attached ("service", "provider", "customer" supported).
*
* @throws InvalidArgumentException
*/
public function load(array &$unavailability, array $resources)
{
if (empty($unavailability) || empty($resources)) {
return;
}
foreach ($resources as $resource) {
$unavailability['provider'] = match ($resource) {
'provider' => $this->db
->get_where('users', [
'id' => $unavailability['id_users_provider'] ?? ($unavailability['providerId'] ?? null),
])
->row_array(),
default => throw new InvalidArgumentException(
'The requested unavailability relation is not supported: ' . $resource,
),
};
}
}
/**
* Convert the database unavailability record to the equivalent API resource.
*
* @param array $unavailability Unavailability data.
*/
public function api_encode(array &$unavailability)
{
$encoded_resource = [
'id' => array_key_exists('id', $unavailability) ? (int) $unavailability['id'] : null,
'book' => $unavailability['book_datetime'],
'start' => $unavailability['start_datetime'],
'end' => $unavailability['end_datetime'],
'hash' => $unavailability['hash'],
'location' => $unavailability['location'],
'notes' => $unavailability['notes'],
'providerId' =>
$unavailability['id_users_provider'] !== null ? (int) $unavailability['id_users_provider'] : null,
'googleCalendarId' =>
$unavailability['id_google_calendar'] !== null ? (int) $unavailability['id_google_calendar'] : null,
];
$unavailability = $encoded_resource;
}
/**
* Convert the API resource to the equivalent database unavailability record.
*
* @param array $unavailability API resource.
* @param array|null $base Base unavailability data to be overwritten with the provided values (useful for updates).
*/
public function api_decode(array &$unavailability, array $base = null)
{
$decoded_request = $base ?: [];
if (array_key_exists('id', $unavailability)) {
$decoded_request['id'] = $unavailability['id'];
}
if (array_key_exists('book', $unavailability)) {
$decoded_request['book_datetime'] = $unavailability['book'];
}
if (array_key_exists('start', $unavailability)) {
$decoded_request['start_datetime'] = $unavailability['start'];
}
if (array_key_exists('end', $unavailability)) {
$decoded_request['end_datetime'] = $unavailability['end'];
}
if (array_key_exists('hash', $unavailability)) {
$decoded_request['hash'] = $unavailability['hash'];
}
if (array_key_exists('location', $unavailability)) {
$decoded_request['location'] = $unavailability['location'];
}
if (array_key_exists('notes', $unavailability)) {
$decoded_request['notes'] = $unavailability['notes'];
}
if (array_key_exists('providerId', $unavailability)) {
$decoded_request['id_users_provider'] = $unavailability['providerId'];
}
if (array_key_exists('googleCalendarId', $unavailability)) {
$decoded_request['id_google_calendar'] = $unavailability['googleCalendarId'];
}
$decoded_request['is_unavailability'] = true;
$unavailability = $decoded_request;
}
}