I am upgrading a client's CLi script that is used to automatically bulk import news items into Joomla articles. The code was originally programmed for Joomla 3 and now needs to support Joomla 4.
I have completed quite a few upgrades, but am now stuck looping through the news item data and storing it using the Content::getInstance('Article', 'ContentModel')
method. I have included my code below for reference.
Updated September 18
Current use statements
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\Component\Content\Administrator\Model\ArticleModel;
use Joomla\CMS\Table\Content;
use Joomla\CMS\Filter\OutputFilter;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Joomla\Console\Command\AbstractCommand;
Use of $app = Factory::getApplication();
Current insertArticles
function
private function insertArticles(array $articles): array {
$articleModel = new ArticleModel();
foreach ($this->removeDuplicateAliases($articles) as $article) {
$articleData = [
'id' => 0,
'catid' => 13,
'title' => ucwords(strtolower($article->title)),
'alias' => OutputFilter::stringURLSafe($article->title),
'introtext' => strip_tags($article->storySummary, ['p', 'img', 'table']),
'fulltext' => strip_tags($article->content, ['p', 'img', 'table']),
'note' => 'DTN supplied topics: ' . str_replace('/', ', ', $article->topic),
'state' => 1,
'access' => 1,
'created_by' => 386,
'created_by_alias' => 'DTN News',
'language' => '*',
'metadata' => [
'xreference' => $article->dtnpfUrl,
],
'attribs' => [
'show_publish_date' => 1,
],
'rules' => [
'core.edit.delete' => [],
'core.edit.edit' => [],
'core.edit.state' => []
],
];
if (!$articleModel->save($articleData)) {
throw new Exception($articleModel->getError());
} else {
$newIds[] = $articleModel->getItem()->id;
}
}
return $newIds ?? [];
}
Updated
Included use statements from the command file for reference:
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\ItemModel;
use Joomla\Component\Content\Site\Model;
use Joomla\CMS\Table\Content;
use Joomla\CMS\Filter\OutputFilter;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Joomla\Console\Command\AbstractCommand;
Command line error
Class "Ploszmarketing\Plugin\Console\Dtnnews\CliCommand\ArticleModel" not found
protected function doExecute(InputInterface $input, OutputInterface $output): int {
$symfonyStyle = new SymfonyStyle($input, $output);
$symfonyStyle->title('DTN News Import');
// Fetch the JSON data and Run the insertArticle bulk data import to articles function
$curlOpts = [
CURLOPT_URL => 'https://api.dtn.com/publishing/news/articles?categoryId=1%2C2%2C3%2C4%2C5%2C6%2C16%2C17&limit=10&maxAge=15&apikey=placeholder',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
];
try {
$fetchedArticles = $this->curlToObject($curlOpts);
if ($fetchedArticles) {
$symfonyStyle->title(Text::_('Fetched Articles: ' . count($fetchedArticles)));
}
// Errors occur here
$insertedIds = $this->insertArticles($fetchedArticles);
if ($insertedIds) {
$symfonyStyle->title(Text::_('Inserted IDs: ' . implode(', ', $insertedIds)));
}
} catch (exception $e) {
$symfonyStyle->error(Text::_($e->getMessage()));
}
$symfonyStyle->success('Successful import!');
return 0;
}
private function curlToObject(array $curlOpts): array {
$ch = curl_init();
curl_setopt_array($ch, $curlOpts);
$result = curl_exec($ch);
$error = curl_error($ch); // Get the last error
curl_close($ch);
if ($error) {
throw new Exception($error);
}
return json_decode($result);
}
private function insertArticles(array $articles): array {
// Replaced articleModel method with recommendation
// $articleModel = Content::getInstance('Article', 'ContentModel');
$articleModel = new ArticleModel();
foreach ($this->removeDuplicateAliases($articles) as $article) {
$articleData = [
'id' => 0,
'catid' => 13,
'title' => ucwords(strtolower($article->title)),
'alias' => OutputFilter::stringURLSafe($article->title),
// I know strip_tags is deprecated for 8.2. I will fix after issues are resolved.
'introtext' => strip_tags($article->storySummary, ['p', 'img', 'table']),
'fulltext' => strip_tags($article->content, ['p', 'img', 'table']),
'note' => 'DTN supplied topics: ' . str_replace('/', ', ', $article->topic),
'state' => 1,
'access' => 1,
'created_by' => 386,
'created_by_alias' => 'DTN News',
'language' => '*',
'metadata' => [
'xreference' => $article->dtnpfUrl,
],
'attribs' => [
'show_publish_date' => 1,
],
'rules' => [
'core.edit.delete' => [],
'core.edit.edit' => [],
'core.edit.state' => []
],
];
if (!$articleModel->save($articleData)) {
throw new Exception($articleModel->getError());
} else {
$newIds[] = $articleModel->getItem()->id;
}
}
return $newIds ?? [];
}
private function removeDuplicateAliases(array $articles): array {
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query
->select('a.alias')
->from($db->quoteName('#__content', 'a'))
->where($db->quoteName('a.catid') . " = " . $db->quote('13'));
$db->setQuery($query);
$aliasLookup = array_flip($db->loadColumn());
foreach ($articles as $i => $article) {
if (isset($aliasLookup[OutputFilter::stringURLSafe($article->title)])) {
unset($articles[$i]);
}
}
return $articles;
}
Error in the command line: Call to a member function save() on bool
Exception trace:
at /var/www/upgrade/plugins/console/dtnnews_cli/src/CliCommand/RunDtnnewsCommand.php:126
Ploszmarketing\Plugin\Console\Dtnnews\CliCommand\RunDtnnewsCommand->insertArticles() at /var/www/upgrade/plugins/console/dtnnews_cli/src/CliCommand/RunDtnnewsCommand.php:68
Ploszmarketing\Plugin\Console\Dtnnews\CliCommand\RunDtnnewsCommand->doExecute() at /var/www/upgrade/libraries/vendor/joomla/console/src/Command/AbstractCommand.php:235
Joomla\Console\Command\AbstractCommand->execute() at /var/www/upgrade/libraries/vendor/joomla/console/src/Application.php:1181
Joomla\Console\Application->runCommand() at /var/www/upgrade/libraries/vendor/joomla/console/src/Application.php:403
Joomla\Console\Application->doExecute() at /var/www/upgrade/libraries/src/Application/ConsoleApplication.php:206
Joomla\CMS\Application\ConsoleApplication->doExecute() at /var/www/upgrade/libraries/vendor/joomla/console/src/Application.php:448
Joomla\Console\Application->execute() at /var/www/upgrade/libraries/src/Application/ConsoleApplication.php:259
Joomla\CMS\Application\ConsoleApplication->execute() at /var/www/upgrade/cli/joomla.php:76
I am unsure of how to handle the for loop
with the new model in Joomla 4.
The Joomla 3 insertArticles function is below
private function insertArticles(array $articles): array {
require_once JPATH_ADMINISTRATOR . '/components/com_content/models/article.php';
$articleModel = new ContentModelArticle([]);
foreach ($this->removeDuplicateAliases($articles) as $article) {
$articleData = [
'id' => 0,
'catid' => 13,
'title' => ucwords(strtolower($article->title)),
'alias' => JFilterOutput::stringURLSafe($article->title),
'introtext' => strip_tags($article->storySummary, ['p', 'img', 'table']),
'fulltext' => strip_tags($article->content, ['p', 'img', 'table']),
'note' => 'DTN supplied topics: ' . str_replace('/', ', ', $article->topic),
'state' => 1,
'access' => 1,
'created_by' => 386,
'created_by_alias' => 'DTN News',
'language' => '*',
'metadata' => [
'xreference' => $article->dtnpfUrl,
],
'attribs' => [
'show_publish_date' => 1,
],
'rules' => [
'core.edit.delete' => [],
'core.edit.edit' => [],
'core.edit.state' => []
],
];
if (!$articleModel->save($articleData)) {
throw new Exception($articleModel->getError());
} else {
$newIds[] = $articleModel->getItem()->id;
}
}
return $newIds ?? [];
}
Any assistance is greatly appreciated.