Your IP : 127.0.0.1


Current Path : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Import/
Upload File :
Current File : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Import/NewsletterSubscriber.php

<?php
/**
 * Copyright (c) 2019. All rights reserved.
 */
namespace Firebear\ImportExport\Model\Import;

use Firebear\ImportExport\Traits\Import\Entity as ImportTrait;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Encryption\Encryptor;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Customer\Model\CustomerFactory;
use Magento\ImportExport\Model\Import\AbstractEntity;
use Magento\ImportExport\Model\ImportFactory;
use Magento\ImportExport\Model\Import;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Newsletter\Model\SubscriberFactory;
use Magento\Newsletter\Model\Subscriber;

/**
 * Newsletter Subscriber Import
 */
class NewsletterSubscriber extends AbstractEntity implements ImportAdapterInterface
{
    use ImportTrait;

    /**
     * Subscriber id column name
     */
    const COL_SUBSCRIBER_ID = 'subscriber_id';

    /**
     * Subscriber email column name
     */
    const COL_SUBSCRIBER_EMAIL = 'subscriber_email';

    /**
     * Store id column name
     */
    const COL_STORE_ID = 'store_id';

    /**
     * Subscriber status column name
     */
    const COL_STATUS = 'subscriber_status';

    /**
     * Customer id column name
     */
    const COL_CUSTOMER_ID = 'customer_id';

    /**
     * Password hash column name
     */
    const COL_PASSWORD_HASH = 'password_hash';

    /**
     * Error codes
     */
    const ERROR_SUBSCRIBER_ID_IS_EMPTY = 'subscriberIdIsEmpty';
    const ERROR_STORE_ID_IS_EMPTY = 'storeIdIsEmpty';
    const ERROR_EMAIL_FORMAT = 'emailFormatInvalid';
    const ERROR_STATUS_VALUE = 'statusInvalid';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $_messageTemplates = [
        self::ERROR_SUBSCRIBER_ID_IS_EMPTY => 'Subscriber id is empty',
        self::ERROR_STORE_ID_IS_EMPTY => 'Store id is empty',
        self::ERROR_EMAIL_FORMAT => 'Email has a wrong format',
        self::ERROR_STATUS_VALUE => 'Unsupported subscriber status value',
    ];

    /**
     * Field list
     *
     * @var array
     */
    protected $fields = [
        'subscriber_id',
        'store_id',
        'change_status_at',
        'subscriber_email',
        'firstname',
        'lastname',
        'password_hash',
        'subscriber_status',
        'subscriber_confirm_code'
    ];

    /**
     * Subscriber factory
     *
     * @var SubscriberFactory
     */
    protected $subscriberFactory;

    /**
     * Store manager
     *
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * Customer factory
     *
     * @var CustomerFactory
     */
    protected $customerFactory;

    /**
     * Encryptor
     *
     * @var EncryptorInterface
     */
    protected $encryptor;

    /**
     * Statuse codes
     *
     * @var array
     */
    protected $status = [
        Subscriber::STATUS_SUBSCRIBED,
        Subscriber::STATUS_NOT_ACTIVE,
        Subscriber::STATUS_UNSUBSCRIBED,
        Subscriber::STATUS_UNCONFIRMED
    ];

    /**
     * Initialize import
     *
     * @param Context $context
     * @param ScopeConfigInterface $scopeConfig
     * @param ImportFactory $importFactory
     * @param SubscriberFactory $subscriberFactory
     * @param CustomerFactory $customerFactory
     * @param StoreManagerInterface $storeManager
     * @param EncryptorInterface $encryptor
     * @param array $data
     */
    public function __construct(
        Context $context,
        ScopeConfigInterface $scopeConfig,
        ImportFactory $importFactory,
        SubscriberFactory $subscriberFactory,
        CustomerFactory $customerFactory,
        StoreManagerInterface $storeManager,
        EncryptorInterface $encryptor,
        array $data = []
    ) {
        $this->_logger = $context->getLogger();
        $this->output = $context->getOutput();
        $this->_importExportData = $context->getImportExportData();
        $this->_resourceHelper = $context->getResourceHelper();
        $this->jsonHelper = $context->getJsonHelper();
        $this->subscriberFactory = $subscriberFactory;
        $this->customerFactory = $customerFactory;
        $this->storeManager = $storeManager;
        $this->encryptor = $encryptor;

        parent::__construct(
            $context->getStringUtils(),
            $scopeConfig,
            $importFactory,
            $context->getResourceHelper(),
            $context->getResource(),
            $context->getErrorAggregator(),
            $data
        );
    }

    /**
     * Import data rows
     *
     * @return boolean
     */
    protected function _importData()
    {
        while ($bunch = $this->_dataSourceModel->getNextBunch()) {
            foreach ($bunch as $rowNumber => $rowData) {
                /* validate data */
                if (!$rowData || !$this->validateRow($rowData, $rowNumber)) {
                    continue;
                }

                if ($this->getErrorAggregator()->hasToBeTerminated()) {
                    $this->getErrorAggregator()->addRowToSkip($rowNumber);
                    continue;
                }

                /* behavior selector */
                switch ($this->getBehavior()) {
                    case Import::BEHAVIOR_DELETE:
                        $this->delete($rowData);
                        break;
                    case Import::BEHAVIOR_REPLACE:
                        $this->delete($rowData);
                        $this->save($rowData);
                        break;
                    case Import::BEHAVIOR_ADD_UPDATE:
                        $this->save($rowData);
                        break;
                }
            }
        }
        return true;
    }

    /**
     * Imported entity type code getter
     *
     * @return string
     */
    public function getEntityTypeCode()
    {
        return 'newsletter_subscriber';
    }

    /**
     * Retrieve All Fields Source
     *
     * @return array
     */
    public function getAllFields()
    {
        return $this->fields;
    }

    /**
     * Validate data row
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return bool
     */
    public function validateRow(array $rowData, $rowNumber)
    {
        if (isset($this->_validatedRows[$rowNumber])) {
            /* check that row is already validated */
            return !$this->getErrorAggregator()->isRowInvalid($rowNumber);
        }

        $this->_validatedRows[$rowNumber] = true;
        $this->_processedEntitiesCount++;

        /* behavior selector */
        switch ($this->getBehavior()) {
            case Import::BEHAVIOR_DELETE:
                $this->validateRowForDelete($rowData, $rowNumber);
                break;
            case Import::BEHAVIOR_REPLACE:
                $this->validateRowForReplace($rowData, $rowNumber);
                break;
            case Import::BEHAVIOR_ADD_UPDATE:
                $this->validateRowForUpdate($rowData, $rowNumber);
                break;
        }
        return !$this->getErrorAggregator()->isRowInvalid($rowNumber);
    }

    /**
     * Validate row data for replace behaviour
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    public function validateRowForReplace(array $rowData, $rowNumber)
    {
        $this->validateRowForUpdate($rowData, $rowNumber);
    }

    /**
     * Validate row data for delete behaviour
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    public function validateRowForDelete(array $rowData, $rowNumber)
    {
        if (!empty($rowData[self::COL_SUBSCRIBER_EMAIL])) {
            $this->validateStore($rowData, $rowNumber);
            $this->validateEmail($rowData, $rowNumber);
        } elseif (empty($rowData[self::COL_SUBSCRIBER_ID])) {
            $this->addRowError(self::ERROR_SUBSCRIBER_ID_IS_EMPTY, $rowNumber);
        }
    }

    /**
     * Validate row data for update behaviour
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    public function validateRowForUpdate(array $rowData, $rowNumber)
    {
        $this->validateRowForDelete($rowData, $rowNumber);
        $this->validateStatus($rowData, $rowNumber);
    }

    /**
     * Validate email string
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    protected function validateEmail(array $rowData, $rowNumber)
    {
        if (!filter_var($rowData[self::COL_SUBSCRIBER_EMAIL], FILTER_VALIDATE_EMAIL)) {
            $this->addRowError(self::ERROR_EMAIL_FORMAT, $rowNumber);
        }
    }

    /**
     * Validate store data
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    protected function validateStore(array $rowData, $rowNumber)
    {
        if (!$this->storeManager->isSingleStoreMode()) {
            if (empty($rowData[self::COL_STORE_ID])) {
                $this->addRowError(self::ERROR_STORE_ID_IS_EMPTY, $rowNumber);
            }
        }
    }

    /**
     * Validate status string
     *
     * @param array $rowData
     * @param int $rowNumber
     * @return void
     */
    protected function validateStatus(array $rowData, $rowNumber)
    {
        if (!empty($rowData[self::COL_STATUS])) {
            if (!in_array($rowData[self::COL_STORE_ID], $this->status)) {
                $this->addRowError(self::ERROR_STATUS_VALUE, $rowNumber);
            }
        }
    }

    /**
     * Delete row
     *
     * @param array $rowData
     * @return $this
     */
    protected function delete(array $rowData)
    {
        $subscriber = $this->subscriberFactory->create();
        if (!empty($rowData[self::COL_SUBSCRIBER_EMAIL])) {
            $subscriber->loadByEmail($rowData[self::COL_SUBSCRIBER_EMAIL]);
        } elseif (!empty($rowData[self::COL_SUBSCRIBER_ID])) {
            $subscriber->load($rowData[self::COL_SUBSCRIBER_ID]);
        }

        if ($subscriber->getId()) {
            $subscriber->delete();
            $this->countItemsDeleted++;
        }
        return $this;
    }

    /**
     * Update entity
     *
     * @param array $rowData
     * @return $this
     */
    protected function save(array $rowData)
    {
        $subscriber = $this->subscriberFactory->create();
        $email = $rowData[self::COL_SUBSCRIBER_EMAIL] ?? null;

        if (!empty($email)) {
            $subscriber->loadByEmail($email);
            if ($subscriber->getId()) {
                unset($rowData[self::COL_SUBSCRIBER_EMAIL]);
            }
        } elseif (!empty($rowData[self::COL_SUBSCRIBER_ID])) {
            $subscriber->load($rowData[self::COL_SUBSCRIBER_ID]);
            unset($rowData[self::COL_SUBSCRIBER_ID]);
        }

        if ($subscriber->getId()) {
            $this->countItemsUpdated++;
        } else {
            $this->countItemsCreated++;
            $rowData[self::COL_SUBSCRIBER_ID] = null;
        }

        unset($rowData[self::COL_CUSTOMER_ID]);
        $subscriber->addData($rowData);

        if (!$subscriber->getCustomerId()) {
            $customer = $this->customerFactory->create();
            if ($customer->getSharingConfig()->isWebsiteScope()) {
                $store = empty($rowData[self::COL_STORE_ID])
                    ? $this->storeManager->getDefaultStoreView()
                    : $this->storeManager->getStore($rowData[self::COL_STORE_ID]);

                $customer->setWebsiteId($store->getWebsiteId());
            }

            $customer->loadByEmail($email);
            if ($customer->getId()) {
                $subscriber->setCustomerId($customer->getId());
            } else {
                if (!empty($rowData['firstname']) &&
                    !empty($rowData['lastname']) &&
                    !empty($rowData[self::COL_PASSWORD_HASH])
                ) {
                    $customer->setFirstname($rowData['firstname']);
                    $customer->setLastname($rowData['lastname']);
                    $customer->setEmail($subscriber->getSubscriberEmail());
                    $customer->setPasswordHash($this->getPasswordHash($rowData));
                    $customer->save();

                    $subscriber->setCustomerId($customer->getId());
                }
            }
        }

        try {
            $subscriber->save();
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage(), $this->getOutput(), 'error');

        }
        return $this;
    }

    /**
     * Retrieve customer password hash
     *
     * @param array $rowData
     * @return string
     */
    protected function getPasswordHash(array $rowData)
    {
        if ($this->encryptor->validateHashVersion($rowData[self::COL_PASSWORD_HASH])) {
            // m2 pasword hash
            return $rowData[self::COL_PASSWORD_HASH];
        }
        // m1 pasword hash
        $parts = explode(Encryptor::DELIMITER, $rowData[self::COL_PASSWORD_HASH]);
        $count = count($parts);
        if (2 == $count) {
            list($hash, $salt) = $parts;
            $version = (32 == strlen($hash)) ? Encryptor::HASH_VERSION_MD5 : Encryptor::HASH_VERSION_SHA256;
            return implode(
                Encryptor::DELIMITER,
                [
                    $hash,
                    $salt,
                    $version
                ]
            );
        }
        return null;
    }

    /**
     * Save Validated Bunches
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    protected function _saveValidatedBunches()
    {
        $source = $this->getSource();
        $currentDataSize = 0;
        $bunchRows = [];
        $startNewBunch = false;
        $nextRowBackup = [];
        $maxDataSize = $this->_resourceHelper->getMaxDataSize();
        $bunchSize = $this->_importExportData->getBunchSize();

        $source->rewind();
        $this->_dataSourceModel->cleanBunches();
        $file = null;
        $jobId = null;
        if (isset($this->_parameters['file'])) {
            $file = $this->_parameters['file'];
        }
        if (isset($this->_parameters['job_id'])) {
            $jobId = $this->_parameters['job_id'];
        }

        while ($source->valid() || $bunchRows) {
            if ($startNewBunch || !$source->valid()) {
                $this->_dataSourceModel->saveBunches(
                    $this->getEntityTypeCode(),
                    $this->getBehavior(),
                    $jobId,
                    $file,
                    $bunchRows
                );
                $bunchRows = $nextRowBackup;
                $currentDataSize = strlen($this->jsonHelper->jsonEncode($bunchRows));
                $startNewBunch = false;
                $nextRowBackup = [];
            }

            if ($source->valid()) {
                try {
                    $rowData = $source->current();
                } catch (\InvalidArgumentException $e) {
                    $this->addRowError($e->getMessage(), $this->_processedRowsCount);
                    $this->_processedRowsCount++;
                    $source->next();
                    continue;
                }
                $rowData = $this->customBunchesData($rowData);
                $this->_processedRowsCount++;
                if ($this->validateRow($rowData, $source->key())) {
                    $rowSize = strlen($this->jsonHelper->jsonEncode($rowData));

                    $isBunchSizeExceeded = $bunchSize > 0 && count($bunchRows) >= $bunchSize;

                    if ($currentDataSize + $rowSize >= $maxDataSize || $isBunchSizeExceeded) {
                            $startNewBunch = true;
                            $nextRowBackup = [$source->key() => $rowData];
                    } else {
                            $bunchRows[$source->key()] = $rowData;
                            $currentDataSize += $rowSize;
                    }
                }
                $source->next();
            }
        }
        return $this;
    }
}