diff --git a/application/models/Services_model.php b/application/models/Services_model.php index 140f8504..335ed023 100644 --- a/application/models/Services_model.php +++ b/application/models/Services_model.php @@ -12,103 +12,81 @@ * ---------------------------------------------------------------------------- */ /** - * Services Model + * Services model + * + * Handles all the database operations of the service resource. * * @package Models */ class Services_model extends EA_Model { /** - * Services_Model constructor. - */ - public function __construct() - { - parent::__construct(); - $this->load->helper('data_validation'); - } - - /** - * Add (insert or update) a service record on the database + * Save (insert or update) a service. * - * @param array $service Contains the service data. If an 'id' value is provided then the record will be updated. + * @param array $service Associative array with the service data. * - * @return int Returns the record id. - * @throws Exception + * @return int Returns the service ID. + * + * @throws InvalidArgumentException */ - public function add($service) + public function save(array $service): int { $this->validate($service); - if ( ! isset($service['id'])) + if (empty($service['id'])) { - $service['id'] = $this->insert($service); + return $this->insert($service); } else { - $this->update($service); + return $this->update($service); } - - return (int)$service['id']; } /** - * Validate a service record data. + * Validate the service data. * - * @param array $service Contains the service data. + * @param array $service Associative array with the service data. * - * @return bool Returns the validation result. - * - * @throws Exception If service validation fails. + * @throws InvalidArgumentException */ - public function validate($service) + public function validate(array $service): void { - // If record id is provided we need to check whether the record exists in the database. - if (isset($service['id'])) + // If a service ID is provided then check whether the record really exists in the database. + if ( ! empty($service['id'])) { - $num_rows = $this->db->get_where('services', ['id' => $service['id']])->num_rows(); + $count = $this->db->get_where('services', ['id' => $service['id']])->num_rows(); - if ($num_rows == 0) + if ( ! $count) { - throw new Exception('Provided service id does not exist in the database.'); + throw new InvalidArgumentException('The provided service ID does not exist in the database: ' . $service['id']); } } - // Check if service category id is valid (only when present). + // Make sure all required fields are provided. + if ( + empty($service['name']) + ) + { + throw new InvalidArgumentException('Not all required fields are provided: ' . print_r($service, TRUE)); + } + + // If a category was provided then make sure it really exists in the database. if ( ! empty($service['id_service_categories'])) { - $num_rows = $this->db->get_where('service_categories', - ['id' => $service['id_service_categories']])->num_rows(); - if ($num_rows == 0) + $count = $this->db->get_where('service_categories', ['id' => $service['id_service_categories']])->num_rows(); + + if ( ! $count) { - throw new Exception('Provided service category id does not exist in database.'); + throw new InvalidArgumentException('The provided category ID was not found in the database: ' . $service['id_service_categories']); } } - // Check for required fields - if ($service['name'] == '') + // Make sure the duration value is valid. + if ( ! empty($service['duration'])) { - throw new Exception('Not all required service fields where provided: ' - . print_r($service, TRUE)); - } - - // Duration must be int - if ($service['duration'] !== NULL) - { - if ( ! is_numeric($service['duration'])) - { - throw new Exception('Service duration is not numeric.'); - } - if ((int)$service['duration'] < EVENT_MINIMUM_DURATION) { - throw new Exception('The service duration cannot be less than ' . EVENT_MINIMUM_DURATION . ' minutes.'); - } - } - - if ($service['price'] !== NULL) - { - if ( ! is_numeric($service['price'])) - { - throw new Exception('Service price is not numeric.'); + throw new InvalidArgumentException('The service duration cannot be less than ' . EVENT_MINIMUM_DURATION . ' minutes long.'); } } @@ -120,219 +98,146 @@ class Services_model extends EA_Model { . ' or ' . AVAILABILITIES_TYPE_FIXED . ' (given ' . $service['availabilities_type'] . ')'); } - if ($service['attendants_number'] !== NULL && ( ! is_numeric($service['attendants_number']) - || $service['attendants_number'] < 1)) + // Validate the availabilities type value. + if ( + ! empty($service['availabilities_type']) + && ! in_array($service['availabilities_type'], [AVAILABILITIES_TYPE_FLEXIBLE, AVAILABILITIES_TYPE_FIXED]) + ) { - throw new Exception('Service attendants number must be numeric and greater or equal to one: ' - . $service['attendants_number']); + throw new InvalidArgumentException('The provided availabilities type is invalid: ' . $service['availabilities_type']); } - return TRUE; + // Validate the attendants number value. + if (empty($service['attendants_number']) || (int)$service['attendants_number'] < 1) + { + throw new InvalidArgumentException('The provided attendants number is invalid: ' . $service['attendants_number']); + } } /** - * Insert service record into database. + * Insert a new service into the database. * - * @param array $service Contains the service record data. + * @param array $service Associative array with the service data. * - * @return int Returns the new service record id. + * @return int Returns the service ID. * - * @throws Exception If service record could not be inserted. + * @throws RuntimeException */ - protected function insert($service) + protected function insert(array $service): int { if ( ! $this->db->insert('services', $service)) { - throw new Exception('Could not insert service record.'); + throw new RuntimeException('Could not insert service.'); } - return (int)$this->db->insert_id(); + + return $this->db->insert_id(); } /** - * Update service record. + * Update an existing service. * - * @param array $service Contains the service data. The record id needs to be included in the array. + * @param array $service Associative array with the service data. * - * @throws Exception If service record could not be updated. + * @return int Returns the service ID. + * + * @throws RuntimeException */ - protected function update($service) + protected function update(array $service): int { - $this->db->where('id', $service['id']); - if ( ! $this->db->update('services', $service)) + if ( ! $this->db->update('services', $service, ['id' => $service['id']])) { - throw new Exception('Could not update service record'); + throw new RuntimeException('Could not update service.'); + } + + return $service['id']; + } + + /** + * Remove an existing service from the database. + * + * @param int $service_id Service ID. + * + * @throws RuntimeException + */ + public function delete(int $service_id): void + { + if ( ! $this->db->delete('services', ['id' => $service_id])) + { + throw new RuntimeException('Could not delete service.'); } } /** - * Checks whether an service record already exists in the database. + * Get a specific service from the database. * - * @param array $service Contains the service data. Name, duration and price values are mandatory in order to - * perform the checks. + * @param int $service_id The ID of the record to be returned. * - * @return bool Returns whether the service record exists. + * @return array Returns an array with the service data. * - * @throws Exception If required fields are missing. + * @throws InvalidArgumentException */ - public function exists($service) + public function find(int $service_id): array { - if ( ! isset( - $service['name'], - $service['duration'], - $service['price'] - )) + if ( ! $this->db->get_where('services', ['id' => $service_id])->num_rows()) { - throw new Exception('Not all service fields are provided in order to check whether ' - . 'a service record already exists: ' . print_r($service, TRUE)); + throw new InvalidArgumentException('The provided service ID was not found in the database: ' . $service_id); } - $num_rows = $this->db->get_where('services', [ - 'name' => $service['name'], - 'duration' => $service['duration'], - 'price' => $service['price'] - ])->num_rows(); - - return $num_rows > 0; - } - - /** - * Get the record id of an existing record. - * - * Notice: The record must exist, otherwise an exception will be raised. - * - * @param array $service Contains the service record data. Name, duration and price values are mandatory for this - * method to complete. - * - * @return int - * - * @throws Exception If required fields are missing. - * @throws Exception If requested service was not found. - */ - public function find_record_id($service) - { - if ( ! isset($service['name']) - || ! isset($service['duration']) - || ! isset($service['price'])) - { - throw new Exception('Not all required fields where provided in order to find the ' - . 'service record id.'); - } - - $result = $this->db->get_where('services', [ - 'name' => $service['name'], - 'duration' => $service['duration'], - 'price' => $service['price'] - ]); - - if ($result->num_rows() == 0) - { - throw new Exception('Could not find service record id'); - } - - return $result->row()->id; - } - - /** - * Delete a service record from database. - * - * @param int $service_id Record id to be deleted. - * - * @return bool Returns the delete operation result. - * - * @throws Exception If $service_id argument is invalid. - */ - public function delete($service_id) - { - if ( ! is_numeric($service_id)) - { - throw new Exception('Invalid argument type $service_id (value:"' . $service_id . '"'); - } - - $num_rows = $this->db->get_where('services', ['id' => $service_id])->num_rows(); - if ($num_rows == 0) - { - return FALSE; // Record does not exist - } - - return $this->db->delete('services', ['id' => $service_id]); - } - - /** - * Get a specific row from the services db table. - * - * @param int $service_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 $service_id argument is not valid. - */ - public function get_row($service_id) - { - if ( ! is_numeric($service_id)) - { - throw new Exception('$service_id argument is not an numeric (value: "' . $service_id . '")'); - } return $this->db->get_where('services', ['id' => $service_id])->row_array(); } /** * Get a specific field value from the database. * - * @param string $field_name The field name of the value to be - * returned. - * @param int $service_id The selected record's id. + * @param int $service_id Service 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 service value from the database. * - * @throws Exception If $service_id argument is invalid. - * @throws Exception If $field_name argument is invalid. - * @throws Exception if requested service does not exist in the database. - * @throws Exception If requested field name does not exist in the database. + * @throws InvalidArgumentException */ - public function get_value($field_name, $service_id) + public function value(int $service_id, string $field): string { - if ( ! is_numeric($service_id)) + if (empty($field)) { - throw new Exception('Invalid argument provided as $service_id: ' . $service_id); + throw new InvalidArgumentException('The field argument is cannot be empty.'); } - if ( ! is_string($field_name)) + if (empty($service_id)) { - throw new Exception('$field_name argument is not a string: ' . $field_name); + throw new InvalidArgumentException('The service ID argument cannot be empty.'); } - if ($this->db->get_where('services', ['id' => $service_id])->num_rows() == 0) + // Check whether the service exists. + $query = $this->db->get_where('services', ['id' => $service_id]); + + if ( ! $query->num_rows()) { - throw new Exception('The record with the $service_id argument does not exist in the database: ' . $service_id); + throw new InvalidArgumentException('The provided service ID was not found in the database: ' . $service_id); } - $row_data = $this->db->get_where('services', ['id' => $service_id])->row_array(); + // Check if the required field is part of the service data. + $service = $query->row_array(); - if ( ! array_key_exists($field_name, $row_data)) + if ( ! array_key_exists($field, $service)) { - throw new Exception('The given $field_name argument does not exist in the database: ' - . $field_name); + throw new InvalidArgumentException('The requested field was not found in the service data: ' . $field); } - return $row_data[$field_name]; + return $service[$field]; } /** - * Get all, or specific records from service's table. + * Get all services 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->services_model->get_batch(['id' => $record_id]); - * - * @param mixed $where - * @param int|null $limit - * @param int|null $offset - * @param mixed $order_by - * - * @return array Returns the rows from the database. + * @return array Returns an array of services. */ - public function get_batch($where = NULL, $limit = NULL, $offset = NULL, $order_by = NULL) + public function get($where = NULL, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array { if ($where !== NULL) { @@ -348,165 +253,90 @@ class Services_model extends EA_Model { } /** - * This method returns all the services from the database. + * Get all the service records that are assigned to at least one provider. * - * @return array Returns an object array with all the database services. + * @return array Returns an array of services. */ - public function get_available_services() + public function get_available_services(): array { - $this->db->distinct(); - return $this->db - ->select('services.*, service_categories.name AS category_name, ' - . 'service_categories.id AS category_id') + return $this + ->db + ->distinct() + ->select('services.*, service_categories.name AS category_name, service_categories.id AS category_id') ->from('services') - ->join('services_providers', - 'services_providers.id_services = services.id', 'inner') - ->join('service_categories', - 'service_categories.id = services.id_service_categories', 'left') + ->join('services_providers', 'services_providers.id_services = services.id', 'inner') + ->join('service_categories', 'service_categories.id = services.id_service_categories', 'left') ->order_by('name ASC') - ->get()->result_array(); + ->get() + ->result_array(); } /** - * Add (insert or update) a service category record into database. + * Get the query builder interface, configured for use with the services table. * - * @param array $category Contains the service category data. - * - * @return int Returns the record ID. - * - * @throws Exception If service category data are invalid. + * @return CI_DB_query_builder */ - public function add_category($category) + public function query(): CI_DB_query_builder { - if ( ! $this->validate_category($category)) - { - throw new Exception('Service category data are invalid.'); - } - - if ( ! isset($category['id'])) - { - $this->db->insert('service_categories', $category); - $category['id'] = $this->db->insert_id(); - } - else - { - $this->db->where('id', $category['id']); - $this->db->update('service_categories', $category); - } - - return (int)$category['id']; + return $this->db->from('services'); } /** - * Validate a service category record data. This method must be used before adding - * a service category record into database in order to secure the record integrity. + * Search services by the provided keyword. * - * @param array $category Contains the service category data. + * @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 bool Returns the validation result. - * - * @throws Exception If required fields are missing. + * @return array Returns an array of services. */ - public function validate_category($category) + public function search(string $keyword, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array { - try + return $this + ->db + ->select() + ->from('services') + ->like('name', $keyword) + ->or_like('description', $keyword) + ->limit($limit) + ->offset($offset) + ->order_by($order_by) + ->get() + ->result_array(); + } + + /** + * Attach related resources to a service. + * + * @param array $service Associative array with the service data. + * @param array $resources Resource names to be attached ("service_category" supported). + * + * @throws InvalidArgumentException + */ + public function attach(array &$service, array $resources): void + { + if (empty($service) || empty($resources)) { - // Required Fields - if ( ! isset($category['name'])) + return; + } + + foreach ($resources as $resource) + { + switch ($resource) { - throw new Exception('Not all required fields where provided '); + case 'service_category': + $service['service_category'] = $this + ->db + ->get_where('service_categories', [ + 'id' => $service['id_service_categories'] + ]) + ->row_array(); + break; + + default: + throw new InvalidArgumentException('The requested appointment relation is not supported: ' . $resource); } - - if ($category['name'] == '' || $category['name'] == NULL) - { - throw new Exception('Required fields cannot be empty or null ($category: ' - . print_r($category, TRUE) . ')'); - } - - return TRUE; } - catch (Exception $exception) - { - return FALSE; - } - } - - /** - * Delete a service category record from the database. - * - * @param int $category_id Record id to be deleted. - * - * @return bool Returns the delete operation result. - * - * @throws Exception if Service category record was not found. - */ - public function delete_category($category_id) - { - if ( ! is_numeric($category_id)) - { - throw new Exception('Invalid argument given for $category_id: ' . $category_id); - } - - $num_rows = $this->db->get_where('service_categories', ['id' => $category_id]) - ->num_rows(); - if ($num_rows == 0) - { - throw new Exception('Service category record not found in database.'); - } - - $this->db->where('id', $category_id); - return $this->db->delete('service_categories'); - } - - /** - * Get a service category record data. - * - * @param int $category_id Record id to be retrieved. - * - * @return array Returns the record data from the database. - * - * @throws Exception If $category_id argument is invalid. - * @throws Exception If service category record does not exist. - */ - public function get_category($category_id) - { - if ( ! is_numeric($category_id)) - { - throw new Exception('Invalid argument type given $category_id: ' . $category_id); - } - - $result = $this->db->get_where('service_categories', ['id' => $category_id]); - - if ($result->num_rows() == 0) - { - throw new Exception('Service category record does not exist.'); - } - - return $result->row_array(); - } - - /** - * Get all service category records from database. - * - * @param mixed $where - * @param int|null $limit - * @param int|null $offset - * @param mixed $order_by - * - * @return array Returns an array that contains all the service category records. - */ - public function get_all_categories($where = NULL, $limit = NULL, $offset = NULL, $order_by = NULL) - { - if ($where !== NULL) - { - $this->db->where($where); - } - - if ($order_by !== NULL) - { - $this->db->order_by($order_by); - } - - return $this->db->get('service_categories', $limit, $offset)->result_array(); } }