Skip to content

Instantly share code, notes, and snippets.

@DeRain
Forked from nicanaca0/ImportProductsCommand.php
Created April 27, 2018 17:20
Show Gist options
  • Select an option

  • Save DeRain/3ef101acff18dd71e177635ca666f18d to your computer and use it in GitHub Desktop.

Select an option

Save DeRain/3ef101acff18dd71e177635ca666f18d to your computer and use it in GitHub Desktop.

Revisions

  1. @nicanaca0 nicanaca0 revised this gist Jul 5, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ImportProductsCommand.php
    Original file line number Diff line number Diff line change
    @@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

    $this->channel = $this->getContainer()->get('sylius.context.channel')->getChannel();

    /* AssoicationType */
    /* AssociationType */
    /** @var ProductAssociationTypeInterface $associationType */
    if (!$associationType = $this->associationTypeRepository->findOneBy(['code' => 'related_product'])) {
    $associationType = $this->associationTypeFactory->createNew();
  2. @nicanaca0 nicanaca0 created this gist Jul 5, 2017.
    279 changes: 279 additions & 0 deletions ImportProductsCommand.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,279 @@
    <?php

    namespace AppBundle\Command;

    use Sylius\Component\Core\Model\ChannelPricingInterface;
    use Sylius\Component\Core\Model\ProductInterface;
    use Sylius\Component\Core\Model\ProductVariantInterface;
    use Sylius\Component\Product\Model\ProductAssociationInterface;
    use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
    use Sylius\Component\Taxonomy\Model\TaxonInterface;
    use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    use Symfony\Component\HttpFoundation\File\UploadedFile;

    class CsvIterator {

    const DELIM = ",";
    const QUOTE = '"';

    protected $file;
    protected $rows = array();

    public function __construct($file) {
    $this->file = fopen($file, 'r');
    }

    public function getFile() {
    return $this->file;
    }

    public function parse() {
    $headers = array_map('trim', fgetcsv($this->file, 4096, self::DELIM, self::QUOTE));
    while (!feof($this->file)) {
    $row = array_map('trim', (array)fgetcsv($this->file, 4096, self::DELIM, self::QUOTE));
    if (count($headers) !== count($row)) {
    continue;
    }
    $this->rows[] = array_combine($headers, $row);
    }
    return $this->rows;
    }
    }

    class ImportProductsCommand extends ContainerAwareCommand
    {
    private $locale = 'en_US';

    private $productFactory;
    private $productRepository;
    private $productManager;

    private $pricingFactory;

    private $associationFactory;
    private $associationRepository;

    private $associationTypeFactory;
    private $associationTypeRepository;

    private $taxonFactory;
    private $taxonRepository;
    private $taxonManager;

    private $channel;


    protected function configure()
    {
    $this
    ->setName('import:products')
    ->setDescription('Import products from csv file')
    ->addArgument(
    'csvFilePath',
    InputArgument::REQUIRED,
    'Specify path to CSV file'
    )
    ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $this->productFactory = $this->getContainer()->get('sylius.factory.product');
    $this->productRepository = $this->getContainer()->get('sylius.repository.product');
    $this->productManager = $this->getContainer()->get('sylius.manager.product');

    $this->pricingFactory = $this->getContainer()->get('sylius.factory.channel_pricing');

    $this->associationFactory = $this->getContainer()->get('sylius.factory.product_association');
    $this->associationRepository = $this->getContainer()->get('sylius.repository.product_association');

    $this->associationTypeFactory = $this->getContainer()->get('sylius.factory.product_association_type');
    $this->associationTypeRepository = $this->getContainer()->get('sylius.repository.product_association_type');

    $this->taxonFactory = $this->getContainer()->get('sylius.factory.taxon');
    $this->taxonRepository = $this->getContainer()->get('sylius.repository.taxon');
    $this->taxonManager = $this->getContainer()->get('sylius.manager.taxon');

    $this->channel = $this->getContainer()->get('sylius.context.channel')->getChannel();

    /* AssoicationType */
    /** @var ProductAssociationTypeInterface $associationType */
    if (!$associationType = $this->associationTypeRepository->findOneBy(['code' => 'related_product'])) {
    $associationType = $this->associationTypeFactory->createNew();
    $associationType->setCode('related_product');
    $associationType->setName('Related Product');
    $this->associationTypeRepository->add($associationType);
    } ;

    /* CSV */
    $csvFilePath = $input->getArgument('csvFilePath');

    $csv = new CsvIterator($csvFilePath);
    if ($csv->getFile() === false) {
    die(sprintf('CSV file not valid. path: %s'.PHP_EOL, $csvFilePath));
    }
    $count = 0;

    foreach ($csv->parse() as $row) {

    $code = trim($row['Product Code']);
    $name = trim($row['Name']);

    dump($code, $name);

    /* Product - load or create */
    $output->writeln('<comment>Product</comment>');
    /** @var ProductInterface $product */
    if (!$product = $this->productRepository->findOneByCode($code, $this->locale)) {
    $product = $this->productFactory->createWithVariant();
    } ;

    $product->setCode($code); // Both Product and Variant needs a valid 'Code'
    $product->setName($name);
    $product->setDescription(trim($row['Full Description']));
    $product->setSlug(str_replace(' ', '', $code));
    $product->setVariantSelectionMethod($product::VARIANT_SELECTION_CHOICE);
    $product->addChannel($this->channel);

    /* Variant */
    $output->writeln('<comment>Variant</comment>');
    /** @var ProductVariantInterface $product_variant */
    $product_variant = $product->getVariants()[0];
    $product_variant->setCode($code); // Both Product and Variant needs a valid 'Code'
    $product_variant->setWidth((int) trim($row['Width']));
    $product_variant->setWeight((int) trim($row['Weight']));
    // Thickness
    // Length


    /* Pricing - set per channel (only one in our case) */
    $output->writeln('<comment>Pricing</comment>');
    /** @var ChannelPricingInterface $channelPricing */
    if (!$channelPricing = $product_variant->getChannelPricingForChannel($this->channel)) {
    $channelPricing = $this->pricingFactory->createNew();
    $product_variant->addChannelPricing($channelPricing);
    } ;

    $channelPricing->setChannelCode($this->channel->getCode());
    $channelPricing->setPrice($this->cleanPrice($row['Std Sell Price']));


    /* Taxons - Tree */
    $output->writeln('<comment>Taxons</comment>');
    $taxonTreeArray = array_filter(array(
    $row['Product Group Level 1'],
    $row['Product Group Level 2'],
    $row['Product Group Level 3'],
    $row['Product Group Level 4'],
    $row['Product Group Level 5'],
    )
    );
    $this->createTaxonTree($taxonTreeArray);


    /* Taxons - Main */
    $output->writeln('<comment>Taxons</comment>');
    $taxon = $this->taxonRepository->findOneBySlug($this->cleanString($row['Product Group']), $this->locale); // case-insensitive
    $product->setMainTaxon($taxon);


    /* Image */
    $private_dir = realpath(__DIR__ . '/../..') . '/private/datafeed/current/';
    $import_dir = $private_dir . 'Product Info/';

    $matches = array();
    preg_match('/^\\\\\\\\2012SQL\\\\bistrack\\\\Product Info\\\\(.*)$/i', $row['udfWebImage'], $matches);
    $imageUrl = $import_dir . str_replace('\\', '/', $matches[1]);
    if (file_exists($imageUrl)) {
    $output->writeln('<comment>Image</comment>');
    $product->addImage($this->getImage($imageUrl));
    }


    /* Associations */
    $associatedProductCodes = array_filter(array(
    $row['Related Product 1'],
    $row['Related Product 2'],
    $row['Related Product 3'],
    $row['Related Product 4'],
    $row['Related Product 5'],
    )
    );
    /** @var ProductAssociationInterface $productAssociation */
    $productAssociation = $this->associationFactory->createNew();
    $productAssociation->setType($associationType);
    foreach ($associatedProductCodes as $associatedProductCode) {
    if ($associatedProduct = $this->productRepository->findOneByCode($associatedProductCode)) {
    $productAssociation->addAssociatedProduct($associatedProduct);
    }
    }
    $product->addAssociation($productAssociation);
    $this->associationRepository->add($productAssociation);

    /* Saving */
    $output->writeln('<comment>Saving</comment>');
    $this->productManager->persist($product);
    if (0 === ++$count % 100) {
    $this->productManager->flush();
    }

    }

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

    private function createTaxonTree($taxonTreeArray)
    {

    $parent = null;
    foreach ($taxonTreeArray as $taxonName) {

    if ($taxon = $this->taxonRepository->findOneBySlug($this->cleanString($taxonName), $this->locale)) {
    $parent = $taxon;
    continue;
    }

    /** @var TaxonInterface $taxon */
    $taxon = $this->taxonFactory->createNew();
    $taxon->setCode($this->cleanString($taxonName));
    $taxon->setName($taxonName);
    $taxon->setSlug($this->cleanString($taxonName));
    if ($parent) {
    $taxon->setParent($parent);
    }
    $parent = $taxon;
    $this->taxonManager->persist($taxon);
    }
    $this->taxonManager->flush();

    }

    private function cleanPrice($price)
    {
    return (int) str_replace([
    utf8_decode("£"),
    utf8_decode("."),
    ], '', $price);
    }

    private function getImage($imageUrl)
    {
    $fileName = substr($imageUrl, strrpos($imageUrl, '/') + 1);

    $img = sys_get_temp_dir() . '/' . $fileName;
    file_put_contents($img, file_get_contents($imageUrl));
    $imageEntity = $this->getContainer()->get('sylius.factory.product_image')->createNew();
    $imageEntity->setFile(new UploadedFile($img, $fileName));
    $this->getContainer()->get('sylius.image_uploader')->upload($imageEntity);

    return $imageEntity;
    }

    private function cleanString($string)
    {
    return strtolower(str_replace([' '], '_', $string));
    }
    }