Your IP : 127.0.0.1


Current Path : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Source/Platform/
Upload File :
Current File : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Source/Platform/Prestashop.php

<?php
/**
 * @copyright: Copyright © 2017 Firebear Studio. All rights reserved.
 * @author   : Firebear Studio <fbeardev@gmail.com>
 */

namespace Firebear\ImportExport\Model\Source\Platform;

use Firebear\ImportExport\Model\Cache\Type\ImportProduct as ImportProductCache;
use Firebear\ImportExport\Model\Import\Product;
use Firebear\ImportExport\Traits\General;
use Magento\Backend\Model\Session;
use Magento\Catalog\Model\Product\Url;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory;
use Magento\Eav\Model\Entity\Context;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\File\Csv;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\File\ReadFactory;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Tax\Model\ClassModelFactory;
use Symfony\Component\Console\Output\ConsoleOutput;
use TMWK\ClientPrestashopApi\PrestaShopWebService;
use Psr\Log\LoggerInterface;

/**
 * Class Prestashop
 *
 * @package Firebear\ImportExport\Model\Source\Platform
 * @author  Firebear Studio <fbeardev@gmail.com>
 */
class Prestashop extends AbstractPlatform
{
    use General;

    protected $parameters;
    protected $prestaShopClient;
    protected $apiURL;
    protected $output;
    protected $separator;

    protected $productOptions = [];
    protected $productOptionValues = [];
    protected $productCombinations = [];
    protected $productCategories = [];

    /**
     * Entity model parameters
     *
     * @var array
     */
    protected $_parameters = [];

    /**
     * @todo instead of language key take from user input in case of multiple languages
     * @var int
     */
    private $languageKey = 1;

    /** @var \Psr\Log\LoggerInterface */
    protected $_logger;

    /** @var \Magento\Catalog\Model\Product\Url  */
    protected $productUrl;

    /**
     * @var CacheInterface
     */
    protected $cache;

    /**
     * Prestashop constructor.
     *
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Framework\Filesystem $filesystem
     * @param \Magento\Framework\Filesystem\File\ReadFactory $readFactory
     * @param \Magento\Framework\File\Csv $csvProcessor
     * @param \Magento\Tax\Model\ClassModelFactory $taxFactory
     * @param \Magento\Catalog\Model\Product\Visibility $visibility
     * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attributeSetCollectionFactory
     * @param \Firebear\ImportExport\Model\Import\Product $importProduct
     * @param \Magento\Eav\Model\Entity\Context $context
     * @param \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attributeFactory
     * @param \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory $resourceFactory
     * @param \Magento\Backend\Model\Session $session
     * @param \Symfony\Component\Console\Output\ConsoleOutput $output
     * @param \Psr\Log\LoggerInterface $logger
     * @param \Magento\Catalog\Model\Product\Url $productUrl
     * @param CacheInterface $cache
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        Filesystem $filesystem,
        ReadFactory $readFactory,
        Csv $csvProcessor,
        ClassModelFactory $taxFactory,
        Visibility $visibility,
        CollectionFactory $attributeSetCollectionFactory,
        Product $importProduct,
        Context $context,
        EavSetupFactory $eavSetupFactory,
        StoreManagerInterface $storeManager,
        Attribute $attributeFactory,
        ResourceModelFactory $resourceFactory,
        Session $session,
        ConsoleOutput $output,
        LoggerInterface $logger,
        Url $productUrl,
        CacheInterface $cache
    ) {
        parent::__construct(
            $scopeConfig,
            $filesystem,
            $readFactory,
            $csvProcessor,
            $taxFactory,
            $visibility,
            $attributeSetCollectionFactory,
            $importProduct,
            $context,
            $eavSetupFactory,
            $storeManager,
            $attributeFactory,
            $resourceFactory,
            $session,
            $cache,
            $output
        );
        $this->output = $output;
        $this->_logger = $logger;
        $this->productUrl = $productUrl;
    }

    /**
     * Processed to prepareColumn Values before import
     *
     * @param array $rowData The rowData to filter things
     *
     * @return mixed
     */
    public function prepareColumns($rowData)
    {
        if (in_array('_root_category', $rowData) || in_array('_category', $rowData)) {
            $key = array_search('_root_category', $rowData);
            if ($key !== false) {
                $rowData[$key] = 'categories';
            }
            $keySecond = array_search('_category', $rowData);

            if ($keySecond !== false) {
                if ($key !== false) {
                    unset($rowData[$keySecond]);
                } else {
                    $rowData[$keySecond] = 'categories';
                }
            }
        }

        return $rowData;
    }

    /**
     * Delete Columns
     *
     * @param array $array
     *
     * @return mixed
     */
    public function deleteColumns($array)
    {
        return $array;
    }

    /**
     * @param array $rowData
     * @param array $maps
     *
     * @return mixed
     */
    public function afterColumns($rowData, $maps)
    {
        if (empty($maps)) {
            return $rowData;
        }
        $systems = [];
        foreach ($maps as $field) {
            $systems[] = $field['system'];
        }
        foreach ($rowData as $key => $item) {
            if (!in_array($item, $systems)) {
                unset($rowData[$key]);
            }
        }

        return $rowData;
    }

    /**
     * @todo improve validation
     * Save Validated Bunches
     *
     * @param $source
     * @param $maxDataSize
     * @param $bunchSize
     * @param $dataSourceModel
     * @param $parameters
     * @param $entityTypeCode
     * @param $behavior
     * @param $processedRowsCount
     * @param $separator
     * @param Product $model
     *
     * @return $this
     */
    public function saveValidatedBunches(
        $source,
        $maxDataSize,
        $bunchSize,
        $dataSourceModel,
        $parameters,
        $entityTypeCode,
        $behavior,
        $processedRowsCount,
        $separator,
        Product $model
    ) {
        if (!class_exists(PrestaShopWebService::class)) {
            $this->addLogWriteln(
                __('Please run composer require tmwk/client-prestashop-api at root'),
                $this->output,
                'error'
            );
            return $this;
        }
        $this->parameters = $parameters;
        $this->fetchPrestashopDetails($parameters);
        $currentDataSize = 0;
        $bunchRows = [];
        $prevData = [];
        $startNewBunch = false;
        $nextRowBackup = [];
        $repeatStore = 0;
        $source->rewind();
        $dataSourceModel->cleanBunches();
        $file = null;
        $jobId = null;

        if (isset($parameters['file'])) {
            $file = $parameters['file'];
        }
        if (isset($parameters['job_id'])) {
            $jobId = $parameters['job_id'];
        }
        $repeats = 0;
        $end = 0;
        while ($source->valid() || $bunchRows) {
            if ($startNewBunch || !$source->valid()) {
                $dataSourceModel->saveBunches(
                    $entityTypeCode,
                    $behavior,
                    $jobId,
                    $file,
                    $bunchRows
                );
                $bunchRows = $nextRowBackup;
                $currentDataSize = strlen($model->getJsonHelper()->jsonEncode($bunchRows));
                $startNewBunch = false;
                $nextRowBackup = [];
            }
            if ($source->valid()) {
                try {
                    $rowData = $source->current();
                    $isCached = $parameters['cache_products'] ?? false;
                    if ($isCached) {
                        $isRowDataInCache = $this->isRowDataInCache($model, $rowData);
                        if ($isRowDataInCache) {
                            $source->next();
                            continue;
                        }
                    }
                } catch (\InvalidArgumentException $e) {
                    $model->addRowError($e->getMessage(), $processedRowsCount);
                    $processedRowsCount++;
                    $source->next();
                    continue;
                }
                if (empty($rowData['sku']) && !$end) {
                    $prevData = $this->mergeData($rowData, $prevData, $separator);
                    $source->next();
                    $repeats++;
                    if ($source->valid()) {
                        continue;
                    } else {
                        $end = 1;
                    }
                }

                $rowData = $model->customFieldsMapping($rowData);
                if (empty($rowData['name'])) {
                    $repeatStore = 1;
                }
                if (!empty($prevData) && $repeats > 0) {
                    $this->separator = $separator;
                    $prevData = $this->prepareRow($prevData);
                    if ($simplesCount > 0 && isset($prevData['config'])) {
                        $configurables['items'][] = 'sku=' . $prevData['sku'] . $prevData['config'];
                    }
                    $processedRowsCount++;
                    $rowSize = strlen($model->getJsonHelper()->jsonEncode($prevData));
                    $isBunchSizeExceeded = $bunchSize > 0 && count($bunchRows) >= $bunchSize;
                    if ($currentDataSize + $rowSize >= $maxDataSize || $isBunchSizeExceeded) {
                        $startNewBunch = true;
                        $nextRowBackup = [$processedRowsCount => $prevData];
                    } else {
                        $bunchRows[$processedRowsCount] = $prevData;
                        $currentDataSize += $rowSize;
                    }
                }
                if ($repeatStore) {
                    $simplesCount++;
                    $prevData = array_merge($prevData, $this->deleteEmpty($rowData));
                    if ($simplesCount == 1) {
                        $configurables = ['data' => $prevData, 'items' => []];
                    }
                    $repeatStore = 0;
                } else {
                    if (!empty($configurables)) {
                        $confData = $configurables['data'];
                        $confData['sku'] .= '-Conf';
                        $confData['product_type'] = 'configurable';
                        $confData['configurable_variations'] = implode("|", $configurables['items']);
                        $processedRowsCount++;
                        $rowSize = strlen($model->getJsonHelper()->jsonEncode($confData));
                        $isBunchSizeExceeded = $bunchSize > 0 && count($bunchRows) >= $bunchSize;
                        if ($currentDataSize + $rowSize >= $maxDataSize || $isBunchSizeExceeded) {
                            $startNewBunch = true;
                            $nextRowBackup = [$processedRowsCount => $prevData];
                        } else {
                            $bunchRows[$processedRowsCount] = $confData;
                            $currentDataSize += $rowSize;
                        }
                    }
                    $simplesCount = 0;
                    $prevData = $rowData;
                }
                if (!$end) {
                    $repeats = 1;
                    $key = $source->key();
                }

                $source->next();
                if (!$source->valid() && $end == 0) {
                    $source->rewind();
                    $source->seek($key);
                    $end = 1;
                }
            }
        }
        $this->setProcessedRowsCount($processedRowsCount);
        if (empty($processedRowsCount)) {
            $errorMessage = __('This file is empty. Please try another one.');
            $model->addLogWriteln($errorMessage, null, 'warning');
        }
        $this->saveRowDataInBuffCache($model);
        return $this;
    }

    /**
     * Fetch All Details from Presta Shop
     *
     * @param array $parameters
     *
     * @since 3.0
     *
     * @return void
     */
    protected function fetchPrestashopDetails($parameters)
    {
        preg_match(
            '/^((?:http:\/\/|https:\/\/)?(?:.+?))(?:\s*$|\/.*$)/',
            $parameters['request_url'],
            $apiURL
        );
        $this->apiURL = $apiURL[1];
        $this->productOptions = $this->getProductOptions();
        $this->productOptionValues = $this->getProductOptionValues();
        $this->productCategories = $this->getProductCategories();
        $this->productCombinations = $this->getProductCombinations();
    }

    /**
     * Get Prestashop Categories
     *
     * @return array
     */
    protected function getProductCategories()
    {
        $categoriesArray = [];
        try {
            $prestashop = $this->getPrestaShopClient();
            $this->addLogWriteln(
                __('Fetching Product Categories'),
                $this->output,
                'info'
            );
            foreach ($prestashop->Categories()->findAll() as $categories) {
                foreach ($categories->xpath('category') as $category) {
                    $category = $this->convertToArray1($category);
                    $categoriesArray[$category['id']] = [
                        'name' => $category['name']['language'][$this->languageKey],
                    ];
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage());
        }
        return $categoriesArray;
    }

    /**
     * Get Product Combinations from Presta Shop
     *
     * @return array
     */
    protected function getProductCombinations()
    {
        $combinations = [];
        try {
            $prestashop = $this->getPrestaShopClient();
            $this->addLogWriteln(
                __('Fetching Product Combinations'),
                $this->output,
                'info'
            );
            foreach ($prestashop->Combinations()->findAll() as $productCombinations) {
                foreach ($productCombinations as $productCombination) {
                    $productCombination = $this->convertToArray1($productCombination);
                    $combinations[$productCombination['id']] = $productCombination;
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage());
        }
        return $combinations;
    }

    /**
     * @return array
     */
    protected function getProductOptions()
    {
        $options = [];
        try {
            $prestashop = $this->getPrestaShopClient();
            $this->addLogWriteln(__('Fetching Product Options from Prestashop'), $this->output, 'info');
            foreach ($prestashop->ProductOptions()->findAll() as $productOptions) {
                foreach ($productOptions->xpath('product_option') as $productOption) {
                    $productOption = $this->convertToArray1($productOption);
                    $options[$productOption['id']] = [
                        'type' => $productOption['group_type'],
                        'name' => $productOption['name']['language'][$this->languageKey],
                    ];
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage());
        }
        return $options;
    }

    /**
     * @return \TMWK\ClientPrestashopApi\PrestaShopWebService
     */
    protected function getPrestaShopClient()
    {
        if (!$this->prestaShopClient) {
            $requestOption = json_decode($this->parameters['request_options'], true);
            $this->prestaShopClient = new PrestaShopWebService($this->apiURL, $requestOption['username'], false);
        }

        return $this->prestaShopClient;
    }

    /**
     * @param $xmlObject
     * @param array $out
     *
     * @return array
     */
    public function convertToArray1($xmlObject, $out = [])
    {
        foreach ((array)$xmlObject as $index => $node) {
            $out[$index] = (is_object($node)) ? $this->convertToArray1($node) : $node;
        }
        return $out;
    }

    /**
     * @return array
     */
    protected function getProductOptionValues()
    {
        $options = [];
        try {
            $prestashop = $this->getPrestaShopClient();
            $this->addLogWriteln(__('Fetching Product Option Values from Prestashop'), $this->output, 'info');
            foreach ($prestashop->ProductOptionValues()->findAll() as $productOptions) {
                foreach ($productOptions->xpath('product_option_value') as $productOption) {
                    $productOption = $this->convertToArray1($productOption);
                    $options[$productOption['id']] = [
                        'code' => $productOption['id_attribute_group'],
                        'name' => $productOption['name']['language'][$this->languageKey],
                    ];
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage());
        }
        return $options;
    }

    /**
     * Prepare row method
     *
     * @param  [] $rowData
     *
     * @return  []
     */
    public function prepareRow($rowData)
    {
        $rowData['url_key'] = $rowData['name'] . '-' . $rowData['sku'];

        if (isset($rowData['excludeImportCategories']) && $rowData['excludeImportCategories'] == "false") {
            if (isset($rowData['categories_link'])) {
                $catName = [];
                foreach (explode($this->separator, $rowData['categories_link']) as $categoryId) {
                    $name = $this->getCategoryName($categoryId);
                    if ($name != '' && isset($rowData['_root_category'])) {
                        $catName[] = $rowData['_root_category'] . '/' . $name;
                    } elseif ($name != '') {
                        $catName[] = $name;
                    } else {
                        $catName[] = $rowData['_root_category'];
                    }
                }
                if (!empty($catName)) {
                    $rowData['categories'] = implode(',', $catName);
                }
            }
        }

        if (isset($rowData['config_product_id']) && $rowData['config_product_id'] > 0) {
            $configData = $this->getCombinationProduct($rowData['config_product_id'], $rowData);
            $rowData = array_merge($rowData, $configData);
        }

        /** @todo improve image fetching assigning logic */
        if (isset($this->parameters['request_options'])) {
            $requestOption = json_decode($this->parameters['request_options'], true);
            if (isset($requestOption['username'])) {
                if (isset($rowData['image'])) {
                    $rowData['image'] = str_replace(
                        'https://',
                        'http://' . $requestOption['username'] . '@',
                        $rowData['image']
                    );
                }
                if (isset($rowData['additional_images'])) {
                    $rowData['additional_images'] = str_replace(
                        'https://',
                        'http://' . $requestOption['username'] . '@',
                        $rowData['additional_images']
                    );
                }
            }
        }
        if (isset($rowData['additional_images']) && $rowData['additional_images'] != '') {
            $images = explode($this->separator, $rowData['additional_images']);
            if (!isset($rowData['image'])) {
                $rowData['image'] = $images[0];
                unset($images[0]);
            }
            $rowData['additional_images'] = implode($this->separator, $images);
        }
        return $rowData;
    }

    /**
     * @param $id
     * @param $rowData
     *
     * @return array
     */
    protected function getCombinationProduct($id, $rowData)
    {
        $configData = [];
        if ($id === '') {
            return $configData;
        }
        try {
            if (isset($this->productCombinations[$id])) {
                $combination = $this->convertToArray1($this->productCombinations[$id]);
                if (\is_array($combination)) {
                    $configData['sku'] = $combination['reference'] ?? $combination['id'];
                    $configData['url_key'] = $this->productUrl
                        ->formatUrlKey($combination['reference'] . '-' . $rowData['name']);
                    if (isset($combination['quantity']) && $combination['quantity'] > 0) {
                        $configData['qty'] = $combination['quantity'];
                    }
                    $configData['ean13'] = $combination['ean13'] ?? '';
                    if (isset($combination['price']) && $combination['price'] > 0) {
                        $configData['price'] = $combination['price'];
                    }
                    if (isset($combination['associations']['product_option_values']['product_option_value'])) {
                        $productOptionValues = $combination['associations']['product_option_values'];
                        foreach ($productOptionValues['product_option_value'] as $product_option_value) {
                            $product_option_value = $this->convertToArray1($product_option_value);
                            if (isset($product_option_value['id'])) {
                                if (isset($this->productOptionValues[$product_option_value['id']])) {
                                    $productOptionValue = $this->productOptionValues[$product_option_value['id']];
                                    $attrCode = $this->productOptions[$productOptionValue['code']];
                                    if ($attrCode['type'] == 'select') {
                                        $configData[strtolower($attrCode['name'])] = $productOptionValue['name'];
                                    }
                                }
                            }
                        }
                    }
                    $images = [];
                    if (isset($combination['associations']['images']['image'])) {
                        $endPoint = 'api/' . $combination['associations']['images']['@attributes']['api'];
                        foreach ($combination['associations']['images']['image'] as $image) {
                            $image = $this->convertToArray1($image);
                            if (isset($image['id'])) {
                                $images[] = $this->apiURL . '/' . $endPoint . '/' .
                                    $combination['id_product'] . '/' . $image['id'];
                            }
                        }
                    }
                    if (!empty($images)) {
                        $configData['additional_images'] = \implode($this->separator, $images);
                    }
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage(), $this->output, 'error');
        }
        return $configData;
    }

    /**
     * @param $id
     *
     * @return string
     */
    protected function getCategoryName($id)
    {
        $catName = '';
        if ($id == '') {
            return $catName;
        }
        try {
            if (isset($this->productCategories[$id])) {
                $catName = $this->productCategories[$id]['name'];
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage());
        }
        return $catName;
    }

    /**
     * @param $array
     *
     * @return array
     */
    protected function deleteEmpty($array)
    {
        if (isset($array['sku'])) {
            unset($array['sku']);
        }
        $newElement = [];
        foreach ($array as $key => $element) {
            if (is_object($element) || is_array($element)) {
                continue;
            }
            if (strlen($element)) {
                $newElement[$key] = $element;
            }
        }

        return $newElement;
    }
}