- Moves ImportExport under Subscribers namespace

- Updates tests
This commit is contained in:
MrCasual
2015-11-13 12:33:34 -05:00
parent 6a3166c311
commit c96ac06423
12 changed files with 29 additions and 29 deletions

View File

@@ -0,0 +1,296 @@
<?php
namespace MailPoet\Subscribers\ImportExport\Import;
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberCustomField;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Util\Helpers;
class Import {
public function __construct($data) {
$this->subscribersData = $data['subscribers'];
$this->segments = $data['segments'];
$this->updateSubscribers = $data['updateSubscribers'];
$this->subscriberFields = $this->getSubscriberFields(
array_keys($this->subscribersData)
);
$this->subscriberCustomFields = $this->getCustomSubscriberFields(
array_keys($this->subscribersData)
);
$this->subscribersCount = count(reset($this->subscribersData));
$this->currentTime = date('Y-m-d H:i:s');
$this->profilerStart = microtime(true);
}
function process() {
$subscriberFields = $this->subscriberFields;
$subscriberCustomFields = $this->subscriberCustomFields;
$subscribersData = $this->subscribersData;
$subscribersData = $this->filterSubscriberStatus($subscribersData);
list($subscribersData, $subscriberFields) = $this->extendSubscribersAndFields(
$subscribersData, $subscriberFields
);
list($existingSubscribers, $newSubscribers) =
$this->filterExistingAndNewSubscribers($subscribersData);
$createdSubscribers = $updatedSubscribers = array();
try {
if($newSubscribers) {
$createdSubscribers =
$this->createOrUpdateSubscribers(
'create',
$newSubscribers,
$subscriberFields,
$subscriberCustomFields
);
}
if($existingSubscribers && $this->updateSubscribers) {
$updatedSubscribers =
$this->createOrUpdateSubscribers(
'update',
$existingSubscribers,
$subscriberFields,
$subscriberCustomFields
);
if($createdSubscribers) {
// subtract added from updated subscribers when DB operation takes <1s
$updatedSubscribers = array_diff_key(
$updatedSubscribers,
$createdSubscribers,
$subscriberCustomFields
);
}
}
} catch (\PDOException $e) {
return array(
'result' => false,
'error' => $e->getMessage()
);
}
$segments = new BootStrapMenu('import');
return array(
'result' => true,
'data' => array(
'created' => count($createdSubscribers),
'updated' => count($updatedSubscribers),
'segments' => $segments->getSegments()
),
'profile' => $this->timeExecution()
);
}
function filterExistingAndNewSubscribers($subscribersData) {
$existingRecords = array_filter(
array_map(function ($subscriberEmails) {
return Subscriber::selectMany(array('email'))
->whereIn('email', $subscriberEmails)
->findArray();
}, array_chunk($subscribersData['email'], 200))
);
if(!$existingRecords) {
return array(
false,
$subscribersData
);
}
$existingRecords = Helpers::flattenArray($existingRecords);
$newRecords = array_keys(
array_diff(
$subscribersData['email'],
$existingRecords
)
);
if(!$newRecords) {
return array(
$subscribersData,
false
);
}
$newSubscribers =
array_filter(
array_map(function ($subscriber) use ($newRecords) {
return array_map(function ($index) use ($subscriber) {
return $subscriber[$index];
}, $newRecords);
}, $subscribersData)
);
$existingSubscribers =
array_map(function ($subscriber) use ($newRecords) {
return array_values( // reindex array
array_filter( // remove NULL entries
array_map(function ($index, $data) use ($newRecords) {
if(!in_array($index, $newRecords)) return $data;
}, array_keys($subscriber), $subscriber)
)
);
}, $subscribersData);
return array(
$existingSubscribers,
$newSubscribers
);
}
function extendSubscribersAndFields($subscribersData, $subscriberFields) {
$subscribersData['created_at'] = $this->filterSubscriberCreatedAtDate();
$subscriberFields[] = 'created_at';
return array(
$subscribersData,
$subscriberFields
);
}
function getSubscriberFields($subscriberFields) {
return array_values(
array_filter(
array_map(function ($field) {
if(!is_int($field)) return $field;
}, $subscriberFields)
)
);
}
function getCustomSubscriberFields($subscriberFields) {
return array_values(
array_filter(
array_map(function ($field) {
if(is_int($field)) return $field;
}, $subscriberFields)
)
);
}
function filterSubscriberCreatedAtDate() {
return array_fill(0, $this->subscribersCount, $this->currentTime);
}
function filterSubscriberStatus($subscribersData) {
if(!in_array('status', $this->subscriberFields)) return;
$statuses = array(
'subscribed' => array(
'subscribed',
'confirmed',
1,
'1',
'true'
),
'unsubscribed' => array(
'unsubscribed',
-1,
'-1',
'false'
)
);
$subscribersData['status'] = array_map(function ($state) use ($statuses) {
if(in_array(strtolower($state), $statuses['subscribed'])) {
return 'confirmed';
}
if(in_array(strtolower($state), $statuses['unsubscribed'])) {
return 'unsubscribed';
}
return 'confirmed'; // make "subscribed" a default status
}, $subscribersData['status']);
return $subscribersData;
}
function createOrUpdateSubscribers(
$action,
$subscribersData,
$subscriberFields,
$subscriberCustomFields
) {
$subscribersCount = count(reset($subscribersData)) - 1;
$subscribers = array_map(function ($index) use ($subscribersData, $subscriberFields) {
return array_map(function ($field) use ($index, $subscribersData) {
return $subscribersData[$field][$index];
}, $subscriberFields);
}, range(0, $subscribersCount));
$currentTime = ($action === 'update') ? date('Y-m-d H:i:s') : $this->currentTime;
foreach (array_chunk($subscribers, 200) as $data) {
if($action == 'create') {
Subscriber::createMultiple(
$subscriberFields,
$data
);
}
if($action == 'update') {
Subscriber::updateMultiple(
$subscriberFields,
$data,
$currentTime
);
}
}
$result = Helpers::arrayColumn( // return id=>email array of results
Subscriber::selectMany(
array(
'id',
'email'
))
->where(($action === 'create') ? 'created_at' : 'updated_at', $currentTime)
->findArray(),
'email', 'id'
);
if($subscriberCustomFields) {
$this->createOrUpdateCustomFields(
($action === 'create') ? 'create' : 'update',
$result,
$subscribersData,
$subscriberCustomFields
);
}
$this->addSubscribersToSegments(
array_keys($result),
$this->segments
);
return $result;
}
function createOrUpdateCustomFields(
$action,
$dbSubscribers,
$subscribersData,
$subscriberCustomFields
) {
$subscribers = array_map(
function ($column) use ($dbSubscribers, $subscribersData) {
$count = range(0, count($subscribersData[$column]) - 1);
return array_map(
function ($index, $value)
use ($dbSubscribers, $subscribersData, $column) {
$subscriberId = array_search(
$subscribersData['email'][$index],
$dbSubscribers
);
return array(
$column,
$subscriberId,
$value
);
}, $count, $subscribersData[$column]);
}, $subscriberCustomFields)[0];
foreach (array_chunk($subscribers, 200) as $data) {
if($action === 'create') {
SubscriberCustomField::createMultiple(
$data
);
}
if($action === 'update') {
SubscriberCustomField::updateMultiple(
$data
);
}
}
}
function addSubscribersToSegments($subscribers, $segments) {
foreach (array_chunk($subscribers, 200) as $data) {
SubscriberSegment::createMultiple($segments, $data);
}
}
function timeExecution() {
$profilerEnd = microtime(true);
return ($profilerEnd - $this->profilerStart) / 60;
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace MailPoet\Subscribers\ImportExport\Import;
use MailPoet\Util\Helpers;
class MailChimp {
function __construct($APIKey, $lists = false) {
$this->APIKey = $this->getAPIKey($APIKey);
$this->maxPostSize = Helpers::getMaxPostSize('bytes');
$this->dataCenter = $this->getDataCenter($this->APIKey);
$this->listsURL = 'https://%s.api.mailchimp.com/2.0/lists/list?apikey=%s';
$this->exportURL = 'https://%s.api.mailchimp.com/export/1.0/list/?apikey=%s&id=%s';
}
function getLists() {
if(!$this->APIKey || !$this->dataCenter) {
return $this->processError('API');
}
$connection = @fopen(sprintf($this->listsURL, $this->dataCenter, $this->APIKey), 'r');
if(!$connection) {
return $this->processError('connection');
} else {
$response = '';
while (!feof($connection)) {
$buffer = fgets($connection, 4096);
if(trim($buffer) !== '') {
$response .= $buffer;
}
}
fclose($connection);
}
$response = json_decode($response);
if(!$response) {
return $this->processError('API');
}
foreach ($response->data as $list) {
$lists[] = array(
'id' => $list->id,
'name' => $list->name
);
}
return array(
'result' => true,
'data' => $lists
);
}
function getSubscribers($lists = array()) {
if(!$this->APIKey || !$this->dataCenter) {
return $this->processError('API');
}
if(!$lists) {
return $this->processError('lists');
}
$bytesFetched = 0;
foreach ($lists as $list) {
$url = sprintf($this->exportURL, $this->dataCenter, $this->APIKey, $list);
$connection = @fopen($url, 'r');
if(!$connection) {
return $this->processError('connection');
} else {
$i = 0;
$header = array();
while (!feof($connection)) {
$buffer = fgets($connection, 4096);
if(trim($buffer) !== '') {
$obj = json_decode($buffer);
if($i === 0) {
$header = $obj;
if(is_object($header) && isset($header->error)) {
return $this->processError('lists');
}
if(!isset($headerHash)) {
$headerHash = md5(implode(',', $header));
} else {
if(md5(implode(',', $header) !== $headerHash)) {
return $this->processError('headers');
}
}
} else {
$subscribers[] = $obj;
}
$i++;
}
$bytesFetched += strlen($buffer);
if($bytesFetched > $this->maxPostSize) {
return $this->processError('size');
}
}
fclose($connection);
}
}
if(!count($subscribers)) {
return $this->processError('subscribers');
}
return array(
'result' => true,
'data' => array(
'subscribers' => $subscribers,
'invalid' => false,
'duplicate' => false,
'header' => $header,
'count' => count($subscribers)
)
);
}
function getDataCenter($APIKey) {
// double parantheses: http://phpsadness.com/sad/51
return ($APIKey) ? end((explode('-', $APIKey))) : false;
}
function getAPIKey($APIKey) {
return (preg_match('/[a-zA-Z0-9]{32}-[a-zA-Z0-9]{3,}/', $APIKey)) ? $APIKey : false;
}
function processError($error) {
switch ($error) {
case 'API':
$errorMessage = __('Invalid API key.');
break;
case 'connection':
$errorMessage = __('Could not connect to your MailChimp account.');
break;
case 'headers':
$errorMessage = __('The selected lists do not have matching columns (headers).');
break;
case 'size':
$errorMessage = __('Information received from MailChimp is too large for processing. Please limit the number of lists.');
break;
case 'subscribers':
$errorMessage = __('Did not find any active subscribers.');
break;
case 'lists':
$errorMessage = __('Did not find any valid lists');
break;
}
return array(
'result' => false,
'error' => $errorMessage
);
}
}