:::{php:namespace} Atk4\Ui :::
:::{php:class} Console :::
:::{figure} images/console.png :::
With console you can output real-time information to the user directly from PHP. It can
be used do direct output from slow method or even execute commands on the server (such as ping
).
Demo: https://ui.atk4.org/demos/interactive/console.php
:::{php:method} set($callback) :::
:::{php:method} send($callback) :::
After adding a console to your {ref}render_tree
, you just need to set a callback:
$console = Console::addTo($app);
$console->set(function (Console $console) {
// this will be executed through SSE request
$console->output('hello');
echo 'world'; // also will be redirected to console
sleep(2);
$console->send(new \Atk4\Ui\Js\JsExpression('alert([])', ['The wait is over']));
});
Console uses {ref}sse
which works pretty much out-of-the-box with the modern browsers and unlike websockets
do not require you to set up additional ports on the server. JavaScript in a browser captures real-time
events and displays it on a black background.
Console integrates nicely with DebugTrait (https://atk4-core.readthedocs.io/en/develop/debug.html?highlight=debug), and also allows you to execute shell process on the server while redirecting output in real-time.
:::{php:method} runMethod($callback) :::
We recommend that you pack up your busineess logic into your Model methods. When it's time to call your method, you could either do this:
$user->generateReport(30);
Which would execute your own routine for some report generation, but doing it though a normal request will look like your site is slow and is unable to load page quick. Alternative is to run it through a console:
$console->runMethod($user, 'generateReport', [30]);
This will display console to the user and will even output information from inside the model:
use \Atk4\Core\DebugTrait();
public function generateReport($pages)
{
$this->info('converting report to PDF');
// slow stuff
$this->info('almost done, be patient..');
// more slow stuff
return true;
}
You can also execute static methods:
$console->runMethod('StaticLib', 'myStaticMethod');
:::{php:method} exec($cmd, $args) :::
:::{php:attr} lastExitCode :::
To execute a command, use:
$console->exec('/sbin/ping', ['-c', '5', '-i', '1', '192.168.0.1']);
This will run a command, and will stream command output to you. Console is implemented to capture both STDOUT and STDERR in real-time then display it on the console using color. Console does not support ANSI output.
Method exec can be executed directly on the $console or inside the callback:
$console->set(function (Console $console) {
$console->eval();
});
Without callback, eval will wrap itself into a callback but you can only execute a single command. When using callback form, you can execute multiple commands:
Console::addTo($app)->set(function (Console $c) {
$c
->exec('/sbin/ping', ['-c', '5', '-i', '1', '192.168.0.1'])
->exec('/sbin/ping', ['-c', '5', '-i', '2', '8.8.8.8'])
->exec('/bin/no-such-command');
});
Method exec() will return $this
if command was run inside callback and was successful. It will return false
on error
and will return null
if called outside of callback. You may also refer to {php:attr}Console::$lastExitCode
which
contains exit code of the last command.
Normally it's safe to chain exec
which ensures that execution will stack. Should any command fail, the subsequent
exec
won't be performed.
NOTE that for each invocation exec
will spawn a new process, but if you want to execute multiple processes, you
can wrap them into bash -c
:
Console::addTo($app)->exec('bash', [
'-c',
'cd ..; echo \'Running "composer update" in `pwd`\'; composer --no-ansi update; echo \'Self-updated. OK to refresh now!\'',
]);
This also demonstrates argument escaping.