Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,179 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
final class PipedriveClientService
{
/** @var string[] $endPoints */
private $endPoints = [
'allPersons' => '/v1/persons',
'recentlyUpdatedPersons' => '/v1/recents',
'deleteContact' => '/v1/persons/:id',
'updateContact' => '/v1/persons/:id',
'createContact' => '/v1/persons',
'getContactById' => '/v1/persons/:id',
'recentlyUpdatedDeals' => '/v1/recents',
'createDeal' => '/v1/deals',
'allDeals' => '/v1/deals',
'deleteDeal' => '/v1/deals/:id',
'updateDeal' => '/v1/deals/:id',
'getDealById' => '/v1/deals/:id',
'getPersonFields' => '/v1/personFields',
'getOnePersonField' => '/v1/personFields/:id',
'getStages' => '/v1/stages',
'getPipelines' => '/v1/pipelines',
];
/** @var string $authMethod */
private $authMethod = 'key';
/** @var string|null $apiKey */
private $apiKey;
/** @var PipedriveHttpClientService $client */
private $client;
/** @var PipedriveConfigurationService $confService */
private $confService;
/**
* @param PipedriveHttpClientService $client
* @param PipedriveConfigurationService $confService
* @param string|null $apiKey
*/
public function __construct(
PipedriveHttpClientService $client,
PipedriveConfigurationService $confService,
?string $apiKey = null
) {
$this->client = $client;
$this->apiKey = $apiKey;
$this->confService = $confService;
}
/** @var string $apiUrl */
private $apiUrl = 'https://api.pipedrive.com%s';
/**
* @param string $resource
* @param array $args
* @param string|null $suffix
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return string
*/
protected function getEndPoint(string $resource, array $args = [], ?string $suffix = null): string
{
if (!array_key_exists($resource, $this->endPoints)) {
throw new PipedriveClientException('Undefined resource endpoint');
}
$suffixUrl = $suffix ?? $this->endPoints[$resource];
$url = sprintf($this->apiUrl, $suffixUrl);
if ($this->authMethod === 'key') {
$apiKey = $this->apiKey ?? $this->getConfApiKey();
$url .= sprintf('?api_token=%s', $apiKey);
}
if (!empty($args)) {
preg_match_all('/:[a-zA-Z0-9._-]+/', $url, $match);
if (!empty($match) && !empty($match[0])) {
$url = str_replace($match[0], $args, $url);
}
}
return $url;
}
/**
* @param string $ressource
* @param array $data
* @param array $endPointArgs
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function read(string $ressource, array $data = [], array $endPointArgs = []): PipedriveServerResponseInterface
{
return $this->client->get($this->getEndPoint($ressource, $endPointArgs), $data);
}
/**
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return string|null
*/
protected function getConfApiKey(): ?string
{
return $this->confService->getDecryptedConfiguration();
}
/**
* @param string $ressource
* @param array $data
* @param array $endPointArgs
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function post(string $ressource, array $data = [], array $endPointArgs = []): PipedriveServerResponseInterface
{
return $this->client->post($this->getEndPoint($ressource, $endPointArgs), $data);
}
/**
* @param string $ressource
* @param array $data
* @param array $endPointArgs
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function delete(string $ressource, array $endPointArgs = [], array $data = []): PipedriveServerResponseInterface
{
return $this->client->delete($this->getEndPoint($ressource, $endPointArgs), $data);
}
/**
* @param string $ressource
* @param array $data
* @param array $endPointArgs
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function put(string $ressource, array $data = [], array $endPointArgs = []): PipedriveServerResponseInterface
{
return $this->client->put($this->getEndPoint($ressource, $endPointArgs), $data);
}
}
@@ -0,0 +1,488 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
use Xentral\Modules\Pipedrive\Gateway\PipedriveDealGateway;
use Xentral\Modules\Pipedrive\Gateway\PipedrivePersonPropertyGateway;
use Xentral\Modules\Pipedrive\Wrapper\PipedriveAddAddressRoleWrapper;
use Xentral\Modules\SystemConfig\SystemConfigModule;
final class PipedriveConfigurationService
{
/** @var string */
private const PIPEDRIVE_SETTINGS = 'pipedrive_settings';
/** @var string */
private const PIPEDRIVE_CONF_NAME = 'pipedrive_conf.json';
/** @var array $_defaultSettings */
private static $_defaultSettings = [
'pd_sync_deals' => true,
'pd_sync_addresses' => true,
'pd_api_key' => null,
];
/** @var SystemConfigModule $configWrapper */
private $configWrapper;
/** @var PipedriveMetaWriterService $metaWriterService */
private $metaWriterService;
/** @var PipedrivePersonPropertyGateway $propertyGateway */
private $propertyGateway;
/** @var PipedriveDealGateway $pipedriveDealGateway */
private $pipedriveDealGateway;
/** @var PipedriveMetaReaderService $metaReaderService */
private $metaReaderService;
/** @var PipedriveAddAddressRoleWrapper $addAddressRoleWrapper */
private $addAddressRoleWrapper;
/**
* @param SystemConfigModule $configWrapper
* @param PipedriveMetaWriterService $metaWriterService
* @param PipedrivePersonPropertyGateway $propertyGateway
* @param PipedriveDealGateway $pipedriveDealGateway
* @param PipedriveMetaReaderService $metaReaderService
* @param PipedriveAddAddressRoleWrapper $addAddressRoleWrapper
*/
public function __construct(
SystemConfigModule $configWrapper,
PipedriveMetaWriterService $metaWriterService,
PipedrivePersonPropertyGateway $propertyGateway,
PipedriveDealGateway $pipedriveDealGateway,
PipedriveMetaReaderService $metaReaderService,
PipedriveAddAddressRoleWrapper $addAddressRoleWrapper
) {
$this->configWrapper = $configWrapper;
$this->metaWriterService = $metaWriterService;
$this->propertyGateway = $propertyGateway;
$this->pipedriveDealGateway = $pipedriveDealGateway;
$this->metaReaderService = $metaReaderService;
$this->addAddressRoleWrapper = $addAddressRoleWrapper;
}
/**
* @param string $name
* @param string $value
*
* @throws PipedriveConfigurationException
*
* @return void
*/
public function trySetConfiguration(string $name, string $value): void
{
if (empty($name)) {
throw new PipedriveConfigurationException('Cannot set Configuration');
}
$this->configWrapper->setValue(self::PIPEDRIVE_SETTINGS, $name, $value);
}
/**
* @param string $name
*
* @throws PipedriveConfigurationException
*
* @return string|null
*/
public function tryGetConfiguration(string $name): ?string
{
if (empty($name)) {
throw new PipedriveConfigurationException('Cannot get configuration on Empty');
}
return $this->configWrapper->tryGetValue(self::PIPEDRIVE_SETTINGS, $name);
}
/**
* @param array $settings
* @param string $value
*
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return array
*/
public function getEncryptedConfiguration(array $settings, string $value): array
{
if (empty($settings)) {
throw new PipedriveConfigurationException('Cannot set Configuration');
}
$encValue = $this->encrypt($value);
$settings['pd_api_key'] = $encValue;
return $settings;
}
/**
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return string|null
*/
public function getDecryptedConfiguration(): ?string
{
$settings = $this->getSettings();
return $settings['pd_api_key'] ?? null;
}
/**
* @param string $plaintext
* @param string $sCipher
*
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return string
*/
protected function encrypt(string $plaintext, string $sCipher = 'aes-128-gcm'): string
{
if (!in_array($sCipher, openssl_get_cipher_methods(), true)) {
throw new PipedriveConfigurationException(sprintf('Cipher method %s does not exist', $sCipher));
}
if (null === $this->getNonceSalt()) {
return $plaintext;
}
$key = hash('sha256', $this->getNonceSalt());
$ivLen = openssl_cipher_iv_length($sCipher);
$iv = openssl_random_pseudo_bytes($ivLen, $crypto_strong);
if ($iv === false || $crypto_strong === false) {
throw new PipedriveConfigurationException('Bad Random length');
}
$cipherTextRaw = openssl_encrypt($plaintext, $sCipher, $key, $options = 0, $iv, $tag);
return base64_encode($iv . $cipherTextRaw . '..' . $tag);
}
/**
* @param string $string
* @param string $sCipher
*
* @throws PipedriveMetaException
*
* @return false|string|null
*/
protected function decrypt(string $string, string $sCipher = 'aes-128-gcm')
{
if (empty($string) || !$this->isBase64Encoded($string)) {
return '';
}
if (null === $this->getNonceSalt()) {
return $this->isBase64Encoded($string) ? null : $string;
}
$stringDecode = base64_decode($string);
$encExploded = explode('..', $stringDecode);
$enc = array_shift($encExploded);
$tag = implode('', $encExploded);
$key = hash('sha256', $this->getNonceSalt());
$ivLen = openssl_cipher_iv_length($sCipher);
$iv = substr($enc, 0, $ivLen);
$cipherTextRaw = substr($enc, $ivLen);
return openssl_decrypt($cipherTextRaw, $sCipher, $key, $options = 0, $iv, $tag);
}
/**
* @param string $string
*
* @return bool
*/
private function isBase64Encoded(string $string): bool
{
return base64_encode(base64_decode($string)) === $string;
}
/**
* @return false|string|null
*/
private function generateSecureSalt()
{
$rand = sprintf('%s', mt_rand());
return password_hash(uniqid($rand, true), PASSWORD_BCRYPT);
}
/**
* @param bool $force
*
* @throws PipedriveMetaException
*
* @return false|int
*/
public function createSalt(bool $force = false)
{
if ($force === true) {
$this->metaWriterService->delete(self::PIPEDRIVE_CONF_NAME);
}
if ($this->metaReaderService->exists(self::PIPEDRIVE_CONF_NAME) && $this->metaReaderService->hasKey(
'nonce_salt',
self::PIPEDRIVE_CONF_NAME
)) {
return -1;
}
return $this->metaWriterService->save(self::PIPEDRIVE_CONF_NAME, ['nonce_salt' => $this->generateSecureSalt()]);
}
/**
* @throws PipedriveMetaException
*
* @return string|null
*/
private function getNonceSalt(): ?string
{
$data = $this->metaReaderService->readFromFile(self::PIPEDRIVE_CONF_NAME);
return $data['nonce_salt'] ?? null;
}
/**
* @param array $hContact
*
* @throws PipedriveConfigurationException
*
* @return array
*/
public function formatAddressByResponse(array $hContact): array
{
if (empty($hContact)) {
throw new PipedriveConfigurationException('Invalid contact');
}
$leadFields = $this->matchSelectedAddressFreeField();
$lsField = $leadFields['pipedrive_ls_field'];
$ahEmail = array_map(
static function ($email) {
if (!array_key_exists('primary', $email) && $email['primary'] === true) {
return null;
}
return $email;
},
$hContact['email']
);
$email = array_filter($ahEmail);
$primaryEmail = is_array($email[0]) && array_key_exists('value', $email[0]) ? $email[0]['value'] : '';
$ahPhone = array_map(
static function ($phone) {
if (!array_key_exists('primary', $phone) && $phone['primary'] === true) {
return null;
}
return $phone;
},
$hContact['phone']
);
$phone = array_filter($ahPhone);
$primaryPhone = is_array($phone[0]) && array_key_exists('value', $phone[0]) ? $phone[0]['value'] : '';
return [
'lead' => 1,
'typ' => !empty($hContact['org_name']) ? 'firma' : 'herr',
'sprache' => 'deutsch',
'name' => $hContact['org_name'] ?? $hContact['name'],
'vorname' => empty($hContact['first_name']) ? 'Pipedrive - ' : $hContact['first_name'],
'nachname' => empty($hContact['last_name']) ? $primaryEmail : $hContact['last_name'],
'land' => empty($hContact['country']) ? 'DE' : $hContact['country'],
'telefon' => $primaryPhone ?? '',
'email' => $primaryEmail,
'kundenfreigabe' => 1,
'waehrung' => 'EUR',
'ansprechpartner' => !empty($hContact['org_name']) ? $hContact['name'] : '',
$lsField => empty($hContact['label']) ? '' : $hContact['label'],
];
}
/**
* @throws PipedriveConfigurationException
*
* @return array
*/
public function matchSelectedAddressFreeField(): array
{
$hFields = [];
$asAddressFreeFieldValues = $this->propertyGateway->getConfiguredFreeAddressFieldValues();
$pdConfFields = [
'pipedrive_ls_field' => $this->tryGetConfiguration('pipedrive_ls_field'),
];
foreach ($asAddressFreeFieldValues as $fieldName) {
$addrField = 'adresse' . $fieldName;
if (in_array($addrField, $pdConfFields, true)) {
$indexField = array_search($addrField, $pdConfFields, true);
$hFields[$indexField] = $fieldName;
}
}
if (empty($hFields)) {
throw new PipedriveConfigurationException('Pipedrive Label-Status fields cannot be matched');
}
return $hFields;
}
/**
* @param array $address
*
* @throws PipedriveConfigurationException
*
* @return array
*/
public function formatAddressToPipedriveContact(array $address): array
{
if (empty($address)) {
throw new PipedriveConfigurationException('Address is invalid');
}
$leadFields = $this->matchSelectedAddressFreeField();
$lsField = $leadFields['pipedrive_ls_field'];
return [
'email' => $address['email'],
'first_name' => empty($address['vorname']) ? $address['name'] : $address['vorname'],
'last_name' => empty($address['nachname']) ? $address['name'] : $address['nachname'],
'name' => $address['name'],
'phone' => $address['telefon'],
'label' => $address[$lsField],
];
}
/**
* @param array $hDeal
*
* @throws PipedriveConfigurationException
*
* @return array
*/
public function formatDealToInternal(array $hDeal): array
{
if (empty($hDeal)) {
throw new PipedriveConfigurationException('Error! Deal cannot be formatted for Xentral');
}
$dealStage = $this->propertyGateway->getMappingByValueAndType($hDeal['stage_id'], 'deals');
$asAddTime = [];
$addTime = $hDeal['add_time'] ?? null;
if ($addTime !== null) {
$asAddTime = explode(' ', $addTime);
}
return [
'bezeichnung' => $hDeal['title'],
'datum_angelegt' => !empty($asAddTime) ? $asAddTime[0] : null,
'zeit_angelegt' => !empty($asAddTime) ? $asAddTime[1] : null,
'datum_erinnerung' => null,
'zeit_erinnerung' => null,
'betrag' => array_key_exists('value', $hDeal) ? (float)$hDeal['value'] : 0.00,
'stages' => !empty($dealStage['wiedervorlage_stage_id']) ?
$dealStage['wiedervorlage_stage_id'] : 0,
'chance' => !empty($hDeal['probability']) ? $hDeal['probability'] : 0,
];
}
/**
* @param array $resubmission
*
* @throws PipedriveConfigurationException
*
* @return array
*/
public function formatResubmissionToPipedriveDeal(array $resubmission): array
{
if (empty($resubmission)) {
throw new PipedriveConfigurationException('Resubmission is invalid');
}
$status = 'open';
if (!empty($resubmission['abgeschlossen'])) {
if ($resubmission['status'] === 'gewonnen') {
$status = 'won';
} elseif ($resubmission['status'] === 'verloren') {
$status = 'lost';
}
}
$mapping = $this->pipedriveDealGateway->getMappingStageByResubmissionStageId($resubmission['stages']);
return [
'title' => $resubmission['bezeichnung'],
'stage_id' => !empty($mapping) ? $mapping['value'] : null,
'value' => empty($resubmission['betrag']) ? 0.00 : $resubmission['betrag'],
'probability' => $resubmission['chance'],
'status' => $status,
];
}
/**
* @param array $settings
*
* @throws PipedriveConfigurationException
*/
public function setSettings($settings = []): void
{
$this->trySetConfiguration(
self::PIPEDRIVE_SETTINGS,
json_encode($settings, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
);
}
/**
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return array
*/
public function getSettings(): array
{
$settingsRaw = $this->tryGetConfiguration(self::PIPEDRIVE_SETTINGS);
if (empty($settingsRaw)) {
return static::$_defaultSettings;
}
$settings = json_decode($settingsRaw, true);
if ($settings === null && json_last_error() === JSON_ERROR_NONE) {
throw new PipedriveConfigurationException(json_last_error_msg());
}
if (empty($settings)) {
return static::$_defaultSettings;
}
if (array_key_exists('pd_api_key', $settings) && !empty($settings['pd_api_key'])) {
$settings['pd_api_key'] = $this->decrypt($settings['pd_api_key']);
}
return $settings;
}
/**
* @param int $contactId
*
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return void
*/
public function addContactToGroup(int $contactId = 0): void
{
$defaultSettings = $this->getSettings();
$contactGrpId = array_key_exists('pd_contact_grp', $defaultSettings) ? $defaultSettings['pd_contact_grp'] : 0;
if (!empty($contactGrpId)) {
$this->addAddressRoleWrapper->add($contactId, $contactGrpId);
}
}
}
@@ -0,0 +1,186 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Components\Database\Database;
use Xentral\Modules\Pipedrive\Exception\PipedriveClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveDealPropertyServiceException;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
use Xentral\Modules\Pipedrive\Gateway\PipedrivePersonPropertyGateway;
use Xentral\Modules\Pipedrive\Wrapper\PipedriveResubmissionWrapper;
use Xentral\Modules\Resubmission\Exception\StageNotFoundException;
use Xentral\Modules\Resubmission\Exception\ViewNotFoundException;
use Xentral\Modules\Resubmission\Service\ResubmissionGateway;
final class PipedriveDealPropertyService
{
/** @var PipedriveClientService $client */
private $client;
/** @var Database $db */
private $db;
/** @var PipedrivePersonPropertyGateway $propertyGateway */
private $propertyGateway;
/** @var ResubmissionGateway $resubmissionGateway */
private $resubmissionGateway;
/** @var PipedriveResubmissionWrapper $resubmissionWrapper */
private $resubmissionWrapper;
/**
* @param PipedriveClientService $client
* @param Database $db
* @param PipedrivePersonPropertyGateway $propertyGateway
* @param ResubmissionGateway $resubmissionGateway
* @param PipedriveResubmissionWrapper $resubmissionWrapper
*/
public function __construct(
PipedriveClientService $client,
Database $db,
PipedrivePersonPropertyGateway $propertyGateway,
ResubmissionGateway $resubmissionGateway,
PipedriveResubmissionWrapper $resubmissionWrapper
) {
$this->client = $client;
$this->db = $db;
$this->propertyGateway = $propertyGateway;
$this->resubmissionGateway = $resubmissionGateway;
$this->resubmissionWrapper = $resubmissionWrapper;
}
/**
* @param int $pipelineId
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveDealPropertyServiceException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return array
*/
public function getDealStages(int $pipelineId = 0): array
{
$data = [];
if ($pipelineId !== 0) {
$data = ['pipeline_id' => $pipelineId];
}
$response = $this->client->read('getStages', $data);
if ($response->getStatusCode() !== 200) {
throw new PipedriveDealPropertyServiceException($response->getError());
}
return $response->getData();
}
/**
* @param int|null $pipelineId
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveDealPropertyServiceException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws StageNotFoundException
*
* @return void
*/
public function installDealStages(?int $pipelineId = null): void
{
// Get Deal Stages
$firstStage = 0;
$viewId = 0;
if ($dealStages = $this->propertyGateway->getLeadsByType('deals')) {
$stage = array_unique(array_column($dealStages, 'wiedervorlage_stage_id'));
$firstStage = $stage[0];
}
if ($firstStage > 0) {
$viewId = $this->resubmissionGateway->getViewIdByStage($firstStage);
}
if (empty($firstStage) || empty($viewId)) {
try {
$viewId = $this->resubmissionGateway->getViewIdByNameAndDescription('Pipedrive', 'Pipedrive');
} catch (ViewNotFoundException $exception) {
$viewId = $this->resubmissionWrapper->addResubmissionView('Pipedrive', 'Pipedrive');
}
}
// Default Pipeline
if ($pipelineId === null) {
$pipeline = $this->getDefaultPipeline();
$pipelineId = $pipeline['id'] ?? 0;
}
if ($viewId > 0 && ($ahDealStages = $this->getDealStages($pipelineId))) {
$position = $this->resubmissionGateway->getMaxSortByViewId($viewId) + 1;
foreach ($ahDealStages as $hDealStage) {
if ($this->db->fetchValue(
'SELECT hm.id FROM `pipedrive_mappings` AS `hm` WHERE hm.value=:value AND hm.type = :type',
[
'value' => $hDealStage['id'],
'type' => 'deals',
]
)) {
continue;
}
$stage = [
'desc' => $hDealStage['name'],
'name' => $hDealStage['name'],
'position' => $position,
'wiedervorlage_view_id' => $viewId,
'enabled' => 1,
'ausblenden' => 0,
];
$stageId = $this->resubmissionWrapper->addResubmissionStage($stage);
if (!empty($stageId)) {
$this->db->perform(
'INSERT INTO `pipedrive_mappings` (`label`, `value`, `type`, `wiedervorlage_stage_id`,
`is_system`, `wiedervorlage_view_id`)
VALUES(:label, :value,:type, :wstage_id, :is_system, :view_id)',
[
'label' => $hDealStage['name'],
'value' => $hDealStage['id'],
'type' => 'deals',
'wstage_id' => $stageId,
'is_system' => 1,
'view_id' => $viewId,
]
);
}
$position++;
}
}
}
/**
* @throws PipedriveClientException
* @throws PipedriveDealPropertyServiceException
* @throws PipedriveHttpClientException
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return array
*/
public function getDefaultPipeline(): array
{
$response = $this->client->read('getPipelines');
if ($response->getStatusCode() !== 200) {
throw new PipedriveDealPropertyServiceException($response->getError());
}
$data = $response->getData();
return array_shift($data);
}
}
@@ -0,0 +1,216 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveDealServiceException;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
use Xentral\Modules\Pipedrive\Exception\PipedriveValidatorException;
use Xentral\Modules\Pipedrive\Validator\PipedriveDealValidator;
final class PipedriveDealService
{
/** @var array $allowedSyncDealsOptions */
private $allowedSyncDealsOptions = [
'pipedrive_recently_updated_deals' => 'getRecentlyUpdatedDeals',
'pipedrive_all_deals' => 'getDeals',
];
/** @var array $itemOption */
private $itemOption = [
'limit' => 100,
'items' => 'deal',
'start' => 0,
'since_timestamp' => '1970-01-01 23:59:59',
];
/** @var PipedriveClientService $client */
private $client;
/** @var PipedriveDealValidator $validator */
private $validator;
/** @var PipedriveMetaReaderService $metaReaderService */
private $metaReaderService;
/**
* @param PipedriveClientService $client
* @param PipedriveDealValidator $validator
* @param PipedriveMetaReaderService $metaReaderService
*/
public function __construct(
PipedriveClientService $client,
PipedriveDealValidator $validator,
PipedriveMetaReaderService $metaReaderService
) {
$this->client = $client;
$this->validator = $validator;
$this->metaReaderService = $metaReaderService;
}
/**
* @param array $data
*
* @throws PipedriveClientException
* @throws PipedriveDealServiceException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedriveValidatorException
* @throws PipedriveConfigurationException
*
* @return PipedriveServerResponseInterface
*/
public function createDeal(array $data = []): PipedriveServerResponseInterface
{
$default = ['status' => 'open', 'stage_id' => 1];
$data += $default;
if (!$this->validator->isValid($data)) {
throw new PipedriveDealServiceException(sprintf('%s::createDeal Invalid Deal data', get_class($this)));
}
$deal = $this->validator->getData();
return $this->client->post('createDeal', $deal);
}
/**
* @param int $dealId
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getDealById(int $dealId): PipedriveServerResponseInterface
{
return $this->client->read('getDealById', [], [$dealId]);
}
/**
* @param array $options
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getDeals(array $options = []): PipedriveServerResponseInterface
{
$options += $this->itemOption;
return $this->client->read('allDeals', $options);
}
/**
* @param array $options
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getRecentlyUpdatedDeals(array $options = []): PipedriveServerResponseInterface
{
$options += $this->itemOption;
return $this->client->read('recentlyUpdatedDeals', $options);
}
/**
* @param int $dealId
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function deleteDeal(int $dealId): PipedriveServerResponseInterface
{
return $this->client->delete('deleteDeal', [$dealId]);
}
/**
* @param int $dealId
* @param array $data
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveDealServiceException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedriveValidatorException
*
* @return PipedriveServerResponseInterface
*/
public function updateDealById(int $dealId, array $data = []): PipedriveServerResponseInterface
{
if (!$this->validator->isValid($data)) {
throw new PipedriveDealServiceException(sprintf('%s::updateDealById Invalid Deal data', get_class($this)));
}
$deal = $this->validator->getData();
return $this->client->put('updateDeal', $deal, [$dealId]);
}
/**
* @param string $type
* @param array $options
*
* @throws PipedriveDealServiceException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function pullDeals(
string $type = 'pipedrive_recently_updated_deals',
array $options = []
): PipedriveServerResponseInterface {
if ('pipedrive_all_deals' !== $type && !array_key_exists($type, $this->allowedSyncDealsOptions)) {
throw new PipedriveDealServiceException(sprintf('Sync Type %s not allowed', $type));
}
$metaFile = sprintf('%s.json', $type);
if ($type !== 'pipedrive_all_deals') {
$options = $this->addMetaOption($metaFile, $options);
}
/** @var PipedriveServerResponseInterface $response */
return $this->{$this->allowedSyncDealsOptions[$type]}($options);
}
/**
* @param string $metaFile
* @param array $options
*
* @throws PipedriveMetaException
*
* @return array
*/
private function addMetaOption(string $metaFile, array $options) : array
{
$metaInfo = $this->metaReaderService->readFromFile($metaFile);
if (!empty($metaInfo)) {
$timeOffset = $metaInfo['timeOffset'];
$offset = strtotime($metaInfo['timeOffset']);
if ($offset !== false) {
$timeOffset = gmdate('Y-m-d H:i:s', $offset - 3600);
}
$options = array_merge($options, ['since_timestamp' => $timeOffset]);
}
return $options;
}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Components\Database\Database;
use Xentral\Components\Database\Exception\DatabaseExceptionInterface;
use Xentral\Modules\Pipedrive\Exception\PipedriveEventException;
final class PipedriveEventService
{
/** @var Database $db */
private $db;
/**
* @param Database $db
*/
public function __construct(Database $db)
{
$this->db = $db;
}
/**
* @param string $event
*
* @throws PipedriveEventException
*
* @return int
*/
public function add(string $event): int
{
$add = 'INSERT INTO `pipedrive_events` (`event`, `created_at`)
VALUES (:event, NOW())';
try {
$this->db->perform($add, ['event' => $event]);
} catch (DatabaseExceptionInterface $exception) {
throw new PipedriveEventException($exception->getMessage());
}
return $this->db->lastInsertId();
}
/**
* @param int $id
*
* @return void
*/
public function deleteById(int $id): void
{
$this->db->perform('DELETE FROM `pipedrive_events` WHERE `id` = :id', ['id' => $id]);
}
/**
* @return void
*/
public function deleteAll(): void
{
$this->db->perform('DELETE FROM `pipedrive_events`');
}
/**
* @param int $days
*
* @return void
*/
public function deleteByInterval(int $days = 30): void
{
$sql = 'DELETE FROM `pipedrive_events` WHERE `created_at` < DATE_SUB(NOW(), INTERVAL :days DAY)';
$this->db->perform($sql, ['days' => $days]);
}
}
@@ -0,0 +1,246 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Components\HttpClient\Exception\TransferErrorExceptionInterface;
use Xentral\Components\HttpClient\HttpClientFactory;
use Xentral\Components\HttpClient\HttpClientInterface;
use Xentral\Components\HttpClient\Request\ClientRequest;
use \Xentral\Components\HttpClient\RequestOptions;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
final class PipedriveHttpClientService
{
/** @var string */
private const GET_REQUEST = 'GET';
/** @var string */
private const POST_REQUEST = 'POST';
/** @var string */
private const DELETE_REQUEST = 'DELETE';
/** @var string */
private const PATCH_REQUEST = 'PATCH';
/** @var string */
private const PUT_REQUEST = 'PUT';
/** @var null|string $endpoint */
protected $endpoint;
/** @var array $userAgent */
protected $userAgent = [];
/** @var array $hRequestVerbs */
protected $hRequestVerbs = [
self::GET_REQUEST => null,
self::POST_REQUEST => 'json',
self::PUT_REQUEST => 'json',
self::PATCH_REQUEST => 'json',
self::DELETE_REQUEST => null,
];
/** @var int $timeout */
private $timeout = 10;
/** @var array $_headers */
private $_headers = [];
/** @var HttpClientInterface $client */
private $client;
/** @var null|RequestOptions $requestOption */
private $requestOption;
/** @var HttpClientFactory|null $factory */
private $factory;
/**
* @param HttpClientFactory $factory
* @param int $timeout
* @param HttpClientInterface|null $client
*
* @throws PipedriveHttpClientException
*/
public function __construct(
HttpClientFactory $factory,
int $timeout = 0,
?HttpClientInterface $client = null
) {
if (!empty($timeout)) {
$this->timeout = $timeout;
}
$this->factory = $factory;
$this->client = $client ?? $this->createClient();
}
/**
* @param string $url
* @param string $method
* @param array $data
* @param array $headers
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
protected function performRequest(
string $url,
string $method,
array $data = [],
array $headers = []
): ?PipedriveServerResponseInterface {
$this->setHeader($headers);
$keyParam = $this->hRequestVerbs[$method];
$paramData = null;
if ($keyParam !== null && $keyParam === 'json') {
$paramData = json_encode($data);
}
$rqHeaders = array_merge(
['Accept' => 'application/json', 'Content-Type' => 'application/json'],
$this->getHeaders()
);
$request = new ClientRequest($method, $url, $rqHeaders);
if (!empty($paramData)) {
if ($this->requestOption === null) {
$this->requestOption = new RequestOptions();
}
$this->requestOption->setBody($paramData);
}
try {
$response = $this->client->sendRequest($request, $this->requestOption);
return new PipedriveHttpResponseService($response);
} catch (TransferErrorExceptionInterface $exception) {
throw new PipedriveHttpClientException($exception->getMessage());
}
}
/**
* @throws PipedriveHttpClientException
*
* @return HttpClientInterface
*/
private function createClient(): HttpClientInterface
{
if (!is_int($this->timeout) || $this->timeout < 0) {
throw new PipedriveHttpClientException(
sprintf('Connection timeout must be an int >= 0, got "%s".', gettype($this->timeout))
);
}
if ($this->factory === null) {
throw new PipedriveHttpClientException('HttpClientFactory is missing!');
}
$options = new RequestOptions();
if ($this->timeout > 0) {
$options->setTimeout($this->timeout);
}
$options->setHeader('Accept', 'application/json');
$options->setHeader('Content-Type', 'application/json');
$this->requestOption = $options;
return $this->factory->createClient($this->requestOption);
}
/**
* @param string $url
* @param array $data
* @param array $header
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
public function get(string $url, array $data = [], array $header = []): ?PipedriveServerResponseInterface
{
if (!empty($data)) {
$query = parse_url($url, PHP_URL_QUERY);
$newQuery = http_build_query($data);
$url = $query ? $url . '&' . $newQuery : $url . '?' . $newQuery;
}
return $this->performRequest($url, self::GET_REQUEST, [], $header);
}
/**
* @param string $url
* @param array $data
* @param array $header
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
public function post(string $url, array $data = [], array $header = []): ?PipedriveServerResponseInterface
{
return $this->performRequest($url, self::POST_REQUEST, $data, $header);
}
/**
* @param string $url
* @param array $data
* @param array $header
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
public function patch(string $url, array $data = [], array $header = []): ?PipedriveServerResponseInterface
{
return $this->performRequest($url, self::PATCH_REQUEST, $data, $header);
}
/**
* @param string $url
* @param array $data
* @param array $header
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
public function delete(string $url, array $data = [], array $header = []): ?PipedriveServerResponseInterface
{
return $this->performRequest($url, self::DELETE_REQUEST, $data, $header);
}
/**
* @param array $option
*/
protected function setHeader(array $option = []): void
{
$this->_headers += $option;
}
/**
* @return array
*/
protected function getHeaders(): array
{
$default = ['User-Agent' => 'Xentral-ERP-CRM'];
return $this->_headers += $default;
}
/**
* @param string $url
* @param array $data
* @param array $header
*
* @throws PipedriveHttpClientException
*
* @return PipedriveServerResponseInterface|null
*/
public function put(string $url, array $data = [], array $header = []): ?PipedriveServerResponseInterface
{
return $this->performRequest($url, self::PUT_REQUEST, $data, $header);
}
}
@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Psr\Http\Message\StreamInterface;
use Xentral\Components\HttpClient\Response\ServerResponseInterface;
final class PipedriveHttpResponseService implements PipedriveServerResponseInterface
{
/** @var ServerResponseInterface $response */
private $response;
/** @var null|array $json */
private $json;
/**
* @param ServerResponseInterface $response
*/
public function __construct(ServerResponseInterface $response)
{
$this->response = $response;
$this->json = json_decode((string)$this->response->getBody(), true);
}
/**
* Returns the json response body
*
* @return null|array
*/
public function getJson(): ?array
{
return $this->json;
}
/**
* @return StreamInterface
*/
public function getBody(): StreamInterface
{
return $this->response->getBody();
}
/**
* @return int
*/
public function getStatusCode(): int
{
return $this->response->getStatusCode();
}
/**
* @return bool
*/
public function isSuccess(): bool
{
$success = false;
if (null !== $this->json && is_array($this->json)) {
$success = array_key_exists('success', $this->json) && $this->json['success'] === true;
}
return $success;
}
/**
* @return array
*/
public function getData(): array
{
$data = [];
if (null !== $this->json && is_array($this->json) && array_key_exists('data', $this->json)) {
$data = $this->json['data'] ?? [];
}
return $data;
}
/**
* Returns the error message
*
* @return string
*/
public function getError(): string
{
$error = '';
if (null !== $this->json && is_array($this->json) && array_key_exists('error', $this->json) &&
!in_array($this->getStatusCode(), [200, 201])) {
$error = $this->json['error'] ?? 'Unknown Error';
}
return $error;
}
/**
* @return array
*/
public function getAdditionalData(): array
{
$additionalData = [];
if (null !== $this->json && is_array($this->json) && array_key_exists('additional_data', $this->json)) {
$additionalData = $this->json['additional_data'];
}
return $additionalData;
}
/**
* @return array|null
*/
public function getPagination(): ?array
{
$pagination = null;
if (($additional_data = $this->getAdditionalData()) && array_key_exists('pagination', $additional_data)) {
$pagination = $additional_data['pagination'];
}
return $pagination;
}
}
@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveExceptionInterface;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
final class PipedriveMetaReaderService
{
/** @var string $tmpDir directory to save the meta file */
private $tmpDir;
/**
* @param string $tmpDir
*/
public function __construct(string $tmpDir)
{
$this->tmpDir = $tmpDir;
}
/**
* @param string $fileName
*
* @throws PipedriveMetaException
*
* @return array|null
*/
public function readFromFile(string $fileName): ?array
{
if (empty($fileName)) {
throw new PipedriveMetaException(
sprintf('::readFromFile() Expects Meta content to be non empty string file, %s given', $fileName)
);
}
if (!$this->exists($fileName)) {
return null;
}
$fullFileName = $this->getFullFileName($fileName);
$meta = @file_get_contents($fullFileName);
if (($meta = json_decode($meta, true)) === null || (json_last_error() !== JSON_ERROR_NONE)) {
return [];
}
return $meta;
}
/**
* @param string $fileName
*
* @throws PipedriveMetaException
*
* @return string|null
*/
private function getFullFileName(string $fileName): ?string
{
$metaFile = sprintf($this->tmpDir . DIRECTORY_SEPARATOR . '%s', $fileName);
if (!is_file($metaFile)) {
throw new PipedriveMetaException(sprintf('File "%s" was not found', $metaFile));
}
return $metaFile;
}
/**
* @param string $fileName
*
* @return bool
*/
public function exists(string $fileName): bool
{
try {
$fullFileName = $this->getFullFileName($fileName);
return file_exists($fullFileName) && is_file($fullFileName);
} catch (PipedriveExceptionInterface $exception) {
//
}
return false;
}
/**
* @param string $key
* @param string $fileName
*
* @throws PipedriveMetaException
*
* @return bool
*/
public function hasKey(string $key, string $fileName): bool
{
return $this->exists($fileName) && ($meta = $this->readFromFile($fileName)) && array_key_exists($key, $meta);
}
}
@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
final class PipedriveMetaWriterService
{
/** @var string $tmpDir directory to save the meta file */
private $tmpDir;
/**
* PipedriveMetaWriterService constructor.
*
* @param string $tmpDir
*/
public function __construct(string $tmpDir)
{
$this->tmpDir = $tmpDir;
}
/**
* @param string $fileName
* @param array $data
*
* @throws PipedriveMetaException
*
* @return false|int
*/
public function save(string $fileName, array $data)
{
if (empty($fileName)) {
throw new PipedriveMetaException('Name cannot be empty');
}
if (!function_exists('json_encode')) {
throw new PipedriveMetaException('Required PHP extension "json" is missing.');
}
$content = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
return file_put_contents(
$this->getFullFileName($fileName),
$content
);
}
/**
* @param string $fileName
*
* @throws PipedriveMetaException
*
* @return string
*/
private function getFullFileName(string $fileName): string
{
if (!is_dir($this->tmpDir) && !@mkdir($this->tmpDir, 0777, true) && !is_dir($this->tmpDir)) {
throw new PipedriveMetaException(sprintf('Directory "%s" was not created', $this->tmpDir));
}
return sprintf($this->tmpDir . DIRECTORY_SEPARATOR . '%s', $fileName);
}
/**
* @param string $fileName
*
* @throws PipedriveMetaException
*
* @return bool
*/
public function delete(string $fileName): bool
{
$metaFile = $this->getFullFileName($fileName);
return file_exists($metaFile) && is_file($metaFile) && @unlink($metaFile);
}
}
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
use Xentral\Modules\Pipedrive\Exception\PipedrivePersonPropertyServiceException;
final class PipedrivePersonPropertyService
{
/** @var PipedriveClientService $client */
private $client;
/**
* @param PipedriveClientService $client
*/
public function __construct(PipedriveClientService $client)
{
$this->client = $client;
}
/**
* @throws PipedriveClientException
* @throws PipedriveHttpClientException
* @throws PipedriveConfigurationException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getProperties(): PipedriveServerResponseInterface
{
return $this->client->read('getPersonFields');
}
/**
* @param int $id
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getProperty(int $id): PipedriveServerResponseInterface
{
return $this->client->read('getOnePersonField', [], [$id]);
}
/**
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedrivePersonPropertyServiceException
*
* @return array
*/
public function getPdLeadStatus(): array
{
$response = $this->getProperty(9039);
if ($response->getStatusCode() !== 200) {
throw new PipedrivePersonPropertyServiceException($response->getError());
}
if (($data = $response->getData()) && array_key_exists('options', $data)) {
return $data['options'];
}
return [];
}
}
@@ -0,0 +1,241 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Xentral\Modules\Pipedrive\Exception\PipedriveClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveConfigurationException;
use Xentral\Modules\Pipedrive\Exception\PipedriveHttpClientException;
use Xentral\Modules\Pipedrive\Exception\PipedriveMetaException;
use Xentral\Modules\Pipedrive\Exception\PipedrivePersonServiceException;
use Xentral\Modules\Pipedrive\Exception\PipedriveValidatorException;
use Xentral\Modules\Pipedrive\Validator\PipedrivePersonValidator;
final class PipedrivePersonService
{
/** @var array $itemOption */
private $itemOption = [
'limit' => 100,
'items' => 'person',
'start' => 0,
'since_timestamp' => '1970-01-01 23:59:59',
];
/** @var string[] $allowedSyncPeronOptions */
private $allowedSyncPeronOptions = [
'pipedrive_recently_updated' => 'getRecentlyUpdatedPersons',
'pipedrive_all' => 'getAllPersons',
];
/** @var PipedriveClientService $client */
private $client;
/** @var PipedriveMetaReaderService $metaReaderService */
private $metaReaderService;
/** @var PipedrivePersonValidator $validator */
private $validator;
/**
* PipedrivePersonService constructor.
*
* @param PipedriveClientService $client
* @param PipedrivePersonValidator $validator
* @param PipedriveMetaReaderService $metaReaderService
*/
public function __construct(
PipedriveClientService $client,
PipedrivePersonValidator $validator,
PipedriveMetaReaderService $metaReaderService
) {
$this->client = $client;
$this->validator = $validator;
$this->metaReaderService = $metaReaderService;
}
/**
* @param array $options
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getAllPersons(array $options = []): PipedriveServerResponseInterface
{
return $this->client->read('allPersons', $options);
}
/**
* @param array $options
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function getRecentlyUpdatedPersons(array $options = []): PipedriveServerResponseInterface
{
$options = array_merge($this->itemOption, $options);
return $this->client->read('recentlyUpdatedPersons', $options);
}
/**
* @param int $contactId
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function deleteContact(int $contactId = 0): PipedriveServerResponseInterface
{
return $this->client->delete('deleteContact', [$contactId]);
}
/**
* @param array $data
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedrivePersonServiceException
* @throws PipedriveValidatorException
*
* @return PipedriveServerResponseInterface
*/
public function createContact(array $data = []): PipedriveServerResponseInterface
{
if (!$this->validator->isValid($data)) {
throw new PipedrivePersonServiceException(
sprintf('%s::createContact Invalid contact data', get_class($this))
);
}
$identity = $this->formatContactIdentity($this->validator->getData());
return $this->client->post('createContact', $identity);
}
/**
* @param int $contactId
* @param array $data
*
* @throws PipedriveClientException
* @throws PipedriveConfigurationException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedrivePersonServiceException
* @throws PipedriveValidatorException
*
* @return PipedriveServerResponseInterface
*/
public function updateContactById(int $contactId, array $data = []): PipedriveServerResponseInterface
{
if (!$this->validator->isValid($data)) {
throw new PipedrivePersonServiceException(
sprintf('%s::updateContactById Invalid contact data', get_class($this))
);
}
$identity = $this->formatContactIdentity($this->validator->getData());
return $this->client->put('updateContact', $identity, [$contactId]);
}
/**
* @param array $data
*
* @return array
*/
private function formatContactIdentity(array $data): array
{
$identity = [];
foreach ($data as $property => $value) {
if (in_array($property, ['email', 'phone'])) {
$identity[$property][] = [
'label' => 'other',
'value' => $value,
];
} else {
$identity[$property] = $value;
}
}
return $identity;
}
/**
* @param string $type
* @param array $options
*
* @throws PipedrivePersonServiceException
* @throws PipedriveMetaException
*
* @return PipedriveServerResponseInterface
*/
public function pullPersons(string $type = 'pipedrive_all', array $options = []): PipedriveServerResponseInterface
{
$options = array_merge($this->itemOption, $options);
if ('pipedrive_all' !== $type && !array_key_exists($type, $this->allowedSyncPeronOptions)) {
throw new PipedrivePersonServiceException(sprintf('Sync Type %s not allowed', $type));
}
$metaFile = sprintf('%s.json', $type);
if ($type !== 'pipedrive_all') {
$options = $this->addMetaOption($metaFile, $options);
}
/** @var PipedriveServerResponseInterface $response */
return $this->{$this->allowedSyncPeronOptions[$type]}($options);
}
/**
* @param int $contactId
*
* @throws PipedriveClientException
* @throws PipedriveHttpClientException
* @throws PipedriveMetaException
* @throws PipedriveConfigurationException
*
* @return PipedriveServerResponseInterface
*/
public function getContactById(int $contactId): PipedriveServerResponseInterface
{
return $this->client->read('getContactById', [], [$contactId]);
}
/**
* @param string $metaFile
* @param array $options
*
* @throws PipedriveMetaException
*
* @return array
*/
private function addMetaOption(string $metaFile, array $options) : array
{
$metaInfo = $this->metaReaderService->readFromFile($metaFile);
if (!empty($metaInfo)) {
$timeOffset = $metaInfo['timeOffset'];
$offset = strtotime($metaInfo['timeOffset']);
if ($offset !== false) {
$timeOffset = gmdate('Y-m-d H:i:s', $offset - 3600);
}
$options = array_merge($options, ['since_timestamp' => $timeOffset]);
}
return $options;
}
}
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Pipedrive\Service;
use Psr\Http\Message\StreamInterface;
interface PipedriveServerResponseInterface
{
/**
* Returns the json response body
*
* @return array|mixed
*/
public function getJson();
/**
* Gets the response body.
*
* @return StreamInterface
*/
public function getBody(): StreamInterface;
/**
* Gets the response status code.
*
* @return int Status code.
*/
public function getStatusCode(): int;
/**
* Returns the error message
*
* @return string
*/
public function getError(): string;
/**
* Checks whether the call was successful or not
*
* @return bool
*/
public function isSuccess(): bool;
/**
* Retrieves Data from the response
*
* @return array
*/
public function getData(): array;
/**
* Retrieves Additional Data from the response
*
* @return array
*/
public function getAdditionalData(): array;
}