<?php
namespace App\Newsletter\ProviderHandler;
use App\Model\DataObject\Customer;
use App\Newsletter\ProviderHandler\Evalanche\PoolExporter;
use App\Newsletter\ProviderHandler\Evalanche\ProfileExporter;
use CustomerManagementFrameworkBundle\ActivityManager\ActivityManagerInterface;
use CustomerManagementFrameworkBundle\CustomerProvider\CustomerProviderInterface;
use CustomerManagementFrameworkBundle\DataValidator\EmailValidator;
use CustomerManagementFrameworkBundle\Model\Activity\MailchimpStatusChangeActivity;
use CustomerManagementFrameworkBundle\Model\MailchimpAwareCustomerInterface;
use CustomerManagementFrameworkBundle\Model\NewsletterAwareCustomerInterface;
use CustomerManagementFrameworkBundle\Newsletter\ProviderHandler\NewsletterProviderHandlerInterface;
use CustomerManagementFrameworkBundle\Newsletter\Queue\Item\DefaultNewsletterQueueItem;
use CustomerManagementFrameworkBundle\Newsletter\Queue\Item\NewsletterQueueItemInterface;
use CustomerManagementFrameworkBundle\Newsletter\Queue\NewsletterQueueInterface;
use CustomerManagementFrameworkBundle\SegmentManager\SegmentManagerInterface;
use CustomerManagementFrameworkBundle\Traits\LoggerAware;
use Pimcore\File;
use Pimcore\Log\ApplicationLogger;
use Pimcore\Model\DataObject\CustomerSegmentGroup;
use Pimcore\Model\DataObject\EvalancheAttributeValue;
class Evalanche implements NewsletterProviderHandlerInterface
{
use LoggerAware;
const PERMISSION_UNCONFIRMED = '0';
const PERMISSION_OPT_IN = '1';
const PERMISSION_DOUBLEOPT_IN = '2';
const PERMISSION_OPT_OUT = '3';
const STATUS_SUBSCRIBED = 'subscribed';
const STATUS_UNSUBSCRIBED = 'unsubscribed';
const STATUS_PENDING = 'pending';
const ARTICLE_TEMPLATE_TYPE_EMAIL = 33;
const ARTICLE_TEMPLATE_TYPE_TEXT = 34;
const ARTICLE_TEMPLATE_TYPE_PDF = 35;
const ARTICLE_TEMPLATE_TYPE_WEB_MOBILE = 36;
const SALUTATION_FEMALE = 1;
const SALUTATION_MALE = 2;
const SALUTATION_FAMILY = 3;
const SALUTATION_COMPANY = 4;
const COUNTRYMAPPING = [
"-" => 0,
"DE" => 1,
"AT" => 2,
"AF" => 62,
"AL" => 63,
"DZ" => 64,
"AS" => 128,
"VI" => 129,
"Anderes" => 60,
"AD " => 65,
"AO" => 66,
"AI" => 130,
"AQ" => 131,
"AG" => 132,
"AR" => 134,
"AM" => 67,
"AW" => 135,
"AU" => 115,
"AZ" => 68,
"BS" => 136,
"BH" => 69,
"BD" => 70,
"BB" => 137,
"BY" => 71,
"BE" => 15,
"BZ" => 138,
"BJ" => 72,
"BM" => 262,
"BT" => 139,
"BO" => 140,
"BA" => 29,
"BW" => 73,
"BV" => 142,
"BR" => 124,
"VG" => 143,
"IO" => 144,
"BN" => 145,
"BG" => 30,
"BF" => 74,
"BI" => 146,
"EA" => 147,
"CL" => 125,
"CN" => 32,
"CK" => 148,
"CR" => 149,
"CW" => 265,
"CI" => 150,
"CD" => 188,
"DM" => 151,
"DO" => 152,
"DJ" => 153,
"DK" => 16,
"EC" => 154,
"SV" => 155,
"ER" => 156,
"EE" => 34,
"FK" => 157,
"FJ" => 159,
"FI" => 17,
"FR" => 18,
"GF" => 160,
"PF" => 161,
"TF" => 162,
"FO" => 158,
"GA" => 163,
"GM" => 79,
"GE" => 80,
"GH" => 81,
"GI" => 164,
"GD" => 165,
"GR" => 19,
"GB" => 20,
"GL" => 166,
"GP" => 167,
"GU" => 168,
"GT" => 169,
"GG" => 170,
"GN" => 171,
"GW" => 172,
"GY" => 173,
"HT" => 174,
"HM" => 175,
"HN" => 176,
"HK" => 116,
"IN" => 82,
"ID" => 83,
"IM" => 177,
"IR" => 84,
"IQ" => 85,
"IE" => 21,
"IS" => 35,
"IL" => 36,
"IT" => 22,
"JM" => 178,
"JP" => 37,
"JE" => 179,
"JO" => 38,
"KY" => 180,
"KH" => 181,
"CM" => 75,
"CA" => 31,
"IC" => 182,
"CV" => 183,
"BQ" => 264,
"KZ" => 86,
"KE" => 87,
"KG" => 89,
"KI" => 184,
"CC" => 185,
"CO" => 186,
"KM" => 187,
"CG" => 77,
"XK " => 263,
"HR" => 40,
"CU" => 189,
"KW" => 88,
"LA" => 190,
"LS" => 191,
"LV" => 41,
"LB" => 42,
"LR" => 192,
"LY" => 90,
"LI" => 91,
"LT" => 43,
"LU" => 23,
"MO" => 193,
"MG" => 194,
"MW" => 92,
"MY" => 121,
"MV" => 195,
"ML" => 196,
"MT" => 45,
"MA" => 95,
"MH" => 197,
"MQ" => 198,
"MR" => 199,
"MU" => 200,
"YT" => 201,
"MK" => 44,
"MX" => 122,
"FM" => 202,
"MD" => 93,
"MC" => 94,
"MN" => 203,
"ME" => 204,
"MS" => 205,
"MZ" => 96,
"MM" => 206,
"NA" => 207,
"NR" => 208,
"NP" => 97,
"NC" => 209,
"NZ" => 117,
"NI" => 210,
"NL" => 24,
"AN" => 211,
"NE " => 98,
"NG" => 99,
"NU" => 212,
"KP" => 120,
"NF" => 214,
"NO" => 61,
"MP" => 213,
"OM" => 46,
"TL" => 215,
"PK" => 100,
"PW" => 216,
"PS" => 101,
"PA" => 217,
"PG" => 218,
"PY" => 219,
"PE" => 220,
"PH" => 221,
"PN" => 222,
"PL" => 47,
"PT " => 25,
"PR" => 223,
"QA" => 102,
"RW" => 225,
"RO" => 48,
"RU" => 49,
"RE" => 224,
"BL" => 227,
"MF" => 228,
"SB" => 226,
"WS" => 229,
"SM" => 230,
"SA" => 50,
"SE" => 26,
"CH" => 3,
"SN" => 232,
"RS" => 39,
"SC" => 233,
"SL" => 234,
"SG" => 114,
"SX" => 267,
"Sk" => 51,
"SI" => 52,
"SO" => 235,
"ES" => 27,
"LK" => 103,
"SH" => 236,
"KN" => 237,
"LC" => 238,
"PM" => 239,
"VC" => 240,
"SD" => 104,
"SR" => 242,
"SJ" => 243,
"SZ" => 105,
"SY" => 106,
"ST" => 231,
"KR" => 118,
"ZA" => 126,
"GS" => 241,
"SS" => 266,
"TJ" => 244,
"TW" => 119,
"TZ" => 107,
"TH" => 245,
"TG" => 246,
"TK" => 247,
"TO" => 248,
"TT" => 249,
"TD" => 250,
"CZ" => 53,
"TN" => 55,
"TM" => 251,
"TC" => 252,
"TV " => 253,
"TR " => 54,
"US" => 57,
"UG" => 108,
"UA" => 109,
"HU" => 56,
"UM" => 254,
"UY" => 255,
"UZ" => 110,
"VU" => 256,
"VA" => 257,
"VE" => 258,
"AE" => 58,
"VN" => 123,
"WF" => 259,
"CX" => 260,
"EH" => 261,
"YE" => 111,
"ZM" => 112,
"CF" => 76,
"ZW" => 113,
"CY" => 59,
"EG" => 28,
"GQ" => 133,
"ET" => 78,
"AX" => 127,
];
/**
* @var string
*/
protected $shortcut, $poolId, $host, $username, $password;
/** @var \Scn\EvalancheSoapApiConnector\EvalancheConnectionInterface */
protected $connection;
/** @var ProfileExporter */
protected $profileExporter;
/** @var PoolExporter */
protected $poolExporter;
/**
* @var array
*/
private $statusMapping;
/**
* @var array
*/
private $reverseStatusMapping;
/**
* @var array
*/
private $mergeFieldMapping;
/**
* @var array
*/
private $fieldTransformers;
/**
* @var int
*/
protected $batchThreshold = 50;
/**
* @var SegmentManagerInterface
*/
private $segmentManager;
/**
* @var array
*/
private $confirmationMailingIDs;
/**
* Evalanche constructor.
* @param $shortcut
* @param $poolId
* @param $host
* @param $username
* @param $password
* @param array $confirmationMailingIDs
* @param array $statusMapping
* @param array $reverseStatusMapping
* @param array $mergeFieldMapping
* @param array $fieldTransformers
* @param SegmentManagerInterface $segmentManager
* @throws \Exception
*/
public function __construct($shortcut, $poolId, $host, $username, $password, array $confirmationMailingIDs = [], array $statusMapping = [], array $reverseStatusMapping = [], array $mergeFieldMapping = [], array $fieldTransformers = [], SegmentManagerInterface $segmentManager)
{
if (!strlen($shortcut) || !File::getValidFilename($shortcut)) {
throw new \Exception('Please provide a valid newsletter provider handler shortcut.');
}
$this->shortcut = $shortcut;
$this->poolId = $poolId;
$this->host = $host;
$this->username = $username;
$this->password = $password;
$this->statusMapping = $statusMapping;
$this->reverseStatusMapping = $reverseStatusMapping;
$this->mergeFieldMapping = $mergeFieldMapping;
$this->fieldTransformers = $fieldTransformers;
$this->segmentManager = $segmentManager;
$this->confirmationMailingIDs = $confirmationMailingIDs;
}
/**
* @return \Scn\EvalancheSoapApiConnector\EvalancheConnectionInterface
*/
public function getConnection() {
if ($this->connection == '') {
$this->connection = \Scn\EvalancheSoapApiConnector\EvalancheConnection::create(
$this->host,
$this->username,
$this->password
);
}
return $this->connection;
}
/**
* @return string
*/
public function getPoolId(): string
{
return $this->poolId;
}
protected function getProfileExporter() {
if ($this->profileExporter == '') {
$this->profileExporter = new ProfileExporter($this, $this->mergeFieldMapping);
}
return $this->profileExporter;
}
protected function getPoolExporter() {
if ($this->poolExporter == '') {
$this->poolExporter = new PoolExporter($this);
}
return $this->poolExporter;
}
public function getShortcut()
{
return $this->shortcut;
}
public function processCustomerQueueItems(array $items, $forceUpdate = false)
{
$items = $this->getUpdateNeededItems($items, $forceUpdate);
list($emailChangedItems, $regularItems) = $this->determineEmailChangedItems($items);
//Customers where the email address changed need to be handled by the single exporter as the batch exporter does not allow such operations.
if (count($emailChangedItems)) {
$this->getLogger()->info(
sprintf(
'[Evalanche][%s] process %s items where the email address changed...',
$this->getShortcut(),
count($emailChangedItems)
)
);
foreach ($emailChangedItems as $item) {
$this->customerExportSingle($item);
}
}
$itemCount = count($regularItems);
if (!$itemCount) {
$this->getLogger()->info(
sprintf(
'[Evalanche][%s] 0 items to process...',
$this->getShortcut()
)
);
} elseif ($itemCount <= $this->batchThreshold) {
$this->getLogger()->info(
sprintf(
'[Evalanche][%s] Data count (%d) is below batch threshold (%d), sending one request per entry...',
$this->getShortcut(),
$itemCount,
$this->batchThreshold
)
);
foreach ($regularItems as $item) {
$this->customerExportSingle($item);
}
} else {
$this->getLogger()->info(
sprintf(
'[Evalanche][%s] Sending data as batch request',
$this->getShortcut()
)
);
$this->customerExportBatch($regularItems);
}
}
public function updateSegmentGroups($forceUpdate = false)
{
$groups = $this->getExportableSegmentGroups();
$groupIds = [];
foreach ($groups as $group) {
$remoteGroupId = $this->getPoolExporter()->exportGroup($group, $this->poolId, false, $forceUpdate);
$groupIds[] = $remoteGroupId;
$segments = $this->segmentManager->getSegmentsFromSegmentGroup($group);
$this->getPoolExporter()->exportSegments($segments, $this->poolId, $remoteGroupId, $forceUpdate);
}
// $this->getPoolExporter()->deleteNonExistingGroups($groupIds, $this->poolId); DO NOT DELETE NON EXISTING GROUPS AS WE CANNOT DIFFERENTIATE BETWEEN ATTRIBUTES CREATED BY US OR IN THE EVALANCHE SYSTEM
}
protected function getExportableSegmentGroups()
{
$fieldname = 'exportNewsletterProvider' . ucfirst($this->getShortcut());
$groups = $this->segmentManager->getSegmentGroups();
$groups->addConditionParam($fieldname . ' = 1');
return $groups;
}
public function subscribeCustomer(NewsletterAwareCustomerInterface $customer)
{
return $this->subscribeCustomerWithStatus($customer, self::STATUS_SUBSCRIBED);
}
/**
* Directly Subscribes/exports a customer with given mailchimp status "subscribed" via the Mailchimp API.
*
* @param NewsletterAwareCustomerInterface $customer
* @return bool success
*/
public function subscribeCustomerWithStatus(NewsletterAwareCustomerInterface $customer, string $status)
{
/**
* @var MailchimpAwareCustomerInterface $customer;
*/
if (!$newsletterStatus = $this->reverseMapNewsletterStatus($status)) {
$this->getLogger()->error(sprintf('subscribe failed: could not reverse map evalanche status %s', $status));
return false;
}
try {
$this->setNewsletterStatus($customer, $newsletterStatus);
$item = new DefaultNewsletterQueueItem(
$customer->getId(),
$customer,
$customer->getEmail(),
NewsletterQueueInterface::OPERATION_UPDATE
);
$success = $this->getProfileExporter()->update($customer, $item, $this);
if ($success) {
$customer->saveWithOptions(
$customer->getSaveManager()->getSaveOptions()
->disableNewsletterQueue()
->disableDuplicatesIndex()
->disableOnSaveSegmentBuilders()
);
}
} catch (\Exception $e) {
$this->getLogger()->error('subscribe customer failed: '.$e->getMessage());
return false;
}
return $success;
}
/**
* Directly Subscribes/exports a customer with evalanche status "pending".
*
* @param NewsletterAwareCustomerInterface $customer
* @return bool success
*/
public function subscribeCustomerPending(NewsletterAwareCustomerInterface $customer)
{
return $this->subscribeCustomerWithStatus($customer, self::STATUS_PENDING);
}
public function unsubscribeCustomer(NewsletterAwareCustomerInterface $customer)
{
/**
* @var MailchimpAwareCustomerInterface $customer;
*/
if (!$newsletterStatus = $this->reverseMapNewsletterStatus(self::STATUS_UNSUBSCRIBED)) {
$this->getLogger()->error(sprintf('subscribe failed: could not reverse map evalanche status %s', self::STATUS_UNSUBSCRIBED));
return false;
}
try {
$this->setNewsletterStatus($customer, $newsletterStatus);
$item = new DefaultNewsletterQueueItem(
$customer->getId(),
$customer,
$customer->getEmail(),
NewsletterQueueInterface::OPERATION_UPDATE
);
$success = $this->getProfileExporter()->update($customer, $item, $this);
if ($success) {
$customer->saveWithOptions(
$customer->getSaveManager()->getSaveOptions()
->disableNewsletterQueue()
->disableDuplicatesIndex()
->disableOnSaveSegmentBuilders()
);
}
} catch (\Exception $e) {
$this->getLogger()->error('unsubscribe customer failed: '.$e->getMessage());
return false;
}
return $success;
}
/**
* @param NewsletterQueueItemInterface[] $items
*
* @return array
*/
protected function determineEmailChangedItems(array $items)
{
$emailChangedItems = [];
$regularItems = [];
foreach ($items as $item) {
if ($item->getOperation() != NewsletterQueueInterface::OPERATION_UPDATE) {
$regularItems[] = $item;
continue;
}
if (!$item->getCustomer()) {
$regularItems[] = $item;
continue;
}
if ($item->getCustomer()->getEmail() != $item->getEmail()) {
$emailChangedItems[] = $item;
continue;
}
$regularItems[] = $item;
}
return [$emailChangedItems, $regularItems];
}
/**
* @param array $items
* @param bool $forceUpdate
* @return NewsletterQueueItemInterface[]
* @throws \Exception
*/
protected function getUpdateNeededItems(array $items, $forceUpdate = false)
{
$updateNeededItems = [];
foreach ($items as $item) {
$emailValidator = new EmailValidator();
if ($item->getCustomer() && !$emailValidator->isValid($item->getCustomer()->getEmail()) && !$emailValidator->isValid(!$item->getEmail())) {
$this->getLogger()->info(
sprintf(
'[Evalanche][CUSTOMER %s][%s] Export not needed as the customer has no valid email address.',
$item->getCustomer() ? $item->getCustomer()->getId() : '',
$this->getShortcut()
)
);
$item->setSuccessfullyProcessed(true);
} elseif (!$item->getCustomer()) {
$updateNeededItems[] = $item;
} elseif ($item->getOperation() == NewsletterQueueInterface::OPERATION_UPDATE) {
if (!$item->getCustomer()->needsExportByNewsletterProviderHandler($this)) {
/* Update item only if a mailchimp status is set in the customer.
Otherwise the customer should not exist in the mailchimp list and therefore no deletion should be needed.
Cleaned customers will be ignored as the email adress is invalid
*/
$evalancheStatus = $this->getEvalancheStatus($item->getCustomer());
if ($evalancheStatus) {
$updateNeededItems[] = $item;
} else {
$this->getLogger()->info(
sprintf(
'[Evalanche][CUSTOMER %s][%s] Export not needed as the export data did not change (customer is not in export list).',
$item->getCustomer()->getId(),
$this->getShortcut()
)
);
$item->setSuccessfullyProcessed(true);
}
} elseif ($forceUpdate || $this->getProfileExporter()->didExportDataChangeSinceLastExport($item->getCustomer(), $this->poolId, $this->buildEntry($item->getCustomer()))) {
$evalancheStatus = $this->getEvalancheStatus($item->getCustomer());
if (!$evalancheStatus) {
$entry = $this->buildEntry($item->getCustomer());
$setStatus = isset($entry['status_if_new']) ?: $entry['status'];
if ($setStatus == self::STATUS_UNSUBSCRIBED) {
$this->getLogger()->info(
sprintf(
'[Evalanche][CUSTOMER %s][%s] Export not needed as the customer is unsubscribed and was not exported yet.',
$item->getCustomer()->getId(),
$this->getShortcut()
)
);
$item->setSuccessfullyProcessed(true);
} else {
$updateNeededItems[] = $item;
}
} else {
$updateNeededItems[] = $item;
}
}
} else {
$updateNeededItems[] = $item;
}
}
return $updateNeededItems;
}
public function setEvalancheStatus(NewsletterAwareCustomerInterface $customer, $status)
{
$setter = 'setEvalancheStatus' . ucfirst($this->getShortcut());
if (!method_exists($customer, $setter)) {
throw new \Exception(sprintf(
'Customer needs to have a field %s in order to be able to hold the evalanche status for newsletter provider handler with shortcut %s',
$setter,
$this->getShortcut()
));
}
$customer->$setter($status);
}
public function getEvalancheStatus(NewsletterAwareCustomerInterface $customer)
{
$getter = 'getEvalancheStatus' . ucfirst($this->getShortcut());
if (!method_exists($customer, $getter)) {
throw new \Exception(sprintf(
'Customer needs to have a field %s in order to be able to hold the evalanche status for newsletter provider handler with shortcut %s',
$getter,
$this->getShortcut()
));
}
return $customer->$getter();
}
public function buildEntry(NewsletterAwareCustomerInterface $customer)
{
$mergeFieldsMapping = count($this->mergeFieldMapping) ? $this->mergeFieldMapping : [
"firstname" => "FIRSTNAME",
"lastname" => "NAME"
];
// build data array
$result = [
'EMAIL' => $customer->getEmail()
];
foreach (array_keys($mergeFieldsMapping) as $field) {
$mapping = $this->mapMergeField($field, $customer);
$result[$mapping['field']] = $mapping['value'];
}
// add attribute values
$result = $this->addAttributeValues($customer, $result);
// add segment data
$result = $this->addCustomerSegmentData($customer, $result);
$result = $this->addNewsletterStatusToEntry($customer, $result);
// ApplicationLogger::getInstance()->info('[POOL ' . $this->getPoolId() . ']: building entry: ' . PHP_EOL . json_encode(['result' => $result, 'backtrace' => debug_backtrace()], JSON_PRETTY_PRINT), [
// 'component' => 'Evalanche',
// 'relatedObject' => $customer
// ]);
return $result;
}
public function getAttributesList() {
$mergeFieldsMapping = sizeof($this->mergeFieldMapping) ? $this->mergeFieldMapping : [
"firstname" => "FIRSTNAME",
"lastname" => "NAME"
];
return array_values($mergeFieldsMapping);
}
/**
* Maps Pimcore class field newsletterStatus to mailchimpNewsletterStatus
* @param NewsletterAwareCustomerInterface $customer
* @param array $entry
*/
protected function addNewsletterStatusToEntry(NewsletterAwareCustomerInterface $customer, array $entry) {
$status = $this->getNewsletterStatus($customer);
$evalancheStatus = $this->getEvalancheStatus($customer);
if (!isset($this->statusMapping[$status])) {
$status = self::STATUS_UNSUBSCRIBED;
} else {
$status = $this->statusMapping[$status];
}
if (!$customer->needsExportByNewsletterProviderHandler($this)) {
$status = null;
}
if ($status != $evalancheStatus) {
$entry['status'] = $status;
} else {
$entry['status_if_new'] = $status;
}
if ($status == self::STATUS_PENDING) {
$entry['PERMISSION'] = self::PERMISSION_UNCONFIRMED;
$entry['DELETED'] = 0;
$entry['UNSUBSCRIBE_DATE'] = 0;
} else if ($status == self::STATUS_SUBSCRIBED) {
$entry['PERMISSION'] = self::PERMISSION_DOUBLEOPT_IN;
$entry['DELETED'] = 0;
$entry['UNSUBSCRIBE_DATE'] = 0;
} else if ($status == self::STATUS_UNSUBSCRIBED) {
$entry['PERMISSION'] = self::PERMISSION_OPT_OUT;
$entry['DELETED'] = 1;
if ($status != $evalancheStatus) {
$entry['UNSUBSCRIBE_DATE'] = time();
}
}
return $entry;
}
private function addCustomerSegmentData(NewsletterAwareCustomerInterface $customer, array $result)
{
$data = [];
foreach ($customer->getAllSegments() as $customerSegment) {
$remoteSegmentId = $this->getPoolExporter()->getRemoteId($customerSegment, $this->poolId);
$group = $customerSegment->getGroup();
if(!$remoteSegmentId || !$group instanceof CustomerSegmentGroup) {
continue;
}
$data[$group->getName()][] = $remoteSegmentId;
}
foreach ($this->getExportableSegmentGroups() as $segmentGroup) {
if (!empty($data[$segmentGroup->getName()])) {
$result[PoolExporter::getValidAttributeName($segmentGroup->getName())] = implode('|', $data[$segmentGroup->getName()]);
} else {
$result[PoolExporter::getValidAttributeName($segmentGroup->getName())] = '';
}
}
return $result;
}
private function addAttributeValues(NewsletterAwareCustomerInterface $customer, array $result) {
$attributeValuesPerAttribute = [];
if ($customer instanceof Customer) {
foreach($customer->getEvalancheAttributeValues() as $attributeValue) {
if ($attributeValue->getPool() == $this->getPoolId()) {
if (array_key_exists($attributeValue->getAttribute(), $attributeValuesPerAttribute)) {
$attributeValuesPerAttribute[$attributeValue->getAttribute()][] = $attributeValue->getEvalancheId();
} else {
$attributeValuesPerAttribute[$attributeValue->getAttribute()] = [$attributeValue->getEvalancheId()];
}
}
}
}
foreach($this->getExportableAttributes() as $attribute) {
if (array_key_exists($attribute, $attributeValuesPerAttribute) && !empty($attributeValuesPerAttribute[$attribute])) {
$result[$attribute] = implode('|', $attributeValuesPerAttribute[$attribute]);
} else {
$result[$attribute] = '';
}
}
return $result;
}
public function getExportableAttributes() {
$evalancheAtributeValues = new EvalancheAttributeValue\Listing();
$evalancheAtributeValues->addConditionParam('pool = :pool', ['pool' => $this->getPoolId()]);
$evalancheAtributeValues->setGroupBy('attribute');
$attributes = [];
foreach($evalancheAtributeValues as $attributeValue) {
if (!in_array($attributeValue->getAttribute(), $attributes)) {
$attributes[] = $attributeValue->getAttribute();
}
}
return $attributes;
}
public function getSegmentGroupAttributes() {
$attributes = [];
foreach($this->getExportableSegmentGroups() as $segmentGroup) {
$attributes[] = PoolExporter::getValidAttributeName($segmentGroup->getName());
}
return $attributes;
}
/**
* @param $email
* @param int|false $customerId
* @return bool
*/
public function doesOtherSubscribedCustomerWithEmailExist($email, $customerId = false)
{
if(!$email) {
return false;
}
$customerProvider = $this->getCustomerProvider();
$list = $customerProvider->getList();
$customerProvider->addActiveCondition($list);
if($customerId) {
$list->setCondition('trim(lower(email)) = ? and o_id != ?', [trim(strtolower($email)), $customerId]);
} else {
$list->setCondition('trim(lower(email)) = ?', [trim(strtolower($email))]);
}
foreach($list as $_customer) {
if(in_array($this->getEvalancheStatus($_customer), array(self::STATUS_PENDING, self::STATUS_SUBSCRIBED))) {
return true;
}
}
return false;
}
protected function customerExportSingle(NewsletterQueueItemInterface $item)
{
$this->getProfileExporter()->singleExport($item, $this);
}
/**
* @param NewsletterQueueItemInterface[] $items
*/
protected function customerExportBatch(array $items)
{
$this->getProfileExporter()->batchExport($items, $this);
}
/**
* @param $field
* @param NewsletterAwareCustomerInterface $customer
* @return array|false
*/
public function mapMergeField($field, NewsletterAwareCustomerInterface $customer)
{
$getter = 'get' . ucfirst($field);
$value = $customer->$getter();
if (isset($this->mergeFieldMapping[$field])) {
$to = $this->mergeFieldMapping[$field];
if ($to == 'COUNTRY') {
$value = self::getCountryNumberFromCountryCode($value);
}
if (isset($this->fieldTransformers[$field])) {
$transformer = $this->fieldTransformers[$field];
$value = $transformer->transformFromPimcoreToMailchimp($value);
}
$value = is_null($value) ? '' : $value;
return ['field' => $to, 'value' => $value];
}
}
/**
* @return array|false
*/
public function reverseMapMergeField($field, $value)
{
foreach ($this->mergeFieldMapping as $from => $to) {
if ($to == $field) {
if ($from == 'COUNTRY') {
$value = self::getCountryCodeFromCountryNumber($value);
}
if (isset($this->fieldTransformers[$from])) {
$transformer = $this->fieldTransformers[$from];
$value = $transformer->transformFromMailchimpToPimcore($value);
}
return ['field' => $from, 'value' => $value];
}
}
}
/**
* @param string $pimcoreField
* @param mixed $pimcoreData
* @param mixed $evalancheImportData
*/
public function didMergeFieldDataChange($pimcoreField, $pimcoreData, $evalancheImportData)
{
if (!isset($this->fieldTransformers[$pimcoreField])) {
return $pimcoreData != $evalancheImportData;
}
return $this->fieldTransformers[$pimcoreField]->didMergeFieldDataChange($pimcoreData, $evalancheImportData);
}
/**
* Map evalanche status to pimcore object newsletterStatus
*
* @param $evalancheStatus
*
* @return mixed|null
*/
public function reverseMapNewsletterStatus($evalancheStatus)
{
if (isset($this->reverseStatusMapping[$evalancheStatus])) {
return $this->reverseStatusMapping[$evalancheStatus];
}
return null;
}
public function getNewsletterStatus(NewsletterAwareCustomerInterface $customer)
{
$getter = 'getNewsletterStatus' . ucfirst($this->getShortcut());
if (!method_exists($customer, $getter)) {
throw new \Exception(sprintf(
'Customer needs to have a field %s in order to be able to hold the newsletter status for newsletter provider handler with shortcut %s',
$getter,
$this->getShortcut()
));
}
return $customer->$getter();
}
public function setNewsletterStatus(NewsletterAwareCustomerInterface $customer, $status)
{
$setter = 'setNewsletterStatus' . ucfirst($this->getShortcut());
if (!method_exists($customer, $setter)) {
throw new \Exception(sprintf(
'Customer needs to have a field %s in order to be able to hold the newsletter status for newsletter provider handler with shortcut %s',
$setter,
$this->getShortcut()
));
}
$customer->$setter($status);
}
protected function trackStatusChangeActivity(NewsletterAwareCustomerInterface $customer, $status)
{
$activity = new MailchimpStatusChangeActivity($customer, $status, ['listId' => $this->getPoolId(), 'shortcut' => $this->getShortcut()]);
/**
* @var ActivityManagerInterface $activityManager
*/
$activityManager = \Pimcore::getContainer()->get('cmf.activity_manager');
$activityManager->trackActivity($activity);
}
public function updateEvalancheStatus(NewsletterAwareCustomerInterface $customer, $status, $saveCustomer = true)
{
$getter = 'getEvalancheStatus' . ucfirst($this->getShortcut());
// status did not changed => no customer save needed
if ($customer->$getter() == $status) {
return;
}
$this->setEvalancheStatus($customer, $status);
$this->trackStatusChangeActivity($customer, $status);
if ($saveCustomer) {
/* The newsletter queue needs to be disabled to avoid endless loops.
Some other components are disabled for performance reasons as they are not needed here.
If somebody ever wants to build segments based on the evalanche status then they could be handled via the segment building queue.
*/
$customer->saveWithOptions(
$customer->getSaveManager()->getSaveOptions(true)
->disableNewsletterQueue()
->disableOnSaveSegmentBuilders()
->disableValidator()
->disableDuplicatesIndex()
);
}
}
/**
* @param null $language
* @return int|null
*/
public function getConfirmationEmail($language = null) {
if (!empty($this->confirmationMailingIDs)) {
return $this->confirmationMailingIDs[$language] ?: $this->confirmationMailingIDs['default'];
}
return null;
}
/**
* @param array $attributeNames
* @param int $timestampStart
* @param int $timestampEnd
* @return \Scn\EvalancheSoapStruct\Struct\Generic\HashMapInterface[]
* @throws \Scn\EvalancheSoapApiConnector\Exception\EmptyResultException
*/
public function getModifiedProfiles(array $attributeNames, int $timestampStart, int $timestampEnd) {
return $this->getConnection()->createProfileClient()->getModifiedProfiles($this->poolId, $attributeNames, $timestampStart, $timestampEnd);
}
/**
* @param NewsletterAwareCustomerInterface $customer
* @return \Scn\EvalancheSoapStruct\Struct\Generic\HashMapInterface[]
* @throws \Scn\EvalancheSoapApiConnector\Exception\EmptyResultException
*/
public function getProfileDataForCustomer(NewsletterAwareCustomerInterface $customer, array $attributesArray) {
return $this->getProfileExporter()->getEvalancheProfile($customer, $attributesArray, $this->poolId);
}
public function getAttributesFromPool() {
return $this->getConnection()->createPoolClient()->getAttributesByPool($this->poolId);
}
/**
* @param string|null $countryCode
* @return int
*/
public static function getCountryNumberFromCountryCode(string $countryCode = null) {
return array_key_exists($countryCode, self::COUNTRYMAPPING) ? self::COUNTRYMAPPING[$countryCode] : 0;
}
/**
* @param string|null $countryNumber
* @return string|null
*/
public static function getCountryCodeFromCountryNumber(string $countryNumber = null) {
foreach(self::COUNTRYMAPPING as $countryCode => $cNumber) {
if ($cNumber == $countryNumber) {
return $countryCode == '-' ? null : $countryCode;
}
}
return null;
}
protected function getCustomerProvider(): CustomerProviderInterface
{
/**
* @var CustomerProviderInterface $customerProvider
*/
$customerProvider = \Pimcore::getContainer()->get(CustomerProviderInterface::class);
return $customerProvider;
}
}