Related
So I have a Laravel controller:
class YeahMyController extends BaseController {
public function getSomething() {
Console::info('mymessage'); // <-- what do I put here?
return 'yeahoutputthistotheresponse';
}
}
Currently, I'm running the application using artisan (which runs PHP's built-in development web server under the hood):
php artisan serve
I would like to log console messages to the STDOUT pipe for the artisan process.
Aha!
This can be done with the following PHP function:
error_log('Some message here.');
Found the answer here: Print something in PHP built-in web server
The question relates to serving via artisan and so Jrop's answer is ideal in that case. I.e, error_log logging to the apache log.
However, if your serving via a standard web server then simply use the Laravel specific logging functions:
\Log::info('This is some useful information.');
\Log::warning('Something could be going wrong.');
\Log::error('Something is really going wrong.');
Or with current version of Laravel, like this:
info('This is some useful information.');
This logs to Laravel's log file located at /laravel/storage/logs/laravel-<date>.log (laravel 5.0). Monitor the log - linux/osx: tail -f /laravel/storage/logs/laravel-<date>.log
Laravel 5.0 http://laravel.com/docs/5.0/errors
Laravel 4.2: http://laravel.com/docs/4.2/errors
I haven't tried this myself, but a quick dig through the library suggests you can do this:
$output = new Symfony\Component\Console\Output\ConsoleOutput();
$output->writeln("<info>my message</info>");
I couldn't find a shortcut for this, so you would probably want to create a facade to avoid duplication.
It's very simple.
You can call it from anywhere in APP.
$out = new \Symfony\Component\Console\Output\ConsoleOutput();
$out->writeln("Hello from Terminal");
In Laravel 6 there is a channel called 'stderr'. See config/logging.php:
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
In your controller:
use Illuminate\Support\Facades\Log;
Log::channel('stderr')->info('Something happened!');
For better explain Dave Morrissey's answer I have made these steps for wrap with Console Output class in a laravel facade.
1) Create a Facade in your prefer folder (in my case app\Facades):
class ConsoleOutput extends Facade {
protected static function getFacadeAccessor() {
return 'consoleOutput';
}
}
2) Register a new Service Provider in app\Providers as follow:
class ConsoleOutputServiceProvider extends ServiceProvider
{
public function register(){
App::bind('consoleOutput', function(){
return new \Symfony\Component\Console\Output\ConsoleOutput();
});
}
}
3) Add all this stuffs in config\app.php file, registering the provider and alias.
'providers' => [
//other providers
App\Providers\ConsoleOutputServiceProvider::class
],
'aliases' => [
//other aliases
'ConsoleOutput' => App\Facades\ConsoleOutput::class,
],
That's it, now in any place of your Laravel application, just call your method in this way:
ConsoleOutput::writeln('hello');
Hope this help you.
If you want the fancy command IO from Laravel (like styling, asking and table) then I created this class below
Instructions
I have not fully verified everywhere that it is THE cleanest solution etc, but it works nice (but I only tested it from within a unit test case, under Laravel 5.5).
So most probably you can use it however you like:
$cmd = new ConsoleCommand;
$cmd->error("Aw snap!");
$cmd->table($headers, $rows);
$answer = $cmd->ask("Tell me, what do you need?");
//even Symfony's progress bar
$cmd->outputStyle->progressStart(5); //set n = 100% (here 100% is 5 steps)
$cmd->outputStyle->progressAdvance(); //you can call it n times
$cmd->outputStyle->progressFinish(); //set to 100%
Or course you can also wrap in your own facade, or some static singleton etc, or anyway you wish.
The class itself
class ConsoleCommand extends \Illuminate\Console\Command
{
protected $name = 'NONEXISTENT';
protected $hidden = true;
public $outputSymfony;
public $outputStyle;
public function __construct($argInput = null)
{
parent::__construct();
$this->input = new \Symfony\Component\Console\Input\StringInput($argInput);
$this->outputSymfony = new \Symfony\Component\Console\Output\ConsoleOutput();
$this->outputStyle = new \Illuminate\Console\OutputStyle($this->input, $this->outputSymfony);
$this->output = $this->outputStyle;
}
}
I wanted my logging information to be sent to stdout because it's easy to tell Amazon's Container service (ECS) to collect stdout and send it to CloudWatch Logs. So to get this working, I added a new stdout entry to my config/logging.php file like so:
'stdout' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'with' => [
'stream' => 'php://stdout',
],
'level' => 'info',
],
Then I simply added 'stdout' as one of the channels in the stack log channel:
'default' => env('LOG_CHANNEL', 'stack'),
'stack' => [
'driver' => 'stack',
'channels' => ['stdout', 'daily'],
],
This way, I still get logs in a file for local development (or even on the instance if you can access it), but more importantly they get sent to the stdout which is saved in CloudWatch Logs.
If you want to log to STDOUT you can use any of the ways Laravel provides; for example (from wired00's answer):
Log::info('This is some useful information.');
The STDOUT magic can be done with the following (you are setting the file where info messages go):
Log::useFiles('php://stdout', 'info');
Word of caution: this is strictly for debugging. Do no use anything in production you don't fully understand.
Bit late to this...I'm surprised that no one mentioned Symfony's VarDumper component that Laravel includes, in part, for its dd() (and lesser-known, dump()) utility functions.
$dumpMe = new App\User([ 'name' => 'Cy Rossignol' ]);
(new Symfony\Component\VarDumper\Dumper\CliDumper())->dump(
(new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($dumpMe)
);
There's a bit more code needed, but, in return, we get nice formatted, readable output in the console—especially useful for debugging complex objects or arrays:
App\User {#17
#attributes: array:1 [
"name" => "Cy Rossignol"
]
#fillable: array:3 [
0 => "name"
1 => "email"
2 => "password"
]
#guarded: array:1 [
0 => "*"
]
#primaryKey: "id"
#casts: []
#dates: []
#relations: []
... etc ...
}
To take this a step further, we can even colorize the output! Add this helper function to the project to save some typing:
function toConsole($var)
{
$dumper = new Symfony\Component\VarDumper\Dumper\CliDumper();
$dumper->setColors(true);
$dumper->dump((new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($var));
}
If we're running the app behind a full webserver (like Apache or Nginx—not artisan serve), we can modify this function slightly to send the dumper's prettified output to the log (typically storage/logs/laravel.log):
function toLog($var)
{
$lines = [ 'Dump:' ];
$dumper = new Symfony\Component\VarDumper\Dumper\CliDumper();
$dumper->setColors(true);
$dumper->setOutput(function ($line) use (&$lines) {
$lines[] = $line;
});
$dumper->dump((new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($var));
Log::debug(implode(PHP_EOL, $lines));
}
...and, of course, watch the log using:
$ tail -f storage/logs/laravel.log
PHP's error_log() works fine for quick, one-off inspection of simple values, but the functions shown above take the hard work out of debugging some of Laravel's more complicated classes.
Here's another way to go about it:
$stdout = fopen('php://stdout', 'w');
fwrite($stdout, 'Hello, World!' . PHP_EOL);
The PHP_EOL adds new line.
In command class
before class
use Symfony\Component\Console\Output\ConsoleOutput;
Inside the class methods
$output = new ConsoleOutput();
$output->writeln('my text that appears in command line ');
You can use echo and prefix "\033", simple:
Artisan::command('mycommand', function () {
echo "\033======== Start ========\n";
});
And change color text:
if (App::environment() === 'production') {
echo "\033[0;33m======== WARNING ========\033[0m\n";
}
From Larave 6.0+
$this->info('This will appear in console');
$this->error('This error will appear in console');
$this->line('This line will appear in console);
Documentation https://laravel.com/docs/6.x/artisan#writing-output
I have recently been learning about the AppServiceProvider. I have registered a service in the AppServiceProvider which creates a singleton - an instantiated GuzzleHttp Client, like so:
$this->app->singleton('GuzzleHttp\Client', function($api) {
return new Client([
'base_uri' => env('ELASTICSEARCH_HOST'),
'auth' => [
env('ELASTICSEARCH_USER'),
env('ELASTICSEARCH_PASS')
],
]);
});
This is connecting to an ElasticSearch API, and that currently works:
$response = app('GuzzleHttp\Client')->request('GET');
I have set up a facade called ElasticSearchFacade, which contains only the getFacadeAccessor():
protected static function getFacadeAccessor()
{
return 'elasticSearch';
}
I have also registered elasticSearch in my AppServiceProvider, like so:
$this->app->bind('elasticSearch', function() {
return new ElasticSearch();
});
This creates a new ElasticSearch instance. However, I would love to pass the GuzzleHttp\Client into the elasticSearch service. So I have tried adding the following to my ElasticSearch.php file:
use GuzzleHttp\Client;
class ElasticSearch
{
protected $client;
public function __contruct(Client $client)
{
$this->client = $client;
}
public function handle()
{
$response = $this->client->request('GET');
die($response->getBody()->getContents());
}
}
I have now changed the registered service to pass through the GuzzleHttp Client like so:
$this->app->bind('elasticSearch', function() {
return new ElasticSearch(app('GuzzleHttp\Client'));
});
However I am getting the error:
PHP Error: Call to a member function request() on null
The constructor method is __construct not __contruct. You have not defined a custom constructor for your ElasticSearch class. So that member variable is null.
Side Note: do not call env outside of the configuration files.
To avoid having to make these env calls outside of configuration files you can just add configuration files as needed or add to current configuration files. Something like Elastic Search credentials can probably get added to the services.php configuration file:
<?php
return [
...
'elasticsearch' => [
'host' => env('ELASTICSEARCH_HOST'),
'user' => env('ELASTICSEARCH_USER'),
'password' => env('ELASTICSEARCH_PASS'),
],
...
];
Now that you have these in the configuration you can use the configuration system to pull these values:
config('services.elasticsearch'); // that whole array of values
config('services.elasticsearch.host'); // just that host value
Config::get('services.elasticsearch');
app('config')->get(...);
There are multiple ways to access the configuration system.
I created an application with Laravel using Graphql. But I dont how to create my unit tests. Only do it simple request with PHPUnit or have other better way to do it?
Example Query Graphql in Laravel:
class ClientQuery extends Query
{
protected $attributes = [
'name' => 'ClientQuery',
'description' => 'A query'
];
public function type()
{
return GraphQL::type("Client");
}
public function args()
{
return [
'id' => [
'type' => Type::nonNull(Type::int()),
],
];
}
public function resolve($root, $args, $context, ResolveInfo $info)
{
return Client::find($args['id']);
}
}
I'm currently using GraphQL like you.
Because I've used GraphQL files to describe my data model, I have only my resolver in PHP (like you no?).
I think you can create Unit test but it is not necessary because is the role of data model to avoid errors of Type. But you can make it to perform a better product/platform yes.
In this way, Integration tests are very important, to test resolvers.
I'm currently using API call to test resolvers, but it can change because I'm not an expert and I don't think it's the better way but for now that make the job.
I'm trying to create unit tests to test some specific classes. I use app()->make() to instantiate the classes to test. So actually, no HTTP requests are needed.
However, some of the tested functions need information from the routing parameters so they'll make calls e.g. request()->route()->parameter('info'), and this throws an exception:
Call to a member function parameter() on null.
I've played around a lot and tried something like:
request()->attributes = new \Symfony\Component\HttpFoundation\ParameterBag(['info' => 5]);
request()->route(['info' => 5]);
request()->initialize([], [], ['info' => 5], [], [], [], null);
but none of them worked...
How could I manually initialize the router and feed some routing parameters to it? Or simply make request()->route()->parameter() available?
Update
#Loek: You didn't understand me. Basically, I'm doing:
class SomeTest extends TestCase
{
public function test_info()
{
$info = request()->route()->parameter('info');
$this->assertEquals($info, 'hello_world');
}
}
No "requests" involved. The request()->route()->parameter() call is actually located in a service provider in my real code. This test case is specifically used to test that service provider. There isn't a route which will print the returning value from the methods in that provider.
I assume you need to simulate a request without actually dispatching it. With a simulated request in place, you want to probe it for parameter values and develop your testcase.
There's an undocumented way to do this. You'll be surprised!
The problem
As you already know, Laravel's Illuminate\Http\Request class builds upon Symfony\Component\HttpFoundation\Request. The upstream class does not allow you to setup a request URI manually in a setRequestUri() way. It figures it out based on the actual request headers. No other way around.
OK, enough with the chatter. Let's try to simulate a request:
<?php
use Illuminate\Http\Request;
class ExampleTest extends TestCase
{
public function testBasicExample()
{
$request = new Request([], [], ['info' => 5]);
dd($request->route()->parameter('info'));
}
}
As you mentioned yourself, you'll get a:
Error: Call to a member function parameter() on null
We need a Route
Why is that? Why route() returns null?
Have a look at its implementation as well as the implementation of its companion method; getRouteResolver(). The getRouteResolver() method returns an empty closure, then route() calls it and so the $route variable will be null. Then it gets returned and thus... the error.
In a real HTTP request context, Laravel sets up its route resolver, so you won't get such errors. Now that you're simulating the request, you need to set up that by yourself. Let's see how.
<?php
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
class ExampleTest extends TestCase
{
public function testBasicExample()
{
$request = new Request([], [], ['info' => 5]);
$request->setRouteResolver(function () use ($request) {
return (new Route('GET', 'testing/{info}', []))->bind($request);
});
dd($request->route()->parameter('info'));
}
}
See another example of creating Routes from Laravel's own RouteCollection class.
Empty parameters bag
So, now you won't get that error because you actually have a route with the request object bound to it. But it won't work yet. If we run phpunit at this point, we'll get a null in the face! If you do a dd($request->route()) you'll see that even though it has the info parameter name set up, its parameters array is empty:
Illuminate\Routing\Route {#250
#uri: "testing/{info}"
#methods: array:2 [
0 => "GET"
1 => "HEAD"
]
#action: array:1 [
"uses" => null
]
#controller: null
#defaults: []
#wheres: []
#parameters: [] <===================== HERE
#parameterNames: array:1 [
0 => "info"
]
#compiled: Symfony\Component\Routing\CompiledRoute {#252
-variables: array:1 [
0 => "info"
]
-tokens: array:2 [
0 => array:4 [
0 => "variable"
1 => "/"
2 => "[^/]++"
3 => "info"
]
1 => array:2 [
0 => "text"
1 => "/testing"
]
]
-staticPrefix: "/testing"
-regex: "#^/testing/(?P<info>[^/]++)$#s"
-pathVariables: array:1 [
0 => "info"
]
-hostVariables: []
-hostRegex: null
-hostTokens: []
}
#router: null
#container: null
}
So passing that ['info' => 5] to Request constructor has no effect whatsoever. Let's have a look at the Route class and see how its $parameters property is getting populated.
When we bind the request object to the route, the $parameters property gets populated by a subsequent call to the bindParameters() method which in turn calls bindPathParameters() to figure out path-specific parameters (we don't have a host parameter in this case).
That method matches request's decoded path against a regex of Symfony's Symfony\Component\Routing\CompiledRoute (You can see that regex in the above dump as well) and returns the matches which are path parameters. It will be empty if the path doesn't match the pattern (which is our case).
/**
* Get the parameter matches for the path portion of the URI.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function bindPathParameters(Request $request)
{
preg_match($this->compiled->getRegex(), '/'.$request->decodedPath(), $matches);
return $matches;
}
The problem is that when there's no actual request, that $request->decodedPath() returns / which does not match the pattern. So the parameters bag will be empty, no matter what.
Spoofing the request URI
If you follow that decodedPath() method on the Request class, you'll go deep through a couple of methods which will finally return a value from prepareRequestUri() of Symfony\Component\HttpFoundation\Request. There, exactly in that method, you'll find the answer to your question.
It's figuring out the request URI by probing a bunch of HTTP headers. It first checks for X_ORIGINAL_URL, then X_REWRITE_URL, then a few others and finally for the REQUEST_URI header. You can set either of these headers to actually spoof the request URI and achieve minimum simulation of a http request. Let's see.
<?php
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
class ExampleTest extends TestCase
{
public function testBasicExample()
{
$request = new Request([], [], [], [], [], ['REQUEST_URI' => 'testing/5']);
$request->setRouteResolver(function () use ($request) {
return (new Route('GET', 'testing/{info}', []))->bind($request);
});
dd($request->route()->parameter('info'));
}
}
To your surprise, it prints out 5; the value of info parameter.
Cleanup
You might want to extract the functionality to a helper simulateRequest() method, or a SimulatesRequests trait which can be used across your test cases.
Mocking
Even if it was absolutely impossible to spoof the request URI like the approach above, you could partially mock the request class and set your expected request URI. Something along the lines of:
<?php
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
class ExampleTest extends TestCase
{
public function testBasicExample()
{
$requestMock = Mockery::mock(Request::class)
->makePartial()
->shouldReceive('path')
->once()
->andReturn('testing/5');
app()->instance('request', $requestMock->getMock());
$request = request();
$request->setRouteResolver(function () use ($request) {
return (new Route('GET', 'testing/{info}', []))->bind($request);
});
dd($request->route()->parameter('info'));
}
}
This prints out 5 as well.
I ran into this problem today using Laravel7 here is how I solved it, hope it helps somebody
I'm writing unit tests for a middleware, it needs to check for some route parameters, so what I'm doing is creating a fixed request to pass it to the middleware
$request = Request::create('/api/company/{company}', 'GET');
$request->setRouteResolver(function() use ($company) {
$stub = $this->createStub(Route::class);
$stub->expects($this->any())->method('hasParameter')->with('company')->willReturn(true);
$stub->expects($this->any())->method('parameter')->with('company')->willReturn($company->id); // not $adminUser's company
return $stub;
});
Since route is implemented as a closure, you can access a route parameter directly in the route, without explicitly calling parameter('info'). These two calls returns the same:
$info = $request->route()->parameter('info');
$info = $request->route('info');
The second way, makes mocking the 'info' parameter very easy:
$request = $this->createMock(Request::class);
$request->expects($this->once())->method('route')->willReturn('HelloWorld');
$info = $request->route('info');
$this->assertEquals($info, 'HelloWorld');
Of course to exploit this method in your tests, you should inject the Request object in your class under test, instead of using the Laravel global request object through the request() method.
Using the Laravel phpunit wrapper, you can let your test class extend TestCase and use the visit() function.
If you want to be stricter (which in unit testing is probably a good thing), this method isn't really recommended.
class UserTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testExample()
{
// This is readable but there's a lot of under-the-hood magic
$this->visit('/home')
->see('Welcome')
->seePageIs('/home');
// You can still be explicit and use phpunit functions
$this->assertTrue(true);
}
}
So I have a Laravel controller:
class YeahMyController extends BaseController {
public function getSomething() {
Console::info('mymessage'); // <-- what do I put here?
return 'yeahoutputthistotheresponse';
}
}
Currently, I'm running the application using artisan (which runs PHP's built-in development web server under the hood):
php artisan serve
I would like to log console messages to the STDOUT pipe for the artisan process.
Aha!
This can be done with the following PHP function:
error_log('Some message here.');
Found the answer here: Print something in PHP built-in web server
The question relates to serving via artisan and so Jrop's answer is ideal in that case. I.e, error_log logging to the apache log.
However, if your serving via a standard web server then simply use the Laravel specific logging functions:
\Log::info('This is some useful information.');
\Log::warning('Something could be going wrong.');
\Log::error('Something is really going wrong.');
Or with current version of Laravel, like this:
info('This is some useful information.');
This logs to Laravel's log file located at /laravel/storage/logs/laravel-<date>.log (laravel 5.0). Monitor the log - linux/osx: tail -f /laravel/storage/logs/laravel-<date>.log
Laravel 5.0 http://laravel.com/docs/5.0/errors
Laravel 4.2: http://laravel.com/docs/4.2/errors
I haven't tried this myself, but a quick dig through the library suggests you can do this:
$output = new Symfony\Component\Console\Output\ConsoleOutput();
$output->writeln("<info>my message</info>");
I couldn't find a shortcut for this, so you would probably want to create a facade to avoid duplication.
It's very simple.
You can call it from anywhere in APP.
$out = new \Symfony\Component\Console\Output\ConsoleOutput();
$out->writeln("Hello from Terminal");
In Laravel 6 there is a channel called 'stderr'. See config/logging.php:
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
In your controller:
use Illuminate\Support\Facades\Log;
Log::channel('stderr')->info('Something happened!');
For better explain Dave Morrissey's answer I have made these steps for wrap with Console Output class in a laravel facade.
1) Create a Facade in your prefer folder (in my case app\Facades):
class ConsoleOutput extends Facade {
protected static function getFacadeAccessor() {
return 'consoleOutput';
}
}
2) Register a new Service Provider in app\Providers as follow:
class ConsoleOutputServiceProvider extends ServiceProvider
{
public function register(){
App::bind('consoleOutput', function(){
return new \Symfony\Component\Console\Output\ConsoleOutput();
});
}
}
3) Add all this stuffs in config\app.php file, registering the provider and alias.
'providers' => [
//other providers
App\Providers\ConsoleOutputServiceProvider::class
],
'aliases' => [
//other aliases
'ConsoleOutput' => App\Facades\ConsoleOutput::class,
],
That's it, now in any place of your Laravel application, just call your method in this way:
ConsoleOutput::writeln('hello');
Hope this help you.
If you want the fancy command IO from Laravel (like styling, asking and table) then I created this class below
Instructions
I have not fully verified everywhere that it is THE cleanest solution etc, but it works nice (but I only tested it from within a unit test case, under Laravel 5.5).
So most probably you can use it however you like:
$cmd = new ConsoleCommand;
$cmd->error("Aw snap!");
$cmd->table($headers, $rows);
$answer = $cmd->ask("Tell me, what do you need?");
//even Symfony's progress bar
$cmd->outputStyle->progressStart(5); //set n = 100% (here 100% is 5 steps)
$cmd->outputStyle->progressAdvance(); //you can call it n times
$cmd->outputStyle->progressFinish(); //set to 100%
Or course you can also wrap in your own facade, or some static singleton etc, or anyway you wish.
The class itself
class ConsoleCommand extends \Illuminate\Console\Command
{
protected $name = 'NONEXISTENT';
protected $hidden = true;
public $outputSymfony;
public $outputStyle;
public function __construct($argInput = null)
{
parent::__construct();
$this->input = new \Symfony\Component\Console\Input\StringInput($argInput);
$this->outputSymfony = new \Symfony\Component\Console\Output\ConsoleOutput();
$this->outputStyle = new \Illuminate\Console\OutputStyle($this->input, $this->outputSymfony);
$this->output = $this->outputStyle;
}
}
I wanted my logging information to be sent to stdout because it's easy to tell Amazon's Container service (ECS) to collect stdout and send it to CloudWatch Logs. So to get this working, I added a new stdout entry to my config/logging.php file like so:
'stdout' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'with' => [
'stream' => 'php://stdout',
],
'level' => 'info',
],
Then I simply added 'stdout' as one of the channels in the stack log channel:
'default' => env('LOG_CHANNEL', 'stack'),
'stack' => [
'driver' => 'stack',
'channels' => ['stdout', 'daily'],
],
This way, I still get logs in a file for local development (or even on the instance if you can access it), but more importantly they get sent to the stdout which is saved in CloudWatch Logs.
If you want to log to STDOUT you can use any of the ways Laravel provides; for example (from wired00's answer):
Log::info('This is some useful information.');
The STDOUT magic can be done with the following (you are setting the file where info messages go):
Log::useFiles('php://stdout', 'info');
Word of caution: this is strictly for debugging. Do no use anything in production you don't fully understand.
Bit late to this...I'm surprised that no one mentioned Symfony's VarDumper component that Laravel includes, in part, for its dd() (and lesser-known, dump()) utility functions.
$dumpMe = new App\User([ 'name' => 'Cy Rossignol' ]);
(new Symfony\Component\VarDumper\Dumper\CliDumper())->dump(
(new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($dumpMe)
);
There's a bit more code needed, but, in return, we get nice formatted, readable output in the console—especially useful for debugging complex objects or arrays:
App\User {#17
#attributes: array:1 [
"name" => "Cy Rossignol"
]
#fillable: array:3 [
0 => "name"
1 => "email"
2 => "password"
]
#guarded: array:1 [
0 => "*"
]
#primaryKey: "id"
#casts: []
#dates: []
#relations: []
... etc ...
}
To take this a step further, we can even colorize the output! Add this helper function to the project to save some typing:
function toConsole($var)
{
$dumper = new Symfony\Component\VarDumper\Dumper\CliDumper();
$dumper->setColors(true);
$dumper->dump((new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($var));
}
If we're running the app behind a full webserver (like Apache or Nginx—not artisan serve), we can modify this function slightly to send the dumper's prettified output to the log (typically storage/logs/laravel.log):
function toLog($var)
{
$lines = [ 'Dump:' ];
$dumper = new Symfony\Component\VarDumper\Dumper\CliDumper();
$dumper->setColors(true);
$dumper->setOutput(function ($line) use (&$lines) {
$lines[] = $line;
});
$dumper->dump((new Symfony\Component\VarDumper\Cloner\VarCloner())->cloneVar($var));
Log::debug(implode(PHP_EOL, $lines));
}
...and, of course, watch the log using:
$ tail -f storage/logs/laravel.log
PHP's error_log() works fine for quick, one-off inspection of simple values, but the functions shown above take the hard work out of debugging some of Laravel's more complicated classes.
Here's another way to go about it:
$stdout = fopen('php://stdout', 'w');
fwrite($stdout, 'Hello, World!' . PHP_EOL);
The PHP_EOL adds new line.
In command class
before class
use Symfony\Component\Console\Output\ConsoleOutput;
Inside the class methods
$output = new ConsoleOutput();
$output->writeln('my text that appears in command line ');
You can use echo and prefix "\033", simple:
Artisan::command('mycommand', function () {
echo "\033======== Start ========\n";
});
And change color text:
if (App::environment() === 'production') {
echo "\033[0;33m======== WARNING ========\033[0m\n";
}
From Larave 6.0+
$this->info('This will appear in console');
$this->error('This error will appear in console');
$this->line('This line will appear in console);
Documentation https://laravel.com/docs/6.x/artisan#writing-output