<commit_before><?php

namespace ShopwarePlugins\Connect\Components;

use Shopware\Components\Model\ModelManager;
use Shopware\Models\Article\Article;
use Shopware\Models\Article\Detail;
use \Shopware\Models\Article\Image;
use \Shopware\Models\Media\Media;
use \Shopware\Models\Attribute\Media as MediaAttribute;
use \Shopware\Models\Attribute\ArticleImage as ImageAttribute;
use Symfony\Component\HttpFoundation\File\File;
use Shopware\Models\Article\Supplier;
use Shopware\Components\Thumbnail\Manager as ThumbnailManager;


class ImageImport
{

    /** @var \Shopware\Components\Model\ModelManager */
    protected $manager;

    /** @var  Helper */
    protected $helper;

    /**
     * @var ThumbnailManager
     */
    protected $thumbnailManager;

    /** @var  \ShopwarePlugins\Connect\Components\Logger */
    protected $logger;

    public function __construct(
        ModelManager $manager,
        Helper $helper,
        ThumbnailManager $thumbnailManager,
        Logger $logger
    ) {
        $this->manager = $manager;
        $this->helper = $helper;
        $this->thumbnailManager = $thumbnailManager;
        $this->logger = $logger;
    }

    /**
     * Helper to determine, if there is a main image for a given articleId
     *
     * @param $articleId
     * @return bool
     */
    public function hasArticleMainImage($articleId)
    {
        $builder = $this->manager->createQueryBuilder();
        $builder->select(array('images'))
            ->from('Shopware\Models\Article\Image', 'images')
            ->where('images.articleId = :articleId')
            ->andWhere('images.parentId IS NULL')
            ->andWhere('images.main = :main')
            ->setParameter('main', 1)
            ->setParameter('articleId', $articleId)
            ->setFirstResult(0)
            ->setMaxResults(1);

        $result = $builder->getQuery()->getResult();
        return !empty($result);
    }

    /**
     * Get ids of products that needs an image import
     * @param null $limit
     * @return array        Ids of products needing an image import
     */
    public function getProductsNeedingImageImport($limit=null)
    {
        $updateFlags = $this->helper->getUpdateFlags();
        $updateFlagsByName = array_flip($updateFlags);

        $initialImportFlag = $updateFlagsByName['imageInitialImport'];

        $builder = $this->manager->createQueryBuilder();
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'at');
        $builder->innerJoin('at.articleDetail', 'detail');
        $builder->select('at.articleId');
        $builder->andWhere('at.shopId IS NOT NULL')
            ->andWHere('at.lastUpdateFlag IS NOT NULL')
            ->andWHere('BIT_AND(at.lastUpdateFlag, :initialImportFlag) > 0')
            ->setParameter('initialImportFlag', $initialImportFlag);

        if ($limit) {
            $builder->setMaxResults($limit);
        }

        $ids = $builder->getQuery()->getArrayResult();
        return array_map('array_pop', $ids);

    }

    /**
     * Batch import images for new products without images
     *
     * @param int|null $limit
     */
    public function import($limit = null)
    {
        $articleRepository = $this->manager->getRepository('Shopware\Models\Article\Article');

        $flags = $this->helper->getUpdateFlags();
        $flagsByName = array_flip($flags);

        $ids = $this->getProductsNeedingImageImport($limit);

        foreach ($ids as $id) {
            /** @var \Shopware\Models\Article\Article $article */
            $article = $articleRepository->find($id);
            $connectAttributes = $this->helper->getConnectAttributesByArticle($article);

            /** @var \Shopware\CustomModels\Connect\Attribute $connectAttribute */
            foreach ($connectAttributes as $connectAttribute) {
                $lastUpdate = json_decode($connectAttribute->getLastUpdate(), true);
                $this->importImagesForArticle(array_diff($lastUpdate['image'], $lastUpdate['variantImages']), $article);
                $this->importImagesForDetail($lastUpdate['variantImages'], $connectAttribute->getArticleDetail());
                $connectAttribute->flipLastUpdateFlag($flagsByName['imageInitialImport']);
            }

            $this->manager->flush();
        }
    }

    /**
     * Handles the image import of a product. This will:
     * - delete all images imported from connect before and not in the current import list
     * - create new images which have not already been imported
     * - set the main image, if there is no main image, yet
     *
     * Images are identified via the URL of the connect image. So we don't need to md5 the
     * actual image content every time.
     *
     * @param array $images
     * @param $article \Shopware\Models\Article\Article
     */
    public function importImagesForArticle($images, Article $article)
    {
        $localImagesFromConnect = $this->getImportedImages($article);
        $remoteImagesFromConnect = array_flip($images);

        // Build up arrays of images to delete and images to create
        $imagesToDelete = array_diff_key($localImagesFromConnect, $remoteImagesFromConnect);
        $imagesToCreate = array_diff_key($remoteImagesFromConnect, $localImagesFromConnect);

        // Delete old connect images and media objects
        foreach ($imagesToDelete as $hash => $data) {
            /** @var \Shopware\Models\Article\Image $image */
            $image = $data['image'];
            // if the image has mapping, it's variant image and shouldn't be deleted
            if (!empty($image->getMappings())) {
                continue;
            }
            $this->manager->remove($data['image']);
            $this->manager->remove($data['media']);
        }
        $this->manager->flush();

        try {
            $this->importImages($imagesToCreate, $article);
        } catch (\Exception $e) {
            // log exception message if for some reason
            // image import fails
            $this->logger->write(true, 'Import images', $e->getMessage());
        }

        $this->manager->flush();
    }

    /**
     * Handles the image import of a product. This will:
     * - delete all images imported from connect before and not in the current import list
     * - create new images which have not already been imported
     * - set the main image, if there is no main image, yet
     *
     * Images are identified via the URL of the connect image. So we don't need to md5 the
     * actual image content every time.
     *
     * @param array $variantImages
     * @param $detail \Shopware\Models\Article\Detail<commit_msg>CON-3701 Fixed image duplication<commit_after><?php

namespace ShopwarePlugins\Connect\Components;

use Shopware\Components\Model\ModelManager;
use Shopware\Models\Article\Article;
use Shopware\Models\Article\Detail;
use \Shopware\Models\Article\Image;
use \Shopware\Models\Media\Media;
use \Shopware\Models\Attribute\Media as MediaAttribute;
use \Shopware\Models\Attribute\ArticleImage as ImageAttribute;
use Symfony\Component\HttpFoundation\File\File;
use Shopware\Models\Article\Supplier;
use Shopware\Components\Thumbnail\Manager as ThumbnailManager;


class ImageImport
{

    /** @var \Shopware\Components\Model\ModelManager */
    protected $manager;

    /** @var  Helper */
    protected $helper;

    /**
     * @var ThumbnailManager
     */
    protected $thumbnailManager;

    /** @var  \ShopwarePlugins\Connect\Components\Logger */
    protected $logger;

    public function __construct(
        ModelManager $manager,
        Helper $helper,
        ThumbnailManager $thumbnailManager,
        Logger $logger
    ) {
        $this->manager = $manager;
        $this->helper = $helper;
        $this->thumbnailManager = $thumbnailManager;
        $this->logger = $logger;
    }

    /**
     * Helper to determine, if there is a main image for a given articleId
     *
     * @param $articleId
     * @return bool
     */
    public function hasArticleMainImage($articleId)
    {
        $builder = $this->manager->createQueryBuilder();
        $builder->select(array('images'))
            ->from('Shopware\Models\Article\Image', 'images')
            ->where('images.articleId = :articleId')
            ->andWhere('images.parentId IS NULL')
            ->andWhere('images.main = :main')
            ->setParameter('main', 1)
            ->setParameter('articleId', $articleId)
            ->setFirstResult(0)
            ->setMaxResults(1);

        $result = $builder->getQuery()->getResult();
        return !empty($result);
    }

    /**
     * Get ids of products that needs an image import
     * @param null $limit
     * @return array        Ids of products needing an image import
     */
    public function getProductsNeedingImageImport($limit=null)
    {
        $updateFlags = $this->helper->getUpdateFlags();
        $updateFlagsByName = array_flip($updateFlags);

        $initialImportFlag = $updateFlagsByName['imageInitialImport'];

        $builder = $this->manager->createQueryBuilder();
        $builder->from('Shopware\CustomModels\Connect\Attribute', 'at');
        $builder->innerJoin('at.articleDetail', 'detail');
        $builder->select('at.articleId');
        $builder->andWhere('at.shopId IS NOT NULL')
            ->andWHere('at.lastUpdateFlag IS NOT NULL')
            ->andWHere('BIT_AND(at.lastUpdateFlag, :initialImportFlag) > 0')
            ->setParameter('initialImportFlag', $initialImportFlag);

        if ($limit) {
            $builder->setMaxResults($limit);
        }

        $ids = $builder->getQuery()->getArrayResult();
        return array_map('array_pop', $ids);

    }

    /**
     * Batch import images for new products without images
     *
     * @param int|null $limit
     */
    public function import($limit = null)
    {
        $articleRepository = $this->manager->getRepository('Shopware\Models\Article\Article');

        $flags = $this->helper->getUpdateFlags();
        $flagsByName = array_flip($flags);

        $ids = $this->getProductsNeedingImageImport($limit);

        foreach ($ids as $id) {
            /** @var \Shopware\Models\Article\Article $article */
            $article = $articleRepository->find($id);
            $connectAttributes = $this->helper->getConnectAttributesByArticle($article);

            /** @var \Shopware\CustomModels\Connect\Attribute $connectAttribute */
            foreach ($connectAttributes as $connectAttribute) {
                $lastUpdate = json_decode($connectAttribute->getLastUpdate(), true);
                $this->importImagesForArticle(array_diff($lastUpdate['image'], $lastUpdate['variantImages']), $article);
                $this->importImagesForDetail($lastUpdate['variantImages'], $connectAttribute->getArticleDetail());
                $connectAttribute->flipLastUpdateFlag($flagsByName['imageInitialImport']);
            }

            $this->manager->flush();
        }
    }

    /**
     * Handles the image import of a product. This will:
     * - delete all images imported from connect before and not in the current import list
     * - create new images which have not already been imported
     * - set the main image, if there is no main image, yet
     *
     * Images are identified via the URL of the connect image. So we don't need to md5 the
     * actual image content every time.
     *
     * @param array $images
     * @param $article \Shopware\Models\Article\Article
     */
    public function importImagesForArticle($images, Article $article)
    {
        $localImagesFromConnect = $this->getImportedImages($article);
        $remoteImagesFromConnect = array_flip($images);

        // Build up arrays of images to delete and images to create
        $imagesToDelete = array_diff_key($localImagesFromConnect, $remoteImagesFromConnect);
        $imagesToCreate = array_diff_key($remoteImagesFromConnect, $localImagesFromConnect);

        // Delete old connect images and media objects
        foreach ($imagesToDelete as $hash => $data) {
            /** @var \Shopware\Models\Article\Image $image */
            $image = $data['image'];
            // if the image has mapping, it's variant image and shouldn't be deleted
            if (count($image->getMappings()) > 0) {
                continue;
            }
            $this->manager->remove($image);
            $this->manager->remove($data['media']);
        }
        $this->manager->flush();

        try {
            $this->importImages($imagesToCreate, $article);
        } catch (\Exception $e) {
            // log exception message if for some reason
            // image import fails
            $this->logger->write(true, 'Import images', $e->getMessage());
        }

        $this->manager->flush();
    }

    /**
     * Handles the image import of a product. This will:
     * - delete all images imported from connect before and not in the current import list
     * - create new images which have not already been imported
     * - set the main image, if there is no main image, yet
     *
     * Images are identified via the URL of the connect image. So we don't need to md5 the
     * actual image content every time.
     *
     * @param array $variantImages
     * @param $detail \Shopware\Models\Article\Detail
{'fraction_non_alphanumeric': 0.1213738163234631, 'fraction_numerical': 0.0012776191191943484, 'mean_word_length': 2.56851702869402, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 128, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4861264', 'n_tokens_mistral': 3577, 'n_tokens_neox': 3451, 'n_words': 885}