diff --git a/application/models/Appointments_model.php b/application/models/Appointments_model.php index a757636c..52ddf91c 100644 --- a/application/models/Appointments_model.php +++ b/application/models/Appointments_model.php @@ -18,289 +18,205 @@ */ class Appointments_model extends EA_Model { /** - * Appointments_Model constructor. + * Appointments_model constructor. */ public function __construct() { parent::__construct(); - $this->load->helper('data_validation'); + + $this->load->helper('validation'); $this->load->helper('string'); } /** - * Add an appointment record to the database. + * Save (insert or update) an appointment. * - * This method adds a new appointment to the database. If the appointment doesn't exists it is going to be inserted, - * otherwise the record is going to be updated. + * @param array $appointment Associative array with the appointment data. * - * @param array $appointment Associative array with the appointment data. Each key has the same name with the - * database fields. + * @return int Returns the appointment ID. * - * @return int Returns the appointments id. - * @throws Exception + * @throws InvalidArgumentException */ - public function add($appointment) + public function save(array $appointment): int { - // Validate the appointment data before doing anything. $this->validate($appointment); - // Perform insert() or update() operation. - if ( ! isset($appointment['id'])) + if (empty($appointment['id'])) { - $appointment['id'] = $this->insert($appointment); + return $this->insert($appointment); } else { - $this->update($appointment); + return $this->update($appointment); } - - return $appointment['id']; } /** - * Validate appointment data before the insert or update operations are executed. + * Validate the appointment data. * - * @param array $appointment Contains the appointment data. + * @param array $appointment Associative array with the appointment data. * - * @return bool Returns the validation result. - * - * @throws Exception If appointment validation fails. + * @throws InvalidArgumentException */ - public function validate($appointment) + public function validate(array $appointment): void { - // If a appointment id is given, check whether the record exists in the database. - if (isset($appointment['id'])) + // If an appointment ID is provided then check whether the record really exists in the database. + if ( ! empty($appointment['id'])) { - $num_rows = $this->db->get_where('appointments', ['id' => $appointment['id']])->num_rows(); + $count = $this->db->get_where('appointments', ['id' => $appointment['id']])->num_rows(); - if ($num_rows === 0) + if ( ! $count) { - throw new Exception('Provided appointment id does not exist in the database.'); + throw new InvalidArgumentException('The provided appointment ID does not exist in the database: ' . $appointment['id']); } } - // Check if appointment dates are valid. - if ( ! validate_mysql_datetime($appointment['start_datetime'])) + // Make sure all required fields are provided. + if ( + empty($appointment['start_datetime']) + || empty($appointment['end_datetime']) + || empty($appointment['id_services']) + || empty($appointment['id_users_provider']) + || empty($appointment['id_users_customer']) + ) { - throw new Exception('Appointment start datetime is invalid.'); + throw new InvalidArgumentException('Not all required fields are provided: ' . print_r($appointment, TRUE)); } - if ( ! validate_mysql_datetime($appointment['end_datetime'])) + // Make sure that the provided appointment date time values are valid. + if ( ! validate_datetime($appointment['start_datetime'])) { - throw new Exception('Appointment end datetime is invalid.'); + throw new InvalidArgumentException('The appointment start date time is invalid.'); } - // Ensure the appointment lasts longer than the minimum duration (in minutes). + if ( ! validate_datetime($appointment['end_datetime'])) + { + throw new InvalidArgumentException('The appointment end date time is invalid.'); + } + + // Make the appointment lasts longer than the minimum duration (in minutes). $diff = (strtotime($appointment['end_datetime']) - strtotime($appointment['start_datetime'])) / 60; if ($diff < EVENT_MINIMUM_DURATION) { - throw new Exception('The appointment duration is less than the minimum duration (' - . EVENT_MINIMUM_DURATION . ' minutes).'); + throw new InvalidArgumentException('The appointment duration cannot be less than ' . EVENT_MINIMUM_DURATION . ' minutes.'); } - // Check if the provider's id is valid. - $num_rows = $this->db - ->select('*') + // 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', $appointment['id_users_provider']) ->where('roles.slug', DB_SLUG_PROVIDER) - ->get()->num_rows(); + ->get() + ->num_rows(); - if ($num_rows === 0) + if ( ! $count) { - throw new Exception('Appointment provider id is invalid.'); + throw new InvalidArgumentException('The appointment provider ID was not found in the database: ' . $appointment['id_users_provider']); } - if ($appointment['is_unavailable'] == FALSE) + if ( ! filter_var($appointment['is_unavailable'], FILTER_VALIDATE_BOOLEAN)) { - // Check if the customer's id is valid. - $num_rows = $this->db - ->select('*') + // Make sure the customer ID really exists in the database. + $count = $this + ->db + ->select() ->from('users') ->join('roles', 'roles.id = users.id_roles', 'inner') ->where('users.id', $appointment['id_users_customer']) ->where('roles.slug', DB_SLUG_CUSTOMER) ->get()->num_rows(); - if ($num_rows === 0) + if ( ! $count) { - throw new Exception('Appointment customer id is invalid.'); + throw new InvalidArgumentException('The appointment customer ID was not found in the database: ' . $appointment['id_users_customer']); } - // Check if the service id is valid. - $num_rows = $this->db->get_where('services', ['id' => $appointment['id_services']])->num_rows(); + // Make sure the service ID really exists in the database. + $count = $this->db->get_where('services', ['id' => $appointment['id_services']])->num_rows(); - if ($num_rows === 0) + if ( ! $count) { - throw new Exception('Appointment service id is invalid.'); + throw new InvalidArgumentException('Appointment service id is invalid.'); } } - - return TRUE; } /** - * Insert a new appointment record to the database. + * Insert a new appointment into the database. * - * @param array $appointment Associative array with the appointment's data. Each key has the same name with the - * database fields. + * @param array $appointment Associative array with the appointment data. * - * @return int Returns the id of the new record. + * @return int Returns the appointment ID. * - * @throws Exception If appointment record could not be inserted. + * @throws RuntimeException */ - protected function insert($appointment) + protected function insert(array $appointment): int { $appointment['book_datetime'] = date('Y-m-d H:i:s'); $appointment['hash'] = random_string('alnum', 12); if ( ! $this->db->insert('appointments', $appointment)) { - throw new Exception('Could not insert appointment record.'); + throw new RuntimeException('Could not insert appointment.'); } - return (int)$this->db->insert_id(); + return $this->db->insert_id(); } /** - * Update an existing appointment record in the database. + * Update an existing appointment. * - * The appointment data argument should already include the record ID in order to process the update operation. + * @param array $appointment Associative array with the appointment data. * - * @param array $appointment Associative array with the appointment's data. Each key has the same name with the - * database fields. + * @return int Returns the appointment ID. * - * @throws Exception If appointment record could not be updated. + * @throws RuntimeException */ - protected function update($appointment) + protected function update(array $appointment): int { $this->db->where('id', $appointment['id']); - if ( ! $this->db->update('appointments', $appointment)) + + if ( ! $this->db->update('appointments', $appointment, ['id' => $appointment['id']])) { - throw new Exception('Could not update appointment record.'); + throw new RuntimeException('Could not update appointment record.'); + } + + return $appointment['id']; + } + + /** + * Remove an existing appointment from the database. + * + * @param int $appointment_id Appointment ID. + * + * @throws RuntimeException + */ + public function delete(int $appointment_id): void + { + if ( ! $this->db->delete('users', ['id' => $appointment_id])) + { + throw new RuntimeException('Could not delete appointment.'); } } /** - * Check if a particular appointment record already exists. + * Get a specific appointment from the database. * - * This method checks whether the given appointment already exists in the database. It doesn't search with the id, - * but by using the following fields: "start_datetime", "end_datetime", "id_users_provider", "id_users_customer", - * "id_services". + * @param int $appointment_id The ID of the record to be returned. * - * @param array $appointment Associative array with the appointment's data. Each key has the same name with the - * database fields. + * @return array Returns an array with the appointment data. * - * @return bool Returns whether the record exists or not. - * - * @throws Exception If appointment fields are missing. + * @throws InvalidArgumentException */ - public function exists($appointment) + public function find(int $appointment_id): array { - if ( ! isset( - $appointment['start_datetime'], - $appointment['end_datetime'], - $appointment['id_users_provider'], - $appointment['id_users_customer'], - $appointment['id_services'] - )) + if ( ! $this->db->get_where('appointments', ['id' => $appointment_id])->num_rows()) { - throw new Exception('Not all appointment field values are provided: ' - . print_r($appointment, TRUE)); - } - - $num_rows = $this->db->get_where('appointments', [ - 'start_datetime' => $appointment['start_datetime'], - 'end_datetime' => $appointment['end_datetime'], - 'id_users_provider' => $appointment['id_users_provider'], - 'id_users_customer' => $appointment['id_users_customer'], - 'id_services' => $appointment['id_services'], - ]) - ->num_rows(); - - return $num_rows > 0; - } - - /** - * Find the database id of an appointment record. - * - * The appointment data should include the following fields in order to get the unique id from the database: - * "start_datetime", "end_datetime", "id_users_provider", "id_users_customer", "id_services". - * - * IMPORTANT: The record must already exists in the database, otherwise an exception is raised. - * - * @param array $appointment Array with the appointment data. The keys of the array should have the same names as - * the db fields. - * - * @return int Returns the db id of the record that matches the appointment data. - * - * @throws Exception If appointment could not be found. - */ - public function find_record_id($appointment) - { - $this->db->where([ - 'start_datetime' => $appointment['start_datetime'], - 'end_datetime' => $appointment['end_datetime'], - 'id_users_provider' => $appointment['id_users_provider'], - 'id_users_customer' => $appointment['id_users_customer'], - 'id_services' => $appointment['id_services'] - ]); - - $result = $this->db->get('appointments'); - - if ($result->num_rows() == 0) - { - throw new Exception('Could not find appointment record id.'); - } - - return $result->row()->id; - } - - /** - * Delete an existing appointment record from the database. - * - * @param int $appointment_id The record id to be deleted. - * - * @return bool Returns the delete operation result. - * - * @throws Exception If $appointment_id argument is invalid. - */ - public function delete($appointment_id) - { - if ( ! is_numeric($appointment_id)) - { - throw new Exception('Invalid argument type $appointment_id (value:"' . $appointment_id . '")'); - } - - $num_rows = $this->db->get_where('appointments', ['id' => $appointment_id])->num_rows(); - - if ($num_rows == 0) - { - return FALSE; // Record does not exist. - } - - $this->db->where('id', $appointment_id); - return $this->db->delete('appointments'); - } - - /** - * Get a specific row from the appointments table. - * - * @param int $appointment_id The record's id to be returned. - * - * @return array Returns an associative array with the selected record's data. Each key has the same name as the - * database field names. - * - * @throws Exception If $appointment_id argumnet is invalid. - */ - public function get_row($appointment_id) - { - if ( ! is_numeric($appointment_id)) - { - throw new Exception('Invalid argument given. Expected integer for the $appointment_id: ' - . $appointment_id); + throw new InvalidArgumentException('The provided appointment ID was not found in the database: ' . $appointment_id); } return $this->db->get_where('appointments', ['id' => $appointment_id])->row_array(); @@ -309,63 +225,55 @@ class Appointments_model extends EA_Model { /** * Get a specific field value from the database. * - * @param string $field_name The field name of the value to be returned. - * @param int $appointment_id The selected record's id. + * @param int $appointment_id Appointment ID. + * @param string $field Name of the value to be returned. * - * @return string Returns the records value from the database. + * @return string Returns the selected appointment value from the database. * - * @throws Exception If $appointment_id argument is invalid. - * @throws Exception If $field_name argument is invalid. - * @throws Exception If requested appointment record was not found. - * @throws Exception If requested field name does not exist. + * @throws InvalidArgumentException */ - public function get_value($field_name, $appointment_id) + public function value(int $appointment_id, string $field): string { - if ( ! is_numeric($appointment_id)) + if (empty($field)) { - throw new Exception('Invalid argument given, expected integer for the $appointment_id: ' - . $appointment_id); + throw new InvalidArgumentException('The field argument is cannot be empty.'); } - if ( ! is_string($field_name)) + if (empty($appointment_id)) { - throw new Exception('Invalid argument given, expected string for the $field_name: ' . $field_name); + throw new InvalidArgumentException('The appointment ID argument cannot be empty.'); } - if ($this->db->get_where('appointments', ['id' => $appointment_id])->num_rows() == 0) + // Check whether the appointment exists. + $query = $this->db->get_where('appointments', ['id' => $appointment_id]); + + if ( ! $query->num_rows()) { - throw new Exception('The record with the provided ID does not exist in the database: ' - . $appointment_id); + throw new InvalidArgumentException('The provided appointment ID was not found in the database: ' . $appointment_id); } - $row_data = $this->db->get_where('appointments', ['id' => $appointment_id])->row_array(); + // Check if the required field is part of the appointment data. + $appointment = $query->row_array(); - if ( ! array_key_exists($field_name, $row_data)) + if ( ! array_key_exists($field, $appointment)) { - throw new Exception('The given field name does not exist in the database: ' . $field_name); + throw new InvalidArgumentException('The requested field was not found in the appointment data: ' . $field); } - return $row_data[$field_name]; + return $appointment[$field]; } /** - * Get all, or specific records from appointment's table. + * Get all appointments that match the provided criteria. * - * Example: + * @param array|string $where Where conditions. + * @param int|null $limit Record limit. + * @param int|null $offset Record offset. + * @param string|null $order_by Order by. * - * $this->appointments_model->get_batch(['id' => $record_id]); - * - * @param mixed|null $where (OPTIONAL) The WHERE clause of the query to be executed. - * @param int|null $limit - * @param int|null $offset - * @param mixed|null $order_by - * @param bool $aggregates (OPTIONAL) Defines whether to add aggregations or not. - * - * @return array Returns the rows from the database. - * - * @throws Exception + * @return array Returns an array of appointments. */ - public function get_batch($where = NULL, $limit = NULL, $offset = NULL, $order_by = NULL, $aggregates = FALSE) + public function get($where = NULL, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array { if ($where !== NULL) { @@ -377,229 +285,262 @@ class Appointments_model extends EA_Model { $this->db->order_by($order_by); } - $appointments = $this->db->get('appointments', $limit, $offset)->result_array(); - - foreach ($appointments as &$appointment) - { - if ($aggregates) - { - $appointment = $this->get_aggregates($appointment); - } - } - - return $appointments; + return $this->db->get('appointments', $limit, $offset)->result_array(); } /** - * Get the aggregates of an appointment. + * Save (insert or update) an unavailable. * - * @param array $appointment Appointment data. + * @param array $unavailable Associative array with the unavailable data. * - * @return array Returns the appointment with the aggregates. + * @return int Returns the unavailable ID. + * + * @throws InvalidArgumentException */ - private function get_aggregates(array $appointment) + public function add_unavailable(array $unavailable): int { - $appointment['service'] = $this->db->get_where('services', [ - 'id' => $appointment['id_services'] - ])->row_array(); - - $appointment['provider'] = $this->db->get_where('users', [ - 'id' => $appointment['id_users_provider'] - ])->row_array(); - - $appointment['customer'] = $this->db->get_where('users', [ - 'id' => $appointment['id_users_customer'] - ])->row_array(); - - return $appointment; - } - - /** - * Inserts or updates an unavailable period record in the database. - * - * @param array $unavailable Contains the unavailable data. - * - * @return int Returns the record id. - * - * @throws Exception If unavailability validation fails. - * @throws Exception If provider record could not be found in database. - */ - public function add_unavailable($unavailable) - { - // Validate period + // Make sure the start date time is before the end date time. $start = strtotime($unavailable['start_datetime']); + $end = strtotime($unavailable['end_datetime']); if ($start > $end) { - throw new Exception('Unavailable period start must be prior to end.'); + throw new InvalidArgumentException('Unavailable period start date time must be before the end date time.'); } - // Validate provider record - $where_clause = [ + // Make sure the provider ID really exists in the database. + $role = $this->db->get_where('roles', ['slug' => DB_SLUG_PROVIDER])->row_array(); + + $count = $this->db->get_where('users', [ 'id' => $unavailable['id_users_provider'], - 'id_roles' => $this->db->get_where('roles', ['slug' => DB_SLUG_PROVIDER])->row()->id - ]; + 'id_roles' => $role['id'], + ])->num_rows(); - if ($this->db->get_where('users', $where_clause)->num_rows() == 0) + if ( ! $count) { - throw new Exception('Provider id was not found in database.'); + throw new InvalidArgumentException('Provider id was not found in database.'); } - // Add record to database (insert or update). - if ( ! isset($unavailable['id'])) + if (empty($unavailable['id'])) { $unavailable['book_datetime'] = date('Y-m-d H:i:s'); + $unavailable['is_unavailable'] = TRUE; $this->db->insert('appointments', $unavailable); - $unavailable['id'] = $this->db->insert_id(); + + return $this->db->insert_id(); } else { - $this->db->where(['id' => $unavailable['id']]); - $this->db->update('appointments', $unavailable); + return $this->db->update('appointments', $unavailable, ['id' => $unavailable['id']]); } - - return $unavailable['id']; } /** - * Delete an unavailable period. + * Remove an existing unavailable from the database. * * @param int $unavailable_id Record id to be deleted. * * @return bool Returns the delete operation result. - * - * @throws Exception If $unavailable_id argument is invalid. */ - public function delete_unavailable($unavailable_id) + public function delete_unavailable(int $unavailable_id): bool { - if ( ! is_numeric($unavailable_id)) - { - throw new Exception('Invalid argument type $unavailable_id: ' . $unavailable_id); - } - - $num_rows = $this->db->get_where('appointments', ['id' => $unavailable_id])->num_rows(); - - if ($num_rows === 0) - { - return FALSE; // Record does not exist. - } - - $this->db->where('id', $unavailable_id); - - return $this->db->delete('appointments'); + return $this->db->delete('appointments', ['id' => $unavailable_id]); } /** - * Clear google sync IDs from appointment record. + * Remove all the Google Calendar event IDs from appointment records. * - * @param int $provider_id The appointment provider record id. - * - * @throws Exception If $provider_id argument is invalid. + * @param int $provider_id Matching provider ID. */ - public function clear_google_sync_ids($provider_id) + public function clear_google_sync_ids(int $provider_id): void { - if ( ! is_numeric($provider_id)) - { - throw new Exception('Invalid argument type $provider_id: ' . $provider_id); - } - - $this->db->update('appointments', ['id_google_calendar' => NULL], [ - 'id_users_provider' => $provider_id - ]); + $this->db->update('appointments', ['id_google_calendar' => NULL], ['id_users_provider' => $provider_id]); } /** - * Get appointment count for the provided start datetime. + * Get the attendants number for the requested period. * - * @param int $service_id Selected service ID. - * @param string $selected_date Selected date string. - * @param string $hour Selected hour string. + * @param DateTime $start Period start. + * @param DateTime $end Period end. + * @param int $service_id Service ID. + * @param int $provider_id Provider ID. + * @param int|null $exclude_appointment_id Exclude an appointment from the result set. * - * @return int Returns the appointment number at the selected start time. + * @return int Returns the number of appointments that match the provided criteria. */ - public function appointment_count_for_hour($service_id, $selected_date, $hour) - { - return $this->db->get_where('appointments', [ - 'id_services' => $service_id, - 'start_datetime' => date('Y-m-d H:i:s', strtotime($selected_date . ' ' . $hour . ':00')) - ])->num_rows(); - } - - /** - * Returns the attendants number for selection period. - * - * @param DateTime $slot_start When the slot starts - * @param DateTime $slot_end When the slot ends. - * @param int $service_id Selected service ID. - * @param int $provider_id Selected provider ID. - * @param int|null $exclude_appointment_id Exclude an appointment from the availability generation. - * - * @return int Returns the number of attendants for selected time period. - */ - public function get_attendants_number_for_period(DateTime $slot_start, DateTime $slot_end, $service_id, $provider_id, $exclude_appointment_id = NULL) + public function get_attendants_number_for_period(DateTime $start, DateTime $end, int $service_id, int $provider_id, int $exclude_appointment_id = NULL): int { if ($exclude_appointment_id) { $this->db->where('id !=', $exclude_appointment_id); } - return (int)$this->db + $result = $this + ->db ->select('count(*) AS attendants_number') ->from('appointments') ->group_start() ->group_start() - ->where('start_datetime <=', $slot_start->format('Y-m-d H:i:s')) - ->where('end_datetime >', $slot_start->format('Y-m-d H:i:s')) + ->where('start_datetime <=', $start->format('Y-m-d H:i:s')) + ->where('end_datetime >', $start->format('Y-m-d H:i:s')) ->group_end() ->or_group_start() - ->where('start_datetime <', $slot_end->format('Y-m-d H:i:s')) - ->where('end_datetime >=', $slot_end->format('Y-m-d H:i:s')) + ->where('start_datetime <', $end->format('Y-m-d H:i:s')) + ->where('end_datetime >=', $end->format('Y-m-d H:i:s')) ->group_end() ->group_end() ->where('id_services', $service_id) ->where('id_users_provider', $provider_id) ->get() - ->row() - ->attendants_number; + ->row_array(); + + return $result['attendants_number']; } /** + * * Returns the number of the other service attendants number for the provided time slot. * - * @param DateTime $slot_start When the slot starts - * @param DateTime $slot_end When the slot ends. - * @param int $service_id Selected service ID. - * @param int|null $exclude_appointment_id Exclude an appointment from the availability generation. + * @param DateTime $start Period start. + * @param DateTime $end Period end. + * @param int $service_id Service ID. + * @param int $provider_id Provider ID. + * @param int|null $exclude_appointment_id Exclude an appointment from the result set. * - * @return int Returns the number of attendants for selected time period. + * @return int Returns the number of appointments that match the provided criteria. */ - public function get_other_service_attendants_number(DateTime $slot_start, DateTime $slot_end, $service_id, $provider_id, $exclude_appointment_id = NULL) + public function get_other_service_attendants_number(DateTime $start, DateTime $end, int $service_id, $provider_id, $exclude_appointment_id = NULL): int { if ($exclude_appointment_id) { $this->db->where('id !=', $exclude_appointment_id); } - return (int)$this->db + $result = $this + ->db ->select('count(*) AS attendants_number') ->from('appointments') ->group_start() ->group_start() - ->where('start_datetime <=', $slot_start->format('Y-m-d H:i:s')) - ->where('end_datetime >', $slot_start->format('Y-m-d H:i:s')) + ->where('start_datetime <=', $start->format('Y-m-d H:i:s')) + ->where('end_datetime >', $start->format('Y-m-d H:i:s')) ->group_end() ->or_group_start() - ->where('start_datetime <', $slot_end->format('Y-m-d H:i:s')) - ->where('end_datetime >=', $slot_end->format('Y-m-d H:i:s')) + ->where('start_datetime <', $end->format('Y-m-d H:i:s')) + ->where('end_datetime >=', $end->format('Y-m-d H:i:s')) ->group_end() ->group_end() ->where('id_services !=', $service_id) ->where('id_users_provider', $provider_id) ->get() - ->row() - ->attendants_number; + ->row_array(); + + return $result['attendants_number']; + } + + /** + * Get the query builder interface, configured for use with the appointments table. + * + * @return CI_DB_query_builder + */ + public function query(): CI_DB_query_builder + { + return $this->db->from('appointments'); + } + + /** + * Search appointments 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 appointments. + */ + public function search(string $keyword, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array + { + return $this + ->db + ->select() + ->from('appointments') + ->join('services', 'services.id = appointments.id_services', 'left') + ->join('users AS providers', 'providers.id = appointments.id_users_provider', 'inner') + ->join('users AS customers', 'customers.id = appointment.id_users_customer', 'left') + ->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('service.name', $keyword) + ->or_like('service.description', $keyword) + ->or_like('providers.first_name', $keyword) + ->or_like('providers.last_name', $keyword) + ->or_like('providers.email', $keyword) + ->or_like('providers.phone_number', $keyword) + ->or_like('customers.first_name', $keyword) + ->or_like('customers.last_name', $keyword) + ->or_like('customers.email', $keyword) + ->or_like('customers.phone_number', $keyword) + ->limit($limit) + ->offset($offset) + ->order_by($order_by) + ->get() + ->result_array(); + } + + /** + * Attach related resources to an appointment. + * + * @param array $appointment Associative array with the appointment data. + * @param array $resources Resource names to be attached ("service", "provider", "customer" supported). + * + * @throws InvalidArgumentException + */ + public function attach(array &$appointment, array $resources): void + { + if (empty($appointment) || empty($resources)) + { + return; + } + + foreach ($resources as $resource) + { + switch ($resource) + { + case 'service': + $appointment['service'] = $this + ->db + ->get_where('services', [ + 'id' => $appointment['id_services'] + ]) + ->row_array(); + break; + + case 'provider': + $appointment['provider'] = $this + ->db + ->get_where('users', [ + 'id' => $appointment['id_users_provider'] + ]) + ->row_array(); + break; + + case 'customer': + $appointment['customer'] = $this + ->db + ->get_where('users', [ + 'id' => $appointment['id_users_customer'] + ]) + ->row_array(); + break; + + default: + throw new InvalidArgumentException('The requested appointment relation is not supported: ' . $resource); + } + } } }