From c08625e667cf7b1556d06a93026cde7dbb3ca1c6 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Fri, 9 May 2025 14:21:54 +0200 Subject: [PATCH 1/8] TOURCMS-11047 Type methods parameters and returns, use consts and improve code --- src/TourCMS.php | 1878 +++++++++++++++++++++++++---------------------- 1 file changed, 1017 insertions(+), 861 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index 5939a23..beb9ffd 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -1,6 +1,6 @@ marketp_id = $mp; - $this->private_key = $k; - $this->result_type = $res; - $this->timeout = $to; - } - - /** - * request - * - * @author Paul Slugocki - * @param $path API path to call - * @param $channel Channel ID, defaults to zero - * @param $verb HTTP Verb, defaults to GET - * @return String or SimpleXML - */ - public function request($path, $channel = 0, $verb = 'GET', $post_data = null) { - // Prepare the URL we are sending to - $url = $this->base_url.$path; - // We need a signature for the header - - $outbound_time = time(); - $signature = $this->generate_signature($path, $verb, $channel, $outbound_time); - - // Build headers - $this->add_header("Content-type", "text/xml;charset=\"utf-8\""); - $this->add_header("Date", gmdate('D, d M Y H:i:s \G\M\T', $outbound_time)); - $this->add_header("Authorization", "TourCMS $channel:$this->marketp_id:$signature"); - // Add user-agent to headers array - if (!empty($this->user_agent)) { - $finalUserAgent = $this->prepend_caller_to_user_agent ? $this->user_agent." (".$this->marketp_id."_".$channel.")" : $this->user_agent; - $this->add_header("User-Agent", $finalUserAgent); - } - - $this->headers = array_merge($this->permanent_headers, $this->headers); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_TIMEOUT, (is_int($this->timeout) && $this->timeout > 0) ? $this->timeout : 0 ); - curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); - curl_setopt($ch, CURLOPT_HEADER, true); - - /* +class TourCMS +{ + // ENDPOINTS CONSTS + + public const PATH_API_RATE_LIMIT = '/api/rate_limit_status.xml'; + + + // Account(s) + public const PATH_API_ACCOUNT_CREATE = "/p/account/create.xml"; + public const PATH_API_ACCOUNT_UPDATE = "/p/account/update.xml"; + public const PATH_API_ACCOUNT_SHOW = "/p/account/show.xml"; + public const PATH_API_ACCOUNT_CUSTOM_FIELDS_GET = "/api/account/custom_fields/get.xml"; + + + // Agent(s) + public const PATH_API_AGENT_PROFILE_GET = "/api/agent/profile/get.xml"; + public const PATH_API_AGENT_PROFILE_UPDATE = "/api/agent/profile/update.xml"; + public const PATH_API_AGENTS_SEARCH = '/c/agents/search.xml'; + public const PATH_API_START_AGENT_LOGIN = '/c/start_agent_login.xml'; + public const PATH_API_AGENT_BOOKING_KEY_RETRIEVE = '/c/retrieve_agent_booking_key.xml'; + public const PATH_API_AGENTS_UPDATE = '/c/agents/update.xml'; + + + // Channel(s) + public const PATH_API_CHANNELS_LIST = '/p/channels/list.xml'; + public const PATH_API_CHANNEL_LOGO_UPLOAD_GET_URL = "/c/channel/logo/upload/url.xml"; + public const PATH_API_CHANNEL_LOGO_UPLOAD_PROCESS = "/c/channel/logo/upload/process.xml"; + public const PATH_API_CHANNEL_SHOW = '/c/channel/show.xml'; + public const PATH_API_P_CHANNELS_PERFORMANCE = '/p/channels/performance.xml'; + public const PATH_API_C_CHANNELS_PERFORMANCE = '/c/channel/performance.xml'; + public const PATH_API_CHANNEL_CREATE = "/p/channel/create.xml"; + public const PATH_API_CHANNEL_UPDATE = "/p/channel/update.xml"; + + + // Tour(s) / Hotel(s) + public const PATH_API_P_TOURS_SEARCH = '/p/tours/search.xml'; + public const PATH_API_C_TOURS_SEARCH = '/c/tours/search.xml'; + public const PATH_API_P_HOTELS_SEARCH_RANGE = '/p/hotels/search_range.xml'; + public const PATH_API_C_HOTELS_SEARCH_RANGE = '/c/hotels/search_range.xml'; + public const PATH_API_P_HOTELS_SEARCH_AVAIL = '/p/hotels/search_avail.xml'; + public const PATH_API_C_HOTELS_SEARCH_AVAIL = '/c/hotels/search_avail.xml'; + public const PATH_API_TOURS_FILTERS = '/c/tours/filters.xml'; + public const PATH_API_TOUR_UPDATE = '/c/tour/update.xml'; + public const PATH_API_P_TOURS_LIST = '/p/tours/list.xml'; + public const PATH_API_C_TOURS_LIST = '/c/tours/list.xml'; + public const PATH_API_P_TOURS_IMAGES_LIST = '/p/tours/images/list.xml'; + public const PATH_API_C_TOURS_IMAGES_LIST = '/c/tours/images/list.xml'; + public const PATH_API_P_TOURS_LOCATIONS = '/p/tours/locations.xml'; + public const PATH_API_C_TOURS_LOCATIONS = '/c/tours/locations.xml'; + public const PATH_API_TOUR_DELETE = "/c/tour/delete.xml"; + public const PATH_API_TOUR_SHOW = "/c/tour/show.xml"; + public const PATH_API_TOURS_FILE_UPLOAD_GET_URL = "/c/tours/files/upload/url.xml"; + public const PATH_API_TOURS_FILES_UPLOAD_PROCESS = "/c/tours/files/upload/process.xml"; + public const PATH_API_TOUR_IMAGES_DELETE = "/c/tour/images/delete.xml"; + public const PATH_API_TOUR_DOCUMENT_DELETE = "/c/tour/document/delete.xml"; + public const PATH_API_SHOW_TOUR_AVAILABILITY = "/c/tour/datesprices/checkavail.xml"; + public const PATH_API_TOUR_DATES_AND_DEALS = "/c/tour/datesprices/datesndeals/search.xml"; + public const PATH_API_SHOW_TOUR_DEPARTURES = "/c/tour/datesprices/dep/show.xml"; + public const API_PATH_SHOW_TOUR_FREESALE = "/c/tour/datesprices/freesale/show.xml"; + public const PATH_API_TOURS_SEARCH_CRITERIA_GET = "/api/tours/search_criteria/get.xml"; + + + // Departures + public const PATH_API_SEARCH_RAW_DEPARTURES = "/c/tour/datesprices/dep/manage/search.xml"; + public const PATH_API_DEPARTURE_SHOW = "/c/tour/datesprices/dep/manage/show.xml"; + public const PATH_API_DEPARTURE_CREATE = "/c/tour/datesprices/dep/manage/new.xml"; + public const PATH_API_DEPARTURE_UPDATE = "/c/tour/datesprices/dep/manage/update.xml"; + public const PATH_API_DEPARTURE_DELETE = "/c/tour/datesprices/dep/manage/delete.xml"; + + + // Promo codes + public const PATH_API_PROMO_SHOW = "/c/promo/show.xml"; + + + // Bookings + public const PATH_API_BOOKING_GET_REDIRECT_URL = "/c/booking/new/get_redirect_url.xml"; + public const PATH_API_BOOKING_START = "/c/booking/new/start.xml"; + public const PATH_API_BOOKING_COMMIT = "/c/booking/new/commit.xml"; + public const PATH_API_P_BOOKINGS_SEARCH = "/p/bookings/search.xml"; + public const PATH_API_C_BOOKINGS_SEARCH = "/c/bookings/search.xml"; + public const PATH_API_P_BOOKINGS_LIST = '/p/bookings/list.xml'; + public const PATH_API_C_BOOKINGS_LIST = '/c/bookings/list.xml'; + public const PATH_API_BOOKINGS_SHOW = '/c/booking/show.xml'; + public const PATH_API_BOOKING_UPDATE = '/c/booking/update.xml'; + public const PATH_API_BOOKING_CANCEL = '/c/booking/cancel.xml'; + public const PATH_API_BOOKING_DELETE = '/c/booking/delete.xml'; + public const PATH_API_OPTION_CHECK_AVAILABILITY = '/c/booking/options/checkavail.xml'; + public const PATH_API_BOOKING_COMPONENT_NEW = '/c/booking/component/new.xml'; + public const PATH_API_BOOKING_COMPONENT_DELETE = '/c/booking/component/delete.xml'; + public const PATH_API_BOOKING_COMPONENT_UPDATE = '/c/booking/component/update.xml'; + public const PATH_API_BOOKING_NOTE_NEW = '/c/booking/note/new.xml'; + public const PATH_API_BOOKING_EMAIL_SEND = '/c/booking/email/send.xml'; + + + // Payments + public const PATH_API_PAYMENT_NEW = '/c/booking/payment/new.xml'; + public const PATH_API_PAYMENT_FAIL = '/c/booking/payment/fail.xml'; + public const PATH_API_PAYMENT_SPREEDLY_CREATE = '/c/booking/payment/spreedly/new.xml'; + public const PATH_API_PAYMENT_SPREEDLY_COMPLETE = '/c/booking/gatewaytransaction/spreedlycomplete.xml'; + public const PATH_API_PAYMENTS_LIST = '/c/booking/payment/list.xml'; + public const PATH_API_PAYMENTS_PAYWORKS_NEW = '/c/booking/payment/payworks/new.xml'; + + + // Voucher + public const PATH_API_P_VOUCHER_SEARCH = '/p/voucher/search.xml'; + public const PATH_API_C_VOUCHER_SEARCH = '/c/voucher/search.xml'; + public const PATH_API_VOUCHER_REDEEM = '/c/voucher/redeem.xml'; + + + // Enquiry + public const PATH_API_ENQUIRY_NEW = '/c/enquiry/new.xml'; + public const PATH_API_P_ENQUIRIES_SEARCH = '/p/enquiries/search.xml'; + public const PATH_API_C_ENQUIRIES_SEARCH = '/c/enquiries/search.xml'; + public const PATH_API_ENQUIRY_SHOW = '/c/enquiry/show.xml'; + + + // Customer(s) + public const PATH_API_CUSTOMER_SHOW = '/c/customer/show.xml'; + public const PATH_API_CUSTOMER_UPDATE = '/c/customer/update.xml'; + public const PATH_API_CUSTOMER_LOGIN_SEARCH = '/c/customers/login_search.xml'; + + + // Pickups + public const PATH_API_PICKUPS_LIST = '/c/pickups/list.xml'; + public const PATH_API_PICKUPS_NEW = '/c/pickups/new.xml'; + public const PATH_API_PICKUPS_UPDATE = '/c/pickups/update.xml'; + public const PATH_API_PICKUPS_DELETE = '/c/pickups/delete.xml'; + + + // Pickup Routes + public const PATH_API_TOUR_PICKUP_ROUTES_SHOW = "/api/tours/pickup/routes/show.xml"; + public const PATH_API_TOUR_PICKUP_ROUTES_UPDATE = "/api/tours/pickup/routes/update.xml"; + public const PATH_API_TOUR_PICKUP_ROUTES_ADD_PICKUP = "/api/tours/pickup/routes/pickup_add.xml"; + public const PATH_API_TOUR_PICKUP_ROUTES_UPDATE_PICKUP = "/api/tours/pickup/routes/pickup_update.xml"; + public const PATH_API_TOUR_PICKUP_ROUTES_DELETE_PICKUP = "/api/tours/pickup/routes/pickup_delete.xml"; + + + // Geos + public const PATH_API_TOUR_GEOS_CREATE = "/api/tours/geos/create.xml"; + public const PATH_API_TOUR_GEOS_UPDATE = "/api/tours/geos/update.xml"; + public const PATH_API_TOUR_GEOS_DELETE = "/api/tours/geos/delete.xml"; + + + // Importer + public const PATH_API_TOUR_FACETS_GET = "/api/tours/importer/get_tour_facets.xml"; + public const PATH_API_LIST_TOURS_GET = "/api/tours/importer/get_tour_list.xml"; + public const PATH_API_IMPORT_TOURS_STATUS = "/api/tours/importer/get_import_tours_status.xml"; + public const PATH_API_LIST_TOUR_BOOKINGS_RESTRICTIONS = "/api/tours/restrictions/list_tour_bookings_restrictions.xml"; + + + // Staff + public const PATH_API_STAFF_LIST = '/c/staff/list.xml'; + + // Supplier + public const PATH_API_SUPPLIER_SHOW = '/c/supplier/show.xml'; + + // Markups + public const PATH_API_MARKUP_SCHEME_SHOW = "/c/markups/show.xml"; + + + // HTTP VERBS CONST + public const HTTP_VERB_POST = 'POST'; + public const HTTP_VERB_GET = 'GET'; + public const HEADER_X_REQUEST_ID = 'X-Request-Id'; + + public const RESULT_TYPE_RAW = "raw"; + public const RESULT_TYPE_XML = "simplexml"; + + // General settings + protected string $baseUrl = "https://api.tourcms.com"; + protected int $marketplaceId = 0; + protected string $privateKey = ""; + protected string $resultType = ""; + protected int $timeout = 0; + protected array $lastRequestHeaders = []; + protected array $lastResponseHeaders = []; + protected string $userAgent = "TourCMS PHP Wrapper v5.0.0"; + protected bool $prependCallerToUserAgent = true; + protected array $headers = []; + protected array $permanentHeaders = []; + + /** + * __construct + * + * @author Paul Slugocki + * @param $mp Marketplace ID + * @param $k API Private Key + * @param $resultType Result type, defaults to raw + * @param $timeout Timeout, default 0 + */ + public function __construct(int $marketplaceId, string $key, string $resultType = self::RESULT_TYPE_RAW, int $timeout = 0) + { + $this->marketplaceId = $marketplaceId; + $this->privateKey = $key; + $this->resultType = $resultType; + $this->timeout = $timeout; + } + + /** + * request + * + * @author Paul Slugocki + * @param $path API path to call + * @param $channel Channel ID, defaults to zero + * @param $verb HTTP Verb, defaults to GET + * @return string|SimpleXMLElement + */ + public function request(string $path, int $channel = 0, string $verb = self::HTTP_VERB_GET, null|string|SimpleXMLElement $postData = null): bool|SimpleXMLElement|string + { + // Prepare the URL we are sending to + $url = $this->baseUrl . $path; + // We need a signature for the header + + $outboundTime = time(); + $signature = $this->generateSignature($path, $verb, $channel, $outboundTime); + + // Build headers + $this->add_header("Content-type", "text/xml;charset=\"utf-8\""); + $this->add_header("Date", gmdate('D, d M Y H:i:s \G\M\T', $outboundTime)); + $this->add_header("Authorization", "TourCMS $channel:$this->marketplaceId:$signature"); + // Add user-agent to headers array + if (!empty($this->userAgent)) { + $finalUserAgent = $this->prependCallerToUserAgent ? $this->userAgent . " (" . $this->marketplaceId . "_" . $channel . ")" : $this->userAgent; + $this->add_header("User-Agent", $finalUserAgent); + } + + $this->headers = array_merge($this->permanentHeaders, $this->headers); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, (is_int($this->timeout) && $this->timeout > 0) ? $this->timeout : 0); + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); + curl_setopt($ch, CURLOPT_HEADER, true); + + /* Windows users having trouble connecting via SSL? Download the CA bundle from: http://curl.haxx.se/docs/caextract.html Finally uncomment the following line and point it to the downloaded file */ - // curl_setopt($ch, CURLOPT_CAINFO, "c:/path/to/ca-bundle.crt"); - - if ($verb == self::HTTP_VERB_POST) { - curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, self::HTTP_VERB_POST); - if (!is_null($post_data)) { - if (is_string($post_data)) { - curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); - } - if ($post_data instanceof SimpleXMLElement) { - curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data->asXML()); - } - } - } - - // Callback function to populate the response headers on curl_exec - $api_response_headers = array(); - curl_setopt($ch, CURLOPT_HEADERFUNCTION, - function($ch, $header) use (&$api_response_headers) - { - $len = strlen($header); - $header = explode(':', $header, 2); - if (count($header) < 2) // ignore invalid headers - return $len; - - $name = strtolower(trim($header[0])); - $api_response_headers[$name] = trim($header[1]); - - return $len; - } - ); - - $response = curl_exec($ch); - - $this->last_response_headers = $api_response_headers; - - $header_size = curl_getinfo( $ch, CURLINFO_HEADER_SIZE ); - $result = substr( $response, $header_size ); - - // Check whether we need to return raw XML or - // convert to SimpleXML first - if($this->result_type == "simplexml") - $result = simplexml_load_string($result); - - $this->last_request_headers = $this->headers; - $this->headers = []; - - return($result); - } - - /** - * get_base_url - * - * @author Paul Slugocki - * @return String - */ - public function get_base_url() { - return $this->base_url; - } - - /** - * set_base_url - * - * @author Paul Slugocki - * @param $url New base url - * @return Boolean - */ - public function set_base_url($url) { - $this->base_url = $url; - return true; - } - - /** - * set_user_agent - * - * @author Francisco Martinez Ramos - * @return bool - */ - public function set_user_agent(string $user_agent, bool $prepend = true) { - $this->prepend_caller_to_user_agent = $prepend; - $this->user_agent = $user_agent; - return true; - } - - /** - * add_header - * - * @author Francisco Martínez Ramos - * @param string $header Key of the header - * @param string $value Value of the header - * @return bool - */ - public function add_header(string $header, string $value, bool $permanent = false): bool - { - $new_header = "$header: $value"; - - if($permanent) { - array_push($this->permanent_headers, $new_header); - } else { - array_push($this->headers, $new_header); - } - - return true; - } - - /** - * set_request_identifier - * - * @author Francisco Martínez Ramos - * @param string $value Value of the request identifier header - * @return bool - */ - public function set_request_identifier(string $value): bool - { - return $this->add_header('X-Request-Id', $value); - } - - # Get last request headers - - public function get_last_request_headers() { - return $this->last_request_headers; - } - - # Get last response headers - - public function get_last_response_headers() { - return $this->last_response_headers; - } - - # Test environment - - public function test_environment($channel = 0) { - include('test.php'); - } - - # API methods (Housekeeping) - - public function api_rate_limit_status($channel = 0) { - return($this->request('/api/rate_limit_status.xml', $channel)); - } - - # Channel methods - - public function list_channels($params = "") { - $params = $this->validateParams($params); - return($this->request('/p/channels/list.xml'.$params)); - } - - public function channel_upload_logo_get_url($channel) - { - $url = "/c/channel/logo/upload/url.xml"; - return($this->request($url, $channel)); - } - - public function channel_upload_logo_process($channel, $upload_info) - { - $url = "/c/channel/logo/upload/process.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $upload_info)); - } - - public function show_channel($channel) { - return($this->request('/c/channel/show.xml', $channel)); - } - - public function channel_performance($channel = 0) { - if($channel==0) - return($this->request('/p/channels/performance.xml')); - else - return($this->request('/c/channel/performance.xml', $channel)); - } - - # Tour/Hotel methods - - public function search_tours($params = "", $channel = 0) { - - $params = $this->validateParams($params); - - if($channel==0) - return($this->request('/p/tours/search.xml'.$params)); - else - return($this->request('/c/tours/search.xml'.$params, $channel)); - } - - public function search_hotels_range($params = "", $tour = "", $channel = 0) { - - $params = $this->validateParams($params); - - if (!empty($tour)) { - - if (empty($params)) { - $params = '?single_tour_id='; - } else { - $params .= "&single_tour_id="; - } - - $params .= $tour; - - } - - if($channel==0) - return($this->request('/p/hotels/search_range.xml'.$params)); - else - return($this->request('/c/hotels/search_range.xml'.$params, $channel)); - } - - public function search_hotels_specific($params = "", $tour = "", $channel = 0) { - $params = $this->validateParams($params); - - if (!empty($tour)) { - - if (empty($params)) { - $params = '?single_tour_id='; - } else { - $params .= "&single_tour_id="; - } - - $params .= $tour; - - } - - if($channel==0) - return($this->request('/p/hotels/search_avail.xml'.$params)); - else - return($this->request('/c/hotels/search_avail.xml'.$params, $channel)); - } - - public function list_product_filters($channel = 0) { - return($this->request('/c/tours/filters.xml', $channel)); - } - - public function update_tour($tour_data, $channel) { - return($this->request('/c/tour/update.xml', $channel, "POST", $tour_data)); - } - - public function update_tour_url($tour, $channel, $tour_url) { - - $url_data = new SimpleXMLElement(''); - $url_data->addChild('tour_id', $tour); - $url_data->addChild('tour_url', $tour_url); - - return($this->update_tour($url_data, $channel)); - } - - public function list_tours($channel = 0, $params = "") { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/tours/list.xml'.$params)); - else - return($this->request('/c/tours/list.xml'.$params, $channel)); - } - - public function list_tour_images($channel = 0, $params = "") - { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/tours/images/list.xml'.$params)); - else - return($this->request('/c/tours/images/list.xml'.$params, $channel)); - } - - public function list_tour_locations($channel = 0, $params = "") - { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/tours/locations.xml'.$params)); - else - return($this->request('/c/tours/locations.xml'.$params, $channel)); - } - - public function delete_tour($tour, $channel) - { - $url = '/c/tour/delete.xml?id='.$tour; - return($this->request($url, $channel, self::HTTP_VERB_POST)); - } - - public function show_tour($tour, $channel, $params = false) - { - $url = '/c/tour/show.xml?id='.$tour; - - /* + // curl_setopt($ch, CURLOPT_CAINFO, "c:/path/to/ca-bundle.crt"); + + if ($verb == self::HTTP_VERB_POST) { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, self::HTTP_VERB_POST); + if (!is_null($postData)) { + if (is_string($postData)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); + } + if ($this->isXMLObject($postData)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData->asXML()); + } + } + } + + // Callback function to populate the response headers on curl_exec + $apiResponseHeaders = []; + curl_setopt( + $ch, + CURLOPT_HEADERFUNCTION, + function ($ch, $header) use (&$apiResponseHeaders) { + $len = strlen($header); + $header = explode(':', $header, 2); + if (count($header) < 2) // ignore invalid headers + return $len; + + $name = strtolower(trim($header[0])); + $apiResponseHeaders[$name] = trim($header[1]); + + return $len; + } + ); + + $response = curl_exec($ch); + + $this->lastResponseHeaders = $apiResponseHeaders; + + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $result = substr($response, $header_size); + + // Check whether we need to return raw XML or + // convert to SimpleXML first + if ($this->resultType == self::RESULT_TYPE_XML) + $result = simplexml_load_string($result); + + $this->lastRequestHeaders = $this->headers; + $this->headers = []; + + return $result; + } + + /** + * get_base_url + * + * @author Paul Slugocki + * @return string + */ + public function get_base_url(): string + { + return $this->baseUrl; + } + + /** + * set_base_url + * + * @author Paul Slugocki + * @param $url New base url + * @return bool + */ + public function set_base_url(string $url): void + { + $this->baseUrl = $url; + } + + /** + * set_user_agent + * + * @author Francisco Martinez Ramos + * @return bool + */ + public function set_user_agent(string $user_agent, bool $prepend = true): void + { + $this->prependCallerToUserAgent = $prepend; + $this->userAgent = $user_agent; + } + + /** + * add_header + * + * @author Francisco Martínez Ramos + * @param string $header Key of the header + * @param string $value Value of the header + * @return void + */ + public function add_header(string $header, string $value, bool $permanent = false): void + { + $newHeader = "$header: $value"; + + if ($permanent) { + array_push($this->permanentHeaders, $newHeader); + } else { + array_push($this->headers, $newHeader); + } + } + + /** + * set_request_identifier + * + * @author Francisco Martínez Ramos + * @param string $value Value of the request identifier header + * @return void + */ + public function set_request_identifier(string $value): void + { + $this->add_header(self::HEADER_X_REQUEST_ID, $value); + } + + # Get last request headers + + public function get_last_request_headers(): array + { + return $this->lastRequestHeaders; + } + + # Get last response headers + + public function get_lastResponseHeaders(): array + { + return $this->lastResponseHeaders; + } + + # Test environment + + public function test_environment(int $channel = 0): void + { + include 'test.php'; + } + + # API methods (Housekeeping) + + public function api_rate_limit_status(int $channel = 0): SimpleXMLElement|string + { + return $this->request(self::PATH_API_RATE_LIMIT, $channel); + } + + # Channel methods + + public function list_channels(string $params = ""): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CHANNELS_LIST . $this->validateParams($params)); + } + + public function channel_upload_logo_get_url(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CHANNEL_LOGO_UPLOAD_GET_URL, $channel); + } + + public function channel_upload_logo_process(int $channel, SimpleXMLElement|string $uploadInfo) + { + return $this->request(self::PATH_API_CHANNEL_LOGO_UPLOAD_PROCESS, $channel, self::HTTP_VERB_POST, $uploadInfo); + } + + public function show_channel(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CHANNEL_SHOW, $channel); + } + + public function channel_performance(int $channel = 0): SimpleXMLElement|string + { + + if ($channel == 0) return $this->request(self::PATH_API_P_CHANNELS_PERFORMANCE); + + return $this->request(self::PATH_API_C_CHANNELS_PERFORMANCE, $channel); + } + + # Tour/Hotel methods + + public function search_tours(string $params = "", int $channel = 0): SimpleXMLElement|string + { + + $params = $this->validateParams($params); + + if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_SEARCH . $params); + + return $this->request(self::PATH_API_C_TOURS_SEARCH . $params, $channel); + } + + public function search_hotels_range(string $params = "", ?int $tourId = null, int $channel = 0) + { + + $params = $this->validateParams($params); + + if (!is_null($tourId)) { + + if (empty($params)) { + $params = '?single_tour_id='; + } else { + $params .= "&single_tour_id="; + } + + $params .= $tourId; + } + + if ($channel == 0) return $this->request(self::PATH_API_P_HOTELS_SEARCH_RANGE . $params); + + return $this->request(self::PATH_API_C_HOTELS_SEARCH_RANGE . $params, $channel); + } + + public function search_hotels_specific(string $params = "", ?int $tourId = null, int $channel = 0) + { + $params = $this->validateParams($params); + + if (!is_null($tourId)) { + + if (empty($params)) { + $params = '?single_tour_id='; + } else { + $params .= "&single_tour_id="; + } + + $params .= $tourId; + } + + if ($channel == 0) return $this->request(self::PATH_API_P_HOTELS_SEARCH_AVAIL . $params); + + return $this->request(self::PATH_API_C_HOTELS_SEARCH_AVAIL . $params, $channel); + } + + public function list_product_filters(int $channel = 0): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOURS_FILTERS, $channel); + } + + public function update_tour($tour_data, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_UPDATE, $channel, self::HTTP_VERB_POST, $tour_data); + } + + public function update_tour_url(int $tourId, int $channel, string $tourUrl): SimpleXMLElement|string + { + + $urlData = new SimpleXMLElement(''); + $urlData->addChild('tour_id', $tourId); + $urlData->addChild('tour_url', $tourUrl); + + return $this->update_tour($urlData, $channel); + } + + public function list_tours(int $channel = 0, string $params = ""): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_LIST . $params); + + return $this->request(self::PATH_API_C_TOURS_LIST . $params, $channel); + } + + public function list_tour_images(int $channel = 0, string $params = ""): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_IMAGES_LIST . $params); + + return $this->request(self::PATH_API_C_TOURS_IMAGES_LIST . $params, $channel); + } + + public function list_tour_locations(int $channel = 0, string $params = ""): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_LOCATIONS . $params); + + return $this->request(self::PATH_API_C_TOURS_LOCATIONS . $params, $channel); + } + + public function delete_tour(int $tourId, int $channel): SimpleXMLElement|string + { + $url = self::PATH_API_TOUR_DELETE .'?id=' . $tourId; + return $this->request($url, $channel, self::HTTP_VERB_POST); + } + + public function show_tour(int $tourId, int $channel, ?string $params = null) + { + $url = self::PATH_API_TOUR_SHOW . '?id=' . $tourId; + + /* Third param for show tour could be: @@ -410,528 +559,535 @@ public function show_tour($tour, $channel, $params = false) */ - if(is_string($params)) { + if (is_string($params)) { - $url .= "&" . $params; + $url .= "&" . $params; + } else { - } else { + if ($params) + $url .= "&show_options=1"; + } - if($params) - $url .= "&show_options=1"; + if ($tourId > 0) { + return $this->request($url, $channel); + } + } - } + public function tour_upload_file_get_url($tour, $channel, $file_type, $file_id): SimpleXMLElement|string + { + $url = self::PATH_API_TOURS_FILE_UPLOAD_GET_URL . "?id=$tour&file_type=$file_type&file_id=$file_id"; + return $this->request($url, $channel, self::HTTP_VERB_GET); + } - if((int)$tour > 0) { - return($this->request($url, $channel)); - } - } + public function tour_upload_file_process(int $channel, SimpleXMLElement|string $uploadInfo): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOURS_FILES_UPLOAD_PROCESS, $channel, self::HTTP_VERB_POST, $uploadInfo); + } - public function tour_upload_file_get_url($tour, $channel, $file_type, $file_id) - { - $url = "/c/tours/files/upload/url.xml?id=$tour&file_type=$file_type&file_id=$file_id"; - return($this->request($url, $channel, self::HTTP_VERB_GET)); - } + public function delete_tour_image(int $channel, SimpleXMLElement|string $image_info): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_IMAGES_DELETE, $channel, self::HTTP_VERB_POST, $image_info); + } - public function tour_upload_file_process($channel, $upload_info) - { - $url = "/c/tours/files/upload/process.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $upload_info)); - } + public function delete_tour_document(int $channel, $documentXML): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_DOCUMENT_DELETE, $channel, self::HTTP_VERB_POST, $documentXML); + } - public function delete_tour_image($channel, $image_info) - { - $url = "/c/tour/images/delete.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $image_info)); - } - public function delete_tour_document($channel, $document_xml) - { - $url = "/c/tour/document/delete.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $document_xml)); - } + public function check_tour_availability(string $params, int $tourId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_SHOW_TOUR_AVAILABILITY . '?id=' . $tourId . $this->validateParams($params), $channel); + } + public function show_tour_datesanddeals(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_DATES_AND_DEALS .'?id=' . $tourId . $this->validateParams($params), $channel); + } - public function check_tour_availability($params, $tour, $channel) - { - if (!empty($params)) $params = "&" . $params; - return ($this->request('/c/tour/datesprices/checkavail.xml?id='.$tour.$params, $channel)); - } - public function show_tour_datesanddeals($tour, $channel, $qs = "") - { - if (!empty($qs)) $qs = "&" . $qs; - return($this->request('/c/tour/datesprices/datesndeals/search.xml?id='.$tour.$qs, $channel)); - } + public function show_tour_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + { + return $this->request(self::PATH_API_SHOW_TOUR_DEPARTURES . '?id=' . $tourId . $this->validateParams($params), $channel); + } + public function show_tour_freesale(int $tourId, int $channel): SimpleXMLElement|string + { + return $this->request(self::API_PATH_SHOW_TOUR_FREESALE . '?id=' . $tourId, $channel); + } - public function show_tour_departures($tour, $channel, $qs = "") - { - if (!empty($qs)) $qs = "&" . $qs; - return($this->request('/c/tour/datesprices/dep/show.xml?id='.$tour.$qs, $channel)); - } + public function tours_search_criteria(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOURS_SEARCH_CRITERIA_GET, $channel); + } - public function show_tour_freesale($tour, $channel) - { - return($this->request('/c/tour/datesprices/freesale/show.xml?id='.$tour, $channel)); - } - - public function tours_search_criteria($channel) - { - return($this->request(self::PATH_API_TOURS_SEARCH_CRITERIA_GET, $channel)); - } - - /* + /* Raw departure methods */ - public function search_raw_departures($tour, $channel, $qs = "") - { - if (!empty($qs)) $qs = "&" . $qs; - return($this->request('/c/tour/datesprices/dep/manage/search.xml?id='.$tour.$qs, $channel)); - } - - public function show_departure($departure, $tour, $channel) - { - return($this->request('/c/tour/datesprices/dep/manage/show.xml?id='.$tour.'&departure_id='.$departure, $channel)); - } - - public function create_departure($departure_data, $channel) - { - return($this->request('/c/tour/datesprices/dep/manage/new.xml', $channel, "POST", $departure_data)); - } - - public function update_departure($departure_data, $channel) - { - return($this->request('/c/tour/datesprices/dep/manage/update.xml', $channel, "POST", $departure_data)); - } - - public function delete_departure($departure, $tour, $channel) - { - return($this->request('/c/tour/datesprices/dep/manage/delete.xml?id='.$tour.'&departure_id='.$departure, $channel, "POST")); - } - - /* + public function search_raw_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + { + return $this->request(self::PATH_API_SEARCH_RAW_DEPARTURES . '?id=' . $tourId . $this->validateParams($params), $channel); + } + + public function show_departure(int $departure, int $tour, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_DEPARTURE_SHOW . '?id=' . $tour . '&departure_id=' . $departure, $channel); + } + + public function create_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_DEPARTURE_CREATE, $channel, self::HTTP_VERB_POST, $departureData); + } + + public function update_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_DEPARTURE_UPDATE, $channel, self::HTTP_VERB_POST, $departureData); + } + + public function delete_departure(int $departureId, int $tourId, int $channelId): SimpleXMLElement|string + { + return $this->request(self::PATH_API_DEPARTURE_DELETE . '?id=' . $tourId . '&departure_id=' . $departureId, $channelId, self::HTTP_VERB_POST); + } + + /* Promo code */ - public function show_promo($promo, $channel) - { - return($this->request('/c/promo/show.xml?promo_code='.$promo, $channel)); - } + public function show_promo(int $promoId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PROMO_SHOW . '?promo_code=' . $promoId, $channel); + } - # Booking methods + # Booking methods - /* + /* Making bookings */ - public function get_booking_redirect_url($url_data, $channel) - { - return($this->request('/c/booking/new/get_redirect_url.xml', $channel, "POST", $url_data)); - } + public function get_booking_redirect_url(SimpleXMLElement|string $urlData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_GET_REDIRECT_URL, $channel, self::HTTP_VERB_POST, $urlData); + } - public function start_new_booking($booking_data, $channel) - { - return($this->request('/c/booking/new/start.xml', $channel, "POST", $booking_data)); - } + public function start_new_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_START, $channel, self::HTTP_VERB_POST, $bookingData); + } - public function commit_new_booking($booking_data, $channel) - { - return($this->request('/c/booking/new/commit.xml', $channel, "POST", $booking_data)); - } + public function commit_new_booking(SimpleXMLElement|string $bookingData, $channel) + { + return $this->request(self::PATH_API_BOOKING_COMMIT, $channel, self::HTTP_VERB_POST, $bookingData); + } - /* + /* Retrieving bookings */ - public function search_bookings($params = "", $channel = 0) - { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/bookings/search.xml'.$params)); - else - return($this->request('/c/bookings/search.xml'.$params, $channel)); - } - - public function list_bookings($params = "", $channel = 0) - { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/bookings/list.xml'.$params)); - else - return($this->request('/c/bookings/list.xml'.$params, $channel)); - } - - public function show_booking($booking, $channel) { - return($this->request('/c/booking/show.xml?booking_id='.$booking, $channel)); - } - - public function search_voucher($voucher_data = null, $channel = 0) { - - if($voucher_data == null) { - $voucher_data = new SimpleXMLElement(''); - $voucher_data->addChild('barcode_data', ''); - } - - if($channel == 0) { - return($this->request('/p/voucher/search.xml', $channel, 'POST', $voucher_data)); - } else { - return($this->request('/c/voucher/search.xml', $channel, 'POST', $voucher_data)); - } - } - - /* + public function search_bookings(string $params = "", int $channel = 0): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_BOOKINGS_SEARCH . $params); + + return $this->request(self::PATH_API_C_BOOKINGS_SEARCH . $params, $channel); + } + + public function list_bookings(string $params = "", int $channel = 0): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_BOOKINGS_LIST . $params); + + return $this->request(self::PATH_API_C_BOOKINGS_LIST . $params, $channel); + } + + public function show_booking(int $bookingId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKINGS_SHOW . '?booking_id=' . $bookingId, $channel); + } + + public function search_voucher(SimpleXMLElement|string|null $voucherData = null, $channel = 0): SimpleXMLElement|string + { + + if ($voucherData == null) { + $voucherData = new SimpleXMLElement(''); + $voucherData->addChild('barcode_data', ''); + } + + if ($channel == 0) { + return $this->request(self::PATH_API_P_VOUCHER_SEARCH, $channel, self::HTTP_VERB_POST, $voucherData); + } + + return $this->request(self::PATH_API_C_VOUCHER_SEARCH, $channel, self::HTTP_VERB_POST, $voucherData); + } + + /* Updating bookings */ - public function update_booking($booking_data, $channel) - { - return($this->request('/c/booking/update.xml', $channel, "POST", $booking_data)); - } - - public function create_payment($payment_data, $channel) - { - return($this->request('/c/booking/payment/new.xml', $channel, "POST", $payment_data)); - } - - public function log_failed_payment($payment_data, $channel) - { - return($this->request('/c/booking/payment/fail.xml', $channel, "POST", $payment_data)); - } - - public function spreedly_create_payment($payment_data, $channel) - { - return($this->request('/c/booking/payment/spreedly/new.xml', $channel, "POST", $payment_data)); - } - - public function spreedly_complete_payment($transaction_id, $channel) - { - return($this->request('/c/booking/gatewaytransaction/spreedlycomplete.xml?id=' . $transaction_id, $channel, 'POST')); - } - - public function cancel_booking($booking_data, $channel) - { - return($this->request('/c/booking/cancel.xml', $channel, "POST", $booking_data)); - } - - public function delete_booking($booking, $channel) - { - return($this->request('/c/booking/delete.xml?booking_id='.$booking, $channel, "POST")); - } - - public function check_option_availability($booking, $tour_component_id, $channel){ - return ($this->request('/c/booking/options/checkavail.xml?booking_id='.$booking.'&tour_component_id='.$tour_component_id, $channel)); - } - - public function booking_add_component($component_data, $channel){ - return($this->request('/c/booking/component/new.xml', $channel, "POST", $component_data)); - } - - public function booking_remove_component($component_data, $channel){ - return($this->request('/c/booking/component/delete.xml', $channel, "POST", $component_data)); - } - - public function booking_update_component($component_data, $channel){ - return($this->request('/c/booking/component/update.xml', $channel, "POST", $component_data)); - } - - public function add_note_to_booking($booking, $channel, $text, $note_type) { - - $booking_data = new SimpleXMLElement(''); - $booking_data->addChild('booking_id', $booking); - $note = $booking_data->addChild('note'); - $note->addChild('text', $text); - $note->addChild('type', $note_type); - - return($this->request('/c/booking/note/new.xml', $channel, 'POST', $booking_data)); - } - - public function send_booking_email($booking_data, $channel){ - return($this->request('/c/booking/email/send.xml', $channel, "POST", $booking_data)); - } - - public function redeem_voucher($voucher_data, $channel = 0) { - return($this->request('/c/voucher/redeem.xml', $channel, 'POST', $voucher_data)); - } - - # Enquiry and customer methods - - public function create_enquiry($enquiry_data, $channel) - { - return($this->request('/c/enquiry/new.xml', $channel, "POST", $enquiry_data)); - } - - public function search_enquiries($params = "", $channel = 0) { - $params = $this->validateParams($params); - if($channel==0) - return($this->request('/p/enquiries/search.xml'.$params)); - else - return($this->request('/c/enquiries/search.xml'.$params, $channel)); - } - - public function show_enquiry($enquiry, $channel) - { - return($this->request('/c/enquiry/show.xml?enquiry_id='.$enquiry, $channel)); - } - - public function check_customer_login($customer, $password, $channel) { - return ($this->request('/c/customers/login_search.xml?customer_username='.$customer.'&customer_password='.$password, $channel)); - } - - public function create_customer($customer, $channel) - { - return ($this->request('/c/customer/create.xml', $channel, self::HTTP_VERB_POST, $customer)); - } - - public function show_customer($customer, $channel) - { - return ($this->request('/c/customer/show.xml?customer_id='.$customer, $channel)); - } - - public function update_customer($customer, $channel) - { - return ($this->request('/c/customer/update.xml', $channel, self::HTTP_VERB_POST, $customer)); - } - - public function verify_customer($customer, $channel) - { - return ($this->request('/c/customer/verification.xml', $channel, self::HTTP_VERB_POST, $customer)); - } - - # Agents - public function search_agents($params, $channel) - { - $params = $this->validateParams($params); - return($this->request('/c/agents/search.xml'.$params, $channel)); - } - - public function start_new_agent_login($params, $channel) - { - return($this->request('/c/start_agent_login.xml', $channel, "POST", $params)); - } - - public function retrieve_agent_booking_key($private_token, $channel) - { - return($this->request('/c/retrieve_agent_booking_key.xml?k='.$private_token, $channel)); - } - - public function update_agent($update_data, $channel) - { - return ($this->request('/c/agents/update.xml', $channel, "POST", $update_data)); - } - - public function show_agent_profile($agent, $channel = 0) - { - return($this->request(self::PATH_API_AGENT_PROFILE_GET."?id=$agent", $channel)); - } - - public function update_agent_profile($update_data) - { - return ($this->request(self::PATH_API_AGENT_PROFILE_UPDATE, 0, "POST", $update_data)); - } - - # Payments - public function list_payments($params, $channel) - { - $params = $this->validateParams($params); - return($this->request('/c/booking/payment/list.xml'.$params, $channel)); - } - - public function payworks_booking_payment_new($payment, $channel) - { - return ($this->request('/c/booking/payment/payworks/new.xml', $channel, "POST", $payment)); - } - - # Staff members - public function list_staff_members($channel) - { - return($this->request('/c/staff/list.xml', $channel)); - } - - # Internal supplier methods - public function show_supplier($supplier, $channel) - { - return($this->request('/c/supplier/show.xml?supplier_id='.$supplier, $channel)); - } - - # Used for validating webhook signatures - public function validate_xml_hash($xml) - { - return $this->generate_xml_hash($xml) == $xml->signed->hash; - } - - public function generate_xml_hash($xml) - { - $algorithm = $xml->signed->algorithm; - $fields = explode(" ", $xml->signed->hash_fields); - - $values = []; - foreach($fields as $field) { - $xpath_result = $xml->xpath($field); - foreach($xpath_result as $result) { - $values[] = (string)$result[0]; - } - } - - $string_to_hash = implode("|", $values); - $hash = $this->get_hash($algorithm, $string_to_hash); - return $hash; - } - - public function get_hash($algorithm, $string_to_hash) :string - { - return hash_hmac($algorithm, $string_to_hash, $this->private_key, FALSE); - } - - # CRUD Pickup points - public function list_pickups($query_string, $channel) - { - $query_string = $this->validateParams($query_string); - return ($this->request('/c/pickups/list.xml' . $query_string, $channel)); - } - - public function create_pickup($pickup_data, $channel) - { - return ($this->request('/c/pickups/new.xml', $channel, "POST", $pickup_data)); - } - - public function update_pickup($pickup_data, $channel) - { - return ($this->request('/c/pickups/update.xml', $channel, "POST", $pickup_data)); - } - - public function delete_pickup($pickup_data, $channel) - { - return ($this->request('/c/pickups/delete.xml', $channel, "POST", $pickup_data)); - } - - public function show_tours_pickup_routes($tour, $channel) - { - return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_SHOW."?id=$tour", $channel); - } - - public function update_tours_pickup_routes($data, $channel) - { - return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE, $channel, self::HTTP_VERB_POST, $data); - } - - public function tours_pickup_routes_add_pickup($data, $channel) - { - return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_ADD_PICKUP, $channel, self::HTTP_VERB_POST, $data); - } - - public function tours_pickup_routes_update_pickup($data, $channel) - { - return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE_PICKUP, $channel, self::HTTP_VERB_POST, $data); - } - - public function tours_pickup_routes_delete_pickup($data, $channel) - { - return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_DELETE_PICKUP, $channel, self::HTTP_VERB_POST, $data); - } - - # Account - public function create_account($upload_info) { - $url = "/p/account/create.xml"; - return($this->request($url, 0, self::HTTP_VERB_POST, $upload_info)); - } - - public function update_account($upload_info, $channel) { - $url = "/p/account/update.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $upload_info)); - } - - public function show_account($account_id) { - $url = "/p/account/show.xml?account_id=".$account_id; - return($this->request($url, 0)); - } - - public function create_channel($channel_info, $channel) { - $url = "/p/channel/create.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $channel_info)); - } - - public function update_channel($channel_info, $channel) { - $url = "/p/channel/update.xml"; - return($this->request($url, $channel, self::HTTP_VERB_POST, $channel_info)); - } - - public function show_markup_scheme($channel) { - $url = "/c/markups/show.xml"; - return($this->request($url, $channel, self::HTTP_VERB_GET)); - } - - public function create_tour_geopoint($geopoint, $channel) - { - return $this->request(self::PATH_API_TOUR_GEOS_CREATE, $channel, self::HTTP_VERB_POST, $geopoint); - } - - public function update_tour_geopoint($geopoint, $channel) - { - return $this->request(self::PATH_API_TOUR_GEOS_UPDATE, $channel, self::HTTP_VERB_POST, $geopoint); - } - - public function delete_tour_geopoint($geopoint, $channel) - { - return $this->request(self::PATH_API_TOUR_GEOS_DELETE, $channel, self::HTTP_VERB_POST, $geopoint); - } - - public function get_custom_fields($channel) - { - return $this->request(self::PATH_API_ACCOUNT_CUSTOM_FIELDS_GET, $channel, self::HTTP_VERB_GET); - } - - public function get_tour_facets($channel) - { - return $this->request(self::PATH_API_TOUR_FACETS_GET, $channel, self::HTTP_VERB_GET); - } - - public function get_list_tours($channel, $query_string) - { - $query_string = $this->validateParams($query_string); - return $this->request(self::PATH_API_LIST_TOURS_GET.$query_string, $channel, self::HTTP_VERB_GET); - } - - public function get_import_tours_status($channel, $codes) - { - return $this->request(self::PATH_API_IMPORT_TOURS_STATUS, $channel, self::HTTP_VERB_POST, $codes); - } - - public function list_tour_booking_restrictions($channel, $query_string) - { - $query_string = $this->validateParams($query_string); - return $this->request(self::PATH_API_LIST_TOUR_BOOKINGS_RESTRICTIONS.$query_string, $channel, self::HTTP_VERB_GET); - } - -// Internal Functions - - protected function validateParams($params) - { - if (empty($params) || !is_string($params)) { - return ''; - } - - if (!empty($params) && substr($params, 0, 1) !== '?') { - $params = '?'.$params; - } - - return $params; - } - - /** - * generate_signature - * - * @author Paul Slugocki - * @param $path API Path - * @param $verb HTTP Verb - * @param $channel Channel ID - * @return String - */ - protected function generate_signature($path, $verb, $channel, $outbound_time) - { - $string_to_sign = trim($channel."/".$this->marketp_id."/".$verb."/".$outbound_time.$path); - $signature = rawurlencode(base64_encode((hash_hmac("sha256", mb_convert_encoding($string_to_sign, 'UTF-8', 'ISO-8859-1'), $this->private_key, TRUE )))); - return $signature; - } - -} \ No newline at end of file + public function update_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_UPDATE, $channel, self::HTTP_VERB_POST, $bookingData); + } + + public function create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PAYMENT_NEW, $channel, self::HTTP_VERB_POST, $paymentData); + } + + public function log_failed_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PAYMENT_FAIL, $channel, self::HTTP_VERB_POST, $paymentData); + } + + public function spreedly_create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PAYMENT_SPREEDLY_CREATE, $channel, self::HTTP_VERB_POST, $paymentData); + } + + public function spreedly_complete_payment(string $transactionId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PAYMENT_SPREEDLY_COMPLETE . '?id=' . $transactionId, $channel, self::HTTP_VERB_POST); + } + + public function cancel_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_CANCEL, $channel, self::HTTP_VERB_POST, $bookingData); + } + + public function delete_booking(int $bookingId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_DELETE . '?booking_id=' . $bookingId, $channel, self::HTTP_VERB_POST); + } + + public function check_option_availability(int $bookingId, string $tourComponentId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_OPTION_CHECK_AVAILABILITY . '?booking_id=' . $bookingId . '&tour_component_id=' . $tourComponentId, $channel); + } + + public function booking_add_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_COMPONENT_NEW, $channel, self::HTTP_VERB_POST, $componentData); + } + + public function booking_remove_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_COMPONENT_DELETE, $channel, self::HTTP_VERB_POST, $componentData); + } + + public function booking_update_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_COMPONENT_UPDATE, $channel, self::HTTP_VERB_POST, $componentData); + } + + public function add_note_to_booking(int $bookingId, int $channel, string $text, string $noteType): SimpleXMLElement|string + { + + $bookingData = new SimpleXMLElement(''); + $bookingData->addChild('booking_id', $bookingId); + $note = $bookingData->addChild('note'); + $note->addChild('text', $text); + $note->addChild('type', $noteType); + + return $this->request(self::PATH_API_BOOKING_NOTE_NEW, $channel, self::HTTP_VERB_POST, $bookingData); + } + + public function send_booking_email(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_BOOKING_EMAIL_SEND, $channel, self::HTTP_VERB_POST, $bookingData); + } + + public function redeem_voucher(SimpleXMLElement|string $voucherData, int $channel = 0): SimpleXMLElement|string + { + return $this->request(self::PATH_API_VOUCHER_REDEEM, $channel, self::HTTP_VERB_POST, $voucherData); + } + + # Enquiry and customer methods + + public function create_enquiry(SimpleXMLElement|string $enquiryData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_ENQUIRY_NEW, $channel, self::HTTP_VERB_POST, $enquiryData); + } + + public function update_customer(SimpleXMLElement|string $customerData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CUSTOMER_UPDATE, $channel, self::HTTP_VERB_POST, $customerData); + } + + public function search_enquiries(string $params = "", int $channel = 0): SimpleXMLElement|string + { + $params = $this->validateParams($params); + if ($channel == 0) return $this->request(self::PATH_API_P_ENQUIRIES_SEARCH . $params); + + return $this->request(self::PATH_API_C_ENQUIRIES_SEARCH . $params, $channel); + } + + public function show_enquiry(int $enquiryId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_ENQUIRY_SHOW . '?enquiry_id=' . $enquiryId, $channel); + } + + public function show_customer(int $customerId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CUSTOMER_SHOW . '?customer_id=' . $customerId, $channel); + } + + public function check_customer_login(string $username, string $password, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CUSTOMER_LOGIN_SEARCH . '?customer_username=' . $username . '&customer_password=' . $password, $channel); + } + + # Agents + public function search_agents(string $params, int $channel): SimpleXMLElement|string + { + $params = $this->validateParams($params); + return $this->request(self::PATH_API_AGENTS_SEARCH . $params, $channel); + } + + public function start_new_agent_login(string $params, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_START_AGENT_LOGIN, $channel, self::HTTP_VERB_POST, $params); + } + + public function retrieve_agent_booking_key(string $privateToken, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_AGENT_BOOKING_KEY_RETRIEVE . '?k=' . $privateToken, $channel); + } + + public function update_agent(SimpleXMLElement|string $agentData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_AGENTS_UPDATE, $channel, self::HTTP_VERB_POST, $agentData); + } + + public function show_agent_profile(SimpleXMLElement|string $agent, int $channel = 0): SimpleXMLElement|string + { + return $this->request(self::PATH_API_AGENT_PROFILE_GET . "?id=$agent", $channel); + } + + public function update_agent_profile(SimpleXMLElement|string $agentProfileData): SimpleXMLElement|string + { + return $this->request(self::PATH_API_AGENT_PROFILE_UPDATE, 0, self::HTTP_VERB_POST, $agentProfileData); + } + + # Payments + public function list_payments($params, $channel): SimpleXMLElement|string + { + $params = $this->validateParams($params); + return $this->request(self::PATH_API_PAYMENTS_LIST . $params, $channel); + } + + public function payworks_booking_payment_new(SimpleXMLElement|string $payment, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PAYMENTS_PAYWORKS_NEW, $channel, self::HTTP_VERB_POST, $payment); + } + + # Staff members + public function list_staff_members(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_STAFF_LIST, $channel); + } + + # Internal supplier methods + public function show_supplier(int $supplierId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_SUPPLIER_SHOW . '?supplier_id=' . $supplierId, $channel); + } + + # CRUD Pickup points + public function list_pickups(string $params, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PICKUPS_LIST . $this->validateParams($params), $channel); + } + + public function create_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PICKUPS_NEW, $channel, self::HTTP_VERB_POST, $pickupData); + } + + public function update_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PICKUPS_UPDATE, $channel, self::HTTP_VERB_POST, $pickupData); + } + + public function delete_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_PICKUPS_DELETE, $channel, self::HTTP_VERB_POST, $pickupData); + } + + public function show_tours_pickup_routes(int $tourId, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_SHOW . "?id=$tourId", $channel); + } + + public function update_tours_pickup_routes(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE, $channel, self::HTTP_VERB_POST, $data); + } + + public function tours_pickup_routes_add_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_ADD_PICKUP, $channel, self::HTTP_VERB_POST, $data); + } + + public function tours_pickup_routes_update_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE_PICKUP, $channel, self::HTTP_VERB_POST, $data); + } + + public function tours_pickup_routes_delete_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_DELETE_PICKUP, $channel, self::HTTP_VERB_POST, $data); + } + + # Account + public function create_account(SimpleXMLElement|string $uploadInfo): SimpleXMLElement|string + { + return $this->request(self::PATH_API_ACCOUNT_CREATE, 0, self::HTTP_VERB_POST, $uploadInfo); + } + + public function update_account(SimpleXMLElement|string $uploadInfo, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_ACCOUNT_UPDATE, $channel, self::HTTP_VERB_POST, $uploadInfo); + } + + public function show_account(int $accountId): SimpleXMLElement|string + { + $url = self::PATH_API_ACCOUNT_SHOW . "?account_id=" . $accountId; + return $this->request($url, 0); + } + + public function create_channel(SimpleXMLElement|string $channel_info, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CHANNEL_CREATE, $channel, self::HTTP_VERB_POST, $channel_info); + } + + public function update_channel(SimpleXMLElement|string $channelInfo, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CHANNEL_UPDATE, $channel, self::HTTP_VERB_POST, $channelInfo); + } + + public function show_markup_scheme(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_MARKUP_SCHEME_SHOW, $channel, self::HTTP_VERB_GET); + } + + public function create_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_GEOS_CREATE, $channel, self::HTTP_VERB_POST, $geopoint); + } + + public function update_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_GEOS_UPDATE, $channel, self::HTTP_VERB_POST, $geopoint); + } + + public function delete_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_GEOS_DELETE, $channel, self::HTTP_VERB_POST, $geopoint); + } + + public function get_custom_fields(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_ACCOUNT_CUSTOM_FIELDS_GET, $channel, self::HTTP_VERB_GET); + } + + public function get_tour_facets(int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_TOUR_FACETS_GET, $channel, self::HTTP_VERB_GET); + } + + public function get_list_tours(int $channel, string $queryString): SimpleXMLElement|string + { + $queryString = $this->validateParams($queryString); + return $this->request(self::PATH_API_LIST_TOURS_GET . $queryString, $channel, self::HTTP_VERB_GET); + } + + public function get_import_tours_status(int $channel, SimpleXMLElement|string $codes): SimpleXMLElement|string + { + return $this->request(self::PATH_API_IMPORT_TOURS_STATUS, $channel, self::HTTP_VERB_POST, $codes); + } + + public function list_tour_booking_restrictions(int $channel, string $queryString): SimpleXMLElement|string + { + $queryString = $this->validateParams($queryString); + return $this->request(self::PATH_API_LIST_TOUR_BOOKINGS_RESTRICTIONS . $queryString, $channel, self::HTTP_VERB_GET); + } + + # Used for validating webhook signatures + /** + * Validate XML Hash + * @param SimpleXMLElement $xml + * @return bool + */ + public function validate_xml_hash(SimpleXMLElement $xml): bool + { + return $this->generate_xml_hash($xml) == $xml->signed->hash; + } + + /** + * @param \SimpleXMLElement $xml + * @return string + */ + public function generate_xml_hash(SimpleXMLElement $xml): string + { + $algorithm = $xml->signed->algorithm; + $fields = explode(" ", $xml->signed->hash_fields); + + $values = []; + foreach ($fields as $field) { + $xpath_result = $xml->xpath($field); + foreach ($xpath_result as $result) { + $values[] = (string)$result[0]; + } + } + + $stringToHash = implode("|", $values); + $hash = $this->get_hash($algorithm, $stringToHash); + return $hash; + } + + /** + * @param string $algorithm + * @param string $stringToHash + * @return string + */ + public function get_hash(string $algorithm, string $stringToHash): string + { + return hash_hmac($algorithm, $stringToHash, $this->privateKey, false); + } + + // Internal Functions + + protected function validateParams(mixed $params): string + { + if (empty($params) || !is_string($params)) { + return ''; + } + + if (!empty($params) && substr($params, 0, 1) !== '?') { + $params = '?' . $params; + } + + return $params; + } + + /** + * generateSignature + * + * @author Paul Slugocki + * @param $path API Path + * @param $verb HTTP Verb + * @param $channel Channel ID + * @return string + */ + protected function generateSignature(string $path, string $verb, string $channel, int $outboundTime): string + { + $string_to_sign = trim($channel . "/" . $this->marketplaceId . "/" . $verb . "/" . $outboundTime . $path); + $signature = rawurlencode(base64_encode((hash_hmac("sha256", mb_convert_encoding($string_to_sign, 'UTF-8', 'ISO-8859-1'), $this->privateKey, TRUE)))); + return $signature; + } + + protected function isXMLObject(mixed $postData): bool + { + return $postData instanceof SimpleXMLElement; + } +} From de1bec894bd42634c71d0f47524ced7ce6211d4e Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Fri, 9 May 2025 14:51:18 +0200 Subject: [PATCH 2/8] TOURCMS-11047 Restore create customer and verify customer methods and remove isXMLObject method --- src/TourCMS.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index beb9ffd..ae62b7e 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -145,9 +145,11 @@ class TourCMS // Customer(s) + public const PATH_API_CUSTOMER_CREATE = '/c/customer/create.xml'; public const PATH_API_CUSTOMER_SHOW = '/c/customer/show.xml'; public const PATH_API_CUSTOMER_UPDATE = '/c/customer/update.xml'; public const PATH_API_CUSTOMER_LOGIN_SEARCH = '/c/customers/login_search.xml'; + public const PATH_API_CUSTOMER_VERIFICATION = '/c/customer/verification.xml'; // Pickups @@ -276,7 +278,7 @@ public function request(string $path, int $channel = 0, string $verb = self::HTT if (is_string($postData)) { curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); } - if ($this->isXMLObject($postData)) { + if ($postData instanceof SimpleXMLElement) { curl_setopt($ch, CURLOPT_POSTFIELDS, $postData->asXML()); } } @@ -826,6 +828,11 @@ public function show_enquiry(int $enquiryId, int $channel): SimpleXMLElement|str return $this->request(self::PATH_API_ENQUIRY_SHOW . '?enquiry_id=' . $enquiryId, $channel); } + public function create_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CUSTOMER_CREATE, $channel, self::HTTP_VERB_POST, $customer); + } + public function show_customer(int $customerId, int $channel): SimpleXMLElement|string { return $this->request(self::PATH_API_CUSTOMER_SHOW . '?customer_id=' . $customerId, $channel); @@ -836,6 +843,11 @@ public function check_customer_login(string $username, string $password, int $ch return $this->request(self::PATH_API_CUSTOMER_LOGIN_SEARCH . '?customer_username=' . $username . '&customer_password=' . $password, $channel); } + public function verify_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement|string + { + return $this->request(self::PATH_API_CUSTOMER_VERIFICATION, $channel, self::HTTP_VERB_POST, $customer); + } + # Agents public function search_agents(string $params, int $channel): SimpleXMLElement|string { @@ -1086,8 +1098,4 @@ protected function generateSignature(string $path, string $verb, string $channel return $signature; } - protected function isXMLObject(mixed $postData): bool - { - return $postData instanceof SimpleXMLElement; - } } From b0bb45b12243b352d81afa07001aecd90e4d0368 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Fri, 9 May 2025 14:56:49 +0200 Subject: [PATCH 3/8] TOURCMS-11047 Improve docs and use camelCase to name vars --- src/TourCMS.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index ae62b7e..3559a1e 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -215,8 +215,8 @@ class TourCMS * __construct * * @author Paul Slugocki - * @param $mp Marketplace ID - * @param $k API Private Key + * @param $marketplaceId Marketplace ID + * @param $key API Private Key * @param $resultType Result type, defaults to raw * @param $timeout Timeout, default 0 */ @@ -232,9 +232,10 @@ public function __construct(int $marketplaceId, string $key, string $resultType * request * * @author Paul Slugocki - * @param $path API path to call - * @param $channel Channel ID, defaults to zero - * @param $verb HTTP Verb, defaults to GET + * @param string $path API path to call + * @param int $channel Channel ID, defaults to zero + * @param string $verb HTTP Verb, defaults to GET + * @param null|string|SimpleXMLElement $postData POST data to send * @return string|SimpleXMLElement */ public function request(string $path, int $channel = 0, string $verb = self::HTTP_VERB_GET, null|string|SimpleXMLElement $postData = null): bool|SimpleXMLElement|string @@ -306,8 +307,8 @@ function ($ch, $header) use (&$apiResponseHeaders) { $this->lastResponseHeaders = $apiResponseHeaders; - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $result = substr($response, $header_size); + $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $result = substr($response, $headerSize); // Check whether we need to return raw XML or // convert to SimpleXML first @@ -1046,8 +1047,8 @@ public function generate_xml_hash(SimpleXMLElement $xml): string $values = []; foreach ($fields as $field) { - $xpath_result = $xml->xpath($field); - foreach ($xpath_result as $result) { + $xpathResult = $xml->xpath($field); + foreach ($xpathResult as $result) { $values[] = (string)$result[0]; } } From bb1cb479518eaa481c869dc0d3a8b2a9c3366201 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Mon, 12 May 2025 08:38:14 +0200 Subject: [PATCH 4/8] TOURMCS-11047 Maintain return types and methods names --- src/TourCMS.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index 3559a1e..3da2510 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -339,9 +339,11 @@ public function get_base_url(): string * @param $url New base url * @return bool */ - public function set_base_url(string $url): void + public function set_base_url(string $url): bool { $this->baseUrl = $url; + + return true; } /** @@ -350,10 +352,12 @@ public function set_base_url(string $url): void * @author Francisco Martinez Ramos * @return bool */ - public function set_user_agent(string $user_agent, bool $prepend = true): void + public function set_user_agent(string $user_agent, bool $prepend = true): bool { $this->prependCallerToUserAgent = $prepend; $this->userAgent = $user_agent; + + return true; } /** @@ -362,9 +366,9 @@ public function set_user_agent(string $user_agent, bool $prepend = true): void * @author Francisco Martínez Ramos * @param string $header Key of the header * @param string $value Value of the header - * @return void + * @return bool */ - public function add_header(string $header, string $value, bool $permanent = false): void + public function add_header(string $header, string $value, bool $permanent = false): bool { $newHeader = "$header: $value"; @@ -373,6 +377,8 @@ public function add_header(string $header, string $value, bool $permanent = fals } else { array_push($this->headers, $newHeader); } + + return true; } /** @@ -396,7 +402,7 @@ public function get_last_request_headers(): array # Get last response headers - public function get_lastResponseHeaders(): array + public function get_last_response_headers(): array { return $this->lastResponseHeaders; } From 3497db0f9f7c6b38f53005fb7aac34dd7f68a3f4 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Mon, 19 May 2025 13:43:53 +0200 Subject: [PATCH 5/8] TOURCMS-11047 Use camelCase and improve naming --- src/TourCMS.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index 3da2510..b230cf6 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -352,10 +352,10 @@ public function set_base_url(string $url): bool * @author Francisco Martinez Ramos * @return bool */ - public function set_user_agent(string $user_agent, bool $prepend = true): bool + public function set_user_agent(string $userAgent, bool $prepend = true): bool { $this->prependCallerToUserAgent = $prepend; - $this->userAgent = $user_agent; + $this->userAgent = $userAgent; return true; } @@ -509,9 +509,9 @@ public function list_product_filters(int $channel = 0): SimpleXMLElement|string return $this->request(self::PATH_API_TOURS_FILTERS, $channel); } - public function update_tour($tour_data, int $channel): SimpleXMLElement|string + public function update_tour(SimpleXMLElement|string $tour, int $channel): SimpleXMLElement|string { - return $this->request(self::PATH_API_TOUR_UPDATE, $channel, self::HTTP_VERB_POST, $tour_data); + return $this->request(self::PATH_API_TOUR_UPDATE, $channel, self::HTTP_VERB_POST, $tour); } public function update_tour_url(int $tourId, int $channel, string $tourUrl): SimpleXMLElement|string @@ -974,9 +974,9 @@ public function show_account(int $accountId): SimpleXMLElement|string return $this->request($url, 0); } - public function create_channel(SimpleXMLElement|string $channel_info, int $channel): SimpleXMLElement|string + public function create_channel(SimpleXMLElement|string $newChannel, int $channel): SimpleXMLElement|string { - return $this->request(self::PATH_API_CHANNEL_CREATE, $channel, self::HTTP_VERB_POST, $channel_info); + return $this->request(self::PATH_API_CHANNEL_CREATE, $channel, self::HTTP_VERB_POST, $newChannel); } public function update_channel(SimpleXMLElement|string $channelInfo, int $channel): SimpleXMLElement|string From 0f3dfacbedf453de329fa2f555e0a024d798e0b3 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Tue, 20 May 2025 10:33:56 +0200 Subject: [PATCH 6/8] TOURCMS-11047 Return response only as SimpleXMLElement and improve validation of tourId --- src/TourCMS.php | 349 ++++++++++++++++++++++++++++++------------------ 1 file changed, 220 insertions(+), 129 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index b230cf6..d5d8a9c 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -26,6 +26,7 @@ namespace TourCMS\Utils; +use InvalidArgumentException; use \SimpleXMLElement; class TourCMS @@ -195,14 +196,14 @@ class TourCMS public const HTTP_VERB_GET = 'GET'; public const HEADER_X_REQUEST_ID = 'X-Request-Id'; - public const RESULT_TYPE_RAW = "raw"; - public const RESULT_TYPE_XML = "simplexml"; + // ERRORS CONSTS + public const ERROR_MESSAGE_INVALID_CHANNEL_ID = 'Channel ID must be greater than 0'; + public const ERROR_MESSAGE_INVALID_TOUR_ID = 'Tour ID must be greater than 0'; // General settings protected string $baseUrl = "https://api.tourcms.com"; protected int $marketplaceId = 0; protected string $privateKey = ""; - protected string $resultType = ""; protected int $timeout = 0; protected array $lastRequestHeaders = []; protected array $lastResponseHeaders = []; @@ -217,14 +218,12 @@ class TourCMS * @author Paul Slugocki * @param $marketplaceId Marketplace ID * @param $key API Private Key - * @param $resultType Result type, defaults to raw * @param $timeout Timeout, default 0 */ - public function __construct(int $marketplaceId, string $key, string $resultType = self::RESULT_TYPE_RAW, int $timeout = 0) + public function __construct(int $marketplaceId, string $key, int $timeout = 0) { $this->marketplaceId = $marketplaceId; $this->privateKey = $key; - $this->resultType = $resultType; $this->timeout = $timeout; } @@ -236,9 +235,9 @@ public function __construct(int $marketplaceId, string $key, string $resultType * @param int $channel Channel ID, defaults to zero * @param string $verb HTTP Verb, defaults to GET * @param null|string|SimpleXMLElement $postData POST data to send - * @return string|SimpleXMLElement + * @return SimpleXMLElement */ - public function request(string $path, int $channel = 0, string $verb = self::HTTP_VERB_GET, null|string|SimpleXMLElement $postData = null): bool|SimpleXMLElement|string + public function request(string $path, int $channel = 0, string $verb = self::HTTP_VERB_GET, null|string|SimpleXMLElement $postData = null): bool|SimpleXMLElement { // Prepare the URL we are sending to $url = $this->baseUrl . $path; @@ -310,10 +309,8 @@ function ($ch, $header) use (&$apiResponseHeaders) { $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $result = substr($response, $headerSize); - // Check whether we need to return raw XML or - // convert to SimpleXML first - if ($this->resultType == self::RESULT_TYPE_XML) - $result = simplexml_load_string($result); + // We have to convert the result to a SimpleXMLElement object + $result = simplexml_load_string($result); $this->lastRequestHeaders = $this->headers; $this->headers = []; @@ -373,9 +370,9 @@ public function add_header(string $header, string $value, bool $permanent = fals $newHeader = "$header: $value"; if ($permanent) { - array_push($this->permanentHeaders, $newHeader); + $this->permanentHeaders[] = $newHeader; } else { - array_push($this->headers, $newHeader); + $this->headers[] = $newHeader; } return true; @@ -416,34 +413,34 @@ public function test_environment(int $channel = 0): void # API methods (Housekeeping) - public function api_rate_limit_status(int $channel = 0): SimpleXMLElement|string + public function api_rate_limit_status(int $channel = 0): SimpleXMLElement { return $this->request(self::PATH_API_RATE_LIMIT, $channel); } # Channel methods - public function list_channels(string $params = ""): SimpleXMLElement|string + public function list_channels(string $params = ""): SimpleXMLElement { return $this->request(self::PATH_API_CHANNELS_LIST . $this->validateParams($params)); } - public function channel_upload_logo_get_url(int $channel): SimpleXMLElement|string + public function channel_upload_logo_get_url(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CHANNEL_LOGO_UPLOAD_GET_URL, $channel); } - public function channel_upload_logo_process(int $channel, SimpleXMLElement|string $uploadInfo) + public function channel_upload_logo_process(int $channel, SimpleXMLElement|string $uploadInfo): SimpleXMLElement { return $this->request(self::PATH_API_CHANNEL_LOGO_UPLOAD_PROCESS, $channel, self::HTTP_VERB_POST, $uploadInfo); } - public function show_channel(int $channel): SimpleXMLElement|string + public function show_channel(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CHANNEL_SHOW, $channel); } - public function channel_performance(int $channel = 0): SimpleXMLElement|string + public function channel_performance(int $channel = 0): SimpleXMLElement { if ($channel == 0) return $this->request(self::PATH_API_P_CHANNELS_PERFORMANCE); @@ -453,7 +450,7 @@ public function channel_performance(int $channel = 0): SimpleXMLElement|string # Tour/Hotel methods - public function search_tours(string $params = "", int $channel = 0): SimpleXMLElement|string + public function search_tours(string $params = "", int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); @@ -463,7 +460,7 @@ public function search_tours(string $params = "", int $channel = 0): SimpleXMLEl return $this->request(self::PATH_API_C_TOURS_SEARCH . $params, $channel); } - public function search_hotels_range(string $params = "", ?int $tourId = null, int $channel = 0) + public function search_hotels_range(string $params = "", ?int $tourId = null, int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); @@ -484,7 +481,7 @@ public function search_hotels_range(string $params = "", ?int $tourId = null, in return $this->request(self::PATH_API_C_HOTELS_SEARCH_RANGE . $params, $channel); } - public function search_hotels_specific(string $params = "", ?int $tourId = null, int $channel = 0) + public function search_hotels_specific(string $params = "", ?int $tourId = null, int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); @@ -504,17 +501,17 @@ public function search_hotels_specific(string $params = "", ?int $tourId = null, return $this->request(self::PATH_API_C_HOTELS_SEARCH_AVAIL . $params, $channel); } - public function list_product_filters(int $channel = 0): SimpleXMLElement|string + public function list_product_filters(int $channel = 0): SimpleXMLElement { return $this->request(self::PATH_API_TOURS_FILTERS, $channel); } - public function update_tour(SimpleXMLElement|string $tour, int $channel): SimpleXMLElement|string + public function update_tour(SimpleXMLElement|string $tour, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_UPDATE, $channel, self::HTTP_VERB_POST, $tour); } - public function update_tour_url(int $tourId, int $channel, string $tourUrl): SimpleXMLElement|string + public function update_tour_url(int $tourId, int $channel, string $tourUrl): SimpleXMLElement { $urlData = new SimpleXMLElement(''); @@ -524,7 +521,7 @@ public function update_tour_url(int $tourId, int $channel, string $tourUrl): Sim return $this->update_tour($urlData, $channel); } - public function list_tours(int $channel = 0, string $params = ""): SimpleXMLElement|string + public function list_tours(int $channel = 0, string $params = ""): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_LIST . $params); @@ -532,7 +529,7 @@ public function list_tours(int $channel = 0, string $params = ""): SimpleXMLElem return $this->request(self::PATH_API_C_TOURS_LIST . $params, $channel); } - public function list_tour_images(int $channel = 0, string $params = ""): SimpleXMLElement|string + public function list_tour_images(int $channel = 0, string $params = ""): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_IMAGES_LIST . $params); @@ -540,7 +537,7 @@ public function list_tour_images(int $channel = 0, string $params = ""): SimpleX return $this->request(self::PATH_API_C_TOURS_IMAGES_LIST . $params, $channel); } - public function list_tour_locations(int $channel = 0, string $params = ""): SimpleXMLElement|string + public function list_tour_locations(int $channel = 0, string $params = ""): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_TOURS_LOCATIONS . $params); @@ -548,84 +545,127 @@ public function list_tour_locations(int $channel = 0, string $params = ""): Simp return $this->request(self::PATH_API_C_TOURS_LOCATIONS . $params, $channel); } - public function delete_tour(int $tourId, int $channel): SimpleXMLElement|string + public function delete_tour(int $tourId, int $channel): SimpleXMLElement { $url = self::PATH_API_TOUR_DELETE .'?id=' . $tourId; return $this->request($url, $channel, self::HTTP_VERB_POST); } - public function show_tour(int $tourId, int $channel, ?string $params = null) + /** + * Show Tour + * @param int $tourId + * @param int $channel + * @param mixed $params + * @throws \InvalidArgumentException + * @return SimpleXMLElement|string + */ + public function show_tour(int $tourId, int $channel, ?string $params = null): SimpleXMLElement { - $url = self::PATH_API_TOUR_SHOW . '?id=' . $tourId; - - /* - - Third param for show tour could be: - - - bool: show_options=1 / 0 (deprecated) + $this->validateTourId($tourId); - - string: params - - */ + $url = self::PATH_API_TOUR_SHOW . '?id=' . $tourId; if (is_string($params)) { - $url .= "&" . $params; } else { - - if ($params) - $url .= "&show_options=1"; + if ($params) $url .= "&show_options=1"; } - if ($tourId > 0) { - return $this->request($url, $channel); - } + return $this->request($url, $channel); } - public function tour_upload_file_get_url($tour, $channel, $file_type, $file_id): SimpleXMLElement|string + /** + * Tour upload file get URL + * @param int $tourId + * @param int $channel + * @param string $file_type + * @param string $file_id + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function tour_upload_file_get_url(int $tourId, int $channel, string $file_type, string $file_id): SimpleXMLElement { - $url = self::PATH_API_TOURS_FILE_UPLOAD_GET_URL . "?id=$tour&file_type=$file_type&file_id=$file_id"; + $this->validateTourId($tourId); + + $url = self::PATH_API_TOURS_FILE_UPLOAD_GET_URL . "?id=$tourId&file_type=$file_type&file_id=$file_id"; return $this->request($url, $channel, self::HTTP_VERB_GET); } - public function tour_upload_file_process(int $channel, SimpleXMLElement|string $uploadInfo): SimpleXMLElement|string + public function tour_upload_file_process(int $channel, SimpleXMLElement|string $uploadInfo): SimpleXMLElement { return $this->request(self::PATH_API_TOURS_FILES_UPLOAD_PROCESS, $channel, self::HTTP_VERB_POST, $uploadInfo); } - public function delete_tour_image(int $channel, SimpleXMLElement|string $image_info): SimpleXMLElement|string + public function delete_tour_image(int $channel, SimpleXMLElement|string $image_info): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_IMAGES_DELETE, $channel, self::HTTP_VERB_POST, $image_info); } - public function delete_tour_document(int $channel, $documentXML): SimpleXMLElement|string + public function delete_tour_document(int $channel, SimpleXMLElement|string $documentXML): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_DOCUMENT_DELETE, $channel, self::HTTP_VERB_POST, $documentXML); } - - public function check_tour_availability(string $params, int $tourId, int $channel): SimpleXMLElement|string + /** + * Check Tour Availability + * @param string $params + * @param int $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function check_tour_availability(string $params, int $tourId, int $channel): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_SHOW_TOUR_AVAILABILITY . '?id=' . $tourId . $this->validateParams($params), $channel); } - public function show_tour_datesanddeals(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + /** + * Show Tour Dates and Deals + * @param int $tourId + * @param int $channel + * @param string $params + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function show_tour_datesanddeals(int $tourId, int $channel, string $params = ""): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_TOUR_DATES_AND_DEALS .'?id=' . $tourId . $this->validateParams($params), $channel); } - - public function show_tour_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + /** + * Show Tour Departures + * @param int $tourId + * @param int $channel + * @param string $params + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function show_tour_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_SHOW_TOUR_DEPARTURES . '?id=' . $tourId . $this->validateParams($params), $channel); } - public function show_tour_freesale(int $tourId, int $channel): SimpleXMLElement|string + /** + * Show Tour Freesale + * @param int $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function show_tour_freesale(int $tourId, int $channel): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::API_PATH_SHOW_TOUR_FREESALE . '?id=' . $tourId, $channel); } - public function tours_search_criteria(int $channel): SimpleXMLElement|string + public function tours_search_criteria(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOURS_SEARCH_CRITERIA_GET, $channel); } @@ -634,28 +674,57 @@ public function tours_search_criteria(int $channel): SimpleXMLElement|string Raw departure methods */ - public function search_raw_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement|string + /** + * Search Raw Departures + * @param int $tourId + * @param int $channel + * @param string $params + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function search_raw_departures(int $tourId, int $channel, string $params = ""): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_SEARCH_RAW_DEPARTURES . '?id=' . $tourId . $this->validateParams($params), $channel); } - public function show_departure(int $departure, int $tour, int $channel): SimpleXMLElement|string + /** + * Show Departure + * @param int $departure + * @param int $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function show_departure(int $departure, int $tourId, int $channel): SimpleXMLElement { - return $this->request(self::PATH_API_DEPARTURE_SHOW . '?id=' . $tour . '&departure_id=' . $departure, $channel); + $this->validateTourId($tourId); + + return $this->request(self::PATH_API_DEPARTURE_SHOW . '?id=' . $tourId . '&departure_id=' . $departure, $channel); } - public function create_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement|string + public function create_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_DEPARTURE_CREATE, $channel, self::HTTP_VERB_POST, $departureData); } - public function update_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement|string + public function update_departure(SimpleXMLElement|string $departureData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_DEPARTURE_UPDATE, $channel, self::HTTP_VERB_POST, $departureData); } - public function delete_departure(int $departureId, int $tourId, int $channelId): SimpleXMLElement|string + /** + * Delete Departure + * @param int $departureId + * @param int $tourId + * @param int $channelId + * @return SimpleXMLElement + */ + public function delete_departure(int $departureId, int $tourId, int $channelId): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_DEPARTURE_DELETE . '?id=' . $tourId . '&departure_id=' . $departureId, $channelId, self::HTTP_VERB_POST); } @@ -663,7 +732,7 @@ public function delete_departure(int $departureId, int $tourId, int $channelId): Promo code */ - public function show_promo(int $promoId, int $channel): SimpleXMLElement|string + public function show_promo(int $promoId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PROMO_SHOW . '?promo_code=' . $promoId, $channel); } @@ -674,17 +743,17 @@ public function show_promo(int $promoId, int $channel): SimpleXMLElement|string Making bookings */ - public function get_booking_redirect_url(SimpleXMLElement|string $urlData, int $channel): SimpleXMLElement|string + public function get_booking_redirect_url(SimpleXMLElement|string $urlData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_GET_REDIRECT_URL, $channel, self::HTTP_VERB_POST, $urlData); } - public function start_new_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + public function start_new_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_START, $channel, self::HTTP_VERB_POST, $bookingData); } - public function commit_new_booking(SimpleXMLElement|string $bookingData, $channel) + public function commit_new_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_COMMIT, $channel, self::HTTP_VERB_POST, $bookingData); } @@ -693,7 +762,7 @@ public function commit_new_booking(SimpleXMLElement|string $bookingData, $channe Retrieving bookings */ - public function search_bookings(string $params = "", int $channel = 0): SimpleXMLElement|string + public function search_bookings(string $params = "", int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_BOOKINGS_SEARCH . $params); @@ -701,7 +770,7 @@ public function search_bookings(string $params = "", int $channel = 0): SimpleXM return $this->request(self::PATH_API_C_BOOKINGS_SEARCH . $params, $channel); } - public function list_bookings(string $params = "", int $channel = 0): SimpleXMLElement|string + public function list_bookings(string $params = "", int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_BOOKINGS_LIST . $params); @@ -709,12 +778,12 @@ public function list_bookings(string $params = "", int $channel = 0): SimpleXMLE return $this->request(self::PATH_API_C_BOOKINGS_LIST . $params, $channel); } - public function show_booking(int $bookingId, int $channel): SimpleXMLElement|string + public function show_booking(int $bookingId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKINGS_SHOW . '?booking_id=' . $bookingId, $channel); } - public function search_voucher(SimpleXMLElement|string|null $voucherData = null, $channel = 0): SimpleXMLElement|string + public function search_voucher(SimpleXMLElement|string|null $voucherData = null, $channel = 0): SimpleXMLElement { if ($voucherData == null) { @@ -733,62 +802,62 @@ public function search_voucher(SimpleXMLElement|string|null $voucherData = null, Updating bookings */ - public function update_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + public function update_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_UPDATE, $channel, self::HTTP_VERB_POST, $bookingData); } - public function create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + public function create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PAYMENT_NEW, $channel, self::HTTP_VERB_POST, $paymentData); } - public function log_failed_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + public function log_failed_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PAYMENT_FAIL, $channel, self::HTTP_VERB_POST, $paymentData); } - public function spreedly_create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement|string + public function spreedly_create_payment(SimpleXMLElement|string $paymentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PAYMENT_SPREEDLY_CREATE, $channel, self::HTTP_VERB_POST, $paymentData); } - public function spreedly_complete_payment(string $transactionId, int $channel): SimpleXMLElement|string + public function spreedly_complete_payment(string $transactionId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PAYMENT_SPREEDLY_COMPLETE . '?id=' . $transactionId, $channel, self::HTTP_VERB_POST); } - public function cancel_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + public function cancel_booking(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_CANCEL, $channel, self::HTTP_VERB_POST, $bookingData); } - public function delete_booking(int $bookingId, int $channel): SimpleXMLElement|string + public function delete_booking(int $bookingId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_DELETE . '?booking_id=' . $bookingId, $channel, self::HTTP_VERB_POST); } - public function check_option_availability(int $bookingId, string $tourComponentId, int $channel): SimpleXMLElement|string + public function check_option_availability(int $bookingId, string $tourComponentId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_OPTION_CHECK_AVAILABILITY . '?booking_id=' . $bookingId . '&tour_component_id=' . $tourComponentId, $channel); } - public function booking_add_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + public function booking_add_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_COMPONENT_NEW, $channel, self::HTTP_VERB_POST, $componentData); } - public function booking_remove_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + public function booking_remove_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_COMPONENT_DELETE, $channel, self::HTTP_VERB_POST, $componentData); } - public function booking_update_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement|string + public function booking_update_component(SimpleXMLElement|string $componentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_COMPONENT_UPDATE, $channel, self::HTTP_VERB_POST, $componentData); } - public function add_note_to_booking(int $bookingId, int $channel, string $text, string $noteType): SimpleXMLElement|string + public function add_note_to_booking(int $bookingId, int $channel, string $text, string $noteType): SimpleXMLElement { $bookingData = new SimpleXMLElement(''); @@ -800,29 +869,29 @@ public function add_note_to_booking(int $bookingId, int $channel, string $text, return $this->request(self::PATH_API_BOOKING_NOTE_NEW, $channel, self::HTTP_VERB_POST, $bookingData); } - public function send_booking_email(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement|string + public function send_booking_email(SimpleXMLElement|string $bookingData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_BOOKING_EMAIL_SEND, $channel, self::HTTP_VERB_POST, $bookingData); } - public function redeem_voucher(SimpleXMLElement|string $voucherData, int $channel = 0): SimpleXMLElement|string + public function redeem_voucher(SimpleXMLElement|string $voucherData, int $channel = 0): SimpleXMLElement { return $this->request(self::PATH_API_VOUCHER_REDEEM, $channel, self::HTTP_VERB_POST, $voucherData); } # Enquiry and customer methods - public function create_enquiry(SimpleXMLElement|string $enquiryData, int $channel): SimpleXMLElement|string + public function create_enquiry(SimpleXMLElement|string $enquiryData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_ENQUIRY_NEW, $channel, self::HTTP_VERB_POST, $enquiryData); } - public function update_customer(SimpleXMLElement|string $customerData, int $channel): SimpleXMLElement|string + public function update_customer(SimpleXMLElement|string $customerData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CUSTOMER_UPDATE, $channel, self::HTTP_VERB_POST, $customerData); } - public function search_enquiries(string $params = "", int $channel = 0): SimpleXMLElement|string + public function search_enquiries(string $params = "", int $channel = 0): SimpleXMLElement { $params = $this->validateParams($params); if ($channel == 0) return $this->request(self::PATH_API_P_ENQUIRIES_SEARCH . $params); @@ -830,202 +899,211 @@ public function search_enquiries(string $params = "", int $channel = 0): SimpleX return $this->request(self::PATH_API_C_ENQUIRIES_SEARCH . $params, $channel); } - public function show_enquiry(int $enquiryId, int $channel): SimpleXMLElement|string + public function show_enquiry(int $enquiryId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_ENQUIRY_SHOW . '?enquiry_id=' . $enquiryId, $channel); } - public function create_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement|string + public function create_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CUSTOMER_CREATE, $channel, self::HTTP_VERB_POST, $customer); } - public function show_customer(int $customerId, int $channel): SimpleXMLElement|string + public function show_customer(int $customerId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CUSTOMER_SHOW . '?customer_id=' . $customerId, $channel); } - public function check_customer_login(string $username, string $password, int $channel): SimpleXMLElement|string + public function check_customer_login(string $username, string $password, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CUSTOMER_LOGIN_SEARCH . '?customer_username=' . $username . '&customer_password=' . $password, $channel); } - public function verify_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement|string + public function verify_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CUSTOMER_VERIFICATION, $channel, self::HTTP_VERB_POST, $customer); } # Agents - public function search_agents(string $params, int $channel): SimpleXMLElement|string + public function search_agents(string $params, int $channel): SimpleXMLElement { $params = $this->validateParams($params); return $this->request(self::PATH_API_AGENTS_SEARCH . $params, $channel); } - public function start_new_agent_login(string $params, int $channel): SimpleXMLElement|string + public function start_new_agent_login(string $params, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_START_AGENT_LOGIN, $channel, self::HTTP_VERB_POST, $params); } - public function retrieve_agent_booking_key(string $privateToken, int $channel): SimpleXMLElement|string + public function retrieve_agent_booking_key(string $privateToken, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_AGENT_BOOKING_KEY_RETRIEVE . '?k=' . $privateToken, $channel); } - public function update_agent(SimpleXMLElement|string $agentData, int $channel): SimpleXMLElement|string + public function update_agent(SimpleXMLElement|string $agentData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_AGENTS_UPDATE, $channel, self::HTTP_VERB_POST, $agentData); } - public function show_agent_profile(SimpleXMLElement|string $agent, int $channel = 0): SimpleXMLElement|string + public function show_agent_profile(SimpleXMLElement|string $agent, int $channel = 0): SimpleXMLElement { return $this->request(self::PATH_API_AGENT_PROFILE_GET . "?id=$agent", $channel); } - public function update_agent_profile(SimpleXMLElement|string $agentProfileData): SimpleXMLElement|string + public function update_agent_profile(SimpleXMLElement|string $agentProfileData): SimpleXMLElement { return $this->request(self::PATH_API_AGENT_PROFILE_UPDATE, 0, self::HTTP_VERB_POST, $agentProfileData); } # Payments - public function list_payments($params, $channel): SimpleXMLElement|string + public function list_payments($params, $channel): SimpleXMLElement { $params = $this->validateParams($params); return $this->request(self::PATH_API_PAYMENTS_LIST . $params, $channel); } - public function payworks_booking_payment_new(SimpleXMLElement|string $payment, int $channel): SimpleXMLElement|string + public function payworks_booking_payment_new(SimpleXMLElement|string $payment, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PAYMENTS_PAYWORKS_NEW, $channel, self::HTTP_VERB_POST, $payment); } # Staff members - public function list_staff_members(int $channel): SimpleXMLElement|string + public function list_staff_members(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_STAFF_LIST, $channel); } # Internal supplier methods - public function show_supplier(int $supplierId, int $channel): SimpleXMLElement|string + public function show_supplier(int $supplierId, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_SUPPLIER_SHOW . '?supplier_id=' . $supplierId, $channel); } # CRUD Pickup points - public function list_pickups(string $params, int $channel): SimpleXMLElement|string + public function list_pickups(string $params, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PICKUPS_LIST . $this->validateParams($params), $channel); } - public function create_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + public function create_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PICKUPS_NEW, $channel, self::HTTP_VERB_POST, $pickupData); } - public function update_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + public function update_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PICKUPS_UPDATE, $channel, self::HTTP_VERB_POST, $pickupData); } - public function delete_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement|string + public function delete_pickup(SimpleXMLElement|string $pickupData, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_PICKUPS_DELETE, $channel, self::HTTP_VERB_POST, $pickupData); } - public function show_tours_pickup_routes(int $tourId, int $channel): SimpleXMLElement|string + /** + * Show Tour Pickup Routes + * @param int $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ + public function show_tours_pickup_routes(int $tourId, int $channel): SimpleXMLElement { + $this->validateTourId($tourId); + return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_SHOW . "?id=$tourId", $channel); } - public function update_tours_pickup_routes(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + public function update_tours_pickup_routes(SimpleXMLElement|string $data, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE, $channel, self::HTTP_VERB_POST, $data); } - public function tours_pickup_routes_add_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + public function tours_pickup_routes_add_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_ADD_PICKUP, $channel, self::HTTP_VERB_POST, $data); } - public function tours_pickup_routes_update_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + public function tours_pickup_routes_update_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_UPDATE_PICKUP, $channel, self::HTTP_VERB_POST, $data); } - public function tours_pickup_routes_delete_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement|string + public function tours_pickup_routes_delete_pickup(SimpleXMLElement|string $data, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_PICKUP_ROUTES_DELETE_PICKUP, $channel, self::HTTP_VERB_POST, $data); } # Account - public function create_account(SimpleXMLElement|string $uploadInfo): SimpleXMLElement|string + public function create_account(SimpleXMLElement|string $uploadInfo): SimpleXMLElement { return $this->request(self::PATH_API_ACCOUNT_CREATE, 0, self::HTTP_VERB_POST, $uploadInfo); } - public function update_account(SimpleXMLElement|string $uploadInfo, int $channel): SimpleXMLElement|string + public function update_account(SimpleXMLElement|string $uploadInfo, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_ACCOUNT_UPDATE, $channel, self::HTTP_VERB_POST, $uploadInfo); } - public function show_account(int $accountId): SimpleXMLElement|string + public function show_account(int $accountId): SimpleXMLElement { $url = self::PATH_API_ACCOUNT_SHOW . "?account_id=" . $accountId; return $this->request($url, 0); } - public function create_channel(SimpleXMLElement|string $newChannel, int $channel): SimpleXMLElement|string + public function create_channel(SimpleXMLElement|string $newChannel, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CHANNEL_CREATE, $channel, self::HTTP_VERB_POST, $newChannel); } - public function update_channel(SimpleXMLElement|string $channelInfo, int $channel): SimpleXMLElement|string + public function update_channel(SimpleXMLElement|string $channelInfo, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_CHANNEL_UPDATE, $channel, self::HTTP_VERB_POST, $channelInfo); } - public function show_markup_scheme(int $channel): SimpleXMLElement|string + public function show_markup_scheme(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_MARKUP_SCHEME_SHOW, $channel, self::HTTP_VERB_GET); } - public function create_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + public function create_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_GEOS_CREATE, $channel, self::HTTP_VERB_POST, $geopoint); } - public function update_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + public function update_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_GEOS_UPDATE, $channel, self::HTTP_VERB_POST, $geopoint); } - public function delete_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement|string + public function delete_tour_geopoint(SimpleXMLElement|string $geopoint, int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_GEOS_DELETE, $channel, self::HTTP_VERB_POST, $geopoint); } - public function get_custom_fields(int $channel): SimpleXMLElement|string + public function get_custom_fields(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_ACCOUNT_CUSTOM_FIELDS_GET, $channel, self::HTTP_VERB_GET); } - public function get_tour_facets(int $channel): SimpleXMLElement|string + public function get_tour_facets(int $channel): SimpleXMLElement { return $this->request(self::PATH_API_TOUR_FACETS_GET, $channel, self::HTTP_VERB_GET); } - public function get_list_tours(int $channel, string $queryString): SimpleXMLElement|string + public function get_list_tours(int $channel, string $queryString): SimpleXMLElement { $queryString = $this->validateParams($queryString); return $this->request(self::PATH_API_LIST_TOURS_GET . $queryString, $channel, self::HTTP_VERB_GET); } - public function get_import_tours_status(int $channel, SimpleXMLElement|string $codes): SimpleXMLElement|string + public function get_import_tours_status(int $channel, SimpleXMLElement|string $codes): SimpleXMLElement { return $this->request(self::PATH_API_IMPORT_TOURS_STATUS, $channel, self::HTTP_VERB_POST, $codes); } - public function list_tour_booking_restrictions(int $channel, string $queryString): SimpleXMLElement|string + public function list_tour_booking_restrictions(int $channel, string $queryString): SimpleXMLElement { $queryString = $this->validateParams($queryString); return $this->request(self::PATH_API_LIST_TOUR_BOOKINGS_RESTRICTIONS . $queryString, $channel, self::HTTP_VERB_GET); @@ -1089,6 +1167,19 @@ protected function validateParams(mixed $params): string return $params; } + /** + * Validate Tour ID + * @param int $tourId + * @throws \InvalidArgumentException + * @return void + */ + protected function validateTourId(int $tourId): void + { + if ($tourId <= 0) { + throw new InvalidArgumentException(self::ERROR_MESSAGE_INVALID_TOUR_ID); + } + } + /** * generateSignature * From 2180275287aa9eb6ed3cecf5ba1de8b58513f816 Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Thu, 22 May 2025 09:49:12 +0200 Subject: [PATCH 7/8] TOURCMS-11047 Fix extra empty lines and indentation --- src/TourCMS.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/TourCMS.php b/src/TourCMS.php index d5d8a9c..ef81783 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -785,7 +785,6 @@ public function show_booking(int $bookingId, int $channel): SimpleXMLElement public function search_voucher(SimpleXMLElement|string|null $voucherData = null, $channel = 0): SimpleXMLElement { - if ($voucherData == null) { $voucherData = new SimpleXMLElement(''); $voucherData->addChild('barcode_data', ''); @@ -859,7 +858,6 @@ public function booking_update_component(SimpleXMLElement|string $componentData, public function add_note_to_booking(int $bookingId, int $channel, string $text, string $noteType): SimpleXMLElement { - $bookingData = new SimpleXMLElement(''); $bookingData->addChild('booking_id', $bookingId); $note = $bookingData->addChild('note'); @@ -920,9 +918,9 @@ public function check_customer_login(string $username, string $password, int $ch } public function verify_customer(SimpleXMLElement|string $customer, int $channel): SimpleXMLElement - { - return $this->request(self::PATH_API_CUSTOMER_VERIFICATION, $channel, self::HTTP_VERB_POST, $customer); - } + { + return $this->request(self::PATH_API_CUSTOMER_VERIFICATION, $channel, self::HTTP_VERB_POST, $customer); + } # Agents public function search_agents(string $params, int $channel): SimpleXMLElement From 7916b417de4704d1c2ceec27a78e620974ba13dd Mon Sep 17 00:00:00 2001 From: Armando Garrido Date: Wed, 28 May 2025 13:10:54 +0200 Subject: [PATCH 8/8] TOURCMS-11047 Validate tourId --- src/TourCMS.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/TourCMS.php b/src/TourCMS.php index ef81783..e364a0e 100755 --- a/src/TourCMS.php +++ b/src/TourCMS.php @@ -460,6 +460,14 @@ public function search_tours(string $params = "", int $channel = 0): SimpleXMLEl return $this->request(self::PATH_API_C_TOURS_SEARCH . $params, $channel); } + /** + * Summary of search_hotels_range + * @param string $params + * @param mixed $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ public function search_hotels_range(string $params = "", ?int $tourId = null, int $channel = 0): SimpleXMLElement { @@ -467,6 +475,8 @@ public function search_hotels_range(string $params = "", ?int $tourId = null, in if (!is_null($tourId)) { + $this->validateTourId($tourId); + if (empty($params)) { $params = '?single_tour_id='; } else { @@ -487,6 +497,8 @@ public function search_hotels_specific(string $params = "", ?int $tourId = null, if (!is_null($tourId)) { + $this->validateTourId($tourId); + if (empty($params)) { $params = '?single_tour_id='; } else { @@ -545,8 +557,17 @@ public function list_tour_locations(int $channel = 0, string $params = ""): Simp return $this->request(self::PATH_API_C_TOURS_LOCATIONS . $params, $channel); } + /** + * Summary of delete_tour + * @param int $tourId + * @param int $channel + * @throws \InvalidArgumentException + * @return SimpleXMLElement + */ public function delete_tour(int $tourId, int $channel): SimpleXMLElement { + $this->validateTourId($tourId); + $url = self::PATH_API_TOUR_DELETE .'?id=' . $tourId; return $this->request($url, $channel, self::HTTP_VERB_POST); }