* @license MIT https://opensource.org/licenses/MIT * @link / */ namespace LDC\LDCCRM\WordPress; use Exception; use LDC\LDCCRM\CrmApiV2; use LDC\LDCCRM\Enums\ApiError; use LDC\LDCCRM\Enums\LogLevel; use LDC\LDCCRM\Exceptions\ApiErrorException; use LDC\LDCCRM\Exceptions\CrmException; use LDC\LDCCRM\Models\ArcadiaMailDefault; use LDC\LDCCRM\Models\ArcadiaMailGame; use LDC\LDCCRM\Models\Customer; use LDC\LDCCRM\Models\SingleOptin; use LDC\LDCCRM\Utils; use ReflectionClass; // phpcs:ignore Squiz.PHP.CommentedOutCode.Found // TABLE LDC CUSTOMERS // CREATE TABLE `ldc_wp_customers` ( // `hashcode` VARCHAR(36) NOT NULL DEFAULT '' COMMENT 'Le hashcode (UUID)', // `email` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'Le customer email', // `uuid` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Code unique (inscripton, validation, etc)', // PRIMARY KEY (`hashcode`) // ) // COMMENT='Les customers sur un WP liées à la CRM' // COLLATE='utf8mb4_unicode_ci'; /** * Class de gestion des users en session avec Wordpress (ce truc immonde) * * @category API * @package LDCCrmClient * @subpackage Wordpress * @author Jérémy Munsch * @license MIT https://opensource.org/licenses/MIT * @link / */ class WPCrm { private static $sessionKey = 'LDC_CRM_USER'; private static $sessionDestroyed = false; /** * The user object * * @var \LDC\LDCCRM\CrmApiV2 */ protected static $api = null; /** * The user object * * @var \LDCCRM\WPCrmUser */ protected static $user = null; /** * Try to login with CRM API * return api response code if an error occurs * * @param string $email The customer email * @param string $password The customer password * * @return \LDCCRM\WPCrmUser|false */ public static function login($email, $password) { self::bootSessionIfNeeded(); if ($user = self::loginUserWithApi($email, $password)) { $_SESSION[self::$sessionKey] = json_encode($user); } return $user; } /** * Login user by setting user session * * @param string $email The customer email * @param string $password The customer password * * @return \LDCCRM\WPCrmUser|null */ public static function forceLogin() { self::bootSessionIfNeeded(); if ($user = self::getUser()) { $_SESSION[self::$sessionKey] = json_encode($user); } return $user; } /** * Get the current user * return null if the user is not logged in * * @return \LDCCRM\WPCrmUser|null */ public static function getUser() { self::bootSessionIfNeeded(); return self::$user; } /** * Get the current user * return api response code if an error occurs * * @param string $identification The customer hashcode or email * * @return \LDC\LDCCRM\Wordpress\WPCrmUser|false */ public static function getUserFromApi(string $identification) { self::initLdcApi(); try { if (!($response = self::makeApiV2Call(self::$api, 'getCustomer', [$identification]))) { return $response; } } catch (ApiErrorException $e) { switch ($e->getApiError()) { case ApiError::authorizationException(): case ApiError::modelNotFound(): return false; default: throw $e; } } /** @var \LDC\LDCCRM\Models\Customer */ $customer = $response; self::setUser($customer); return self::$user; } /** * Get the current user * return null if the user is not logged in * * @param string $email The customer email * @param string $password The customer password * * @return \LDCCRM\WPCrmUser|false * @throws \LDC\LDCCRM\Exceptions\CrmException * if an error occurs on server side or on getting response * @throws \LDC\LDCCRM\Exceptions\ApiErrorException * If any error or \LDC\LDCCRM\Enums\ApiError occurs */ private static function loginUserWithApi(string $email, string $password) { self::initLdcApi(); if (!($response = self::makeApiV2Call(self::$api, 'login', [$email, $password]))) { return $response; } if ($out = self::getUserFromApi($email)) { self::saveOrUpdateUserToTable(); } return $out; } /** * Destroy the customer from session * and therefore logout * * @return void */ public static function logout() { self::bootSessionIfNeeded(); unset($_SESSION[self::$sessionKey]); session_destroy(); self::$sessionDestroyed = true; } /** * Check if the user is Authenticated * * @return bool */ public static function check() { self::bootSessionIfNeeded(); return (bool)self::getUser(); } /** * Save current customer to * the local database and on crm * * @return boolean true if the operation succeeded false otherwise * @throws \LDC\LDCCRM\Exceptions\ApiErrorException * with \LDC\LDCCRM\Enums\ApiError::customerExists() */ public static function saveUser(): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } try { if (!self::makeApiV2Call($customer, 'save')) { return false; } } catch (ApiErrorException $e) { switch ($e->getApiError()) { case ApiError::modelNotFound(): return false; default: throw $e; } } self::saveOrUpdateUserToTable(); return true; } /** * Delete current customer from * the local database and the crm * * @return boolean true if the operation succeeded */ public static function deleteUser(): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } try { if (!self::makeApiV2Call($customer, 'delete')) { return false; } } catch (ApiErrorException $e) { switch ($e->getApiError()) { case ApiError::modelNotFound(): return false; default: throw $e; } } self::deleteUserFromTable(); return true; } /** * Toggle the current user optin value * on the current user and the crm * * @return boolean true if the operation succeeded * @throws \LDC\LDCCRM\Exceptions\ApiErrorException * with \LDC\LDCCRM\Enums\ApiError::singleOptinCustomerExists() */ public static function toggleUserOptin(): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } try { if (!self::makeApiV2Call($customer, 'save')) { return false; } } catch (ApiErrorException $e) { switch ($e->getApiError()) { case ApiError::modelNotFound(): return false; default: throw $e; } } $customer->opt_in = !$customer->opt_in; return true; } /** * Set the single optin status for an email * on the crm * * @param string $email * @param boolean $opt_in * * @return boolean true if the operation succeeded false otherwise * @throws \LDC\LDCCRM\Exceptions\ApiErrorException * with \LDC\LDCCRM\Enums\ApiError::singleOptinCustomerExists() */ public static function setSingleOptin(string $email, bool $opt_in): bool { return self::makeApiV2Call(SingleOptin::class, 'setStatus', [ $email, $opt_in ]); } /** * send An arcadia mail with type default * This methods requires to have a user in session (to be logged in) * * @param ArcadiaMailDefault $mail * @return boolean true if succeed */ public static function sendArcadiaMailDefault(ArcadiaMailDefault $mail): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } $customer = self::getCustomer(); return $mail->send($customer); } /** * send An arcadia mail with type game * This methods requires to have a user in session (to be logged in) * * @param ArcadiaMailGame $mail * @return boolean true if succeed */ public static function sendArcadiaMailGame(ArcadiaMailGame $mail): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } $customer = self::getCustomer(); return $mail->send($customer); } /** * Toggle the current user optin value * on the current user and the crm * * @return boolean true if the operation succeeded */ public static function activateUser(): bool { if (!self::getUser() or !($customer = self::getCustomer())) { return false; } if ($customer->status) { return true; } if (!self::makeApiV2Call($customer, 'activate')) { return false; } $customer->opt_in = !$customer->opt_in; return true; } /** * Generate a new user * * @return WPCrmUser */ public static function getNewUser(): WPCrmUser { return self::$user = new WPCrmUser(); } /** * Remove active user * to prevent WPCrm::check to return true * * @return void */ public static function unsetActiveUser() { self::$user = null; } // --- PRIVATE --- METHODS /** * Get all customer infos * * @return \LDC\LDCCRM\Models\Customer|null */ private static function getCustomer(): ?Customer { if (!self::getUser()) { return null; } if (!self::getRawProperty(self::$user, 'info')) { self::getUserFromApi(self::$user->hashcode); } /** @var \LDC\LDCCRM\Models\Customer */ $customer = self::getRawProperty(self::$user, 'info'); return $customer; } /** * Create a user * stores it to the session * and finally saves it to the database if it does not exists * * @var \LDC\LDCCRM\Models\Customer $customer * * @return void */ private static function setUser(Customer $customer) { self::bootSessionIfNeeded(); if (!self::$user) { self::$user = new WPCrmUser($customer->hashcode, $customer->email); } self::$user->setInfo($customer); } /** * Get the initialized API object * * @return \LDCCRM\ApiV1 */ private static function initLdcApi() { if (!self::$api) { if (!extension_loaded('curl')) { throw new Exception( 'WPCrm requires php extension curl' ); } self::$api = new CrmApiV2(); } return self::$api; } /** * Make a call using apiV2 * * @param string $method * @param array $arguments * @return mixed|false */ private static function makeApiV2Call($obj, string $method, array $arguments = []) { try { return \forward_static_call_array([$obj, $method], $arguments); } catch (ApiErrorException $e) { switch ($e->getApiError()) { case ApiError::apiAuthFailed(): throw $e; default: Utils::log($e->getMessage(), LogLevel::NOTICE()); throw $e; } } catch (CrmException $e) { Utils::log($e->getMessage(), LogLevel::EMERG()); return false; } } /** * Boot the php session if needed * * @return void */ private static function bootSessionIfNeeded() { if (!session_id() && !self::$sessionDestroyed) { session_start(); } if ( isset($_SESSION[self::$sessionKey]) and isset($_SESSION['lastActivity']) and // 15 minutes session ($_SESSION['lastActivity'] + (15 * 60)) < time() ) { self::$sessionDestroyed = true; unset($_SESSION[self::$sessionKey]); } else { $_SESSION['lastActivity'] = time(); } if (!self::$user and array_key_exists(self::$sessionKey, $_SESSION)) { /** * The user object * * @var \LDCCRM\WPCrmUser */ self::$user = WPCrmUser::parseFromJson( $_SESSION[self::$sessionKey] ?? null ); } } /** * Get a customer from table * * @param string $hashcode The customer hashcode * * @return array|null */ public static function getUserFromTable(string $hashcode): ?array { return self::getWpDb()->get_row( self::getWpDb()->prepare( 'SELECT * FROM `ldc_wp_customers` WHERE `hashcode` = %s', [ 'hashcode' => $hashcode ] ), 'ARRAY_A' ); } /** * Get a customer from table by an email * * @param string $email The customer email * * @return array|null */ public static function getUserFromTableByEmail(string $email): ?array { return self::getWpDb()->get_row( self::getWpDb()->prepare( 'SELECT * FROM `ldc_wp_customers` WHERE `email` = %s', [ 'email' => $email ] ), 'ARRAY_A' ); } /** * Get a customer from table by an email * * @param string $uuid The customer transaction uuid * * @return array|null */ public static function getUserFromTableByUuid(string $uuid): ?array { return self::getWpDb()->get_row( self::getWpDb()->prepare( 'SELECT * FROM `ldc_wp_customers` WHERE `uuid` = %s', [ 'uuid' => $uuid ] ), 'ARRAY_A' ); } /** * Save or update the user to the table * * @return void */ private static function saveOrUpdateUserToTable() { if (is_string(self::$user->hashcode) and self::getUserFromTable(self::$user->hashcode)) { self::query( 'UPDATE `ldc_wp_customers` SET `email` = %s, `uuid` = %s WHERE `hashcode` = %s', [ 'email' => self::$user->email, 'uuid' => self::$user->uuidToken, 'hashcode' => self::$user->hashcode ] ); } else { self::query( 'INSERT INTO `ldc_wp_customers`(hashcode, email, uuid) VALUES (%s, %s, %s)', [ 'hashcode' => self::$user->hashcode, 'email' => self::$user->email, 'uuid' => self::$user->uuidToken ] ); } } /** * Save or update the user to the table * * @return void */ private static function deleteUserFromTable() { self::query( 'DELETE FROM `ldc_wp_customers` WHERE `hashcode` = %s;', [ 'hashcode' => self::$user->hashcode ] ); } /** * Query in DB * * @param string $query La request avec les variables en points d'interrogation * @param array $params Les paramètres des la requète * * @return object Containing the row columns */ private static function query($query, array $params = []) { return self::getWpDb()->query( self::getWpDb()->prepare($query, $params) ); } /** * Get WP 'pdo instance' * * @return object The $wpdb variable */ private static function getWpDb() { // phpcs:ignore Squiz.PHP.GlobalKeyword.NotAllowed global $wpdb; return $wpdb; } /** * Get a property * * @param string $field * @param mixed $value * @return mixed */ protected static function getRawProperty(object $object, string $field) { $refClass = new ReflectionClass(\get_class($object)); $refProp = $refClass->getProperty($field); $refProp->setAccessible(true); return $refProp->getValue($object); } }