Repository: jkocik/laravel-profiler
Branch: master
Commit: cda42631f802
Files: 174
Total size: 292.3 KB
Directory structure:
gitextract_22nd0g50/
├── .docker/
│ ├── etc/
│ │ └── php/
│ │ ├── entrypoint.sh
│ │ ├── php-v1.ini
│ │ └── php-v2.ini
│ └── images/
│ └── php/
│ ├── .bashrc-v1
│ ├── .bashrc-v2
│ ├── Dockerfile-v1
│ └── Dockerfile-v2
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── composer.json
├── config/
│ └── profiler.php
├── docker-compose.yml
├── phpunit-laravel-52.xml
├── phpunit-laravel-53.xml
├── phpunit-laravel-54.xml
├── phpunit-laravel-55.xml
├── phpunit-laravel-56.xml
├── phpunit-laravel-57.xml
├── phpunit-laravel-58.xml
├── phpunit-laravel-6.xml
├── phpunit-laravel-7.xml
├── phpunit-laravel-8.xml
├── src/
│ ├── BaseProfiler.php
│ ├── Console/
│ │ ├── ClientCommand.php
│ │ ├── ServerCommand.php
│ │ └── StatusCommand.php
│ ├── Contracts/
│ │ ├── DataProcessor.php
│ │ ├── DataTracker.php
│ │ ├── ExecutionContent.php
│ │ ├── ExecutionData.php
│ │ ├── ExecutionRequest.php
│ │ ├── ExecutionResponse.php
│ │ ├── ExecutionRoute.php
│ │ ├── ExecutionServer.php
│ │ ├── ExecutionSession.php
│ │ ├── ExecutionWatcher.php
│ │ ├── LaravelListener.php
│ │ ├── Memory.php
│ │ ├── Processor.php
│ │ ├── Profiler.php
│ │ ├── Timer.php
│ │ └── Tracker.php
│ ├── DisabledProfiler.php
│ ├── Events/
│ │ ├── ExceptionHandling.php
│ │ ├── ProfilerBound.php
│ │ ├── ProfilerServerConnectionFailed.php
│ │ ├── ProfilerServerConnectionSuccessful.php
│ │ ├── ResetTrackers.php
│ │ ├── Terminating.php
│ │ └── Tracking.php
│ ├── LaravelDataProcessor.php
│ ├── LaravelDataTracker.php
│ ├── LaravelExecution/
│ │ ├── ConsoleFinishedRequest.php
│ │ ├── ConsoleFinishedResponse.php
│ │ ├── ConsoleStartingRequest.php
│ │ ├── ConsoleStartingResponse.php
│ │ ├── ExceptionHandlerFromVersion7.php
│ │ ├── ExceptionHandlerTillVersion6.php
│ │ ├── HttpContent.php
│ │ ├── HttpRequest.php
│ │ ├── HttpResponse.php
│ │ ├── HttpRoute.php
│ │ ├── HttpServer.php
│ │ ├── HttpSession.php
│ │ ├── LaravelExecutionData.php
│ │ ├── NullContent.php
│ │ ├── NullRequest.php
│ │ ├── NullResponse.php
│ │ ├── NullRoute.php
│ │ ├── NullServer.php
│ │ └── NullSession.php
│ ├── LaravelExecutionWatcher.php
│ ├── LaravelListeners/
│ │ ├── AuthListener.php
│ │ ├── ConsoleCommandFinishedListener.php
│ │ ├── EventsListener.php
│ │ ├── ExceptionListener.php
│ │ ├── HttpRequestHandledListener.php
│ │ ├── PerformanceListener.php
│ │ ├── QueriesListener.php
│ │ ├── RedisListener.php
│ │ └── ViewsListener.php
│ ├── LaravelProfiler.php
│ ├── Processors/
│ │ ├── BroadcastingProcessor.php
│ │ └── StatusCommandProcessor.php
│ ├── ProfilerResolver.php
│ ├── ServiceProvider.php
│ ├── Services/
│ │ ├── ConfigService.php
│ │ ├── ConsoleService.php
│ │ ├── GeneratorService.php
│ │ ├── LogService.php
│ │ ├── ParamsService.php
│ │ ├── Performance/
│ │ │ ├── MemoryService.php
│ │ │ ├── NullTimerService.php
│ │ │ ├── TimerException.php
│ │ │ └── TimerService.php
│ │ └── helpers.php
│ └── Trackers/
│ ├── ApplicationTracker.php
│ ├── AuthTracker.php
│ ├── BaseTracker.php
│ ├── BindingsTracker.php
│ ├── ConfigTracker.php
│ ├── ContentTracker.php
│ ├── EventsTracker.php
│ ├── ExceptionTracker.php
│ ├── PathsTracker.php
│ ├── PerformanceTracker.php
│ ├── QueriesTracker.php
│ ├── RedisTracker.php
│ ├── RequestTracker.php
│ ├── ResponseTracker.php
│ ├── RouteTracker.php
│ ├── ServerTracker.php
│ ├── ServiceProvidersTracker.php
│ ├── SessionTracker.php
│ └── ViewsTracker.php
└── tests/
├── Feature/
│ ├── CommandsTest.php
│ ├── LaravelConsoleExecutionTest.php
│ ├── LaravelExecutionTest.php
│ ├── LaravelHttpExecutionTest.php
│ ├── LaravelNullExecutionTest.php
│ ├── PerformanceTest.php
│ ├── PerformanceTrackerTest.php
│ ├── RegisterProfilerTest.php
│ ├── RunningProfilerTest.php
│ ├── TrackersResetTest.php
│ └── TrackersTest.php
├── Support/
│ ├── Fixtures/
│ │ ├── DummyClassA.php
│ │ ├── DummyClassB.php
│ │ ├── DummyCommand.php
│ │ ├── DummyContractA.php
│ │ ├── DummyContractB.php
│ │ ├── DummyController.php
│ │ ├── DummyEventA.php
│ │ ├── DummyEventB.php
│ │ ├── DummyException.php
│ │ ├── DummyFormRequest.php
│ │ ├── PerformanceProcessor.php
│ │ ├── ProcessorA.php
│ │ ├── ProcessorB.php
│ │ ├── TrackerA.php
│ │ ├── TrackerB.php
│ │ ├── dummy-view-a.blade.php
│ │ └── dummy-view-b.blade.php
│ ├── Framework.php
│ ├── PHPMock.php
│ └── TestListener.php
├── TestCase.php
├── Unit/
│ ├── LaravelExecution/
│ │ ├── ConsoleFinishedRequestTest.php
│ │ ├── ConsoleStartingRequestTest.php
│ │ └── ConsoleStartingResponseTest.php
│ ├── Services/
│ │ ├── ConfigServiceTest.php
│ │ ├── HelpersTest.php
│ │ ├── ParamsServiceTest.php
│ │ └── Performance/
│ │ └── TimerServiceTest.php
│ └── Trackers/
│ ├── ApplicationTrackerTest.php
│ ├── AuthTrackerTest.php
│ ├── BindingsTrackerTest.php
│ ├── ConfigTrackerTest.php
│ ├── ContentTrackerTest.php
│ ├── EventsTrackerTest.php
│ ├── ExceptionTrackerTest.php
│ ├── PathsTrackerTest.php
│ ├── QueriesTrackerTest.php
│ ├── RedisTrackerTest.php
│ ├── RequestTrackerTest.php
│ ├── ResponseTrackerTest.php
│ ├── RouteTrackerTest.php
│ ├── ServerTrackerTest.php
│ ├── ServiceProvidersTrackerTest.php
│ ├── SessionTrackerTest.php
│ └── ViewsTrackerTest.php
└── bootstrap/
└── phpunit.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .docker/etc/php/entrypoint.sh
================================================
#!/bin/sh
redis-server --daemonize yes
setfacl -dR -m u:www-data:rwX /var/www/html
setfacl -R -m u:www-data:rwX /var/www/html
docker-php-entrypoint $@
================================================
FILE: .docker/etc/php/php-v1.ini
================================================
memory_limit = 256M
max_execution_time = 600
================================================
FILE: .docker/etc/php/php-v2.ini
================================================
memory_limit = 256M
max_execution_time = 600
xdebug.mode=coverage
================================================
FILE: .docker/images/php/.bashrc-v1
================================================
alias la52='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-52.xml'
alias la53='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-53.xml'
alias la54='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-54.xml'
alias la55='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-55.xml'
alias la56='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-56.xml'
alias la57='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-57.xml'
alias la58='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-58.xml'
alias la6='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-6.xml'
alias la7='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-7.xml'
alias phpunit-all='la7 && la6 && la58 && la57 && la56 && la55 && la54 && la53 && la52'
alias phpunit-c='la7 --coverage-html coverage'
================================================
FILE: .docker/images/php/.bashrc-v2
================================================
alias la6='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-6.xml'
alias la7='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-7.xml'
alias la8='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-8.xml'
alias la-all='la8 && la7 && la6'
alias la-c='la8 --coverage-html coverage'
================================================
FILE: .docker/images/php/Dockerfile-v1
================================================
FROM php:7.3.10-fpm
COPY ./.bashrc-v1 /root/.bashrc
RUN apt-get update > /dev/null && apt-get install -y \
acl \
unzip \
libzip-dev \
zlib1g-dev \
libpng-dev \
libjpeg-dev \
nodejs \
redis-server
RUN docker-php-ext-install zip pdo_mysql bcmath gd > /dev/null
RUN pecl install xdebug > /dev/null \
&& docker-php-ext-enable xdebug > /dev/null
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer > /dev/null
RUN rm -rf /var/lib/apt/lists/*
================================================
FILE: .docker/images/php/Dockerfile-v2
================================================
FROM php:8.0.6-fpm
COPY ./.bashrc-v2 /root/.bashrc
RUN apt-get update > /dev/null && apt-get install -y \
acl \
unzip \
libzip-dev \
zlib1g-dev \
libpng-dev \
libjpeg-dev \
nodejs \
redis-server
RUN docker-php-ext-install zip pdo_mysql bcmath gd > /dev/null
RUN pecl install xdebug > /dev/null \
&& docker-php-ext-enable xdebug > /dev/null
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer > /dev/null
RUN rm -rf /var/lib/apt/lists/*
================================================
FILE: .gitignore
================================================
/client
/coverage
/frameworks
/vendor
.phpunit.result.cache
composer.lock
================================================
FILE: .travis.yml
================================================
language: php
php:
- 7.3.24
- 7.4.0
- 8.0
services:
- redis-server
before_script:
- composer install --no-interaction
script:
- vendor/bin/phpunit -c phpunit-laravel-6.xml --coverage-clover build/logs/clover.xml
- vendor/bin/phpunit -c phpunit-laravel-7.xml
- vendor/bin/phpunit -c phpunit-laravel-8.xml
after_success:
- travis_retry php vendor/bin/php-coveralls -v
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) Janusz Kocik
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
## Laravel Profiler
[](https://travis-ci.org/jkocik/laravel-profiler)
[](https://coveralls.io/github/jkocik/laravel-profiler?branch=master)
The aim of this project is to track console and web Laravel framework execution and give developers
better understanding what is going on under the hood. Laravel Profiler is designed for Laravel Framework.

### Supported versions
| Laravel Framework version you have | Laravel Profiler version you should use |
| ---------------------------------- | --------------------------------------- |
| 5.2.x - 5.8.x | 1.x |
| 6.x - 8.x | 2.x |
### How does it work?
Profiler delivers data about Laravel framework execution:
- when **tests are run** (PHPUnit, Laravel Dusk)
- when Laravel is executed via **console** (artisan)
- when Laravel is executed via **browser request**
- when Laravel is executed via web request not expecting HTML response (**API**)
- on any other **action that terminates** Laravel framework.
Profiler does not add any routes to your application and does not modify the content of the response.
Profiler is divided into 3 parts:
- Profiler Package - PHP package for Laravel (this repository)
- Profiler Client - Single Page Application to review data delivered by Profiler Package
- Profiler Server - bridge between Profiler Package and Profiler Client.
Profiler Client and Profiler Server both live in [laravel-profiler-client](https://github.com/jkocik/laravel-profiler-client) repository
#### Data flow
Profiler Package tracks Laravel execution and sends collected data to Profiler Server using HTTP.
Profiler Server passes data to Profiler Client using WebSockets.
#### Trackers
Data tracked, collected and delivered to Profiler Client are:
- auth
- redis
- route
- views
- events
- session
- exceptions
- server status
- database queries
- performance metrics
- request (web) / input (console)
- response (web) / output (console)
- application (Laravel status, config, loaded service providers, container bindings, framework paths)
Profiler and its trackers do their job after request / artisan command is finished.
That keeps your framework execution time and peak of memory usage as close to real values (without Profiler impact)
as possible.
## Installation and configuration
### Step 1: Install Profiler Package
Requirements: PHP 7.2+
It is recommended to install Profiler Package only for development
```shell
composer require jkocik/laravel-profiler --dev
```
### Step 2: Publish configuration file
Run command
```shell
php artisan vendor:publish --provider="JKocik\Laravel\Profiler\ServiceProvider"
```
... and check config/profiler.php file for Profiler settings.
### Step 3: Install Profiler Server and Profiler Client
It is recommended to install Profiler Server and Profiler Client only for development
```shell
npm install laravel-profiler-client --save-dev
```
### Step 4: Run Profiler Server and Profiler Client
_Windows users: If you have any issue with running Profiler Server or Profiler Client
check Installation options / issues section below._
Run command
```shell
php artisan profiler:server
```
and
a) for your local machine
```shell
php artisan profiler:client
```
After that your browser should have new tab opened with Profiler Client connected to Profiler Server.
b) for Docker, Vagrant or any other machine different from local
```shell
php artisan profiler:client -m
```
... and open new browser tab according to instructions in console. Remember that you need
to connect Profiler Client to Profiler Server yourself because by default Profiler Client uses localhost.
You can do that in Profiler Client interface.
### Step 5: Verify installation
Run command
```shell
php artisan profiler:status
```
... to check Profiler status and see first data of Laravel execution in Profiler Client.
### Installation options / issues
a) If you have any issue with running Profiler Server or Profiler Client use npm scripts instead of artisan commands.
Add new scripts to your package.json file
```json
"scripts": {
"profiler-server": "node node_modules/laravel-profiler-client/server/server.js http=8099 ws=1901",
"profiler-client": "http-server node_modules/laravel-profiler-client/dist/ -o -s",
"ps": "npm run profiler-server",
"pc": "npm run profiler-client"
}
```
... then run Profiler Server
```shell
npm run ps
```
... and Profiler Client
```shell
npm run pc
```
b) If you don't want to open new browser tab every time you run Profiler Client command use manual option
```shell
php artisan profiler:client -m
```
c) If default ports used by Profiler are taken on your machine configure them in config/profiler.php file.
### Done!
You are ready to use Laravel Profiler. Enjoy!
### Usage
#### Performance metrics
Profiler delivers basic performance metrics including peak of memory usage and Laravel execution time.
You can extend metrics by using Profiler helper functions:
```php
profiler_start('my time metric name');
// my code to track execution time
profiler_finish('my time metric name');
```
Then check results in Profiler Client (Performance > Custom tab). You should keep unique metric names
otherwise duplicates will be skipped and reported as an error (in a way according to your exception handling
settings in config/profiler.php file).
_Important notice: remove Profiler helper functions from your code
before moving to production or any environment without Profiler installed._
#### Laravel Profiler for testing environment
When testing Profiler will deliver the same data as for regular request / artisan command. However application should be
terminated. Lets see two default tests Laravel is shipped with:
```php
public function testBasicTest()
{
$response = $this->get('/');
$response->assertStatus(200);
}
```
First test will terminate application and Profiler will work as expected. However second test
```php
public function testBasicTest()
{
$this->assertTrue(true);
}
```
... will not provide any data because this time application is not terminated. You can force
Profiler to work by adding terminate method:
```php
public function testBasicTest()
{
$this->assertTrue(true);
$this->app->terminate();
}
```
If you want to reset Profiler trackers you can use Profiler helper:
```php
public function testBasicTest()
{
factory(User::class)->create();
profiler_reset();
// act and assert
}
```
_Important notice related to testing environment: peak of memory usage can not be tracked for each test separately
so is not shown in Profiler Client._
#### Using together with Laravel Debugbar
It is not recommended using Laravel Profiler and Laravel Debugbar together. Profiler will finish
its work after Debugbar and Profiler report of framework execution time and peak of memory usage will
be increased by Debugbar activity. Use Profiler or Debugbar one at a time.
================================================
FILE: composer.json
================================================
{
"name": "jkocik/laravel-profiler",
"description": "Profiler for Laravel Framework",
"keywords": ["laravel", "profiler", "debugbar"],
"homepage": "https://github.com/jkocik/laravel-profiler",
"license": "MIT",
"authors": [
{
"name": "Janusz Kocik",
"email": "janusz.kocik@gmail.com"
}
],
"require": {
"php": ">=7.2",
"guzzlehttp/guzzle": "^5.0 || ^6.0 || ^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"php-mock/php-mock": "^2.0",
"php-coveralls/php-coveralls": "^2.1",
"predis/predis": "^1.1",
"fzaninotto/faker": "^1.5",
"phpunit/phpunit": "^8"
},
"autoload": {
"psr-4": {
"JKocik\\Laravel\\Profiler\\": "src/"
},
"files": [
"src/Services/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"JKocik\\Laravel\\Profiler\\Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
"JKocik\\Laravel\\Profiler\\ServiceProvider"
]
}
}
}
================================================
FILE: config/profiler.php
================================================
env('PROFILER_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Override general Laravel Profiler enable / disable setting
|--------------------------------------------------------------------------
|
| Can disable Profiler on particular env. Profiler is disabled by default
| on production (be aware that installation on production is not recommended).
| Setting takes effect only if above (enabled) is set to true.
|
*/
'enabled_overrides' => [
'production' => false,
// 'testing' => false,
// 'local' => false,
],
/*
|--------------------------------------------------------------------------
| Profiler trackers
|--------------------------------------------------------------------------
|
| Trackers collect data of framework execution. You can decide what data
| you want to collect by commenting / uncommenting particular trackers.
|
*/
'trackers' => [
\JKocik\Laravel\Profiler\Trackers\ConfigTracker::class, // App > Config tab
\JKocik\Laravel\Profiler\Trackers\ServiceProvidersTracker::class, // App > Service Providers tab
\JKocik\Laravel\Profiler\Trackers\BindingsTracker::class, // App > Bindings tab
\JKocik\Laravel\Profiler\Trackers\PathsTracker::class, // App > Paths tab
\JKocik\Laravel\Profiler\Trackers\SessionTracker::class, // Request > Session tab
\JKocik\Laravel\Profiler\Trackers\RouteTracker::class, // Request > Route tab
\JKocik\Laravel\Profiler\Trackers\ServerTracker::class, // Request > Server tab
\JKocik\Laravel\Profiler\Trackers\ContentTracker::class, // Response > Content and JSON tabs
\JKocik\Laravel\Profiler\Trackers\ViewsTracker::class, // Views tab
\JKocik\Laravel\Profiler\Trackers\EventsTracker::class, // Events tab
\JKocik\Laravel\Profiler\Trackers\QueriesTracker::class, // Queries tab
// \JKocik\Laravel\Profiler\Trackers\RedisTracker::class, // Redis tab (from Laravel 5.7)
\JKocik\Laravel\Profiler\Trackers\AuthTracker::class, // Auth tab
\JKocik\Laravel\Profiler\Trackers\ExceptionTracker::class, // Exception tab
],
/*
|--------------------------------------------------------------------------
| Profiler Server and Profiler Client connections
|--------------------------------------------------------------------------
|
| These settings let you set up connections between Profiler Package
| (this Laravel package) and Profiler Server using HTTP protocol
| and finally pass data from Profiler Server to Profiler Client
| (Single Page Application accessible via browser) using WebSockets.
|
*/
'server_http' => [
'address' => 'http://localhost',
'port' => '8099',
],
'server_sockets' => [
'port' => '1901',
],
/*
|--------------------------------------------------------------------------
| Profiler processors
|--------------------------------------------------------------------------
|
| Processors process data collected by trackers. Default processor
| broadcasts data through Profiler Server to Profiler Client.
|
*/
'processors' => [
\JKocik\Laravel\Profiler\Processors\BroadcastingProcessor::class,
],
'turn_off_processors_for_paths' => [
'telescope',
'_debugbar',
],
/*
|--------------------------------------------------------------------------
| Data passed to tracked items
|--------------------------------------------------------------------------
|
| That can be very heavy when your views or events receive a lot of data.
| Avoid using it on testing env specially when running whole test suite.
|
*/
'data' => [
'views' => false,
'events' => false,
],
/*
|--------------------------------------------------------------------------
| Grouping
|--------------------------------------------------------------------------
|
| There can be a lot of the same events fired one by one. Grouping can
| help you review them on better organized list of events.
|
*/
'group' => [
'events' => true,
],
/*
|--------------------------------------------------------------------------
| Handle exceptions
|--------------------------------------------------------------------------
|
| Profiler processors and helper functions can throw exceptions.
| They are logged by default to let you know about current issues
| like problems with connection to Profiler Server.
|
| Handle exceptions settings are [int]:
| 0 - catch exceptions and do not report them
| 1 - catch exceptions and report them in logs
| 666 - do not catch exceptions, let them be thrown
|
*/
'handle_exceptions' => 1,
];
================================================
FILE: docker-compose.yml
================================================
version: '3.5'
services:
profiler_v1:
build:
dockerfile: Dockerfile-v1
context: ./.docker/images/php
container_name: profiler_v1
hostname: profiler_v1
entrypoint: sh /bin/entrypoint.sh php-fpm
volumes:
- ./.docker/etc/php/entrypoint.sh:/bin/entrypoint.sh:ro
- ./.docker/etc/php/php-v1.ini:/usr/local/etc/php/php.ini
- .:/var/www/html
profiler_v2:
build:
dockerfile: Dockerfile-v2
context: ./.docker/images/php
container_name: profiler_v2
hostname: profiler_v2
entrypoint: sh /bin/entrypoint.sh php-fpm
volumes:
- ./.docker/etc/php/entrypoint.sh:/bin/entrypoint.sh:ro
- ./.docker/etc/php/php-v2.ini:/usr/local/etc/php/php.ini
- .:/var/www/html
================================================
FILE: phpunit-laravel-52.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-53.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-54.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-55.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-56.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-57.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-58.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-6.xml
================================================
./tests/Feature
./tests/Unit
./src/
./src/LaravelExecution/ExceptionHandlerFromVersion7.php
================================================
FILE: phpunit-laravel-7.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: phpunit-laravel-8.xml
================================================
./tests/Feature
./tests/Unit
./src/
================================================
FILE: src/BaseProfiler.php
================================================
app = $app;
}
/**
* @return void
*/
public function resetTrackers(): void
{
event(new ResetTrackers());
}
/**
* @return void
*/
public function listenForBoot(): void
{
$this->app->beforeBootstrapping(BootProviders::class, function () {
$this->commands();
$this->boot();
});
}
/**
* @return void
*/
abstract protected function boot(): void;
/**
* @return void
*/
private function commands(): void
{
Event::listen(ArtisanStarting::class, function (ArtisanStarting $event) {
$event->artisan->resolveCommands([
StatusCommand::class,
ServerCommand::class,
ClientCommand::class,
]);
});
}
}
================================================
FILE: src/Console/ClientCommand.php
================================================
consoleService = $consoleService;
}
/**
* @return void
*/
public function handle(): void
{
$this->line('Starting Profiler Client ...');
passthru($this->consoleService->profilerClientCmd($this->option('manual')));
}
}
================================================
FILE: src/Console/ServerCommand.php
================================================
consoleService = $consoleService;
}
/**
* @return void
*/
public function handle(): void
{
$this->line('Starting Profiler Server ...');
passthru($this->consoleService->profilerServerCmd());
}
}
================================================
FILE: src/Console/StatusCommand.php
================================================
configService = $configService;
$this->consoleService = $consoleService;
}
/**
* @return void
*/
public function handle(): void
{
$this->configService->overrideProcessors([
StatusCommandProcessor::class,
]);
$this->printProfilerStatus();
if (! $this->configService->isProfilerEnabled()) {
return;
}
$this->printTrackersStatus();
$this->printConnectionStatus();
}
/**
* @return void
*/
protected function printProfilerStatus(): void
{
$this->line("1) {$this->consoleService->envInfo()}");
$this->info($this->consoleService->profilerStatusInfo());
}
/**
* @return void
*/
protected function printTrackersStatus(): void
{
$this->line('');
$this->line("2) {$this->consoleService->trackersStatusInfo()}");
$this->configService->trackers()->each(function ($tracker) {
$this->info("- {$tracker}");
});
$this->comment($this->consoleService->trackersCommentLine1());
$this->comment($this->consoleService->trackersCommentLine2());
}
/**
* @return void
*/
protected function printConnectionStatus(): void
{
$this->line('');
$this->line("3) {$this->consoleService->connectionStatusInfo()}");
Event::listen(ProfilerServerConnectionSuccessful::class, function (ProfilerServerConnectionSuccessful $event) {
$this->info($this->consoleService->connectionSuccessfulInfo());
$this->info($this->consoleService->connectionSuccessfulSocketsInfo($event->socketsPort));
$this->info($this->consoleService->connectionSuccessfulClientsInfo($event->countClients));
$this->connectionStatusIsUnknown = false;
});
Event::listen(ProfilerServerConnectionFailed::class, function () {
$this->error($this->error($this->consoleService->connectionFailedInfo()));
$this->connectionStatusIsUnknown = false;
});
app()->terminating(function () {
if (! $this->connectionStatusIsUnknown) {
return;
}
$this->error($this->consoleService->connectionStatusUnknownInfo());
});
}
}
================================================
FILE: src/Contracts/DataProcessor.php
================================================
bind();
}
/**
* @return void
*/
protected function bind(): void
{
$this->app->singleton(Timer::class, function ($app) {
return $app->make(NullTimerService::class);
});
event(ProfilerBound::class);
}
}
================================================
FILE: src/Events/ExceptionHandling.php
================================================
exception = $exception;
}
}
================================================
FILE: src/Events/ProfilerBound.php
================================================
socketsPort = $socketsPort;
$this->countClients = $countClients;
}
}
================================================
FILE: src/Events/ResetTrackers.php
================================================
app = $app;
$this->logService = $logService;
$this->configService = $configService;
}
/**
* @param DataTracker $dataTracker
* @return void
*/
public function process(DataTracker $dataTracker): void
{
if ($this->shouldNotProcess($dataTracker)) {
return;
}
$this->configService->processors()->each(function (string $processor) use ($dataTracker) {
try {
$this->make($processor)->process($dataTracker);
} catch (Exception $e) {
$this->logService->error($e);
}
});
}
/**
* @param string $processor
* @return Processor
*/
protected function make(string $processor): Processor
{
return $this->app->make($processor);
}
/**
* @param DataTracker $dataTracker
* @return bool
*/
protected function shouldNotProcess(DataTracker $dataTracker): bool
{
if (! $dataTracker->meta()->has('path')) {
return false;
}
return $this->configService->pathsToTurnOffProcessors()->map(function ($path) use ($dataTracker) {
return stripos($dataTracker->meta()->get('path'), $path) !== false;
})->contains(true);
}
}
================================================
FILE: src/LaravelDataTracker.php
================================================
app = $app;
$this->configService = $configService;
$this->trackers = new Collection();
$this->meta = new Collection();
$this->data = new Collection();
}
/**
* @return void
*/
public function track(): void
{
$this->bootTrackers(Collection::make([
ApplicationTracker::class,
PerformanceTracker::class,
RequestTracker::class,
ResponseTracker::class,
]));
$this->bootTrackers($this->configService->trackers());
}
/**
* @return void
*/
public function terminate(): void
{
$this->trackers->each(function (Tracker $tracker) {
$tracker->terminate();
$this->meta = $this->meta->merge($tracker->meta());
$this->data = $this->data->merge($tracker->data());
});
}
/**
* @return Collection
*/
public function meta(): Collection
{
return $this->meta;
}
/**
* @return Collection
*/
public function data(): Collection
{
return $this->data;
}
/**
* @param Collection $trackers
* @return void
*/
protected function bootTrackers(Collection $trackers): void
{
$trackers->each(function (string $tracker) {
$this->trackers->push($this->app->make($tracker));
});
}
}
================================================
FILE: src/LaravelExecution/ConsoleFinishedRequest.php
================================================
command = $command;
$this->input = $input;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make([
'type' => 'command-finished',
'path' => $this->command,
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make([
'arguments' => $this->input->getArguments(),
'options' => $this->input->getOptions(),
]);
}
}
================================================
FILE: src/LaravelExecution/ConsoleFinishedResponse.php
================================================
exitCode = $exitCode;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make([
'status' => $this->exitCode,
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make();
}
}
================================================
FILE: src/LaravelExecution/ConsoleStartingRequest.php
================================================
'command-starting',
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make();
}
}
================================================
FILE: src/LaravelExecution/ConsoleStartingResponse.php
================================================
null,
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make();
}
}
================================================
FILE: src/LaravelExecution/ExceptionHandlerFromVersion7.php
================================================
response = $response;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make();
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make([
'content' => $this->response->getContent(),
]);
}
}
================================================
FILE: src/LaravelExecution/HttpRequest.php
================================================
request = $request;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make([
'type' => 'http',
'method' => $this->request->method(),
'path' => $this->request->path(),
'ajax' => $this->request->ajax(),
'json' => $this->request->isJson(),
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make([
'pjax' => $this->request->pjax(),
'url' => $this->request->url(),
'query' => $this->request->query(),
'ip' => $this->request->ip(),
'header' => $this->request->header(),
'input' => $this->request->input(),
'files' => $this->files(),
'cookie' => $this->request->cookie(),
]);
}
/**
* @return Collection
*/
protected function files(): Collection
{
$files = Collection::make($this->request->allFiles());
return $this->filesMap($files);
}
/**
* @param Collection $files
* @return Collection
*/
protected function filesMap(Collection $files): Collection
{
return $files->map(function ($file) {
if (is_array($file)) {
$files = Collection::make($file);
return $this->filesMap($files);
}
return [get_class($file) => $this->file($file)];
});
}
/**
* @param UploadedFile $file
* @return array
*/
protected function file(UploadedFile $file): array
{
return [
'client original name' => $file->getClientOriginalName(),
'client original extension' => $file->getClientOriginalExtension(),
'client mime type' => $file->getClientMimeType(),
'client size' => $this->clientSize($file),
'path' => $file->path(),
];
}
/**
* @param UploadedFile $file
* @return int
*/
protected function clientSize(UploadedFile $file): int
{
return method_exists($file, 'getClientSize')
? $file->getClientSize()
: $file->getSize();
}
}
================================================
FILE: src/LaravelExecution/HttpResponse.php
================================================
response = $response;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make([
'status' => $this->response->getStatusCode(),
'status_text' => $this->getStatusText(),
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make([
'headers' => $this->response->headers->all(),
]);
}
/**
* @return string
*/
protected function getStatusText(): string
{
return $this->response::$statusTexts[$this->response->getStatusCode()] ?? 'unknown status';
}
}
================================================
FILE: src/LaravelExecution/HttpRoute.php
================================================
route = $route;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make();
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make([
'methods' => $this->route->methods(),
'uri' => $this->route->uri(),
'name' => $this->route->getName(),
'middleware' => $this->route->middleware(),
'parameters' => $this->route->parameters(),
'prefix' => $this->route->getPrefix(),
'uses' => $this->uses(),
]);
}
/**
* @return array
*/
protected function uses(): array
{
$uses = $this->route->getAction();
try {
if ($this->isClosureIn($uses)) {
return $this->closure($uses);
}
if ($this->isControllerIn($uses)) {
return $this->controller($uses);
}
} catch (ReflectionException $e) {}
return [];
}
/**
* @param array $uses
* @return bool
*/
protected function isClosureIn(array $uses): bool
{
return isset($uses['uses']) && $uses['uses'] instanceof Closure;
}
/**
* @param array $uses
* @return array
*/
protected function closure(array $uses): array
{
$action = new ReflectionFunction($uses['uses']);
return [
'closure' => $action->getFileName() . ':' . $action->getStartLine() . '-' . $action->getEndLine(),
'form_request' => $this->formRequest($action->getParameters()),
];
}
/**
* @param array $uses
* @return bool
*/
protected function isControllerIn(array $uses): bool
{
return isset($uses['uses']) && count(explode('@', $uses['uses'])) == 2;
}
/**
* @param array $uses
* @return array
*/
protected function controller(array $uses): array
{
list($controller, $method) = explode('@', $uses['uses']);
$action = new ReflectionMethod($controller, $method);
return [
'controller' => $uses['uses'] . ':' . $action->getStartLine() . '-' . $action->getEndLine(),
'form_request' => $this->formRequest($action->getParameters()),
];
}
/**
* @param array $parameters
* @return string
*/
protected function formRequest(array $parameters): string
{
$formRequest = Collection::make($parameters)->filter(function (ReflectionParameter $parameter) {
return $parameter->getType() && is_subclass_of($parameter->getType()->getName(), FormRequest::class);
})->first();
return $formRequest ? $formRequest->getType()->getName() : '';
}
}
================================================
FILE: src/LaravelExecution/HttpServer.php
================================================
request = $request;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make();
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make(
$this->request->server()
);
}
}
================================================
FILE: src/LaravelExecution/HttpSession.php
================================================
session = $session;
}
/**
* @return Collection
*/
public function meta(): Collection
{
return Collection::make();
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make($this->session->all());
}
}
================================================
FILE: src/LaravelExecution/LaravelExecutionData.php
================================================
setRequest(new NullRequest());
$this->setRoute(new NullRoute());
$this->setSession(new NullSession());
$this->setServer(new NullServer());
$this->setResponse(new NullResponse());
$this->setContent(new NullContent());
}
/**
* @param ExecutionRequest $request
* @return void
*/
public function setRequest(ExecutionRequest $request): void
{
$this->request = $request;
}
/**
* @return ExecutionRequest
*/
public function request(): ExecutionRequest
{
return $this->request;
}
/**
* @param ExecutionRoute $route
* @return void
*/
public function setRoute(ExecutionRoute $route): void
{
$this->route = $route;
}
/**
* @return ExecutionRoute
*/
public function route(): ExecutionRoute
{
return $this->route;
}
/**
* @param ExecutionSession $session
* @return void
*/
public function setSession(ExecutionSession $session): void
{
$this->session = $session;
}
/**
* @return ExecutionSession
*/
public function session(): ExecutionSession
{
return $this->session;
}
/**
* @param ExecutionServer $server
* @return void
*/
public function setServer(ExecutionServer $server): void
{
$this->server = $server;
}
/**
* @return ExecutionServer
*/
public function server(): ExecutionServer
{
return $this->server;
}
/**
* @param ExecutionResponse $response
* @return void
*/
public function setResponse(ExecutionResponse $response): void
{
$this->response = $response;
}
/**
* @return ExecutionResponse
*/
public function response(): ExecutionResponse
{
return $this->response;
}
/**
* @param ExecutionContent $content
* @return void
*/
public function setContent(ExecutionContent $content): void
{
$this->content = $content;
}
/**
* @return ExecutionContent
*/
public function content(): ExecutionContent
{
return $this->content;
}
}
================================================
FILE: src/LaravelExecution/NullContent.php
================================================
null,
]);
}
/**
* @return Collection
*/
public function data(): Collection
{
return Collection::make();
}
}
================================================
FILE: src/LaravelExecution/NullResponse.php
================================================
httpRequestHandledListener = $httpRequestHandledListener;
$this->consoleCommandFinishedListener = $consoleCommandFinishedListener;
}
/**
* @return void
*/
public function watch(): void
{
$this->httpRequestHandledListener->listen();
$this->consoleCommandFinishedListener->listen();
}
}
================================================
FILE: src/LaravelListeners/AuthListener.php
================================================
user = $logout->user;
});
}
/**
* @return User|null
*/
public function user(): ?Model
{
return $this->user ?? Auth::user();
}
}
================================================
FILE: src/LaravelListeners/ConsoleCommandFinishedListener.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function listen(): void
{
Event::listen(\Illuminate\Console\Events\ArtisanStarting::class, function ($event) {
$this->executionData->setRequest(new ConsoleStartingRequest());
$this->executionData->setResponse(new ConsoleStartingResponse());
});
Event::listen(\Illuminate\Console\Events\CommandFinished::class, function ($event) {
$this->executionData->setRequest(new ConsoleFinishedRequest($event->command, $event->input));
$this->executionData->setResponse(new ConsoleFinishedResponse($event->exitCode));
});
}
}
================================================
FILE: src/LaravelListeners/EventsListener.php
================================================
dispatcher = $dispatcher;
$this->configService = $configService;
}
/**
* @return void
*/
public function listen(): void
{
$this->listenEvents();
$this->listenResetTrackers();
}
/**
* @return Collection
*/
public function events(): Collection
{
return Collection::make($this->events);
}
/**
* @return int
*/
public function count(): int
{
return $this->count;
}
/**
* @return void
*/
protected function listenEvents(): void
{
$this->dispatcher->listen('*', function ($event, $payload = null) {
$name = $this->resolveName($event, $payload);
if ($this->shouldSkip($name)) {
return;
}
$this->count++;
if ($this->shouldGroup($name)) {
return $this->groupToPreviousEvent();
}
$this->previousEventName = $name;
array_push($this->events, $this->resolveEvent($name, $event, $payload));
});
}
/**
* @return void
*/
protected function listenResetTrackers(): void
{
$this->dispatcher->listen(ResetTrackers::class, function () {
$this->events = [];
$this->previousEventName = '';
$this->count = 0;
});
}
/**
* @param string $name
* @param $event
* @param $payload
* @return array
*/
protected function resolveEvent(string $name, $event, $payload): array
{
if ($this->configService->isEventsDataEnabled()) {
return [$event, $payload, $name, 1];
}
return [null, null, $name, 1];
}
/**
* @param $event
* @param $payload
* @return string
*/
protected function resolveName($event, $payload): string
{
return is_array($payload) ? $event : $this->dispatcher->firing();
}
/**
* @param string $name
* @return bool
*/
protected function shouldGroup(string $name): bool
{
return $this->configService->isEventsGroupEnabled() && $name == $this->previousEventName;
}
/**
* @return void
*/
protected function groupToPreviousEvent(): void
{
$this->events[count($this->events) - 1][3]++;
}
/**
* @param string $name
* @return bool
*/
protected function shouldSkip(string $name): bool
{
$shouldSkip = Collection::make([
'bootstrapped: ' . \Illuminate\Foundation\Bootstrap\BootProviders::class,
\JKocik\Laravel\Profiler\Events\ExceptionHandling::class,
\JKocik\Laravel\Profiler\Events\ProfilerBound::class,
\JKocik\Laravel\Profiler\Events\ResetTrackers::class,
\JKocik\Laravel\Profiler\Events\Terminating::class,
\JKocik\Laravel\Profiler\Events\Tracking::class,
]);
return $shouldSkip->contains($name);
}
}
================================================
FILE: src/LaravelListeners/ExceptionListener.php
================================================
exception = $exceptionHandling->exception;
});
}
public function exception(): ?Throwable
{
return $this->exception;
}
}
================================================
FILE: src/LaravelListeners/HttpRequestHandledListener.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function listen(): void
{
/** @codeCoverageIgnoreStart */
Event::listen('kernel.handled', function (Request $request, Response $response) {
$this->executionData->setRequest(new HttpRequest($request));
$this->executionData->setRoute($this->routeOf($request));
$this->executionData->setSession(new HttpSession(session()));
$this->executionData->setServer(new HttpServer($request));
$this->executionData->setResponse(new HttpResponse($response));
$this->executionData->setContent(new HttpContent($response));
});
/** @codeCoverageIgnoreEnd */
Event::listen(\Illuminate\Foundation\Http\Events\RequestHandled::class, function ($event) {
$this->executionData->setRequest(new HttpRequest($event->request));
$this->executionData->setRoute($this->routeOf($event->request));
$this->executionData->setSession(new HttpSession(session()));
$this->executionData->setServer(new HttpServer($event->request));
$this->executionData->setResponse(new HttpResponse($event->response));
$this->executionData->setContent(new HttpContent($event->response));
});
}
/**
* @param Request $request
* @return ExecutionRoute
*/
protected function routeOf(Request $request): ExecutionRoute
{
return $request->route() ? new HttpRoute($request->route()) : new NullRoute();
}
}
================================================
FILE: src/LaravelListeners/PerformanceListener.php
================================================
app = $app;
$this->timer = $timer;
$this->memory = $memory;
}
/**
* @return void
*/
public function listen(): void
{
$this->listenHttp();
$this->listenConsole();
}
/**
* @return void
*/
protected function listenHttp(): void
{
Event::listen(Tracking::class, function () {
$this->timer->startLaravel();
});
$this->app->booting(function () {
$this->timer->start('boot');
});
$this->app->booted(function () {
$this->timer->finish('boot');
$this->timer->start($this->resolveRouteName());
});
Event::listen(RouteMatched::class, function () {
$this->timer->finish($this->resolveRouteName());
$this->timer->start('request');
});
/** @codeCoverageIgnoreStart */
Event::listen('kernel.handled', function () {
$this->timer->finish('request');
$this->timer->start('response');
});
/** @codeCoverageIgnoreEnd */
Event::listen(RequestHandled::class, function () {
$this->timer->finish('request');
$this->timer->start('response');
});
Event::listen(Terminating::class, function () {
$this->memory->recordPeak();
$this->timer->finish('response');
$this->timer->finishLaravel();
});
}
/**
* @return void
*/
protected function listenConsole(): void
{
Event::listen(ArtisanStarting::class, function () {
$this->timer->start('command');
});
Event::listen(Terminating::class, function () {
$this->timer->finish('command');
});
}
/**
* @return string
*/
protected function resolveRouteName(): string
{
if ($this->app->runningUnitTests()) {
return 'setup';
}
return 'route';
}
}
================================================
FILE: src/LaravelListeners/QueriesListener.php
================================================
listenQueries();
$this->listenTransactions();
$this->listenResetTrackers();
}
/**
* @return Collection
*/
public function queries(): Collection
{
return Collection::make($this->queries);
}
/**
* @return int
*/
public function count(): int
{
return $this->count;
}
/**
* @return void
*/
protected function listenQueries(): void
{
Event::listen(QueryExecuted::class, function (QueryExecuted $event) {
$this->count++;
list($bindings, $bindingsQuoted) = $this->formatBindings($event);
array_push($this->queries, [
'query',
$event->sql,
$event->time,
$event->connection->getDatabaseName(),
$event->connectionName,
$bindings,
$bindingsQuoted,
]);
});
}
/**
* @return void
*/
protected function listenTransactions(): void
{
Event::listen(TransactionBeginning::class, function (TransactionBeginning $event) {
array_push($this->queries, [
'transaction-begin',
$event->connection->getDatabaseName(),
$event->connectionName,
]);
});
Event::listen(TransactionCommitted::class, function (TransactionCommitted $event) {
array_push($this->queries, [
'transaction-commit',
$event->connection->getDatabaseName(),
$event->connectionName,
]);
});
Event::listen(TransactionRolledBack::class, function (TransactionRolledBack $event) {
array_push($this->queries, [
'transaction-rollback',
$event->connection->getDatabaseName(),
$event->connectionName,
]);
});
}
/**
* @return void
*/
protected function listenResetTrackers(): void
{
Event::listen(ResetTrackers::class, function () {
$this->queries = [];
$this->count = 0;
});
}
/**
* @param QueryExecuted $event
* @return array
*/
protected function formatBindings(QueryExecuted $event): array
{
$preparedBindings = $event->connection->prepareBindings($event->bindings);
foreach ($preparedBindings as $key => $binding) {
$bindings[$key] = $this->truncate($binding);
$bindingsQuoted[$key] = $this->quote($event, $bindings[$key]);
}
return [
$bindings ?? [],
$bindingsQuoted ?? [],
];
}
/**
* @param $binding
* @return mixed
*/
protected function truncate($binding)
{
if (is_string($binding) && strlen($binding) > 255) {
return substr($binding, 0, 255) . '...{truncated}';
}
return $binding;
}
/**
* @param QueryExecuted $event
* @param $binding
* @return mixed
*/
protected function quote(QueryExecuted $event, $binding)
{
if (is_int($binding) || is_float($binding) || is_object($binding)) {
return $binding;
}
return $event->connection->getPdo()->quote($binding);
}
}
================================================
FILE: src/LaravelListeners/RedisListener.php
================================================
listenCommands();
$this->listenResetTrackers();
}
/**
* @return Collection
*/
public function commands(): Collection
{
return Collection::make($this->commands);
}
/**
* @return int
*/
public function count(): int
{
return $this->count;
}
/**
* @return void
*/
protected function listenCommands(): void
{
Event::listen(CommandExecuted::class, function (CommandExecuted $event) {
$this->count++;
array_push($this->commands, [
$event->command,
$event->time,
$event->connectionName,
$event->parameters,
]);
});
}
/**
* @return void
*/
protected function listenResetTrackers(): void
{
Event::listen(ResetTrackers::class, function () {
$this->commands = [];
$this->count = 0;
});
}
}
================================================
FILE: src/LaravelListeners/ViewsListener.php
================================================
listenViews();
$this->listenResetTrackers();
}
/**
* @return Collection
*/
public function views(): Collection
{
return Collection::make($this->views);
}
/**
* @return void
*/
protected function listenViews(): void
{
Event::listen('composing:*', function (...$view) {
array_push($this->views, $this->resolveView($view));
});
}
/**
* @return void
*/
protected function listenResetTrackers(): void
{
Event::listen(ResetTrackers::class, function () {
$this->views = [];
});
}
/**
* @param array $view
* @return View
*/
protected function resolveView(array $view): View
{
return $view[1][0] ?? $view[0];
}
}
================================================
FILE: src/LaravelProfiler.php
================================================
bind();
$this->track();
$this->listenForTerminating();
}
/**
* @return void
*/
protected function bind(): void
{
$this->app->bind(DataTracker::class, LaravelDataTracker::class);
$this->app->bind(DataProcessor::class, LaravelDataProcessor::class);
$this->app->bind(ExecutionWatcher::class, LaravelExecutionWatcher::class);
$this->app->singleton(ExecutionData::class, function ($app) {
return $app->make(LaravelExecutionData::class);
});
$this->app->singleton(Timer::class, function ($app) {
return $app->make(TimerService::class);
});
$this->app->singleton(Memory::class, function ($app) {
return $app->make(MemoryService::class);
});
event(new ProfilerBound());
}
/**
* @return void
*/
protected function track(): void
{
$this->app->make(ExecutionWatcher::class)->watch();
$this->dataTracker = $this->app->make(DataTracker::class);
$this->dataTracker->track();
event(new Tracking());
}
/**
* @return void
*/
protected function listenForTerminating(): void
{
$this->app->afterBootstrapping(BootProviders::class, function () {
$this->registerTerminating();
});
}
/**
* @return void
*/
protected function registerTerminating(): void
{
$this->app->terminating(function () {
event(new Terminating());
$this->dataTracker->terminate();
$this->app->make(DataProcessor::class)->process($this->dataTracker);
});
}
}
================================================
FILE: src/Processors/BroadcastingProcessor.php
================================================
client = $client;
$this->configService = $configService;
}
/**
* @param DataTracker $dataTracker
* @return void
*/
public function process(DataTracker $dataTracker): void
{
$this->broadcast(
$dataTracker,
$this->configService->serverHttpConnectionUrl()
);
}
/**
* @param DataTracker $dataTracker
* @param string $url
* @return Response
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function broadcast(DataTracker $dataTracker, string $url): Response
{
return $this->client->request('POST', $url, [
'json' => [
'meta' => $dataTracker->meta()->toArray(),
'data' => $dataTracker->data()->toArray(),
],
]);
}
}
================================================
FILE: src/Processors/StatusCommandProcessor.php
================================================
broadcast(
$dataTracker,
$this->configService->serverHttpConnectionUrl() . '/status'
);
$body = json_decode($response->getBody());
event(new ProfilerServerConnectionSuccessful($body->sockets, $body->clients));
} catch (ConnectException $e) {
event(new ProfilerServerConnectionFailed());
throw $e;
}
}
}
================================================
FILE: src/ProfilerResolver.php
================================================
app = $app;
$this->configService = $configService;
}
/**
* @return Profiler
*/
public function resolve(): Profiler
{
if (! $this->configService->isProfilerEnabled()) {
return $this->app->make(DisabledProfiler::class);
}
return $this->app->make(LaravelProfiler::class);
}
}
================================================
FILE: src/ServiceProvider.php
================================================
mergeConfigFrom(static::profilerConfigPath(), 'profiler');
$this->app->singleton(Profiler::class, function ($app) {
return $app->make(ProfilerResolver::class)->resolve();
});
$this->app->make(Profiler::class)->listenForBoot();
}
/**
* @return void
*/
public function boot(): void
{
$this->allowConfigFileToBePublished();
}
/**
* @return void
*/
public function allowConfigFileToBePublished(): void
{
$this->publishes([
static::profilerConfigPath() => config_path('profiler.php'),
]);
}
/**
* @return string
*/
public static function profilerConfigPath(): string
{
return __DIR__ . '/../config/profiler.php';
}
}
================================================
FILE: src/Services/ConfigService.php
================================================
app = $app;
$this->config = $config;
}
/**
* @return bool
*/
public function isProfilerEnabled(): bool
{
$enabledOverrides = Collection::make($this->config->get('profiler.enabled_overrides'));
$envToDisable = $enabledOverrides->filter(function ($enabled) {
return ! $enabled;
})->keys();
if ($this->app->environment($envToDisable->toArray())) {
return false;
}
return $this->config->get('profiler.enabled') === true;
}
/**
* @return Collection
*/
public function trackers(): Collection
{
return Collection::make($this->config->get('profiler.trackers'));
}
/**
* @return Collection
*/
public function processors(): Collection
{
return Collection::make($this->config->get('profiler.processors'));
}
/**
* @param array $processors
*/
public function overrideProcessors(array $processors): void
{
$this->config->set('profiler.processors', $processors);
}
/**
* @return Collection
*/
public function pathsToTurnOffProcessors(): Collection
{
return Collection::make($this->config->get('profiler.turn_off_processors_for_paths'));
}
/**
* @return string
*/
public function serverHttpConnectionUrl(): string
{
$address = $this->config->get('profiler.server_http.address');
$port = $this->config->get('profiler.server_http.port');
return $address . ':' . $port;
}
/**
* @return string
*/
public function serverHttpPort(): string
{
return $this->config->get('profiler.server_http.port');
}
/**
* @return string
*/
public function serverSocketsPort(): string
{
return $this->config->get('profiler.server_sockets.port');
}
/**
* @return bool
*/
public function isViewsDataEnabled(): bool
{
return $this->config->get('profiler.data.views');
}
/**
* @return bool
*/
public function isEventsDataEnabled(): bool
{
return $this->config->get('profiler.data.events');
}
/**
* @return bool
*/
public function isEventsGroupEnabled(): bool
{
return $this->config->get('profiler.group.events');
}
/**
* @param int $level
* @return bool
*/
public function handleExceptions(int $level): bool
{
return $this->config->get('profiler.handle_exceptions') === $level;
}
}
================================================
FILE: src/Services/ConsoleService.php
================================================
app = $app;
$this->configService = $configService;
}
/**
* @return string
*/
public function envInfo(): string
{
return "Your current environment is: {$this->app->environment()}";
}
/**
* @return string
*/
public function profilerStatusInfo(): string
{
$status = $this->configService->isProfilerEnabled() ? 'enabled' : 'disabled';
return "Laravel Profiler is: {$status}";
}
/**
* @return string
*/
public function trackersStatusInfo(): string
{
return "You have {$this->configService->trackers()->count()} tracker(s) turned on";
}
/**
* @return string
*/
public function trackersCommentLine1(): string
{
return 'There are 14 trackers available out of the box';
}
/**
* @return string
*/
public function trackersCommentLine2(): string
{
return 'turn them on and off in profiler.php configuration file';
}
/**
* @return string
*/
public function connectionStatusInfo(): string
{
return "Trying to connect to Profiler Server on {$this->configService->serverHttpConnectionUrl()} ...";
}
/**
* @return string
*/
public function connectionSuccessfulInfo(): string
{
return 'Connected successfully';
}
/**
* @param int $socketsPort
* @return string
*/
public function connectionSuccessfulSocketsInfo(int $socketsPort): string
{
return "Profiler Server sockets listening on port: {$socketsPort}";
}
/**
* @param int $countClients
* @return string
*/
public function connectionSuccessfulClientsInfo(int $countClients): string
{
return "You have {$countClients} Profiler Client(s) connected at the moment";
}
/**
* @return string
*/
public function connectionFailedInfo(): string
{
return 'Connection failed';
}
/**
* @return string
*/
public function connectionStatusUnknownInfo(): string
{
return 'BroadcastingProcessor did not report connection status, connection status is unknown';
}
/**
* @return string
*/
public function profilerServerCmd(): string
{
$http = $this->configService->serverHttpPort();
$ws = $this->configService->serverSocketsPort();
return "node node_modules/laravel-profiler-client/server/server.js http={$http} ws={$ws}";
}
/**
* @param bool $manual
* @return string
*/
public function profilerClientCmd(bool $manual): string
{
$options = $manual ? '' : ' -o -s';
return "node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/{$options}";
}
}
================================================
FILE: src/Services/GeneratorService.php
================================================
configService = $configService;
}
/**
* @param Exception $e
* @throws Exception
* @return void
*/
public function error(Exception $e): void
{
if ($this->configService->handleExceptions(self::HANDLE_EXCEPTIONS_THROW)) {
throw $e;
}
if ($this->configService->handleExceptions(self::HANDLE_EXCEPTIONS_LOG)) {
Log::error($e);
}
}
}
================================================
FILE: src/Services/ParamsService.php
================================================
resolveObject($param);
}
if (is_array($param)) {
return array_map(function ($item) {
return $this->resolve($item);
}, $param);
}
return $param;
}
/**
* @param array $params
* @return array
*/
public function resolveFlattenFromArray(array $params): array
{
return array_map(function ($param) {
return $this->resolveFlatten($param);
}, $params);
}
/**
* @param $param
* @return string
*/
protected function resolveFlatten($param): string
{
if ($param instanceof Collection) {
return get_class($param) . ': ' . $param->count() . ' item(s)';
}
if (is_object($param)) {
return get_class($param);
}
if (is_array($param)) {
return 'array: ' . count($param) . ' item(s)';
}
return gettype($param);
}
/**
* @param $param
* @return array|string
*/
protected function resolveObject($param)
{
if (method_exists($param, 'toArray')) {
return $this->resolve($param->toArray());
}
return get_class($param);
}
}
================================================
FILE: src/Services/Performance/MemoryService.php
================================================
app = $app;
$this->memory = Collection::make();
}
/**
* @return void
*/
public function recordPeak(): void
{
$this->memory->put('peak', memory_get_peak_usage());
}
/**
* @return Collection
*/
public function all(): Collection
{
return $this->memory;
}
}
================================================
FILE: src/Services/Performance/NullTimerService.php
================================================
app = $app;
$this->time = Collection::make();
}
/**
* @param string $name
* @return void
*/
public function start(string $name): void
{
$this->time->put($name, [
'start' => $this->now(),
]);
}
/**
* @param string $name
* @return void
*/
public function finish(string $name): void
{
$this->time->put($name, array_merge($this->getByName($name), [
'finish' => $this->now(),
]));
}
/**
* @param string $name
* @return void
* @throws TimerException
*/
public function startCustom(string $name): void
{
$customName = $this->customNamePrefix . $name;
$this->guardTimerAlreadyStarted($customName);
$this->start($customName);
}
/**
* @param string $name
* @return void
* @throws TimerException
*/
public function finishCustom(string $name): void
{
$customName = $this->customNamePrefix . $name;
$this->guardTimerAlreadyFinished($customName);
$this->guardTimerNotStartedYet($customName);
$this->finish($customName);
}
/**
* @return void
*/
public function startLaravel(): void
{
$this->time->put('laravel', [
'start' => $this->laravelStartTimeOrNow(),
]);
}
/**
* @return void
*/
public function finishLaravel(): void
{
$this->finish('laravel');
}
/**
* @param string $name
* @return float
*/
public function milliseconds(string $name): float
{
return $this->millisecondsOf(
$this->getByName($name)
);
}
/**
* @param string $name
* @return float
*/
public function millisecondsCustom(string $name): float
{
return $this->milliseconds($this->customNamePrefix . $name);
}
/**
* @return array
*/
public function all(): array
{
return $this->time->filter(function ($item) {
return $this->isCompleted($item);
})->map(function ($item) {
return $this->millisecondsOf($item);
})->toArray();
}
/**
* @return float
*/
protected function now(): float
{
return \microtime(true);
}
/**
* @return float
*/
protected function laravelStartTimeOrNow(): float
{
return defined('LARAVEL_START') && ! $this->app->environment('testing')
? LARAVEL_START
: $this->now();
}
/**
* @param string $name
* @return array
*/
protected function getByName(string $name): array
{
return $this->time->first(function ($a, $b) use ($name) {
return $a === $name || $b === $name;
}) ?? [];
}
/**
* @param array $item
* @return float
*/
protected function millisecondsOf(array $item): float
{
if (! $this->isCompleted($item)) {
return -1;
}
return ($item['finish'] - $item['start']) * 1000;
}
/**
* @param array $item
* @return bool
*/
protected function isCompleted(array $item): bool
{
return isset($item['start']) && isset($item['finish']);
}
/**
* @param string $name
* @return void
* @throws TimerException
*/
protected function guardTimerAlreadyStarted(string $name): void
{
if ($this->time->has($name)) {
throw new TimerException("Laravel Profiler custom time tracker for {$name} already exists and can not be started twice");
}
}
/**
* @param string $name
* @return void
* @throws TimerException
*/
protected function guardTimerAlreadyFinished(string $name): void
{
if ($this->isCompleted($this->getByName($name))) {
throw new TimerException("Laravel Profiler custom time tracker for {$name} already exists and can not be finished twice");
}
}
/**
* @param string $name
* @return void
* @throws TimerException
*/
protected function guardTimerNotStartedYet(string $name): void
{
if (! $this->time->has($name)) {
throw new TimerException("Laravel Profiler custom time tracker for {$name} is not started yet");
}
}
}
================================================
FILE: src/Services/helpers.php
================================================
make(Timer::class)->startCustom($name);
} catch (TimerException $e) {
app()->make(LogService::class)->error($e);
}
}
}
if (! function_exists('profiler_finish')) {
function profiler_finish(string $name): void
{
try {
app()->make(Timer::class)->finishCustom($name);
} catch (TimerException $e) {
app()->make(LogService::class)->error($e);
}
}
}
if (! function_exists('profiler_reset')) {
function profiler_reset(): void
{
app()->make(Profiler::class)->resetTrackers();
}
}
================================================
FILE: src/Trackers/ApplicationTracker.php
================================================
generatorService = $generatorService;
}
/**
* @return void
*/
public function terminate(): void
{
$this->meta->put('execution_at', time());
$this->meta->put('id', $this->generatorService->unique32CharsId());
$this->meta->put('laravel_version', $this->app->version());
$this->meta->put('php_version', phpversion());
$this->meta->put('env', $this->app->environment());
$this->meta->put('is_running_in_console', $this->app->runningInConsole());
$this->data->put('application', Collection::make([
'locale' => $this->app->getLocale(),
'configuration_is_cached' => $this->app->configurationIsCached(),
'routes_are_cached' => $this->app->routesAreCached(),
'is_down_for_maintenance' => $this->app->isDownForMaintenance(),
'should_skip_middleware' => $this->app->shouldSkipMiddleware(),
]));
}
}
================================================
FILE: src/Trackers/AuthTracker.php
================================================
authListener = $authListener;
$this->authListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$this->data->put('auth', $this->authListener->user());
}
}
================================================
FILE: src/Trackers/BaseTracker.php
================================================
app = $app;
$this->meta = new Collection();
$this->data = new Collection();
}
/**
* @return Collection
*/
public function meta(): Collection
{
return $this->meta;
}
/**
* @return Collection
*/
public function data(): Collection
{
return $this->data;
}
}
================================================
FILE: src/Trackers/BindingsTracker.php
================================================
abstracts()->map(function ($abstract) {
try {
$resolved = $this->resolved($abstract);
} catch (BindingResolutionException $e) {}
return [
'abstract' => $abstract,
'resolved' => $resolved ?? null,
];
});
$this->data->put('bindings', $bindings);
}
/**
* @return Collection
*/
protected function abstracts(): Collection
{
return Collection::make(
array_keys($this->app->getBindings())
);
}
/**
* @param string $abstract
* @return string
* @throws BindingResolutionException
*/
protected function resolved(string $abstract): string
{
if (! $this->app->resolved($abstract)) {
throw new BindingResolutionException();
}
$concrete = $this->app->make($abstract);
if (is_object($concrete)) {
return get_class($concrete);
}
return gettype($concrete);
}
}
================================================
FILE: src/Trackers/ConfigTracker.php
================================================
data->put('config', $this->config());
}
/**
* @return Collection
*/
protected function config(): Collection
{
return Collection::make(
$this->hideSecretValues(
$this->app->make('config')->all()
)
);
}
/**
* @param array $config
* @return array
*/
protected function hideSecretValues(array $config): array
{
$keys = array_keys($config);
return array_map(function ($value) use (&$keys) {
$key = array_shift($keys);
if (is_array($value)) {
return $this->hideSecretValues($value);
}
if (is_string($value) && preg_match('/^(password|key|secret)$/i', $key)) {
$value = str_repeat('*', strlen($value));
}
return $value;
}, $config);
}
}
================================================
FILE: src/Trackers/ContentTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$content = $this->executionData->content();
$this->meta = $content->meta();
$this->data->put('content', $content->data()->get('content'));
}
}
================================================
FILE: src/Trackers/EventsTracker.php
================================================
paramsService = $paramsService;
$this->configService = $configService;
$this->eventsListener = $eventsListener;
$this->eventsListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$events = $this->eventsListener->events()->map(function ($item) {
list($event, $payload, $name, $count) = $item;
if ($this->shouldTrackData($count)) {
return [
'name' => $name,
'count' => $count,
'data' => $this->resolveData($event, $payload),
];
}
return [
'name' => $name,
'count' => $count,
];
});
$this->meta->put('events_count', $this->eventsListener->count());
$this->data->put('events', $events);
}
/**
* @param int $count
* @return bool
*/
protected function shouldTrackData(int $count): bool
{
return $this->configService->isEventsDataEnabled() && $count == 1;
}
/**
* @param $event
* @param $payload
* @return Collection
*/
protected function resolveData($event, $payload): Collection
{
$event = is_array($payload) ? $payload[0] : $event;
$class = new \ReflectionClass($event);
$publicProps = Collection::make(
$class->getProperties(\ReflectionProperty::IS_PUBLIC)
);
if (method_exists($publicProps, 'mapWithKeys')) {
return $this->propsMapWithKeys($publicProps, $event);
}
return $this->propsMap($publicProps, $event); // @codeCoverageIgnore
}
/**
* @param Collection $publicProps
* @param $event
* @return Collection
*/
protected function propsMapWithKeys(Collection $publicProps, $event): Collection
{
return $publicProps->mapWithKeys(function ($prop) use ($event) {
return [
$prop->name => $this->paramsService->resolve($event->{$prop->name}),
];
});
}
/**
* @codeCoverageIgnore
*
* @param Collection $publicProps
* @param $event
* @return Collection
*/
protected function propsMap(Collection $publicProps, $event): Collection
{
return $publicProps->map(function ($prop) use ($event) {
return [
$prop->name => $this->paramsService->resolve($event->{$prop->name}),
];
})->flatten(1);
}
}
================================================
FILE: src/Trackers/ExceptionTracker.php
================================================
exceptionListener = $exceptionListener;
$this->exceptionListener->listen();
$this->bindExceptionHandler($app);
}
/**
* @param Application $app
* @return void
*/
protected function bindExceptionHandler(Application $app): void
{
$version = (int) $app->version();
$handler = $version < 7
? ExceptionHandlerTillVersion6::class
: ExceptionHandlerFromVersion7::class; // @codeCoverageIgnore
$app->singleton(\App\Exceptions\Handler::class, $handler);
}
/**
* @return void
*/
public function terminate(): void
{
$exception = $this->exceptionListener->exception() ? $this->exception() : null;
$this->data->put('exception', $exception);
}
/**
* @return Collection
*/
protected function exception(): Collection
{
$exception = $this->exceptionListener->exception();
return Collection::make([
'message' => $exception->getMessage(),
'exception' => get_class($exception),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => Collection::make($exception->getTrace())->map(function ($trace) {
return Arr::except($trace, ['args', 'type']);
}),
]);
}
}
================================================
FILE: src/Trackers/PathsTracker.php
================================================
paths()->map(function ($path, $name) {
return [
'name' => $name,
'path' => $path,
];
})->values();
$this->data->put('paths', $paths);
}
/**
* @return Collection
*/
protected function paths(): Collection
{
return Collection::make([
'app_path' => $this->app->path(),
'base_path' => $this->app->basePath(),
'lang_path' => $this->app->langPath(),
'config_path' => $this->app->configPath(),
'public_path' => $this->app->publicPath(),
'storage_path' => $this->app->storagePath(),
'resource_path' => $this->resourcePath(),
'database_path' => $this->app->databasePath(),
'bootstrap_path' => $this->app->bootstrapPath(),
'cached_config_path' => $this->app->getCachedConfigPath(),
'cached_routes_path' => $this->app->getCachedRoutesPath(),
'cached_services_path' => $this->app->getCachedServicesPath(),
'cached_packages_path' => $this->getCachedPackagesPath(),
'environment_file_path' => $this->app->environmentFilePath(),
])->filter(function ($item) {
return !! $item;
});
}
/**
* @return string
*/
protected function resourcePath(): string
{
return method_exists($this->app, 'resourcePath')
? $this->app->resourcePath()
: '';
}
/**
* @return string
*/
protected function getCachedPackagesPath(): string
{
return method_exists($this->app, 'getCachedPackagesPath')
? $this->app->getCachedPackagesPath()
: '';
}
}
================================================
FILE: src/Trackers/PerformanceTracker.php
================================================
timer = $timer;
$this->memory = $memory;
$performanceListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$this->data->put('performance', Collection::make([
'timer' => $this->timer->all(),
'memory' => $this->memory->all(),
]));
}
}
================================================
FILE: src/Trackers/QueriesTracker.php
================================================
queriesListener = $queriesListener;
$this->queriesListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$queries = $this->queriesListener->queries()->map(function ($item) {
if ($this->isTransactionType($item[0])) {
return $this->terminateTransaction($item);
}
return $this->terminateQuery($item);
});
$this->meta->put('queries_count', $this->queriesListener->count());
$this->data->put('queries', $queries);
}
/**
* @param array $item
* @return array
*/
protected function terminateTransaction(array $item): array
{
list($type, $database, $name) = $item;
return [
'type' => $type,
'database' => $database,
'name' => $name,
];
}
/**
* @param array $item
* @return array
*/
protected function terminateQuery(array $item): array
{
list($type, $sql, $time, $database, $name, $bindings, $bindingsQuoted) = $item;
$formattedSql = $this->formatSql($sql);
return [
'type' => $type,
'sql' => $formattedSql,
'bindings' => $bindings,
'time' => $time,
'database' => $database,
'name' => $name,
'query' => $this->queryWithBindings($bindingsQuoted, $formattedSql),
];
}
/**
* @param string $type
* @return bool
*/
protected function isTransactionType(string $type): bool
{
$transactionTypes = [
'transaction-begin',
'transaction-commit',
'transaction-rollback',
];
return in_array($type, $transactionTypes);
}
/**
* @param string $sql
* @return string
*/
protected function formatSql(string $sql): string
{
return preg_replace('/"/', '`', $sql);
}
/**
* @param array $bindingsQuoted
* @param string $formattedSql
* @return string
*/
protected function queryWithBindings(array $bindingsQuoted, string $formattedSql): string
{
foreach ($bindingsQuoted as $key => $binding) {
$formattedSql = preg_replace($this->bindingRegex($key), $binding, $formattedSql, 1);
}
return $formattedSql;
}
/**
* @param $key
* @return string
*/
protected function bindingRegex($key): string
{
return is_int($key) ? "/\?/" : "/:{$key}/";
}
}
================================================
FILE: src/Trackers/RedisTracker.php
================================================
enableRedisEvents();
$this->redisListener = $redisListener;
$this->redisListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$commands = $this->redisListener->commands()->map(function ($item) {
return $this->terminateCommands($item);
});
$this->meta->put('redis_count', $this->redisListener->count());
$this->meta->put('redis_can_be_tracked', $this->redisCanBeTracked);
$this->data->put('redis', $commands);
}
/**
* @param array $item
* @return array
*/
protected function terminateCommands(array $item): array
{
list($command, $time, $name, $parameters) = $item;
return [
'command' => $command,
'time' => $time,
'name' => $name,
'parameters' => $parameters,
];
}
/**
* @return void
*/
protected function enableRedisEvents(): void
{
$manager = $this->app->make('redis');
if (! method_exists($manager, 'enableEvents')) {
return; // @codeCoverageIgnore
}
$this->redisCanBeTracked = true;
$manager->enableEvents();
}
}
================================================
FILE: src/Trackers/RequestTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$request = $this->executionData->request();
$this->meta = $request->meta();
$this->data->put('request', $request->data());
}
}
================================================
FILE: src/Trackers/ResponseTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$response = $this->executionData->response();
$this->meta = $response->meta();
$this->data->put('response', $response->data());
}
}
================================================
FILE: src/Trackers/RouteTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$route = $this->executionData->route();
$this->meta = $route->meta();
$this->data->put('route', $route->data());
}
}
================================================
FILE: src/Trackers/ServerTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$server = $this->executionData->server();
$this->meta = $server->meta();
$this->data->put('server', $server->data());
}
}
================================================
FILE: src/Trackers/ServiceProvidersTracker.php
================================================
data->put('service_providers', $this->loadedProviders());
}
/**
* @return Collection
*/
protected function loadedProviders(): Collection
{
return Collection::make(
array_keys($this->app->getLoadedProviders())
);
}
}
================================================
FILE: src/Trackers/SessionTracker.php
================================================
executionData = $executionData;
}
/**
* @return void
*/
public function terminate(): void
{
$session = $this->executionData->session();
$this->meta = $session->meta();
$this->data->put('session', $session->data());
}
}
================================================
FILE: src/Trackers/ViewsTracker.php
================================================
configService = $configService;
$this->paramsService = $paramsService;
$this->viewsListener = $viewsListener;
$this->viewsListener->listen();
}
/**
* @return void
*/
public function terminate(): void
{
$views = $this->viewsListener->views()->map(function (View $view) {
if ($this->configService->isViewsDataEnabled()) {
return [
'name' => $view->name(),
'path' => $view->getPath(),
'data' => $view->getData(),
];
}
return [
'name' => $view->name(),
'path' => $view->getPath(),
'params' => $this->paramsService->resolveFlattenFromArray($view->getData()),
];
})->values();
$this->data->put('views', $views);
}
}
================================================
FILE: tests/Feature/CommandsTest.php
================================================
tapLaravelVersionFrom(5.7, function () {
$this->artisan('profiler:status')
->expectsOutput('1) Your current environment is: ' . $this->app->environment())
->expectsOutput('Laravel Profiler is: enabled');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
}
/** @test */
function lists_trackers_if_profiler_is_enabled()
{
$this->app = $this->appWith(function (Application $app) {
$app->make('config')->set('profiler.trackers', [
TrackerA::class,
TrackerB::class,
]);
});
$this->tapLaravelVersionFrom(5.7, function () {
$this->artisan('profiler:status')
->expectsOutput('2) You have 2 tracker(s) turned on')
->expectsOutput('- ' . TrackerA::class)
->expectsOutput('- ' . TrackerB::class)
->expectsOutput("There are {$this->countAllConfigurableTrackers()} trackers available out of the box")
->expectsOutput('turn them on and off in profiler.php configuration file');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
}
/** @test */
function switches_processor_to_status_processor()
{
$this->artisan('profiler:status');
$configService = $this->app->make(ConfigService::class);
$this->assertCount(1, $configService->processors());
$this->assertEquals(StatusCommandProcessor::class, $configService->processors()->first());
}
/** @test */
function status_processor_handles_when_connection_to_profiler_server_is_successful()
{
$this->tapLaravelVersionFrom(5.4, function () {
Event::fake();
$response = Mockery::mock(Response::class);
$response->shouldReceive('getBody')->once()->andReturn('{"sockets": 1234, "clients": 9}');
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andReturn($response);
$configService = Mockery::mock(ConfigService::class);
$configService->shouldReceive('serverHttpConnectionUrl')->once();
$processor = new StatusCommandProcessor($client, $configService);
$processor->process($this->app->make(DataTracker::class));
Event::assertNotDispatched(ProfilerServerConnectionFailed::class);
Event::assertDispatched(ProfilerServerConnectionSuccessful::class, function ($event) {
return $event->socketsPort === 1234 && $event->countClients === 9;
});
});
$this->tapLaravelVersionTill(5.3, function () {
$this->assertTrue(true);
});
}
/** @test */
function status_processor_handles_when_connection_to_profiler_server_failed()
{
$this->tapLaravelVersionFrom(5.4, function () {
Event::fake();
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andThrows(new ConnectException('', new Request('method', '')));
try {
$processor = new StatusCommandProcessor($client, $this->app->make(ConfigService::class));
$processor->process($this->app->make(DataTracker::class));
} catch (ConnectException $e) {
Event::assertDispatched(ProfilerServerConnectionFailed::class);
Event::assertNotDispatched(ProfilerServerConnectionSuccessful::class);
return;
}
$this->fail('ConnectException should be thrown');
});
$this->tapLaravelVersionTill(5.3, function () {
$this->assertTrue(true);
});
}
/** @test */
function tells_if_connection_to_profiler_server_is_successful()
{
$this->tapLaravelVersionFrom(7, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
$this->tapLaravelVersionBetween(5.7, 6, function () {
$realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class));
$consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing();
$consoleService->shouldReceive('connectionStatusInfo')
->once()
->andReturn($realConsoleService->connectionStatusInfo());
$consoleService->shouldReceive('connectionSuccessfulInfo')
->once()
->andReturn($realConsoleService->connectionSuccessfulInfo());
$consoleService->shouldReceive('connectionSuccessfulSocketsInfo')
->once()
->andReturn($realConsoleService->connectionSuccessfulSocketsInfo(1234));
$consoleService->shouldReceive('connectionSuccessfulClientsInfo')
->once()
->andReturn($realConsoleService->connectionSuccessfulClientsInfo(9));
$consoleService->shouldNotReceive('connectionFailedInfo');
$consoleService->shouldNotReceive('connectionStatusUnknownInfo');
$this->app->instance(ConsoleService::class, $consoleService);
$this->app->terminating(function () {
event(new ProfilerServerConnectionSuccessful(1234, 9));
});
$this->artisan('profiler:status')
->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...')
->expectsOutput('Connected successfully')
->expectsOutput('Profiler Server sockets listening on port: 1234')
->expectsOutput("You have 9 Profiler Client(s) connected at the moment");
$this->turnOffProcessors();
$this->app->terminate();
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
}
/** @test */
function tells_if_connection_to_profiler_server_failed()
{
$this->tapLaravelVersionFrom(7, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
$this->tapLaravelVersionBetween(5.7, 6, function () {
$realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class));
$consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing();
$consoleService->shouldReceive('connectionStatusInfo')
->once()
->andReturn($realConsoleService->connectionStatusInfo());
$consoleService->shouldNotReceive('connectionSuccessfulInfo');
$consoleService->shouldReceive('connectionFailedInfo')
->once()
->andReturn($realConsoleService->connectionFailedInfo());
$consoleService->shouldNotReceive('connectionStatusUnknownInfo');
$this->app->instance(ConsoleService::class, $consoleService);
$this->app->terminating(function () {
event(new ProfilerServerConnectionFailed());
});
$this->artisan('profiler:status')
->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...')
->expectsOutput('Connection failed');
$this->turnOffProcessors();
$this->app->terminate();
$consoleService->shouldNotHaveReceived('connectionUnknownInfo');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
}
/** @test */
function tells_if_connection_to_profiler_server_has_unknown_status()
{
$this->tapLaravelVersionFrom(7, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
$this->tapLaravelVersionBetween(5.7, 6, function () {
$realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class));
$consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing();
$consoleService->shouldReceive('connectionStatusInfo')
->once()
->andReturn($realConsoleService->connectionStatusInfo());
$consoleService->shouldNotReceive('connectionSuccessfulInfo');
$consoleService->shouldNotReceive('connectionFailedInfo');
$consoleService->shouldReceive('connectionStatusUnknownInfo')
->once()
->andReturn($realConsoleService->connectionStatusUnknownInfo());
$this->app->instance(ConsoleService::class, $consoleService);
$this->artisan('profiler:status')
->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...')
->expectsOutput('BroadcastingProcessor did not report connection status, connection status is unknown');
$this->turnOffProcessors();
$this->app->terminate();
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
}
/** @test */
function tells_status_if_profiler_is_disabled()
{
$this->app = $this->appWith(function (Application $app) {
$app->make('config')->set('profiler.enabled', false);
});
$configService = Mockery::spy(ConfigService::class)->shouldIgnoreMissing();
$this->app->instance(ConfigService::class, $configService);
$this->tapLaravelVersionFrom(5.7, function () {
$this->artisan('profiler:status')
->expectsOutput('1) Your current environment is: ' . $this->app->environment())
->expectsOutput('Laravel Profiler is: disabled');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:status');
$this->assertTrue(true);
});
$configService->shouldNotHaveReceived('trackers');
}
/** @test */
function can_start_profiler_server()
{
$consoleService = Mockery::spy(ConsoleService::class);
$this->app->instance(ConsoleService::class, $consoleService);
$this->artisan('profiler:server');
$consoleService->shouldHaveReceived('profilerServerCmd')->once();
}
/** @test */
function can_start_profiler_server_with_configured_ports()
{
$configService = Mockery::mock(ConfigService::class);
$configService->shouldReceive('serverHttpPort')->once()->andReturn('1234');
$configService->shouldReceive('serverSocketsPort')->once()->andReturn('9876');
$this->app->instance(ConfigService::class, $configService);
$consoleService = $this->app->make(ConsoleService::class);
$this->assertEquals(
'node node_modules/laravel-profiler-client/server/server.js http=1234 ws=9876',
$consoleService->profilerServerCmd()
);
}
/** @test */
function tells_starting_message_for_profiler_server()
{
$this->tapLaravelVersionFrom(5.7, function () {
$this->artisan('profiler:server')
->expectsOutput('Starting Profiler Server ...');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:server');
$this->assertTrue(true);
});
}
/** @test */
function can_start_profiler_client()
{
$realConsoleService = $this->app->make(ConsoleService::class);
$consoleService = Mockery::mock(ConsoleService::class);
$consoleService->shouldReceive('profilerClientCmd')->once()->with(false);
$this->app->instance(ConsoleService::class, $consoleService);
Artisan::call('profiler:client');
$this->assertEquals(
'node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/ -o -s',
$realConsoleService->profilerClientCmd(false)
);
}
/** @test */
function can_start_profiler_client_with_manual_option()
{
$consoleService = Mockery::mock(ConsoleService::class);
$consoleService->shouldReceive('profilerClientCmd')->twice()->with(true);
$this->app->instance(ConsoleService::class, $consoleService);
Artisan::call('profiler:client', ['--manual' => true]);
Artisan::call('profiler:client', ['-m' => true]);
$realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class));
$this->assertEquals(
'node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/',
$realConsoleService->profilerClientCmd(true)
);
}
/** @test */
function tells_starting_message_for_profiler_client()
{
$this->tapLaravelVersionFrom(5.7, function () {
$this->artisan('profiler:client')
->expectsOutput('Starting Profiler Client ...');
});
$this->tapLaravelVersionTill(5.6, function () {
$this->artisan('profiler:client');
$this->assertTrue(true);
});
}
/**
* @var array
*/
protected $beforeApplicationDestroyedCallbacks = [];
/**
* @param callable $callback
*/
protected function beforeApplicationDestroyed(callable $callback)
{
$this->beforeApplicationDestroyedCallbacks[] = $callback;
}
}
================================================
FILE: tests/Feature/LaravelConsoleExecutionTest.php
================================================
turnOffProcessors();
$this->executionData = $this->app->make(ExecutionData::class);
$this->app->make(Kernel::class)->registerCommand(new DummyCommand($this->testExitCode));
}
/** @test */
function has_console_request()
{
Artisan::call('dummy-command');
$request = $this->executionData->request();
$this->tapLaravelVersionTill(5.4, function () use ($request) {
$this->assertInstanceOf(ConsoleStartingRequest::class, $request);
});
$this->tapLaravelVersionFrom(5.5, function () use ($request) {
$this->assertInstanceOf(ConsoleFinishedRequest::class, $request);
});
}
/** @test */
function has_request_type()
{
Artisan::call('dummy-command');
$request = $this->executionData->request();
$this->tapLaravelVersionTill(5.4, function () use ($request) {
$this->assertEquals('command-starting', $request->meta()->get('type'));
});
$this->tapLaravelVersionFrom(5.5, function () use ($request) {
$this->assertEquals('command-finished', $request->meta()->get('type'));
});
}
/** @test */
function has_request_method()
{
Artisan::call('dummy-command');
$request = $this->executionData->request();
$this->tapLaravelVersionTill(5.4, function () use ($request) {
$this->assertArrayNotHasKey('path', $request->meta());
});
$this->tapLaravelVersionFrom(5.5, function () use ($request) {
$this->assertEquals('dummy-command', $request->meta()->get('path'));
});
}
/** @test */
function has_request_arguments()
{
Artisan::call('dummy-command', ['user' => 'Abc']);
$request = $this->executionData->request();
$this->tapLaravelVersionTill(5.4, function () use ($request) {
$this->assertArrayNotHasKey('arguments', $request->data());
});
$this->tapLaravelVersionFrom(5.5, function () use ($request) {
$this->assertEquals('dummy-command', $request->data()->get('arguments')['command']);
$this->assertEquals('Abc', $request->data()->get('arguments')['user']);
});
}
/** @test */
function has_request_options()
{
Artisan::call('dummy-command', ['--number' => 5]);
$request = $this->executionData->request();
$this->tapLaravelVersionTill(5.4, function () use ($request) {
$this->assertArrayNotHasKey('options', $request->data());
});
$this->tapLaravelVersionFrom(5.5, function () use ($request) {
$this->assertEquals(5, $request->data()->get('options')['number']);
});
}
/** @test */
function has_null_route()
{
Artisan::call('dummy-command');
$route = $this->executionData->route();
$this->assertInstanceOf(NullRoute::class, $route);
}
/** @test */
function has_null_session()
{
Artisan::call('dummy-command');
$session = $this->executionData->session();
$this->assertInstanceOf(NullSession::class, $session);
}
/** @test */
function has_null_server()
{
Artisan::call('dummy-command');
$server = $this->executionData->server();
$this->assertInstanceOf(NullServer::class, $server);
}
/** @test */
function has_console_response()
{
Artisan::call('dummy-command');
$response = $this->executionData->response();
$this->tapLaravelVersionTill(5.4, function () use ($response) {
$this->assertInstanceOf(ConsoleStartingResponse::class, $response);
});
$this->tapLaravelVersionFrom(5.5, function () use ($response) {
$this->assertInstanceOf(ConsoleFinishedResponse::class, $response);
});
}
/** @test */
function console_response_has_only_status()
{
Artisan::call('dummy-command');
$response = $this->executionData->response();
$this->tapLaravelVersionTill(5.4, function () use ($response) {
$this->assertArrayHasKey('status', $response->meta());
$this->assertNull($response->meta()->get('status'));
$this->assertCount(1, $response->meta());
$this->assertCount(0, $response->data());
});
$this->tapLaravelVersionFrom(5.5, function () use ($response) {
$this->assertEquals($this->testExitCode, $response->meta()->get('status'));
$this->assertCount(1, $response->meta());
$this->assertCount(0, $response->data());
});
}
/** @test */
function has_null_content()
{
Artisan::call('dummy-command');
$content = $this->executionData->content();
$this->assertInstanceOf(NullContent::class, $content);
}
}
================================================
FILE: tests/Feature/LaravelExecutionTest.php
================================================
turnOffProcessors();
}
/** @test */
function laravel_execution_data_is_singleton()
{
$executionDataA = $this->app->make(ExecutionData::class);
$executionDataB = $this->app->make(ExecutionData::class);
$this->assertSame($executionDataA, $executionDataB);
}
}
================================================
FILE: tests/Feature/LaravelHttpExecutionTest.php
================================================
turnOffProcessors();
$this->executionData = $this->app->make(ExecutionData::class);
}
/** @test */
function has_http_request()
{
$this->get('/');
$request = $this->executionData->request();
$this->assertInstanceOf(HttpRequest::class, $request);
}
/** @test */
function has_request_type()
{
$this->get('/');
$request = $this->executionData->request();
$this->assertEquals('http', $request->meta()->get('type'));
}
/** @test */
function has_request_method()
{
$this->post('/', []);
$request = $this->executionData->request();
$this->assertEquals('POST', $request->meta()->get('method'));
}
/** @test */
function has_request_path()
{
$this->get('/abc/xyz');
$request = $this->executionData->request();
$this->assertEquals('abc/xyz', $request->meta()->get('path'));
}
/** @test */
function has_request_is_ajax()
{
$this->get('/');
$this->assertFalse($this->executionData->request()->meta()->get('ajax'));
$this->get('/', ['X-Requested-With' => 'XMLHttpRequest']);
$this->assertTrue($this->executionData->request()->meta()->get('ajax'));
}
/** @test */
function has_request_is_json()
{
$this->get('/');
$this->assertFalse($this->executionData->request()->meta()->get('json'));
$this->get('/', ['Content-Type' => 'application/json']);
$this->assertTrue($this->executionData->request()->meta()->get('json'));
}
/** @test */
function has_request_is_pjax()
{
$this->get('/');
$this->assertFalse($this->executionData->request()->data()->get('pjax'));
$this->get('/', ['X-PJAX' => true]);
$this->assertTrue($this->executionData->request()->data()->get('pjax'));
}
/** @test */
function has_request_url()
{
$this->get('/abc?ab=xy');
$request = $this->executionData->request();
$this->assertEquals("{$this->app->make('request')->root()}/abc", $request->data()->get('url'));
}
/** @test */
function has_request_query()
{
$this->get('/abc?ab=xy');
$this->assertEquals(['ab' => 'xy'], $this->executionData->request()->data()->get('query'));
}
/** @test */
function can_have_empty_request_query()
{
$this->get('/');
$this->assertEquals([], $this->executionData->request()->data()->get('query'));
}
/** @test */
function has_request_ip()
{
$this->get('/');
$request = $this->executionData->request();
$this->assertEquals($this->app->make('request')->ip(), $request->data()->get('ip'));
}
/** @test */
function has_request_server()
{
$this->get('/');
$server = $this->executionData->server();
$this->assertCount(0, $server->meta());
$this->assertEquals($this->app->make('request')->server(), $server->data()->toArray());
}
/** @test */
function has_request_header()
{
$this->get('/');
$request = $this->executionData->request();
$this->assertEquals($this->app->make('request')->header(), $request->data()->get('header'));
}
/** @test */
function has_request_input()
{
$this->post('/', [
'key-a' => 'val-a',
'key-b' => 'val-b',
]);
$request = $this->executionData->request();
$this->assertEquals('val-a', $request->data()->get('input')['key-a']);
$this->assertEquals('val-b', $request->data()->get('input')['key-b']);
}
/** @test */
function has_request_all_files()
{
$this->tapLaravelVersionTill(5.3, function () {
$this->assertTrue(true);
});
$this->tapLaravelVersionBetween(5.4, 6, function () {
$fileA = UploadedFile::fake()->image('file-val-a.png');
$fileB = UploadedFile::fake()->image('file-val-b.png');
$typeA = get_class($fileA);
$typeB = get_class($fileB);
$this->post('/', [
'file-key-a' => $fileA,
'file-key-b' => $fileB,
]);
$request = $this->executionData->request();
$this->assertEquals([
'client original name' => $fileA->getClientOriginalName(),
'client original extension' => $fileA->getClientOriginalExtension(),
'client mime type' => $fileA->getClientMimeType(),
'client size' => $fileA->getClientSize(),
'path' => $fileA->path(),
], $request->data()->get('files')['file-key-a'][$typeA]);
$this->assertEquals([
'client original name' => $fileB->getClientOriginalName(),
'client original extension' => $fileB->getClientOriginalExtension(),
'client mime type' => $fileB->getClientMimeType(),
'client size' => $fileB->getClientSize(),
'path' => $fileB->path(),
], $request->data()->get('files')['file-key-b'][$typeB]);
});
$this->tapLaravelVersionFrom(7, function () {
$fileA = UploadedFile::fake()->image('file-val-a.png');
$fileB = UploadedFile::fake()->image('file-val-b.png');
$typeA = get_class($fileA);
$typeB = get_class($fileB);
$this->post('/', [
'file-key-a' => $fileA,
'file-key-b' => $fileB,
]);
$request = $this->executionData->request();
$this->assertEquals([
'client original name' => $fileA->getClientOriginalName(),
'client original extension' => $fileA->getClientOriginalExtension(),
'client mime type' => $fileA->getClientMimeType(),
'client size' => $fileA->getSize(),
'path' => $fileA->path(),
], $request->data()->get('files')['file-key-a'][$typeA]);
$this->assertEquals([
'client original name' => $fileB->getClientOriginalName(),
'client original extension' => $fileB->getClientOriginalExtension(),
'client mime type' => $fileB->getClientMimeType(),
'client size' => $fileB->getSize(),
'path' => $fileB->path(),
], $request->data()->get('files')['file-key-b'][$typeB]);
});
}
/** @test */
function has_request_all_files_if_they_are_in_array()
{
$this->tapLaravelVersionTill(5.3, function () {
$this->assertTrue(true);
});
$this->tapLaravelVersionFrom(5.4, function () {
$fileA = UploadedFile::fake()->image('file-val-a.png');
$fileB = UploadedFile::fake()->image('file-val-b.png');
$fileX = UploadedFile::fake()->image('file-val-x.png');
$fileY = UploadedFile::fake()->image('file-val-y.png');
$typeA = get_class($fileA);
$typeB = get_class($fileB);
$typeX = get_class($fileX);
$typeY = get_class($fileY);
$this->post('/', [
'file-key-1' => [
'a' => $fileA,
'b' => $fileB,
],
'file-key-2' => [
'subkey' => [
'x' => $fileX,
'y' => $fileY,
],
],
]);
$request = $this->executionData->request();
$this->assertContains($fileA->path(), $request->data()->get('files')['file-key-1']['a'][$typeA]);
$this->assertContains($fileB->path(), $request->data()->get('files')['file-key-1']['b'][$typeB]);
$this->assertContains($fileX->path(), $request->data()->get('files')['file-key-2']['subkey']['x'][$typeX]);
$this->assertContains($fileY->path(), $request->data()->get('files')['file-key-2']['subkey']['y'][$typeY]);
});
}
/** @test */
function has_request_cookie()
{
$this->tapLaravelVersionTill('5.4', function () {
$this->call('GET', '/', [], ['cookie-key-a' => Crypt::encrypt('cookie-val-a')]);
$request = $this->executionData->request();
$this->assertStringContainsString('cookie-val-a', $request->data()->get('cookie')['cookie-key-a']);
});
$this->tapLaravelVersionBetween('5.5', '5.5', function () {
$this->call('GET', '/', [], ['cookie-key-a' => [Crypt::encrypt('cookie-val-a')]]);
$request = $this->executionData->request();
$this->assertStringContainsString('cookie-val-a', Crypt::decrypt($request->data()->get('cookie')['cookie-key-a'][0]));
});
$this->tapLaravelVersionBetween('5.6', '5.8', function () {
$this->call('GET', '/', [], ['cookie-key-a' => Crypt::encrypt('cookie-val-a')]);
$request = $this->executionData->request();
$this->assertStringContainsString('cookie-val-a', $request->data()->get('cookie')['cookie-key-a']);
});
$this->tapLaravelVersionFrom('6', function () {
$this->call('GET', '/', [], ['cookie-key-a' => [Crypt::encrypt('cookie-val-a')]]);
$request = $this->executionData->request();
$this->assertStringContainsString('cookie-val-a', Crypt::decrypt($request->data()->get('cookie')['cookie-key-a'][0]));
});
}
/** @test */
function has_http_route()
{
$this->get('/');
$route = $this->executionData->route();
$this->assertInstanceOf(HttpRoute::class, $route);
}
/** @test */
function has_null_route_when_route_is_not_matched()
{
$this->get('/not-found');
$route = $this->executionData->route();
$this->assertInstanceOf(NullRoute::class, $route);
}
/** @test */
function has_route_methods()
{
Route::get('route-a/{id}', function ($id) {
return $id;
});
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals(['GET', 'HEAD'], $route->data()->get('methods'));
}
/** @test */
function has_route_uri()
{
Route::get('route-a/{id}', function ($id) {
return $id;
});
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals('route-a/{id}', $route->data()->get('uri'));
}
/** @test */
function has_route_name()
{
Route::get('route-a/{id}', function ($id) {
return $id;
})->name('route.a.with.id');
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals('route.a.with.id', $route->data()->get('name'));
}
/** @test */
function has_route_middleware()
{
Route::get('route-a/{id}', function ($id) {
return $id;
})->middleware('auth');
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals(['auth'], $route->data()->get('middleware'));
}
/** @test */
function has_route_parameters()
{
Route::get('route-a/{id}', function ($id) {
return $id;
});
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals(['id' => '123'], $route->data()->get('parameters'));
}
/** @test */
function has_route_prefix()
{
Route::group(['prefix' => 'admin'], function () {
Route::get('route-a/{id}', function ($id) {
return $id;
});
});
$this->get('/admin/route-a/123');
$route = $this->executionData->route();
$this->assertEquals('admin', $route->data()->get('prefix'));
}
/** @test */
function has_route_closure_action()
{
$uses = function (DummyClassA $a, DummyFormRequest $request) {
return $request->get('id');
};
$action = new ReflectionFunction($uses);
Route::get('route-a/{id}', $uses);
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertStringContainsString(
'LaravelHttpExecutionTest.php:' . $action->getStartLine() . '-' . $action->getEndLine(),
$route->data()->get('uses')['closure']
);
$this->assertEquals(
DummyFormRequest::class,
$route->data()->get('uses')['form_request']
);
}
/** @test */
function has_route_controller_action()
{
Route::get('route-a/{id}', '\JKocik\Laravel\Profiler\Tests\Support\Fixtures\DummyController@dummyAction');
$action = new ReflectionMethod(DummyController::class, 'dummyAction');
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertStringContainsString(
'DummyController@dummyAction:' . $action->getStartLine() . '-' . $action->getEndLine(),
$route->data()->get('uses')['controller']
);
$this->assertEquals(
DummyFormRequest::class,
$route->data()->get('uses')['form_request']
);
}
/** @test */
function has_route_without_form_request_if_form_request_is_not_defined()
{
$uses = function ($id) {
return $id;
};
Route::get('route-a/{id}', $uses);
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals('', $route->data()->get('uses')['form_request']);
}
/** @test */
function has_route_with_not_existing_controller()
{
Route::get('route-a/{id}', '\JKocik\Laravel\Profiler\Tests\Support\Fixtures\NotExistingController@dummyAction');
$this->tapLaravelVersionTill(5.2, function () {
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertInstanceOf(NullRoute::class, $route);
});
$this->tapLaravelVersionBetween(5.3, 5.3, function () {
try {
$this->get('/route-a/123');
} catch (ReflectionException $e) {
$this->assertTrue(true);
}
});
$this->tapLaravelVersionFrom(5.4, function () {
$this->get('/route-a/123');
$route = $this->executionData->route();
$this->assertEquals([], $route->data()->get('uses'));
});
}
/** @test */
function has_http_session()
{
$this->get('/');
$session = $this->executionData->session();
$this->assertInstanceOf(HttpSession::class, $session);
}
/** @test */
function has_http_session_data()
{
$this->withSession([
'abc' => 123,
'xyz' => 789,
])->get('/');
$session = $this->executionData->session();
$this->assertEquals(123, $session->data()->get('abc'));
$this->assertEquals(789, $session->data()->get('xyz'));
}
/** @test */
function has_http_response()
{
$this->get('/');
$response = $this->executionData->response();
$this->assertInstanceOf(HttpResponse::class, $response);
}
/** @test */
function has_response_status()
{
$this->get('/i-can-not-find-that-page');
$response = $this->executionData->response();
$this->assertEquals(404, $response->meta()->get('status'));
$this->assertEquals('Not Found', $response->meta()->get('status_text'));
}
/** @test */
function can_have_response_unknown_status()
{
Route::get('unknown', function () {
abort(419);
});
$this->get('/unknown');
$response = $this->executionData->response();
$this->assertEquals(419, $response->meta()->get('status'));
$this->assertEquals('unknown status', $response->meta()->get('status_text'));
}
/** @test */
function has_response_headers()
{
$this->get('/');
$response = $this->executionData->response();
$this->assertArrayHasKey('content-type', $response->data()->get('headers'));
}
/** @test */
function has_response_content()
{
$this->get('/');
$content = $this->executionData->content();
$this->assertCount(0, $content->meta());
$this->assertStringNotContainsString('HTTP/1.1 200 OK', $content->data()->get('content'));
$this->assertStringContainsString('