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?

  • Why you have created two controller? While you can create function in same controller – Gopal Patel Nov 4 '16 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 – Jacques Nov 7 '16 at 8:29
  • OK , I have not started magneto 2 that's why not aware of that concept – Gopal Patel Nov 7 '16 at 8:39
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.

  • 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 – Jacques Nov 29 '16 at 9:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.