marketo_ma-8.x-2.x-dev/modules/marketo_ma_legacy_client/src/Service/MarketoMaApiLegacyClient.php
modules/marketo_ma_legacy_client/src/Service/MarketoMaApiLegacyClient.php
<?php
namespace Drupal\marketo_ma_legacy_client\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\marketo_ma\ActivityType;
use Drupal\marketo_ma\Exception\ProcessingException;
use Drupal\marketo_ma\Exception\SkippedException;
use Drupal\marketo_ma\Exception\SkippedReason;
use Drupal\marketo_ma\Lead;
use Drupal\marketo_ma\Secrets\SecretsInterface;
use Drupal\marketo_ma\Service\MarketoMaApiClientInterface;
use Drupal\marketo_ma\Service\MarketoMaServiceInterface;
use Drupal\marketo_ma_legacy_client\ClientHacks;
use Psr\Log\LoggerInterface;
/**
* Legacy API client.
*/
class MarketoMaApiLegacyClient implements MarketoMaApiClientInterface {
/**
* A logger instance.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* The config used to instantiate the REST client.
*
* @var array
*/
protected $clientConfig = [];
/**
* The API client library.
*
* @var \Drupal\marketo_ma_legacy_client\ClientHacks|null
*
* @see: https://github.com/marketo-api/marketo-rest-client.
*/
protected $client;
/**
* Creates the Marketo API client wrapper service.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* Configuration factory.
* @param \Drupal\marketo_ma\Secrets\SecretsInterface $secrets
* Config secrets.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
*/
public function __construct(ConfigFactoryInterface $configFactory, SecretsInterface $secrets, LoggerInterface $logger) {
$this->logger = $logger;
$config = $configFactory->get(MarketoMaServiceInterface::MARKETO_MA_CONFIG_NAME);
// Build the config for the REST API Client.
$this->clientConfig = [
'munchkin_id' => $config->get('munchkin.account_id'),
'client_id' => $secrets->getClientId(),
'client_secret' => $secrets->getClientSecret(),
];
}
/**
* {@inheritdoc}
*/
public function getFields() {
return $this->getClient()->describeLeads()->getResult();
}
/**
* {@inheritdoc}
*/
public function getActivityTypes() {
$types = [];
foreach ($this->getClient()->getActivityTypes()->getResult() as $type) {
$types[$type['id']] = new ActivityType($type);
}
return $types;
}
/**
* {@inheritdoc}
*/
public function canConnect() {
return !empty($this->clientConfig['client_id']) &&
(!empty($this->clientConfig['url']) || !empty($this->clientConfig['munchkin_id']));
}
/**
* Instantiate the REST API client.
*
* @return \Drupal\marketo_ma_legacy_client\ClientHacks|null
* Test client.
*/
protected function getClient() {
if (!isset($this->client)) {
$config = $this->clientConfig;
// Validate config so we don't generate an invalid argument exception.
if (!empty($config['client_id']) && (!empty($config['url']) || !empty($config['munchkin_id']))) {
// Parent doesn't correctly document static.
/** @var \Drupal\marketo_ma_legacy_client\ClientHacks $client */
$client = ClientHacks::factory($config);
$this->client = $client;
}
else {
$this->logger->warning(
'MarketoMaApiClient::getClient called but rest-api-client is missing some configuration.',
$config
);
}
}
return $this->client;
}
/**
* {@inheritdoc}
*/
public function getLeadById($id) {
$leads_result = $this->getClient()->getLead($id)->getLead();
return !empty($leads_result) ? new Lead($leads_result) : NULL;
}
/**
* {@inheritdoc}
*/
public function getLeadByEmail($email) {
$leads_result = $this->getClient()->getLeadByFilterType('email', $email)->getResult();
return !empty($leads_result[0]) ? new Lead(reset($leads_result)) : NULL;
}
/**
* {@inheritdoc}
*/
public function getLeadActivity(Lead $lead, $activity_type_ids = []) {
// @todo split activity_type_ids into groups of 10 and concatenate results.
// A paging token is required by the activities.json call.
$paging_token = $this->getClient()->getPagingToken(date('c'))->getNextPageToken();
// Calls get lead activities on the API client.
return $this->getClient()->getLeadActivity($paging_token, $lead->id(), $activity_type_ids)->getResult();
}
/**
* {@inheritdoc}
*/
public function syncLead(Lead $lead, $key = 'email', $options = []): ?int {
// Add the create/update leads call to do the association.
$result = $this->getClient()->createOrUpdateLeads([$lead->data()], $key, $options)->getResult();
return !empty($result) ? array_pop($result)['id'] : NULL;
}
/**
* {@inheritdoc}
*/
public function deleteLead($leads, $args = []) {
return $this->getClient()->deleteLead($leads)->getResult();
}
/**
* {@inheritdoc}
*/
public function addLeadsToList($listId, array $leads, array $options = []) {
$leads_raw = $this->getLeadsIds($leads);
// @phpstan-ignore-next-line
return $this->getClient()->addLeadsToList($listId, $leads_raw, $options)->getResult();
}
/**
* {@inheritdoc}
*/
public function addLeadToListByEmail($listId, $email, array $options = []) {
$this->syncLead(new Lead(['email' => $email]));
$this->addLeadsToList($listId, [$this->getLeadByEmail($email)], $options);
}
/**
* Helper method to transform a list of Leads to a coma separated string.
*
* @param array $leads
* An array containing \Drupal\marketo_ma\Lead objects.
*
* @return string
* A coma separated list of ids of the given Lead objects.
*
* @throws \Exception
* In case the given array contains an element which is not a
* \Drupal\marketo_ma\Lead object.
*/
protected function getLeadsIds(array $leads) {
$leads_raw = '';
$total_leads = count($leads);
for ($i = 0; $i < $total_leads; $i++) {
if (!is_a($leads[$i], 'Drupal\marketo_ma\Lead')) {
throw new \Exception('Only lead objects can be passed to the MarketoMaApiClient::addLeadsToList() method.');
}
$leads_raw .= $leads[$i]->id();
if ($i < count($leads) - 1) {
$leads_raw .= ',';
}
}
return $leads_raw;
}
/**
* {@inheritDoc}
*/
public function submitForm(string $form_id, array $fields, ?string $cookie = NULL, array $extra = []) {
$data['input'][0]['leadFormFields'] = $fields;
$data['formId'] = $form_id;
// @todo send cookies to attach session.
$msg = $this->getClient()->post('/rest/v1/leads/submitForm.json', [], json_encode($data));
$msg->setHeader('Content-Type', 'application/json');
$response = $msg->send();
if ($response->getStatusCode() != 200) {
throw new ProcessingException($response->getReasonPhrase(), $response->getStatusCode());
}
$body = json_decode($response->getBody(TRUE));
if (!$body->success) {
// Something went wrong...
// Assume first error has enough information.
$error = array_pop($body->errors);
throw new ProcessingException($error->message, $error->code);
}
$result = $body->result[0];
// Looks like things are probably good but...
if ($result->status == 'skipped') {
// Sad trombone.
throw new SkippedException(
array_map(
function ($reason) {
return new SkippedReason($reason->code, $reason->message);
},
$result->reasons
), 'Skipped processing form'
);
}
return $result->id;
}
}
