ldc-crm-client/src/WordPress/WPCrm.php
2021-09-14 13:44:03 +02:00

634 lines
17 KiB
PHP

<?php
/**
* LDCCRM For Wordpress usage
*
* @category API
* @package None
* @author Jérémy Munsch <jeremy.munsch@ldc.fr>
* @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 <jeremy.munsch@ldc.fr>
* @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);
}
}