0

I'm working with a JoomlaCli Application, called from a external php command via a cronjob. It worked in Joomla 3, but in Joomla 4 some classes have changed.

Our class name is import

Namespaces:

use GreenCape\Import\Core\Logger;
use GreenCape\Import\Core\Timer;
use GreenCape\Import\Exception\BusyException;
use GreenCape\Import\Reader\ReaderInterface;
use GreenCape\Import\Writer\WriterInterface;
use Joomla\Registry\Registry;
use Psr\Log\LoggerInterface;

// Import namespaced classes
use Joomla\CMS\Factory;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Version;
use Joomla\Console\Application;
use Joomla\Console\Command\AbstractCommand;

some inits

// Set flag that this is a parent file.
const _JEXEC = 1;

error_reporting(E_ALL | E_NOTICE);
ini_set('display_errors', 1);
date_default_timezone_set('UTC');

// Load system defines
if (file_exists(dirname(__DIR__) . '/defines.php'))
{
    require_once dirname(__DIR__) . '/defines.php';
}

if (!defined('_JDEFINES'))
{
    define('JPATH_BASE', dirname(__DIR__));
    require_once JPATH_BASE . '/includes/defines.php';
}

require_once JPATH_LIBRARIES . '/import.legacy.php';
require_once JPATH_LIBRARIES . '/cms.php';

// Load the configuration
require_once JPATH_CONFIGURATION . '/configuration.php';

require_once __DIR__ . '/import/autoload.php';

the crucial class definition with the execute definition

 class Import extends JApplicationCli
{
    /** @var JInputCli The input */
    public $input = null;

    /** @var  LoggerInterface */
    protected $logger;

    private $update = true;
    private $delete = false;

    private $quiet = false;
    private $debug = true;
    private $verbose = false;

    private $importConfig;
    private $type;

    /** @var  Lock */
    private $lock;
    private $force;

    public function __construct(JInputCli $input = null, Registry $config = null, JEventDispatcher $dispatcher = null)
    {
        parent::__construct($input, $config, $dispatcher);
    }

    /**
     * Entry point for the script
     *
     * Exit codes:
     *
     *   - 0: Everything went as expected.
     *   - 1: An exception occurred.
     *   - 2: Import is already running.
     *
     * @return  void
     */
    public function doExecute()
    {
        try
        {
            if (!defined('JDEBUG'))
            {
                define('JDEBUG', false);
            }

            JFactory::$application = $this;

            $this->handleOptions();
            $this->hello();

            #$this->logger->debug("Config: " . print_r($this->importConfig, true), ['import']);

            if (count($this->input->args) != 1)
            {
                $this->quiet = false;
                $this->usage();
            }

            $this->type = $this->input->args[0];
            $this->lock = new Lock($this->type);

            if (!isset($this->importConfig[$this->type]))
            {
                $available = implode(', ', array_keys($this->importConfig));
                throw new \RuntimeException("Don't know how to import {$this->type}. Known data types are {$available}");
            }
            $this->importConfig[$this->type]['logger'] = $this->logger;

            $readerClass = $this->importConfig[$this->type]['reader_class'];
            $writerClass = $this->importConfig[$this->type]['writer_class'];

            $this->lock->lock($this->force);
            $this->logger->info("Importing {$this->type}", ['import']);
            $returnValue = $this->import(
                new $readerClass($this->importConfig[$this->type]),
                new $writerClass($this->importConfig[$this->type])
            );
            $this->lock->unlock();
        } catch (BusyException $e)
        {
            $this->out($this->type . " import is already running.");
            $returnValue = 2;
        } catch (\Exception $e)
        {
            $this->out('Exception: ' . $e->getMessage());
            $this->logger->error($e->getMessage());

            if ($this->debug)
            {
                $this->out($e->getTraceAsString());
            }
            $returnValue = 1;
            $this->lock->unlock();
        }

        $this->close($returnValue);
    }
...

and finally the instance called

JApplicationCli::getInstance('Import')->execute();

I got a static error,

Class Import contains 1 abstract method and must therefore be declared abstract or implement the remaining methods

so I defined the missing class with an empty function.

Some hours down the line I still can't call the instance, asking myself if the script can be saved anywhere or if it will be necessary to switch from extends JApplicationCli to extends Application for Joomla 5 anyways.

Any suggestions? I can provide the full code if any helpful, just didn't want to spam the thread.

Thank you!

4
  • I think it should still be possible to get it to work - I found that ok with a Joomla 3 CLI script. The constructor for JApplicationCli has changed in v4. As your constructor doesn't do anything you could try just removing it. Do you get any errors reported? If you want to go down the route of updating to fit in with the Joomla 4 console, then I found that good descriptions are at docs.joomla.org/J4.x:Writing_A_CLI_Application and dionysopoulos.me/book/com-cli.html Jun 28, 2023 at 8:39
  • You should update the question with the errors you're getting now, after implementing the missing methods.
    – Sharky
    Jun 29, 2023 at 5:35
  • Thank you for your feedback. Thats exactly my problem: Getting no errors from joomla or php error output/log but only a blank page. I tried to remove the constructor with no changes in that behavior. Any clue how to find out on what line the script fails or to force any error reports?
    – Corak55
    Jul 5, 2023 at 10:30
  • You might consider creating a new question, with a reference back to this one if you like, showing where you are at now with your code bow that you have a working instance of Joomla 4. It is like your issues is in two parts and the first question has been answered and now we need to see the actual code for the second question to help you get something that works.
    – Irata
    Jul 7, 2023 at 6:06

2 Answers 2

1

Your code needs to be updated to form the Joomla 4 application environment correctly as there are major changes between what you have for Joomla 3 and the way Joomla 4 now loads.

You can use the code I have provided in this post, How to create an instance of the Joomla CMS from the browser or the command line, to replace the second block of the code that you have pasted in your question to get the right instance of Joomla. You will need to use the last block in Part 1, for the CLI application, and remove the previous three blocks of code.

JApplicationCli is still available until Joomla 6, however it can be replaced with Joomla\CMS\Application\CliApplication now. JInput and JFactory are also depreciated.

And if you want to modernise your code you could look at the documentation around Joomla Console to make it a console command and then you can call it as a cron job or via a terminal command line. I have found it better to use the console approach and have been converting my old cli code across when I can.

2
  • Thank you irata, with that input I was able to create a empty but working joomla app container. Right now I'm struggeling with transporting some of the old code into the new script as I don't get any errors reported - just a white page. How would you proceed to get some errors reported? Maybe I overlook something?
    – Corak55
    Jul 5, 2023 at 10:34
  • You could start by turning on Debug and Error Reporting through the Global Settings of your Joomla instance, however if you don't have the normal back-end/administrator interface pages available to this instance then you need to update the values directly in '../configuration.php'
    – Irata
    Jul 5, 2023 at 23:44
0

I found after troubleshooting a Joomla 3 CLI application that was failing to work properly on Joomla 4 that if you use either:

Factory::getConfig();
Factory::getApplication()->getConfig(); 

then you don't get what you expect. You just get a couple of parameters set:

  • 'cwd' - the working directory
  • 'execution' - timestamp

You don't get the global configuration parameters set in configuration.php.

To get the parameters you have to do:

Factory::getContainer()->get('config');

which will return them properly. However, you may be using bits of Joomla library code which expects to call $application->getConfig() to get the parameters, and so these library routines will fail.

(I found a problem with the mailer, as I wasn't setting the sender address in my code. In Joomla 3 it correctly picked the default sender details from the global config, but in Joomla 4 it didn't, and the email got sent with no sender. The receiving email service btinternet seemed to accept that ok, and the email got through, but gmail rejected it).

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.