-
Notifications
You must be signed in to change notification settings - Fork 5
Updating products in batches
This article describes how to create custom "cron controller" for updating product data to Nosto. Please note that this example should NOT be used as is. This example fetches products with the given limit and offset, sorted by last updated timestamp. You MUST implement the logic to only update products that have been changed. This can be achieved for example by checking when the product was last updated and only update the changed ones. This controller does not have any authentication either. The controller is only accessible from localhost.
File modules/mynostocron/mynostocron.php
<?php
if (!defined('_PS_VERSION_'))
exit;
/**
* Module for adding cron controller product updates.
*
*/
class MyNostoCron extends Module
{
/**
* Constructor.
*
* Defines the module.
*/
public function __construct()
{
$this->name = 'mynostocron';
$this->tab = 'advertising_marketing';
$this->version = '0.1.0';
$this->author = 'YourName';
$this->need_instance = 1;
$this->bootstrap = true;
$this->ps_versions_compliancy = array(
'min' => '1.4',
'max' => _PS_VERSION_
);
parent::__construct();
$this->displayName = $this->l('My Nosto Cron');
$this->description = $this->l('Module for adding Nosto custom cron job');
}
/**
* Module installer.
*
* @return bool
*/
public function install()
{
return parent::install();
}
}
File modules/mynostocron/controllers/front/updateProducts.php
<?php
require_once(_PS_MODULE_DIR_ . '/nostotagging/nostotagging.php');
/**
* Cron controller for updating products in batches to Nosto.
*/
class MyNostoCronUpdateProductsModuleFrontController extends ModuleFrontController
{
/**
* Default sorting parameter
*/
const DEFAULT_ORDER_BY = 'date_upd';
/**
* Default sorting direction
*/
const DEFAULT_ORDER_DIRECTION = 'DESC';
/**
* Default limit for how many products to update
*
* @var int
*/
private $limit = 50;
/**
* Default limit for how many products to update
*
* @var int
*/
private $offset = 0;
/**
* How many seconds we should wait for Nosto
*
* @var int
*/
private $maxWait = 60;
/**
* Contains custom messages
*
* @var array
*/
private $customMessages = array();
/**
* Contains custom error messages
*
* @var array
*/
private $customErrors = array();
public function __construct()
{
if ($_SERVER['REMOTE_ADDR'] !== "127.0.0.1") {
die();
}
parent::__construct();
if (Tools::getValue('limit')) {
$this->limit = Tools::getValue('limit');
}
if (Tools::getValue('offset')) {
$this->offset = Tools::getValue('offset');
}
}
/**
* @inheritdoc
*/
public function initContent()
{
$updatedProductsCount = 0;
$shops = Shop::getShops(true);
/* @var Shop $shop */
foreach ($shops as $shop) {
$id_shop = $shop['id_shop'];
$id_shop_group = $shop['id_shop_group'];
$languages = LanguageCore::getLanguages(true, $id_shop);
foreach ($languages as $language) {
$id_language = $language['id_lang'];
/* @var NostoTaggingHelperAccount $accountHelper */
$accountHelper = Nosto::helper('nosto_tagging/account');
$nostoAccount = $accountHelper->find($id_language, $id_shop_group, $id_shop);
if ($nostoAccount instanceof NostoAccount === false) {
$this->customMessages[] = sprintf('No Nosto account find for store %d and language %d', $id_shop, $id_language);
continue;
}
/* @var NostoTaggingHelperContextFactory $contextFactory */
$contextFactory = Nosto::helper('nosto_tagging/context_factory');
$forgedContext = $contextFactory->forgeContext($id_language, $id_shop);
$products = self::getProductsFromStore(
$id_shop,
(int)$this->offset,
(int)$this->limit,
self::DEFAULT_ORDER_BY,
self::DEFAULT_ORDER_DIRECTION,
false,
false,
$forgedContext
);
if (count($products) == 0) {
$this->messages[] = sprintf('No products in store %d', $id_shop);
continue;
}
$nostoProductOperation = new NostoOperationProduct($nostoAccount);
/* @var Product $product */
foreach ($products as $product) {
$prestaProduct = new Product($product['id_product'], true, $id_language, $id_shop, $forgedContext);
$nostoProduct = new NostoTaggingProduct();
$nostoProduct->loadData($forgedContext, $prestaProduct);
if ($nostoProduct instanceof NostoTaggingProduct) {
$nostoProductOperation->addProduct($nostoProduct);
++$updatedProductsCount;
}
}
$this->customMessages[] = sprintf(
'Updating %d products for store #%d',
$updatedProductsCount,
$id_shop
);
try {
$nostoProductOperation->upsert();
} catch (NostoException $e) {
$this->customErrors[] = sprintf('Failed to update products. Reason: %s', $e->getMessage()) ;
}
}
}
$this->printMessages();
die;
}
/**
* Fetches the products by given argurments
*
* @param $storeId
* @param int $start
* @param int $end
* @param null $order_by
* @param null $order_direction
* @param bool $id_category
* @param bool $only_active
* @param null $context
* @return array
*/
private static function getProductsFromStore(
$storeId,
$start = 0,
$end = 1,
$order_by = null,
$order_direction = null,
$id_category = false,
$only_active = false,
$context = null
)
{
if (empty($order_by)) {
$order_by = self::DEFAULT_ORDER_BY;
}
if (empty($order_direction)) {
$order_direction = self::DEFAULT_ORDER_DIRECTION;
}
return ProductCore::getProducts(
$storeId,
$start,
$end,
$order_by,
$order_direction,
$id_category,
$only_active,
$context
);
}
/**
* Prints out the messages generated during the batch update
*/
private function printMessages()
{
echo "\n\n--- Nosto update info ---\n\n";
echo "\nMessages:\n";
foreach ( $this->customMessages as $customMessage ) {
echo " > $customMessage\n";
}
if (count($this->customErrors)) {
echo "\n\nErrors: \n";
foreach ( $this->customErrors as $customError ) {
echo " > $customError \n";
}
} else {
echo "\n\nNo errors\n";
}
echo "\n\n--- End of Nosto update info ---\n\n";
}
}
After the bootstrap and controller are in place you can access the controller from command line by calling curl -v http:/your.store.com/modules/mynostocron/front/updateProducts.php?fc=module&module=mynostocron&controller=updateProducts&limit=50&offset=0
. Please note that this controller is accessible only from localhost.
This wiki content has been moved to https://docs.nosto.com/prestashop