Hello friends,
I'd like to update some products automatically via a custom joomla cli application.
Unfortunalety I did not manage to initialize VM's classes from there.
For testing I added a system plugin triggerd by onAfterInitialise() and used VmModel::getModel('product')->store(). This works as expected as long as I satisfy VMs security checks with a valid admins session and make sure $_REQUEST is populated manually with the VM form token. But CLI applications neither have a session nor $_REQUEST.
Could anywone elaborate on the proper way of initialising VM's classes via a CLI app?
TIA!
VM models aren't written to be used outside of Joomla web environment. Because they perform tasks that are really responsibilities of controllers (reading request data, checking authorization). That reminds me of this old post https://x.com/virtuemart/status/661263708346257408.
Hello ghost, well yes, I know vm classes won't work outside joomla's environment, that's why it's a joomla application. And no, I'm not going to put raw SQL statements anywhere as long as there is any proper way around it.
Anyway, after digging through vmrequest etc., it's working now just fine.
In case anyone else is interested or has some suggestions, here's the code stub, tested on VirtueMart 4.4.4 11101. (Put it anywhere, it does not have to reside in htdocs/cli/)
<?php
use Joomla\CMS\Factory;
if('cli' !== php_sapi_name()) die('Go away.');
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Adjust to your environment
define('WEBROOT', '/var/www/webspace/htdocs');
// Init Joomla
const _JEXEC = 1;
if(file_exists(WEBROOT . '/defines.php')) require_once WEBROOT . '/defines.php';
if( ! defined('_JDEFINES')) {
define('JPATH_BASE', WEBROOT);
require_once JPATH_BASE . '/includes/defines.php';
}
require_once JPATH_LIBRARIES . '/import.legacy.php';
require_once JPATH_LIBRARIES . '/cms.php';
require_once JPATH_CONFIGURATION . '/configuration.php';
$config = new JConfig;
define('JDEBUG', $config->debug);
$lang = JFactory::getLanguage();
global $_SERVER;
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['DOCUMENT_ROOT'] = WEBROOT;
$_SERVER['SCRIPT_NAME'] = basename(__FILE__);
$_SERVER['REMOTE_ADDR'] = getHostByName(getHostName());
class MyFancyStuffCli extends JApplicationCli {
public function doExecute() {
$app = Factory::getApplication('site');
$this->out('My Fancy Stuff CLI application');
$this->out('------------------------------');
// Log in so we have a valid session
if( ! $app->login([
'username' => 'username'
,'password' => 'so-super-secret'
])) {
$this->out('Login failed. Abort.');
die();
}
$user = Factory::getUser();
$this->out('Logged in successfully as ' . $user->name . '' . $user->id . ' [' . $user->username . ']');
// Init virtuemart
if( ! class_exists( 'VmConfig' )) require_once(JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/config.php');
VmConfig::loadConfig();
if( ! class_exists('VmModel')) require_once(JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/vmmodel.php');
// Init virtuemart security
$vmtoken = vRequest::getFormToken();
$app->input->set($vmtoken, 1);
$app->input->set('token', $vmtoken); // propably redundant
$productdata = [
// ...
];
try{
$product_id = (int) VmModel::getModel('product')->store($productdata);
} catch (Exception $e) {
$this->out('Error storing product, caught exception:');
$this->out($e->getMessage());
}
if($product_id > 0) {
$this->out('Stored product with id #' . $product_id);
} else {
$this->out('Did not receive new product id. Hu?.');
}
} // doExecute();
} // class
JApplicationCli::getInstance('MyFancyStuffCli')->execute();
(Tested with J3 as I'm working on an older intranet system)