File: /home/xedaptot/be.naniguide.com/app/Library/MailListFieldMapping.php
<?php
namespace Acelle\Library;
use Exception;
use Acelle\Model\MailList;
use Acelle\Model\Field;
use DB;
class MailListFieldMapping
{
public $mapping = [];
public $list;
// Use lower-case here
public $preservedFields = ['tags', 'status'];
private function __construct($mapping, $list)
{
$this->mapping = $mapping;
$this->list = $list;
}
public static function parse(array $mapping, MailList $list)
{
self::validate($mapping, $list);
$mapObj = new self($mapping, $list);
return $mapObj;
}
public function getHeaders()
{
return array_keys($this->mapping);
}
public static function validate($map, $list)
{
// Check if EMAIL (required) is included in the map
$fieldIds = array_values($map);
$emailFieldId = $list->getEmailField()->id;
if (!in_array($emailFieldId, $fieldIds)) {
throw new Exception(trans('messages.list.import.errors.email_missing'));
}
// Check if field id is valid
foreach ($map as $header => $fieldId) {
if (!$list->fields()->where('id', $fieldId)->exists()) {
throw new Exception(trans('messages.list.import.errors.field_id_invalid', ['id' => $fieldId, 'header' => $header, 'list' => $list->name]));
}
}
}
// Wath a mapping like this: [ 'First Name' => 1, 'Email' => 2 , 'tags' => 'SOME TAGS', 'others' => 'Others' ]
// Transform a record like: [ 'First Name' => 'Joe', 'Email' => '[email protected]', 'tags' => 'SOME TAGS', 'others' => 'Others' ]
// To something like: [ 'field_100' => 'Joe', 'field_102' => '[email protected]', 'tags' => 'SOME TAGS']
//
// i.e. Change header based on mapped field, remove other fields (not in map)
public function processRecord($r, $closure = null)
{
// IMPORTANT: 'tags' must be lower-case
// Extract the relevant fields, including preserved fields
$selectedFields = array_merge($this->getHeaders(), $this->preservedFields);
$record = array_only($r, $selectedFields);
// Change original header to mapped field name
foreach ($this->mapping as $header => $fieldId) {
$field = Field::find($fieldId);
$fieldName = $field->custom_field_name;
$value = $record[$header];
// Allow the calling party to do any further processing if needed
if ($closure) {
$value = $closure($field, $value);
}
$record[$fieldName] = $value;
unset($record[$header]);
}
return $record;
}
public function getCustomFields()
{
$customFields = array_map(function ($fieldId) {
$field = Field::find($fieldId);
$fieldName = $field->custom_field_name;
return $fieldName;
}, $this->mapping);
return $customFields;
}
public function createTmpTableFromMapping()
{
// create a temporary table containing the input subscribers
$tmpTableWithoutPrefix = '__tmp_subscribers_'.$this->list->uid;
$tmpTable = table($tmpTableWithoutPrefix);
$emailField = $this->list->getEmailField();
// @todo: hard-coded charset and COLLATE
$tmpFields = array_map(function ($fieldName) use ($emailField) {
if ($emailField->custom_field_name == $fieldName) {
$dataType = 'VARCHAR(255)'; // VARCHAR type is required if we add an index on this field
} else {
$dataType = 'MEDIUMTEXT';
}
return "`{$fieldName}` {$dataType} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
}, $this->getCustomFields());
// Also create columsn for preserved fields like 'tags'
foreach ($this->preservedFields as $fieldName) {
$tmpFields[] = "`{$fieldName}` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
}
$tmpFields = implode(',', $tmpFields);
// Drop table, create table and create index
DB::statement("DROP TABLE IF EXISTS {$tmpTable};");
DB::statement("CREATE TABLE {$tmpTable}({$tmpFields}) ENGINE=InnoDB;");
DB::statement("CREATE INDEX _index_email_{$tmpTable} ON {$tmpTable}(`{$emailField->custom_field_name}`);");
return [$tmpTable, $tmpTableWithoutPrefix, $emailField->custom_field_name];
}
}