We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Why do I need to pass the modules list as an array in a Console app?

Hello, this is my first post, so bear with me. :)

We're working with a HMVC architecture, and a solid bootstraping platform above phalcon's bootstrapping process. I'm currently trying to get the application to be environment call agnostic, and respond to web calls and CLI calls. What I stumbled on, is this error:

php index.php cms cron backup session

Invalid module definition path in file phalcon/cli/console.zep on line 190

0 /www/tmd/stormy/public/core/classes/Loader/Loader.php(135): Phalcon\Cli\Console->handle(Array)

1 /www/tmd/stormy/public/index.php(16): TMD\Core\Loader->handle()

2 {main}%

Which I thought was strange, since this is what's on that line:

        let module = modules[moduleName];

        if typeof module != "array" {

            throw new Exception("Invalid module definition path");

        }

The modules array I'm passing is an array of callbacks, which is working fine in the regular web call, and the \Phalcon\Mvc\Application.

tl;dr: Why should I pass the module callbacks as an array when I'm in a console call? Is this check needed at all? If it is - why?

edited Jul '16

I did something similar, in terms of making CLI app to reuse services container from main (MVC) app. But, what you're trying here is different, basically you want to have one single index.php (Front Page Controller and CLI app 2in1), then you'd need to apply some logic inside of it.

Main DI for CLI should be defined in as \Phalcon\Di\FactoryDefault\Cli, while main app has different namespace and components (both MVC and Micro). Then Phalcon\Cli\Console is the component which handles CLI tasks, while MVC is defined as:

php $application = new \Phalcon\Mvc\Application($di);

What I would do - try to find the most common components which are valid for both environments. Then, simply switch bootstrap by adding only required components depending on which environment you currently execute.

   switch (php_sapi_name()){ //or just global constant PHP_SAPI
            case 'cli':
                    //define CLI app
                break;
            default:
                //main APP is also default, define it here
                break;
            }

Hello again, and thanks for the reply. You're right, there are some services that need to be entirely different between the CLI and web runs. What I did, was basically set a global config flag whether I'm in a CLI call, and built from that. Also, I abstracted all the shared functionality in a trait, in order to be able to do this:

<?php

    /****
     * Regular app call
     */
    class CmsApp extends \Phalcon\Mvc\Application
    {
        use TMD\Core\Application;
    }

    /****
     * Console app call
     */
    class CmsCliApp extends \Phalcon\Cli\Console
    {

        use TMD\Core\Application;

    }

I did this for the DI also, and I had to stop the manual service instantiation for the router (since the cli app has its own router) and the dispatcher (same story), and I had to write a separate CronModule definition, in order to make phalcon recognize it as a legit module. All in all, it's doable, if still ugly and requiring too many checks that need to ber abstracted away in the core. Good thing I had a Loader class to deal with these, otherwise it would've been a mess.