634 lines
20 KiB
PHP
634 lines
20 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 LDC\LDCCRM\CrmApiV4;
|
|
use LDC\LDCCRM\Enums\ApiError;
|
|
use LDC\LDCCRM\Enums\LogLevel;
|
|
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
|
use LDC\LDCCRM\Exceptions\CrmException;
|
|
use LDC\LDCCRM\Models\Customer;
|
|
use LDC\LDCCRM\Models\SingleOptin;
|
|
use LDC\LDCCRM\Utils;
|
|
|
|
/* 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
|
|
*
|
|
* @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
|
|
{
|
|
/**
|
|
* The session key name
|
|
*
|
|
* @var string|null
|
|
*/
|
|
private static ?string $sessionKey = null;
|
|
|
|
/**
|
|
* The session live status
|
|
*
|
|
* @var boolean
|
|
*/
|
|
private static bool $sessionDestroyed = false;
|
|
|
|
/**
|
|
* The user object
|
|
*
|
|
* @var \LDC\LDCCRM\CrmApiV4|null
|
|
*/
|
|
protected static ?CrmApiV4 $api = null;
|
|
|
|
/**
|
|
* The user object
|
|
*
|
|
* @var \LDC\LDCCRM\WordPress\WPCrmUser|null
|
|
*/
|
|
protected static ?WPCrmUser $user = null;
|
|
|
|
/**
|
|
* Get the current user
|
|
* return null if the user is not logged in
|
|
*
|
|
* @return \LDC\LDCCRM\WordPress\WPCrmUser|null
|
|
*/
|
|
public static function getUser()
|
|
{
|
|
self::bootSessionIfNeeded();
|
|
return self::$user;
|
|
}
|
|
|
|
/**
|
|
* Manually login a user
|
|
* If self::$user is already set.
|
|
*
|
|
* @return \LDCCRM\WPCrmUser|null
|
|
*/
|
|
public static function forceLogin()
|
|
{
|
|
self::bootSessionIfNeeded();
|
|
if ($user = self::getUser()) {
|
|
$_SESSION['wpcrm'][self::$sessionKey] = json_encode($user);
|
|
}
|
|
return $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
|
|
* @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.
|
|
* @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
|
*/
|
|
public static function getUserFromApi(string $identification)
|
|
{
|
|
self::initLdcApi();
|
|
try {
|
|
if (!($response = self::makeApiV4Call(self::$api, 'getCustomer', [$identification]))) {
|
|
return false;
|
|
}
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::modelNotFound->value():
|
|
return false;
|
|
default:
|
|
throw $e;
|
|
}
|
|
}
|
|
/** @var \LDC\LDCCRM\Models\Customer */
|
|
$customer = $response;
|
|
self::setUser($customer);
|
|
return self::$user;
|
|
}
|
|
|
|
/**
|
|
* Try to login with CRM API
|
|
* A session will be started if credentials are valid.
|
|
*
|
|
* @param string $email The customer email.
|
|
* @param string $password The customer password.
|
|
*
|
|
* @return boolean
|
|
* @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.
|
|
* Possibles are : - authFailed, If credentials are not valid.
|
|
* - customerNotActivated, If the account is not activated.
|
|
*/
|
|
public static function login(string $email, string $password)
|
|
{
|
|
self::bootSessionIfNeeded();
|
|
$validCredentials = self::loginUserWithApi($email, $password);
|
|
|
|
if ($validCredentials and ($user = self::getUserFromApi($email))) {
|
|
self::saveOrUpdateUserToTable();
|
|
$_SESSION['wpcrm'][self::$sessionKey] = json_encode($user);
|
|
}
|
|
|
|
return $validCredentials;
|
|
}
|
|
|
|
/**
|
|
* Destroy the customer from session
|
|
* and therefore logout
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function logout()
|
|
{
|
|
self::bootSessionIfNeeded();
|
|
$_SESSION['wpcrm'] = [];
|
|
session_destroy();
|
|
self::$sessionDestroyed = true;
|
|
}
|
|
|
|
/**
|
|
* Check if the user is logged in.
|
|
* This means he has an active valid session.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
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\CrmException If a critical error occured.
|
|
* @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
|
|
* Possibles are : - validationFailed, If provided data is wrong(CRM side).
|
|
* - modelNotFound, If this customer hashcode could not be found.
|
|
* @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
|
*/
|
|
public static function saveUser(): bool
|
|
{
|
|
if (!self::getUser() or !($customer = self::getCustomer())) {
|
|
return false;
|
|
}
|
|
try {
|
|
if (!self::makeApiV4Call($customer, 'save')) {
|
|
return false;
|
|
}
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::modelNotFound->value():
|
|
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
|
|
* @throws \LDC\LDCCRM\Exceptions\CrmException If a critical error occured.
|
|
* @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
|
|
* Possibles are : - modelNotFound, If this customer hashcode could not be found.
|
|
* @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
|
*/
|
|
public static function deleteUser(): bool
|
|
{
|
|
if (!self::getUser() or !($customer = self::getCustomer())) {
|
|
return false;
|
|
}
|
|
try {
|
|
if (!self::makeApiV4Call($customer, 'delete')) {
|
|
return false;
|
|
}
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::authorizationException->value():
|
|
case ApiError::modelNotFound->value():
|
|
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\CrmException If a critical error occured.
|
|
* @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
|
|
* Possibles are : - modelNotFound, If this customer hashcode could not be found.
|
|
* @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
|
|
*/
|
|
public static function toggleUserOptin(): bool
|
|
{
|
|
if (!self::getUser() or !($customer = self::getCustomer())) {
|
|
return false;
|
|
}
|
|
try {
|
|
$customer->opt_in = !$customer->opt_in;
|
|
if (!self::makeApiV4Call($customer, 'save')) {
|
|
return false;
|
|
}
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::authorizationException->value():
|
|
case ApiError::modelNotFound->value():
|
|
return false;
|
|
default:
|
|
throw $e;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the single optin status for an email
|
|
* on the crm
|
|
*
|
|
* @param string $email
|
|
* @param boolean $opt_in
|
|
* @param array|null $answerId
|
|
*
|
|
* @return boolean true if the operation succeeded false otherwise
|
|
* @throws \LDC\LDCCRM\Exceptions\ValidationException If a field email could not be validated.
|
|
* @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.
|
|
* Possibles are : - singleOptinCustomerExists, If a customer exists with this email.
|
|
*/
|
|
public static function setSingleOptin(string $email, bool $opt_in, ?array $answerId = null): bool
|
|
{
|
|
return self::makeApiV4Call(
|
|
SingleOptin::class,
|
|
'setStatus',
|
|
array_filter([$email, $opt_in, $answerId], fn($v) => !is_null($v))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Activate the current user
|
|
*
|
|
* @return boolean True if the operation succeeded.
|
|
* @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
|
|
* Possibles are : - modelNotFound, If this customer hashcode could not be found.
|
|
* - customerAlreadyActive, It the customer is already activated.
|
|
*/
|
|
public static function activateUser(): bool
|
|
{
|
|
if (!self::getUser() or !($customer = self::getCustomer())) {
|
|
return false;
|
|
}
|
|
if ($customer->status) {
|
|
return true;
|
|
}
|
|
try {
|
|
if (!self::makeApiV4Call($customer, 'activate')) {
|
|
return false;
|
|
}
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::authorizationException->value():
|
|
case ApiError::modelNotFound->value():
|
|
return false;
|
|
default:
|
|
throw $e;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Generate a new user
|
|
*
|
|
* @return WPCrmUser
|
|
*/
|
|
public static function getNewUser(): WPCrmUser
|
|
{
|
|
self::$user = new WPCrmUser();
|
|
return self::$user;
|
|
}
|
|
|
|
/**
|
|
* Remove active user
|
|
* to prevent WPCrm::check to return true
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function unsetActiveUser(): void
|
|
{
|
|
self::$user = null;
|
|
}
|
|
|
|
// * --- PRIVATE --- METHODS
|
|
|
|
/**
|
|
* Check customer credentials using the CRM.
|
|
*
|
|
* @param string $email The customer email.
|
|
* @param string $password The customer password.
|
|
*
|
|
* @return boolean
|
|
* @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.
|
|
* Possibles are : - authFailed, If credentials are not valid.
|
|
* - customerNotActivated, If the account is not activated.
|
|
*/
|
|
private static function loginUserWithApi(string $email, string $password): bool
|
|
{
|
|
self::initLdcApi();
|
|
|
|
/** @var boolean $response */
|
|
$response = self::makeApiV4Call(self::$api, 'login', [$email, $password]);
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Get all customer infos
|
|
*
|
|
* @return \LDC\LDCCRM\Models\Customer|null
|
|
*/
|
|
private static function getCustomer(): ?Customer
|
|
{
|
|
if (!self::getUser()) {
|
|
return null;
|
|
}
|
|
if (!Utils::getRawProperty(self::$user, 'info')) {
|
|
self::getUserFromApi(self::$user->hashcode);
|
|
}
|
|
/** @var \LDC\LDCCRM\Models\Customer */
|
|
$customer = Utils::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
|
|
*
|
|
* @param \LDC\LDCCRM\Models\Customer $customer
|
|
*
|
|
* @return void
|
|
*/
|
|
private static function setUser(Customer $customer): void
|
|
{
|
|
self::bootSessionIfNeeded();
|
|
if (!self::$user) {
|
|
self::$user = new WPCrmUser($customer->hashcode, $customer->email);
|
|
}
|
|
self::$user->setInfo($customer);
|
|
}
|
|
|
|
/**
|
|
* Get the initialized API object
|
|
*
|
|
* @return \LDC\LDCCRM\CrmApiV4
|
|
* @throws \ErrorException If php does not have extension curl.
|
|
*/
|
|
private static function initLdcApi(): CrmApiV4
|
|
{
|
|
if (!self::$api) {
|
|
if (!extension_loaded('curl')) {
|
|
throw new \ErrorException(
|
|
'WPCrm requires php extension curl'
|
|
);
|
|
}
|
|
self::$api = new CrmApiV4();
|
|
}
|
|
return self::$api;
|
|
}
|
|
|
|
/**
|
|
* Make a call using apiV4
|
|
*
|
|
* @param object|string $obj An object or a class name.
|
|
* @param string $method The method to call.
|
|
* @param array $arguments Arguments to pass.
|
|
* @return mixed|false
|
|
* @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any of this exception is thrown.
|
|
* @throws \LDC\LDCCRM\Exceptions\CrmException If a critical error occured.
|
|
*/
|
|
private static function makeApiV4Call($obj, string $method, array $arguments = [])
|
|
{
|
|
try {
|
|
return \forward_static_call_array([$obj, $method], $arguments);
|
|
} catch (ApiErrorException $e) {
|
|
switch ($e->getApiError()) {
|
|
case ApiError::apiAuthFailed:
|
|
Utils::log($e->getMessage(), LogLevel::CRIT);
|
|
throw $e;
|
|
default:
|
|
Utils::log($e->getMessage(), LogLevel::DEBUG);
|
|
throw $e;
|
|
}
|
|
} catch (CrmException $e) {
|
|
Utils::log($e->getMessage(), LogLevel::CRIT);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Boot the php session if needed
|
|
*
|
|
* @return void
|
|
*/
|
|
private static function bootSessionIfNeeded(): void
|
|
{
|
|
self::$sessionKey = ($_SERVER['HTTP_USER_AGENT'] ?? '') . ($_SERVER['REMOTE_ADDR'] ?? '');
|
|
/** @var string self::$sessionKey */
|
|
self::$sessionKey = \strlen(self::$sessionKey) ? self::$sessionKey : (date('d') ? date('d') : '');
|
|
if (!session_id() && !self::$sessionDestroyed) {
|
|
session_start();
|
|
}
|
|
if (!isset($_SESSION['wpcrm'])) {
|
|
$_SESSION['wpcrm'] = [];
|
|
}
|
|
if (
|
|
// If session identity is violated.
|
|
count($_SESSION['wpcrm']) > 1 or
|
|
// If session timed out.
|
|
(isset($_SESSION['wpcrm'][self::$sessionKey]) and
|
|
isset($_SESSION['lastActivity']) and
|
|
// * 15 minutes session.
|
|
($_SESSION['lastActivity'] + (15 * 60)) < time())
|
|
) {
|
|
// Destroy session.
|
|
self::$sessionDestroyed = true;
|
|
$_SESSION['wpcrm'] = [];
|
|
} else {
|
|
$_SESSION['lastActivity'] = time();
|
|
}
|
|
if (!self::$user and isset($_SESSION['wpcrm'][self::$sessionKey])) {
|
|
self::$user = WPCrmUser::parseFromJson(
|
|
$_SESSION['wpcrm'][self::$sessionKey]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a customer from table
|
|
*
|
|
* @param string $hashcode The customer hashcode.
|
|
*
|
|
* @return array|null Database query result in format specified by $output or null on failure.
|
|
*/
|
|
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 Database query result in format specified by $output or null on failure.
|
|
*/
|
|
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 Database query result in format specified by $output or null on failure.
|
|
*/
|
|
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 integer The number of row affected on the table.
|
|
*/
|
|
private static function saveOrUpdateUserToTable(): int
|
|
{
|
|
if (is_string(self::$user->hashcode) and self::getUserFromTable(self::$user->hashcode)) {
|
|
return 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
|
|
]
|
|
);
|
|
}
|
|
return 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 integer The number of row removed from the table.
|
|
*/
|
|
private static function deleteUserFromTable(): int
|
|
{
|
|
return 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 integer|boolean Boolean true for CREATE, ALTER, TRUNCATE and DROP queries.
|
|
* Number of rows affected/selected for all other queries. Boolean false on error.
|
|
*/
|
|
private static function query(string $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(): object
|
|
{
|
|
// phpcs:ignore Squiz.PHP.GlobalKeyword.NotAllowed
|
|
global $wpdb;
|
|
return $wpdb;
|
|
}
|
|
}
|