@@ -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 ));
}
}