I've written a custom CLI command to import products from an external database into Magento, however whenever I try to save the product, an Exception is thrown.
[Magento\Framework\Exception\SessionException]
Area code not set: Area code must be set before starting a session.
[Magento\Framework\Exception\LocalizedException]
Area code is not set
I have set the area code as per other questions -
public function __construct(State $state, ProductRepositoryInterface $prepo)
{
// We cannot use core functions (like saving a product) unless the area
// code is explicitly set.
try {
$state->setAreaCode('adminhtml');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
// Intentionally left empty.
echo $e->getMessage();
exit;
}
parent::__construct();
}
However I still get the exception. Please can someone help - this has been driving me mad for days.
HERE IS THE SCRIPT CAUSING THE ISSUE
<?php
/**
* Created by PhpStorm.
* User: steve
* Date: 30/06/2017
* Time: 10:34
*/
namespace BlackLab\Merlin\Console\Command;
use Symfony\Component\Console\Input\{InputInterface, InputArgument, InputOption};
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Framework\App\{ObjectManager, State};
class MerlinImport extends Command {
protected $objectManager;
protected $attributeRepository;
protected $tableFactory;
protected $attributeOptionManagement;
protected $optionLabelFactory;
protected $optionFactory;
protected $_output;
protected $_input;
protected $_page = '/Merlin.asmx';
protected $_ua = 'Merlin-Rainbow/1.0 (compatible; Mozilla 4.0; MSIE 5)';
protected $_url = '';
protected $_datasource = "driver={PostgreSQL UNICODE};";
protected $_headers = '';
protected $_options = [
];
protected $_processing = [];
protected $state;
/**
* Constructor
*
* @param State $state A Magento app State instance
*
* @return void
*/
public function __construct(\Magento\Framework\App\State $state,
\Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
\Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory,
\Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement,
\Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory,
\Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory)
{
// We cannot use core functions (like saving a product) unless the area
// code is explicitly set.
$this->state = $state;
$this->objectManager = ObjectManager::getInstance();
$this->attributeRepository = $attributeRepository;
$this->tableFactory = $tableFactory;
$this->attributeOptionManagement = $attributeOptionManagement;
$this->optionLabelFactory = $optionLabelFactory;
$this->optionFactory = $optionFactory;
parent::__construct();
}
/**
* Configures arguments and display options for this command.
*
* @return void
*/
protected function configure()
{
$this->setName('merlin:import');
$this->setDescription('Import Merlin products & categories into Magento');
$this->addArgument('process', InputArgument::REQUIRED, 'The type of import (products/categories/all) is required.');
parent::configure();
}
/**
* Execute the command to add products or categories.
*
* @param InputInterface $input An input instance
* @param OutputInterface $output An output instance
*
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// $this->state->setAreaCode("admin");
$this->_input = $input;
$this->_output = $output;
$process = $input->getArgument('process');
$config = $this->objectManager->create('BlackLab\Merlin\Model\Config')
->load(1);
if (!$config) {
$output->writeln('<error>No Configuration found please setup the importer in Merlin > Configuration</error>');
}
else {
// Set the config
$this->_options = $config->toArray();
$this->_url = 'http://' . $this->_options['host'] . ':' . $this->_options['port'];
$this->_datasource .= 'server=' . $this->_options['dbhost']
. ';database=' . $this->_options['dbname']
. ';uid=' . $this->_options['dbuser']
. ';pwd=' . $this->_options['dbpass'];
$this->_getProcessing();
switch ( $process ) {
case "products":
$this->importProducts();
break;
}
}
}
public function importProducts() {
$this->state->setAreaCode("admin");
if (isset($this->_processing['products'])) {
if ($this->_processing['products']['is_processing'] == 1) {
return;
}
}
$this->_output->writeln('<info>Running product importer</info>');
$merlinProducts = $this->objectManager->create( 'BlackLab\Merlin\Model\Products' )->getCollection();
$merlinProducts->getSelect();
foreach ($merlinProducts->load() as $merlinProduct) {
// Get the object data as an array
$mPrd = $merlinProduct->getData();
$psuedo = $this->objectManager->create( 'BlackLab\Merlin\Model\Psuedo' )
->getCollection()
->addFieldToFilter( 'stock_part', $merlinProduct->getPart() )
->getFirstItem();
$psd = $psuedo->getData();
if (empty($psd)) {
$this->_output->writeln('<info>No Psuedo object for : ' . $merlinProduct->getPart() . '</info>');
continue;
}
$mPrd['title'] = $psd['name'];
$mPrd['sku'] = $psd['part'];
// Get the category for the product
$category = $this->objectManager->create( 'BlackLab\Merlin\Model\Categories' )
->getCollection()
->addFieldToFilter( 'merlin_id', $mPrd['category'] )
->getFirstItem();
if ($category->getId() == null) {
if ($merlinProduct->getMagentoId() > 0) {
$product = $this->objectManager->create('\Magento\Catalog\Model\Product')
->getCollection()
->addFieldToFilter('sku', $mPrd['sku'])
->getFirstItem();
if ($product->getId() !== null) {
$product->setStoreId(0);
$product->delete();
$merlinProduct->setMagentoId(0);
$merlinProduct->save();
}
}
continue;
}
$cat = $category->getData();
$mPrd['magento_category'] = $cat['magento_id'];
// Get the price group
$pgroup = $this->objectManager->create( 'BlackLab\Merlin\Model\PriceGroup' )
->getCollection()
->addFieldToFilter( 'part', $mPrd['part'] )
->getFirstItem();
$pg = $pgroup->getData();
$mPrd['disc1'] = $pg['disc1'];
$mPrd['disc2'] = $pg['disc2'];
$mPrd['break'] = $pg['break'];
// Get the related products
$related = $this->objectManager->create( 'BlackLab\Merlin\Model\ProductAlt' )
->getCollection()
->addFieldToFilter( 'part_id', $mPrd['stock_id'] )
->addFieldToFilter( 'alt_type', 'L');
// Get the upsells
$upsells = $this->objectManager->create( 'BlackLab\Merlin\Model\ProductAlt' )
->getCollection()
->addFieldToFilter( 'part_id', $mPrd['id'] )
->addFieldToFilter( 'alt_type', 'A');
// Get the crossells
$crossells = $this->objectManager->create( 'BlackLab\Merlin\Model\ProductAlt' )
->getCollection()
->addFieldToFilter( 'part_id', $mPrd['id'] )
->addFieldToFilter( 'alt_type', 'S');
// Get the pictures
$mPrd['pictures'] = [];
$pictures = $this->objectManager->create( 'BlackLab\Merlin\Model\Pictures' )
->getCollection()
->addFieldToFilter( 'part', $mPrd['part'] );
foreach ($pictures->load() as $picture) {
$mPrd['pictures'][] = [
'path' => str_replace("public/../","",$picture->getPath())
];
}
if ($mPrd['magento_id'] == null || $mPrd['magento_id'] == 0) {
$this->_output->writeln('<info>Importing product : ' . $merlinProduct->getPart() . '</info>');
$magentoId = $this->importProduct($mPrd, $related, $crossells, $upsells);
$merlinProduct->setMagentoId($magentoId);
$merlinProduct->save();
}
else {
}
}
}
public function importProduct($prd, $related, $crossells, $upsells) {
$product = $this->objectManager->create('\Magento\Catalog\Model\Product');
$product->setWebsiteIds([0]);
$product->setSku($prd['sku']); // Set your sku here
$product->setName($prd['title']); // Name of Product
$product->setAttributeSetId(4); // Attribute set id
$product->setStatus(1); // Status on product enabled/ disabled 1/0
$product->setStoreId(0);
$product->setWeight(floatval($prd['weight'])); // weight of product
$product->setVisibility(4); // visibilty of product (catalog / search / catalog, search / Not visible individually)
$product->setTaxClassId(2); // Tax class id
$product->setTypeId('simple'); // type of product (simple/virtual/downloadable/configurable)
$product->setCategoryIds([$prd['magento_category']]);
$product->setPrice($prd['disc1']); // price of product
$product->setDescription($prd['description']);
$product->setWebsiteIds(array(1));
$product->setStatus(Status::STATUS_ENABLED);
$product->setAttributeSetId($product->getDefaultAttributeSetId());
$product->setUrlKey($this->_slugify($prd['title'] . ' ' . $prd['sku']));
$product->setTierPrice(
array(
[
'website' => 'all',
'customer_group_id' => 'all',
'price_qty' => (int) $prd['break'],
'price' => floatval($prd['disc2'])
]
)
);
foreach ($prd['pictures'] as $picture) {
// var_dump($picture['path']);
if (file_exists($picture['path'])) {
$product->addImageToMediaGallery( $picture['path'], array(
'image',
'small_image',
'thumbnail'
), true, false );
}
}
$stock = $this->objectManager->create( 'BlackLab\Merlin\Model\Stock' )
->getCollection()
->addFieldToFilter( 'part', $prd['part'] )
->getFirstItem();
$stk = $this->objectManager->create( 'BlackLab\Merlin\Model\Stkuser' )
->getCollection()
->addFieldToFilter( 'part', $prd['part'] )
->getFirstItem();
$duty = $this->objectManager->create( 'BlackLab\Merlin\Model\Duty' )
->getCollection()
->addFieldToFilter( 'code', $stock->getDutyCode() )
->getFirstItem();
$product->setStockData(
array(
'use_config_manage_stock' => 1,
'manage_stock' => 1,
'is_in_stock' => ($stock->getQtyHand() > 0) ? 1:0,
'qty' => $stock->getQtyHand()
)
);
$product->setCategoryIds([$prd['magento_category']]);
// // Now that we've got a valid product - lets set the attributes.
$product->setData('uoi',$stock->getUoi());
$product->setData('duoi',$stock->getDuoi());
$product->setData('barrel_ratio',$stock->getBarrelRatio());
$product->setData('flag_redundant',$stock->getFlagRedundant());
$product->setData('wine_flag',$stock->getWinesFlag());
$product->setData('stock_num',$stock->getPart());
$product->setData('date_amended',$stock->getDateAmended());
$product->setData('last_sold',$stock->getLastSold());
$product->setData('sop_cost',$stock->getCostSop());
$product->setData('recommended',$stock->getAltPart());
$product->setData('barcode_ean',$stock->getMerlinId());
$product->setData('manufacturer',$duty->getDescription());
$product->setData('hide_price', ($stk->getUserchk10() == 'Y') ? 'Yes' : 'No');
$product->setUrlKey($this->_slugify($prd['title'] . ' ' . $prd['sku']));
$linkData = [];
$i = 1;
// Related Products
foreach ($related->load() as $rProduct) {
$rProd = $this->objectManager->create( 'BlackLab\Merlin\Model\Products' )->getCollection()
->addFieldToFilter( 'id', $rProduct->getAltId() )
->getFirstItem();
$rPsuedo = $this->objectManager->create( 'BlackLab\Merlin\Model\Psuedo' )
->getCollection()
->addFieldToFilter( 'stock_part', $rProd['part'] )
->getFirstItem();
$rPsd = $rPsuedo->getData();
if (empty($rPsd)) {
continue;
}
$productLink = $this->objectManager->create('Magento\Catalog\Api\Data\ProductLinkInterface')
->setSku($product->getSku())
->setLinkedProductSku($rPsd['part'])
->setPosition($i)
->setLinkType('related');
$i++;
$linkData[] = $productLink;
}
$i = 1;
// Upsell Products
foreach ($upsells->load() as $uProduct) {
$uProd = $this->objectManager->create( 'BlackLab\Merlin\Model\Products' )->getCollection()
->addFieldToFilter( 'id', $uProduct->getAltId() )
->getFirstItem();
$uPsuedo = $this->objectManager->create( 'BlackLab\Merlin\Model\Psuedo' )
->getCollection()
->addFieldToFilter( 'stock_part', $uProd['part'] )
->getFirstItem();
$uPsd = $uPsuedo->getData();
if (empty($uPsd)) {
continue;
}
$productLink = $this->objectManager->create('Magento\Catalog\Api\Data\ProductLinkInterface')
->setSku($product->getSku())
->setLinkedProductSku($uPsd['part'])
->setPosition($i)
->setLinkType('upsell');
$i++;
$linkData[] = $productLink;
}
$i = 1;
// Crossell Products
foreach ($upsells->load() as $uProduct) {
$cProd = $this->objectManager->create( 'BlackLab\Merlin\Model\Products' )->getCollection()
->addFieldToFilter( 'id', $uProduct->getAltId() )
->getFirstItem();
$cPsuedo = $this->objectManager->create( 'BlackLab\Merlin\Model\Psuedo' )
->getCollection()
->addFieldToFilter( 'stock_part', $cProd['part'] )
->getFirstItem();
$cPsd = $cPsuedo->getData();
if (empty($cPsd)) {
continue;
}
$productLink = $this->objectManager->create('Magento\Catalog\Api\Data\ProductLinkInterface')
->setSku($product->getSku())
->setLinkedProductSku($cPsd['part'])
->setPosition($i)
->setLinkType('crosssell');
$i++;
$linkData[] = $productLink;
}
if (count($linkData) > 0) {
$product->setProductLinks($linkData);
}
try {
$product->save();
$this->_output->writeln('Created product = <comment>' . $prd['name'] . '</comment>');
return $product->getId();
} catch (Exception $e) {
$this->_output->writeln('<error>Unable to create product ' . $prd['name'] . '</error>');
}
}
}