<?php
|
namespace JVBase\integrations;
|
|
use Exception;
|
use WP_Error;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
trait SyncTo {
|
use SyncHelpers;
|
/**
|
* Must be defined according to how each service needs it to be
|
* @param int $itemID
|
* @param string $type
|
* @return array
|
* @throws Exception
|
*/
|
protected function formatForService(int $itemID, string $type = 'post'):array
|
{
|
throw new Exception('formatForService must be implemented by child class');
|
}
|
|
/**
|
* Defaults to an array of formatted items. Can be overridden in child classes
|
* @param array $itemIDs
|
* @param string $type
|
* @return array
|
*/
|
protected function formatItems(array $itemIDs, string $type):array
|
{
|
$items = [];
|
foreach ($itemIDs as $ID) {
|
try {
|
$items[] = $this->formatForService($ID, $type);
|
} catch (Exception $e){
|
$this->logError('Could not format Item for service',[
|
'itemID' => $ID,
|
'type' => $type,
|
'message' => $e->getMessage(),
|
]);
|
}
|
}
|
return $items;
|
}
|
/***************************************************************
|
* Item creation
|
***************************************************************/
|
public function createBatchToService($data):array
|
{
|
$type = $data['type']??'post';
|
|
//Check if any of the submitted ids are already created
|
$created = array_filter($data['items'],
|
function($ID) use ($type) {
|
return !empty($this->getServiceItemID($ID, $type));
|
});
|
|
$updated = [];
|
if (!empty($created)) {
|
$updateData = $data;
|
$updateData['items'] = $created;
|
$updated = $this->updateBatchToService($data);
|
|
//remove any updated items from the original items to process
|
$data['items'] = array_filter($data['items'], function ($ID) use ($created) {
|
return !in_array($ID, $created);
|
});
|
}
|
|
$items = $this->formatItems($data['items'], $type);
|
if (empty($items)) {
|
return $this->noCreatedItems($updated);
|
}
|
|
$response = [
|
'outcome' => 'failed',
|
'result' => [
|
'message' => 'No result'
|
]
|
];
|
if ($this->hasBatchCreate) {
|
$response = $this->sendBatchCreate($items);
|
if (!is_wp_error($response)) {
|
$result = $this->processBatchCreateResponse($data, $response);
|
} else {
|
$this->logError('Batch create failed',[
|
'method' => 'createBatchToService',
|
'item_ids' => $data['items'],
|
'error' => $response
|
]);
|
$this->updateItemStatus($data['items'], 'error');
|
|
$result = [
|
'outcome' => 'failed_permanent',
|
'result' => 'Could not update items'
|
];
|
}
|
} else {
|
$success = $errors = [];
|
foreach ($items as $item) {
|
$itemResult = $this->createOne($item);
|
if (!is_wp_error($itemResult)) {
|
$success[] = $itemResult;
|
} else {
|
$errors[] = $itemResult;
|
}
|
}
|
$result = [
|
'outcome' => empty($errors) ? 'success' : (empty($success) ? 'failed' : 'partial'),
|
'result' => [
|
'success' => $success,
|
'errors' => $errors
|
]
|
];
|
}
|
|
return array_merge($result, $updated);
|
}
|
|
/**
|
* To be implemented by integration extension. Updates a single item
|
* @param array $item
|
* @return array|WP_Error
|
*/
|
protected function createOne(array $item):array|WP_Error
|
{
|
return new WP_Error('invalid', 'Integration '.$this->service_name.' must implement its own createOne');
|
}
|
|
/**
|
* Overridden by child classes
|
* @param array $items
|
* @return array|WP_Error
|
*/
|
protected function sendBatchCreate(array $items):array|WP_Error
|
{
|
return new WP_Error('invalid', 'Integration '.$this->service_name.' must implement its own sendBatchCreate');
|
}
|
|
/**
|
* To be implemented by extensions
|
* @param array $data
|
* @param array $response
|
* @return array
|
*/
|
protected function processBatchCreateResponse(array $data, array $response):array
|
{
|
return [
|
'outcome' => 'failed',
|
'result' => [
|
'message' => $this->service_name.' should implement processBatchCreateResponse.'
|
]
|
];
|
}
|
|
/*****************************************************************
|
* ITEM UPDATING
|
*****************************************************************/
|
public function updateBatchToService(array $data):array
|
{
|
$type = $data['type']??'post';
|
|
$newlyCreated = [];
|
if (!$this->canCreateOnUpdate) {
|
$created = array_filter($data['items'], function($ID) use ($type) {
|
return !empty($this->getServiceItemID($ID, $type));
|
});
|
|
//Test to see if we have any that haven't been created yet.
|
//For some services, items may have to be created before they can be updated
|
if (count($created) !== count($data['items'])) {
|
$notCreated = array_filter($data['items'], function($ID) use ($type) {
|
return empty($this->getServiceItemID($ID, $type));
|
});
|
$newData = $data;
|
$newData['items'] = $notCreated;
|
$newlyCreated = $this->createBatchToService($newData);
|
}
|
|
// If we don't have any that are created, just send the noUpdatedItems response, with any newly created items added
|
if (empty($created)) {
|
return $this->noUpdatedItems($newlyCreated);
|
}
|
$data['items'] = $created;
|
}
|
|
|
$items = $this->formatItems($data['items'], $type);
|
|
if (empty($items)) {
|
return $this->noUpdatedItems($newlyCreated);
|
}
|
|
if ($this->hasBatchUpdate) {
|
$response = $this->sendBatchUpdate($items);
|
if (!is_wp_error($response)) {
|
$result = $this->processBatchUpdateResponse($data, $response);
|
} else {
|
$this->logError('Batch update failed',[
|
'method' => 'updateBatchToService',
|
'item_ids' => $data['items'],
|
'error' => $response
|
]);
|
$this->updateItemStatus($data['items'], 'error');
|
|
$result = [
|
'outcome' => 'failed_permanent',
|
'result' => 'Could not update items'
|
];
|
}
|
} else {
|
$success = $errors = [];
|
//Does not have batch update, manually update each one
|
foreach ($items as $item) {
|
$itemResult = $this->updateOne($item);
|
if (!is_wp_error($itemResult)) {
|
$success[] = $itemResult;
|
} else {
|
$errors[] = $itemResult;
|
}
|
}
|
|
$result = [
|
'outcome' => empty($errors) ? 'success' : (empty($success) ? 'failed' : 'partial'),
|
'result' => [
|
'success' => $success,
|
'errors' => $errors
|
]
|
];
|
}
|
|
return array_merge($result, $newlyCreated);
|
}
|
|
/**
|
* To be implemented by integration extension. Updates a single item
|
* @param array $item
|
* @return array|WP_Error
|
*/
|
protected function updateOne(array $item):array|WP_Error
|
{
|
return new WP_Error('invalid', 'Integration '.$this->service_name.' must implement its own updateOne method');
|
}
|
|
/**
|
* Overridden by child classes
|
* @param array $items
|
* @return array|WP_Error
|
*/
|
protected function sendBatchUpdate(array $items):array|WP_Error
|
{
|
return new WP_Error('invalid', 'Integration '.$this->service_name.' must implement its own sendBatchUpdate');
|
}
|
|
|
/**
|
* To be implemented by extensions
|
* @param array $data
|
* @param array $response
|
* @return array
|
*/
|
protected function processBatchUpdateResponse(array $data, array $response):array
|
{
|
return [
|
'outcome' => 'failed',
|
'result' => [
|
'message' => $this->service_name.' should implement processBatchUpdateResponse.'
|
]
|
];
|
}
|
/*****************************************************************
|
* UTILITY
|
*****************************************************************/
|
protected function noUpdatedItems(array $created):array
|
{
|
$result = [
|
'outcome' => 'success',
|
'result' => [
|
'message' => 'No items to update',
|
'updated' => [],
|
'errors' => [],
|
]
|
];
|
|
if (!empty($created)) {
|
error_log('Result before: '.print_r($result, true));
|
$result = array_merge($result, $created);
|
error_log('Result after merge: '.print_r($result, true));
|
}
|
return $result;
|
}
|
|
protected function noCreatedItems(array $updated):array
|
{
|
$result = [
|
'outcome' => 'success',
|
'result' => [
|
'message' => 'No items to create',
|
'created' => [],
|
'errors' => [],
|
]
|
];
|
if (!empty($updated)) {
|
$result = array_merge($result, $updated);
|
}
|
return $result;
|
}
|
}
|