0

I have what I thought would be a simple challenge: to automate publishing an article and trigger the onAfterContentSave event for saving the article. This code ultimately has to run within another plugin: Community Builder Auto Actions triggered by a Joomla! 4 Task Scheduler task. For now I am testing this at the command line using a verified working framework loading script.

I am not sure what I am doing wrong, but here's the code thus far. The techniques used below (middle to end of code) were obtained elsewhere online.

include ("joomla-framework.php");
use Joomla\CMS\Plugin\PluginHelper;

// (THIS WORKS) Get the oldest unpublished article whose title includes the word "test" and whose publish date is in the future.
$db = JFactory::getDbo();
$db->setQuery("SELECT id FROM `#__content` WHERE title LIKE '%test%' AND state=0 ORDER BY created ASC LIMIT 1;");
$articleId = $db->loadResult();

if ($articleId) // if there isn't one, don't do anything.
{
    //  (THIS WORKS) make sure the article is published
    $article = JTable::getInstance('content');
    $article->load($articleId);
    $article->state = 1;
    $article->store();

    $params = new stdClass();
/*
    // (THIS DOESN'T WORK) trigger the onContentAfterSave event for this article
    PluginHelper::importPlugin('content');
    $app = JFactory::getApplication();
    $app->triggerEvent('onContentAfterSave', array('com_content.article', &$article, &$params, 0));
*/

// This doesn't seem to work either, but it was my last attempt
$dispatcher = Joomla\CMS\Factory::getApplication()->getDispatcher();
$event = new Joomla\Event\Event('onContentAfterSave', array('com_content.article', &$article, &$params, 0));
$res = $dispatcher->dispatch('onContentAfterSave', $event);

The idea here is to trigger onContentAfterSave on the identified article, which has a custom field (flag) telling one of my plugins to send an email containing the article. That plugin works perfectly when saving a published article in either the site front or back end, but I need to be able to trigger it from a Task Scheduler cronjob.

Any assistance would be truly appreciated. Thanks in advance!

P.S. No errors are occurring with either of the two above triggering methods.

Edit: Looking around a bit more, I think that first method was along the right line. Here's what I think that last part should look like. Note that this doesn't trigger the event either.

// trigger the onContentAfterSave event for this article (THIS DOESN'T WORK)
Factory::getApplication()->triggerEvent('onContentAfterSave', ['com_content.article', &$article, false, array()]);

Bruce

2
  • My first guess is you're incorrectly bootstrapping Joomla and the call to Joomla\CMS\Factory::getApplication() is actually causing an error. Would need to see contents of joomla-framework.php to confirm. And if you intend to use Joomla's task scheduler, you should develop a task plugin instead of creating an external script.
    – Sharky
    Sep 14, 2023 at 7:38
  • It doesn't work when run as a CB Auto Action either, which is how it will eventually be used. I'm using the external environment to debug it. If there was an issue reaching any Joomla classes, I'd get an error. Believe me, I've seen plenty of them during this effort. I'd be happy to post the joomla-framework script, but I'll have to do that from home. I didn't write it myself, but it works quite well. Been using it for years.
    – Bruce S
    Sep 14, 2023 at 13:53

1 Answer 1

0

Assuming you're using CliApplication it's maybe the case that it doesn't get everything it needs out of the Dependency Injection container. (I know that it doesn't get the JConfig params for example).

I suggest you try the following. Instead of

$app = Factory::getApplication();

try doing:

$dic = Factory::getContainer();
$app = $dic->get('Joomla\CMS\Application\ConsoleApplication');

For a proper solution you'd be best to go down the route of writing a Joomla 4 CLI Application though.

Update -------------------------------------

The other thing you could try would be to enclose your code after including your joomla-framework.php within a class which extends Joomla\CMS\Application\CliApplication:

use Joomla\CMS\Application\CliApplication;

class Testapp extends CliApplication
{
    public function doExecute()
    {
        Factory::$application = $this;  // you probably need this
        $dic = Factory::getContainer();
        $app = $dic->get('Joomla\CMS\Application\ConsoleApplication');
        Factory::$application = $app;  // you might need this too
        //etc
    }

    public function getName()   // you need to specify this function
    {
        return "test";  // doesn't matter what you set
    }
}

CliApplication::getInstance('Testapp')->execute();
5
  • Hey Robbie, thanks for the suggested alternative code. It did not work either. I have a feeling you're on the right track, though, regarding not having all the necessary dependencies. After all, this event would get triggered through an editor saving an article. I have been guessing the context is content.article and that would suffice, but that doesn't appear to be the case (or I'm doing it wrong). I'll give that CLI page(s) a read to see if it leads anywhere. Much appreciated! -- Bruce
    – Bruce S
    Sep 15, 2023 at 13:50
  • Bruce I've added another suggestion just in case you want to persist with trying to get it to work. But really the way to go is with the newer Joomla 4 CLI approach - it's really quite straightforward. Sep 15, 2023 at 18:09
  • Hey Robbie, I gave the CLI container method a try. And, although it ran without error, it did not work either. So, rather than shooting for this approach where I update the article and (try to) trigger the onContentAfterSave event directly, I am going to look for how Joomla core does it. I already spent some time looking for that, but could not locate that code. It's all about knowing what to grep for. Thanks for all your suggestions thus far.
    – Bruce S
    Sep 15, 2023 at 18:43
  • Yeah it's in AdminModel::save() in libraries/src/MVC/Model/AdminModel.php. The instance variable $this->event_after_save gets set up in the constructor. Sep 15, 2023 at 20:09
  • The part of that save() method that "does the work" of interest is doing much the same thing my code is doing with a couple exceptions. 1) My code does not include any plugins for the save events. I suspect this might be at the heart of the issue, but I have had difficulty getting those to load due to dependencies deep within the core code that somehow aren't met where I'm calling importPlugin. 2) My code does not first trigger any "before save" event. And though I doubt that's critical, it might be part of the whole equation. Anyway, two things I need to work into my logic. Thanks Robbie!
    – Bruce S
    Sep 16, 2023 at 0:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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