QT Console Commands

Softberg Sb
6 min readJun 12, 2022

--

If you are from PHP’s world you have at least used composer to install some libraries or dependencies for your project by opening your terminal window and typing something like:

> php composer install

By doing this, in fact you are running some sort of command. Sure enough you have to have the composer installed previously in order to run this command. Similar to this there are lot's of different commands available depending what libraries or framework you are using. You can create your own custom commands to do some work behind the scene like batch jobs, some supportive tasks via cron etc. Commands are run on the server so nothing will be shown or run on the browser, the browser can even not involved at all. The commands can call other commands as well to accomplish their job.
The Quantum PHP Framework also has ability to interact with console commands and also lets you create your own ones...

Installing New Quantum Project

As always first thing to do is to install new Quantum project via composer and name it as “commands”:

> composer create-project quantum/project commands

As the composer downloads and install the project and its dependencies, you can follow the process of each instruction happening on the terminal screen. At the and of the installation you will see some additional commands appearing on the screen like:

These 4 commands are specific for Quantum PHP framework and they are called by composer at installation. If for some reason one of these commands are not applied, you can run them manually anytime from the terminal . For example:

> php qt core:env

This command creates .env file for your project (in fact it just clones the .env.example with different name).

> php qt core:key --length=64

This command generates app key for your project. Notice that it has also additional option --length=64. We will discuss about options and arguments a bit later.

Ok, I think you got the idea, the first thing is mentioned there is the keyword which is the PHP interpreter itself. After that comes the keyword qt which is the key player of running console commands ( qt is the console application it's an abbreviation of word quantum).
The qt lives in your project root and can be called only from that directory, so you can't call php qt ... outside of root directory or from any other directory.
The next part you will notice is core:{name} where the word before the colons are the namespace and the word after colon is the actual command name.

Exploring Quantum built in commands

The commands we discussed above where core commands, meaning they are located inside frameworks core. Other commands which are project specific are located at shared/Commands directory.
In order to discover what commands are available you can simply type:

> php qt list

The console command structure

Now let’s have a look one of available commands from the project and let’s take the install:demo one which is located at shared/Commands directory (DemoCommand.php).

/** 
* Class DemoCommand
* @package Shared\Commands
*/
class DemoCommand extends QtCommand
{
/**
* Command name
* @var string
*/
protected $name = 'install:demo';
/**
* Command description
* @var string
*/
protected $description = 'Generates demo users and posts';
/**
* Command help text
* @var string
*/
protected $help = 'The command will create 2 new files (users.php and posts.php) and will generate records';
. . .

First thing to notice here is that the command classes should extend QtCommand base class. Next pay attention to the next 3 protected properties:

protected $name - This is the command name (in this case it's install:demo) and in order to call run the command, they should be called by name.

protected $description - This is the command description, which will be displayed with command name when you list the commands.

protected $help - This is some help text you can specify there to help developers understand your command better. In order to see the help text you need to type something like:

> php qt install:demo --help

which will show the help text for that command

Attributes and Options

Commands also can have arguments and options. To tell your command to accept either arguments or options or both together, you need specify them like this:

/** 
* Command arguments
* @var \string[][]
*/
protected $args = [
['email', 'required', 'User email'],
['role', 'optional', 'User role']
];

The $args array contains the list of the arguments, which are also arrays and they have special structure.
The first element is the name of the argument, the second one tells whether it's required or optional. The third one is the description.

/** 
* Command options
* @var array
*/
protected $options = [
['title', 't', 'optional', 'Post title'],
['description', 'd', 'optional', 'Post description']
];

Similarly, the $options array contains the list of command options. The first element is the option name, the second is the shortcut. The third element is the type which can be optional or required (although when it's required it doesn't mean the option should should be provided, it's only becomes required when you specified the option name at command call). Forth is the description.
To receive the argument passed from terminal you can use $this->getArgument('email').
For option use $this->getOption('title').

Next, let’s take a look to the exec() method, which is automatically getting called at command run.

/** 
* Command constructor
*/
public function __construct()
{
parent::__construct();
$this->faker = Factory::create();
$this->faker->addProvider(
new PicsumPhotosProvider($this->faker)
);
}
/**
* Executes the command
* @throws \Quantum\Exceptions\DiException
*/
public function exec()
{
for ($i = 1; $i <= self::USER_COUNT; $i++){
$userArguments = $this->newUser('editor');
$this->runCommand(
self::COMMAND_USER_CREATE,
$userArguments
);
}
$serviceFactory = Di::get(ServiceFactory::class);
$authService = $serviceFactory->get(AuthService::class);
$users = $authService->getAll();
foreach ($users as $user){
for ($i = 1; $i <= self::POST_COUNT_PER_USER; $i++) {
$postArguments = [
'title' => str_replace(
['"', '\'', '-'],
'',
$this->faker->realText(50)
),
'description' => str_replace(
['"', '\'', '-'],
'',
$this->faker->realText(1000)
),
'image' => $this->faker->imageUrl(
640,
480,
true,
0
),
'user_id' => $user['id'],
];
$this->runCommand(
self::COMMAND_POST_CREATE,
$postArguments
);
}
}
$this->info('Demo installed successfully');
}
/**
* Runs the external command
* @throws \Exception
*/
protected function runCommand($commandName, $arguments)
{
$command = $this->getApplication()->find($commandName);
$command->run(new ArrayInput($arguments), new NullOutput);
}

The demo command goal is to create demo users and posts for the project, so if you take a look at the exec() method, you will see that it exactly doing the operations to create demo users and demo posts.

But also notice that the command does not contain the logic of creating users and posts, it’s just calls additional commands (through the runCommand()) which are already there to accomplish its job.

The complete codebase can be found at: https://github.com/softberg/quantum-php-project/blob/master/shared/Commands/DemoCommand.php

You can take a look at the other commands to see what they are doing. You will easily found out that they are all shares the same signature. So if you decide to create your own one, you will also have to follow the same structure of qt console commands.

Good luck with playing qt console commands.

Originally published at http://blog.softberg.org on June 12, 2022.

--

--