Your IP : 127.0.0.1


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

<?php
/**
 * @copyright: Copyright © 2019 Firebear Studio. All rights reserved.
 * @author : Firebear Studio <fbeardev@gmail.com>
 */
namespace Firebear\ImportExport\Model\Export;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Magento\ImportExport\Model\Export\AbstractEntity;
use Magento\ImportExport\Model\Export\Factory as CollectionFactory;
use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory;
use Magento\Review\Model\ResourceModel\Review\Status\Collection as StatusCollection;
use Magento\Review\Model\ResourceModel\Rating\Option\Vote\CollectionFactory as VoteCollectionFactory;
use Magento\Review\Model\ResourceModel\Rating\CollectionFactory as RatingCollectionFactory;
use Magento\Review\Model\Review as ReviewModel;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\App\ResourceConnection;
use Symfony\Component\Console\Output\ConsoleOutput;
use Psr\Log\LoggerInterface;
use Firebear\ImportExport\Traits\Export\Entity as ExportTrait;
use Firebear\ImportExport\Model\ExportJob\Processor;
use Firebear\ImportExport\Model\ResourceModel\Review\Collection as ReviewCollection;
use Magento\Eav\Api\AttributeRepositoryInterface;

/**
 * Review export
 */
class Review extends AbstractEntity implements EntityInterface
{
    use ExportTrait;

    /**
     * Console Output
     *
     * @var \Symfony\Component\Console\Output\ConsoleOutput
     */
    protected $output;

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

    /**
     * Entity collection
     *
     * @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
     */
    protected $entityCollection;

    /**
     * Status map
     *
     * @var array
     */
    protected $statusMap;

    /**
     * Collection factory
     *
     * @var \Magento\ImportExport\Model\Export\Factory
     */
    protected $collectionFactory;

    /**
     * Vote collection factory
     *
     * @var \Magento\Review\Model\ResourceModel\Rating\Option\Vote\CollectionFactory
     */
    protected $voteCollectionFactory;

    /**
     * Rating collection factory
     *
     * @var \Magento\Review\Model\ResourceModel\Rating\CollectionFactory
     */
    protected $ratingCollectionFactory;

    /**
     * Rating fields
     *
     * @var array
     */
    protected $ratingFields;

    /**
     * Export fields
     *
     * @var array
     */
    protected $exportFields = [
        'review_id',
        'sku',
        'nickname',
        'title',
        'detail',
        'status',
        'created_at',
        'product_name'
    ];

    /**
     * Product entity link field
     *
     * @var string
     */
    private $productEntityLinkField;

    /**
     * Resource Model
     *
     * @var ResourceConnection
     */
    protected $_resourceModel;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;
    /**
     * @var AttributeRepositoryInterface
     */
    protected $attributeRepository;

    /**
     * @var MetadataPool
     */
    private $metadataPool;

    /**
     * @param ScopeConfigInterface $scopeConfig
     * @param StoreManagerInterface $storeManager
     * @param CollectionFactory $collectionFactory
     * @param CollectionByPagesIteratorFactory $resourceColFactory
     * @param LoggerInterface $logger
     * @param ConsoleOutput $output
     * @param VoteCollectionFactory $voteCollectionFactory
     * @param RatingCollectionFactory $ratingCollectionFactory
     * @param ResourceConnection $resource
     * @param AttributeRepositoryInterface $attributeRepository
     * @param array $data
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        StoreManagerInterface $storeManager,
        CollectionFactory $collectionFactory,
        CollectionByPagesIteratorFactory $resourceColFactory,
        LoggerInterface $logger,
        ConsoleOutput $output,
        VoteCollectionFactory $voteCollectionFactory,
        RatingCollectionFactory $ratingCollectionFactory,
        ResourceConnection $resource,
        AttributeRepositoryInterface $attributeRepository,
        MetadataPool $metadataPool,
        array $data = []
    ) {
        $this->_logger = $logger;
        $this->output = $output;
        $this->collectionFactory = $collectionFactory;
        $this->voteCollectionFactory = $voteCollectionFactory;
        $this->_resourceModel = $resource;
        $this->ratingCollectionFactory = $ratingCollectionFactory;
        $this->storeManager = $storeManager;
        $this->attributeRepository = $attributeRepository;
        $this->metadataPool = $metadataPool;
        parent::__construct(
            $scopeConfig,
            $storeManager,
            $collectionFactory,
            $resourceColFactory,
            $data
        );

        $this->initRating();
    }

    /**
     * Export process
     *
     * @return array
     */
    public function export()
    {
        //Execution time may be very long
        set_time_limit(0);

        $this->addLogWriteln(__('Begin Export'), $this->output);
        $this->addLogWriteln(__('Scope Data'), $this->output);

        $collection = $this->_getEntityCollection();
        $this->_prepareEntityCollection($collection);
        $writer = $this->getWriter();
        // create export file
        $writer->setHeaderCols($this->_getHeaderColumns());
        $this->_exportCollectionByPages($collection);

        return [
            $writer->getContents(),
            $this->_processedEntitiesCount,
            $this->lastEntityId
        ];
    }

    /**
     * Export one item
     *
     * @param \Magento\Framework\Model\AbstractModel $item
     * @return void
     */
    public function exportItem($item)
    {
        $this->lastEntityId = $item->getId();
        $rowData = $item->toArray($this->getFieldsForExport());
        $statusMap = $this->getStatusMap();

        $rowData['status'] = $statusMap[$item->getStatusId()] ?? '';
        $votes = $this->voteCollectionFactory->create()
            ->setReviewFilter($item->getId())
            ->addRatingInfo();

        $ratingData = array_fill_keys($this->ratingFields, '');
        foreach ($votes as $vote) {
            $field = $this->ratingFields[$vote->getRatingId()] ?? null;
            if (null !== $field) {
                $ratingData[$field] = $vote->getValue();
            }
        }

        $rowData = array_merge($rowData, $ratingData);
        $this->getWriter()->writeRow(
            $this->changeRow($rowData)
        );
        $this->_processedEntitiesCount++;
    }

    /**
     * Entity type code getter
     *
     * @return string
     */
    public function getEntityTypeCode()
    {
        return 'review';
    }

    /**
     * Retrieve header columns
     *
     * @return array
     */
    protected function _getHeaderColumns()
    {
        return $this->changeHeaders(
            $this->getFieldsForExport()
        );
    }

    /**
     * Init rating
     *
     * @return array
     */
    protected function initRating()
    {
        if (null === $this->ratingFields) {
            $collection = $this->ratingCollectionFactory->create()
                ->addEntityFilter(ReviewModel::ENTITY_PRODUCT_CODE);
            foreach ($collection as $rating) {
                $this->ratingFields[$rating->getId()] = 'vote:' . $rating->getRatingCode();
            }
        }
    }

    /**
     * Apply filter to collection
     *
     * @param AbstractCollection $collection
     * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
     */
    protected function _prepareEntityCollection(AbstractCollection $collection)
    {
        if (!empty($this->_parameters[Processor::LAST_ENTITY_ID]) &&
            $this->_parameters[Processor::LAST_ENTITY_SWITCH] > 0
        ) {
            $collection->addFieldToFilter(
                'main_table.review_id',
                ['gt' => $this->_parameters[Processor::LAST_ENTITY_ID]]
            );
        }
        $nameAttributeId = $this->getAttributeIdofProductName();
        $productEntityField = $this->getProductEntityLinkField();
        $collection->getSelect()
            ->joinLeft(
                ['cpev' => $this->_resourceModel
                    ->getTableName('catalog_product_entity_varchar')
                ],
                "main_table.entity_pk_value = cpev." . $productEntityField,
                ["product_name" => "value"]
            )
            ->where("cpev.store_id = " . Store::DEFAULT_STORE_ID)
            ->where(
                "cpev.attribute_id = " . $nameAttributeId
            );

        if (!isset($this->_parameters[Processor::EXPORT_FILTER_TABLE]) ||
            !is_array($this->_parameters[Processor::EXPORT_FILTER_TABLE])) {
            $exportFilter = [];
        } else {
            $exportFilter = $this->_parameters[Processor::EXPORT_FILTER_TABLE];
        }

        $filters = [];
        $entity = $this->getEntityTypeCode();
        foreach ($exportFilter as $data) {
            if ($data['entity'] == $entity) {
                $filters[$data['field']] = $data['value'];
            }
        }

        $fields = [];
        $columns = $this->getFieldColumns();
        foreach ($columns[$this->getEntityTypeCode()] as $field) {
            $fields[$field['field']] = $field['type'];
        }

        foreach ($filters as $key => $value) {
            if (isset($fields[$key])) {
                $type = $fields[$key];

                if ($key == 'review_id') {
                    $key = 'main_table.review_id';
                }
                if ($key == 'created_at') {
                    $key = 'main_table.created_at';
                }
                if ($key == 'status') {
                    $key = 'rs.status_code';
                    $collection->getSelect()->join(
                        ['rs' => 'review_status'],
                        'main_table.status_id = rs.status_id',
                        ['rs.status_code']
                    );
                }
                if ($key == 'product_name') {
                    $key = 'cpev.value';
                }
                if (in_array($key, $this->ratingFields)) {
                    $ratingId = array_search($key, $this->ratingFields);
                    $reviewIds = $this->getReviewIds($ratingId, $value);
                    $collection->addFieldToFilter(
                        'main_table.review_id',
                        ['in' => $reviewIds]
                    );
                    continue;
                }

                if ('text' == $type) {
                    if (is_scalar($value)) {
                        trim($value);
                    }
                    $collection->addFieldToFilter($key, ['like' => "%{$value}%"]);
                } elseif ('select' == $type) {
                    $collection->addFieldToFilter($key, ['eq' => $value]);
                } elseif ('int' == $type) {
                    if (is_array($value) && count($value) == 2) {
                        $from = array_shift($value);
                        $to = array_shift($value);

                        if (is_numeric($from)) {
                            $collection->addFieldToFilter($key, ['from' => $from]);
                        }
                        if (is_numeric($to)) {
                            $collection->addFieldToFilter($key, ['to' => $to]);
                        }
                    }
                } elseif ('date' == $type) {
                    if (is_array($value) && count($value) == 2) {
                        $from = array_shift($value);
                        $to = array_shift($value);

                        if (is_scalar($from) && !empty($from)) {
                            $date = (new \DateTime($from))->format('m/d/Y');
                            $collection->addFieldToFilter($key, ['from' => $date, 'date' => true]);
                        }
                        if (is_scalar($to) && !empty($to)) {
                            $date = (new \DateTime($to))->format('m/d/Y');
                            $collection->addFieldToFilter($key, ['to' => $date, 'date' => true]);
                        }
                    }
                }
            }
        }
        return $collection;
    }

    /**
     * @param $ratingId
     * @param $value
     * @return array|bool
     */
    protected function getReviewIds($ratingId, $value)
    {
        $rovTable = $this->_resourceModel->getTableName('rating_option_vote');
        $reviewTable = $this->_resourceModel->getTableName('review');
        $select = $this->_resourceModel->getConnection()->select();
        $select->from(['r' => $reviewTable], 'r.review_id')
            ->join(
                ['rov' => $rovTable],
                'rov.review_id = r.review_id',
                []
            )
            ->where('rov.rating_id = ?', $ratingId)
            ->where('rov.value IN (?) ', $value);

        $result = $this->_resourceModel->getConnection()->fetchAll($select);
        return $result ? $result : false;
    }

    /**
     * Retrieve entity collection
     *
     * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
     */
    protected function _getEntityCollection()
    {
        if (null === $this->entityCollection) {
            $this->entityCollection = $this->collectionFactory->create(
                ReviewCollection::class
            );
        }
        return $this->entityCollection;
    }

    /**
     * Retrieve status map
     *
     * @return array
     */
    protected function getStatusMap()
    {
        if (null === $this->statusMap) {
            $collection = $this->collectionFactory->create(
                StatusCollection::class
            );
            /** @var \Magento\Review\Model\Review\Status $status */
            foreach ($collection as $status) {
                $this->statusMap[$status->getId()] = $status->getStatusCode();
            }
        }
        return $this->statusMap;
    }

    /**
     * Retrieve entity field columns
     *
     * @return array
     */
    public function getFieldColumns()
    {
        $options = [];
        foreach ($this->getFieldsForExport() as $field) {
            $select = [];
            $type = 'text';
            if ($field == 'review_id') {
                $type = 'int';
            }
            if (in_array($field, $this->ratingFields)) {
                $type = 'int';
            }
            if ($field == 'created_at') {
                $type = 'date';
            }
            if ($field == 'status') {
                $type = 'select';
                $select[] = ['label' => __('Approved'), 'value' => 'Approved'];
                $select[] = ['label' => __('Pending'), 'value' => 'Pending'];
                $select[] = ['label' => __('Not Approved'), 'value' => 'Not Approved'];
            }
            $options[$this->getEntityTypeCode()][] = [
                'field' => $field,
                'type' => $type,
                'select' => $select
            ];
        }
        return $options;
    }

    /**
     * Retrieve entity field for filter
     *
     * @return array
     */
    public function getFieldsForFilter()
    {
        $options = [];
        foreach ($this->getFieldsForExport() as $field) {
            $options[] = [
                'label' => $field,
                'value' => $field
            ];
        }
        return [$this->getEntityTypeCode() => $options];
    }

    /**
     * Retrieve entity field for export
     *
     * @return array
     */
    public function getFieldsForExport()
    {
        return array_merge(
            $this->exportFields,
            $this->ratingFields
        );
    }

    /**
     * Retrieve attributes codes which are appropriate for export
     *
     * @return array
     */
    protected function _getExportAttrCodes()
    {
        return [];
    }

    /**
     * @return mixed
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    private function getAttributeIdofProductName()
    {
        $productNameAttributeId = $this->attributeRepository->get(
            'catalog_product',
            'name'
        )->getId();

        return $productNameAttributeId;
    }

    /**
     * Get product entity Link Field
     *
     * @return string
     */
    protected function getProductEntityLinkField()
    {
        if (!$this->productEntityLinkField) {
            $this->productEntityLinkField = $this->metadataPool
                ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
                ->getLinkField();
        }
        return $this->productEntityLinkField;
    }
}