1

I'm developing a product import function by XML. The import works fine but the input XML is 9000 products and the request already uses 200MB memory with 100 products (even with the clearInstance() calls on each Product and StockItem).

Since it is PHP the request will use more and more memory the longer it runs. So I've decided to spread the functionality out over several requests. I want to loop through the products, execute or send the request foreach product which will import the product and then log the return value, and then continue the loop. Eventually this will become thousands of requests but that only costs time, not memory. The import will run once, at night so the time is not an issue.

Now I made two controllers: One main Index controller which is called from the cron job and another controller which is called by the Index controller. In the main controller I make a JSON redirect but it's not sent. How do I sent a request from inside the Index controller, wait for it's response and then continue execution?

Below is simplified code:

//Module/Import/Controller/Adminhtml/Import/Index.php
class Index extends \Magento\Backend\App\Action
{
 private $productRepository;
 private $productFactory;
 private $resultJsonFactory;
 public function __construct(
 \Magento\Backend\App\Action\Context $context,
 \Magento\Catalog\Model\ProductRepository $productRepository,
 \Magento\Catalog\Model\ProductFactory $productFactory,
 \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
 )
 {
 $this->productRepository = $productRepository;
 $this->productFactory = $productFactory;
 $this->resultJsonFactory = $resultJsonFactory;
 parent::__construct($context);
 }
 public function execute()
 {
 $file = 'import_feed.xml';
 $productNodes = $this->getProductNodesFromXml($file);
 foreach ($productNodes as $product) {
 // Turn XML node into data array
 $data = $this->convertValues();
 $data = json_encode($data);
 $resultRedirect = $this->resultRedirectFactory->create()
 ->setPath('module/import/product', array('data' => $data));
 }
 }
}

And a secundary controller which is called for each product:

//Module/Import/Controller/Adminhtml/Import/Product.php
class Product extends \Magento\Backend\App\Action
{
 private $productRepository;
 private $productFactory;
 private $stockRegistry;
 private $storeManager;
 private $jsonFactory;
 public function __construct(
 \Magento\Backend\App\Action\Context $context,
 \Magento\Catalog\Model\ProductRepository $productRepository,
 \Magento\Catalog\Model\ProductFactory $productFactory,
 \Magento\CatalogInventory\Model\StockRegistry $stockRegistry,
 \Magento\Framework\Controller\Result\JsonFactory $jsonFactory,
 \Magento\Store\Model\StoreManagerInterface $storeManager
 )
 {
 $this->productRepository = $productRepository;
 $this->productFactory = $productFactory;
 $this->stockRegistry = $stockRegistry;
 $this->storeManager = $storeManager;
 $this->jsonFactory = $jsonFactory;
 parent::__construct($context);
 }
 public function execute()
 {
 $data = $this->getRequest()->getParam('data');
 $data = json_decode($data);
 // Create product model
 /** @var \Magento\Catalog\Model\Product $product */
 $product = $this->productFactory->create();
 // Set data, this is obviously more complicated in the real class
 $product->setData($data);
 // Save product
 $product = $this->productRepository->save($product);
 $product->clearInstance();
 $result = $this->jsonFactory->create();
 $result->setHttpResponseCode(200);
 $result->setData(['success' => true]);
 }
}

How can I call the secundary controller from the Index controller and use its return value?

asked Nov 4, 2016 at 15:00
3
  • Why you have created two controller? While you can create function in same controller Commented Nov 4, 2016 at 17:47
  • In Magento 2 you need a separate controller for each action. Every URL has one controller. inchoo.net/magento-2/magento-2-controllers Commented Nov 7, 2016 at 8:29
  • OK , I have not started magneto 2 that's why not aware of that concept Commented Nov 7, 2016 at 8:39

1 Answer 1

1

For your bulk product import you can use FireGento_FastSimpleImport

You just have to create 2D array from your json data.

/** @var \FireGento\FastSimpleImport\Model\Importer $importerModel */
$importerModel = $this->objectManager->create('FireGento\FastSimpleImport\Model\Importer');
$productsArray = array(
array(
 'sku' => 'test1',
 'attribute_set_code' => 'Default',
 'product_type' => 'simple',
 'product_websites' => 'base',
 'name' => 'Test Product1',
 'price' => '1000',
 ),
array(
 'sku' => 'test2',
 'attribute_set_code' => 'Default',
 'product_type' => 'simple',
 'product_websites' => 'base',
 'name' => 'Test Product 2',
 'price' => '1400',
 ),
// add more products here
);
try {
 $importerModel->processImport($productsArray);
} catch (Exception $e) {
 // insert into log $e->getMessage()
}

You have to creat Inner array for each product. By this you dont have to load product model and set-save data for each product. It will import in one go or you can make chunk of 250 to 300.

You can find documentation

Demo to refer.

And using this you dont have to create and call another controller.

answered Nov 4, 2016 at 18:08
1
  • Thank you, I implemented the extension succesfully. As for the images, simply setting the path to the image file in $data['thumbnail'] and $data['small_image'] where $data is the variable used to import the product Commented Nov 29, 2016 at 9:24

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.