Skip to content

Commit 8414f3c

Browse files
authored
Merge pull request #76 from honeybadger-io/user-informer
Implement user informer and feedback form Blade directives
2 parents 3f53100 + 1747519 commit 8414f3c

File tree

7 files changed

+167
-23
lines changed

7 files changed

+167
-23
lines changed

resources/lang/en/feedback.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
return [
4+
'thanks' => 'Thanks for the feedback!',
5+
'heading' => 'Care to help us fix this?',
6+
'explanation' => 'Any information you can provide will help our technical team get to the bottom of this issue.',
7+
'labels' => [
8+
'name' => 'Your name',
9+
'phone' => 'Your phone number',
10+
'email' => 'Your email address',
11+
'comment' => 'Comment (required)',
12+
],
13+
'submit' => 'Send',
14+
];

resources/views/feedback.blade.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
@if(auth()->user() && session('honeybadger_last_error'))
2+
<style>
3+
#honeybadger_feedback { padding-left: 2em; padding-right: 2em; min-width: 80%; color: #9CA3AF; }
4+
#honeybadger_feedback_form h2 { line-height: 1.5em; }
5+
#honeybadger_feedback_name, #honeybadger_feedback_email, #honeybadger_feedback_comment { width: 100%; padding: 0.5em; }
6+
#honeybadger_feedback_comment { height: 10em; }
7+
#honeybadger_feedback_submit { color: initial; padding: 0.5em 1em; }
8+
#honeybadger_feedback_form .honeybadger-feedback-phone { display: none; }
9+
#honeybadger_feedback_link { text-decoration: underline; }
10+
</style>
11+
12+
<script>
13+
function honeybadgerFeedbackResponse(data) {
14+
if (data['result'] == 'OK') {
15+
var form = document.getElementById('honeybadger_feedback_form');
16+
var success = document.getElementById('honeybadger_feedback_success');
17+
18+
form.style.display = 'none';
19+
success.style.display = 'block';
20+
} else {
21+
var message;
22+
23+
if (data['error']) {
24+
message = data['error'];
25+
} else {
26+
message = 'An unknown error occurred. Please try again.';
27+
}
28+
29+
alert(message);
30+
}
31+
}
32+
33+
function sendHoneybadgerFeedback() {
34+
try {
35+
var script = document.createElement('script');
36+
var form = document.getElementById('honeybadger_feedback_form');
37+
script.src = '{{ $action }}?format=js&token={{ session('honeybadger_last_error') }}&name=' + encodeURIComponent(form.name.value) + '&email=' + encodeURIComponent(form.email.value) + '&comment=' + encodeURIComponent(form.comment.value);
38+
form.appendChild(script);
39+
return false;
40+
} catch(e) {
41+
if (window.console) {
42+
console.log('Error caught while processing Honeybadger feedback form: ' + e);
43+
console.log('Submitting form normally...');
44+
}
45+
return true;
46+
}
47+
}
48+
</script>
49+
50+
<div id="honeybadger_feedback">
51+
<div id="honeybadger_feedback_success" style="display:none;">
52+
<p><strong>{{ __('honeybadger::feedback.thanks') }}</strong></p>
53+
</div>
54+
55+
<form action="{{ $action }}" method="POST" id="honeybadger_feedback_form" onsubmit="return sendHoneybadgerFeedback();">
56+
<input type="hidden" name="token" id="honeybadger_feedback_token" value="{{ session('honeybadger_last_error') }}">
57+
58+
<h2>{{ __('honeybadger::feedback.heading') }}</h2>
59+
<p>{{ __('honeybadger::feedback.explanation') }}</p>
60+
61+
<p class="honeybadger-feedback-name">
62+
<label for="honeybadger_feedback_name">{{ __('honeybadger::feedback.labels.name') }}</label><br>
63+
<input type="text" name="name" id="honeybadger_feedback_name" size="60">
64+
</p>
65+
66+
<p class="honeybadger-feedback-phone">
67+
<label for="honeybadger_feedback_phone">{{ __('honeybadger::feedback.labels.phone') }}</label><br>
68+
<input type="text" name="phone" id="honeybadger_feedback_phone" size="60">
69+
</p>
70+
71+
<p class="honeybadger-feedback-email">
72+
<label for="honeybadger_feedback_email">{{ __('honeybadger::feedback.labels.email') }}</label><br>
73+
<input type="email" name="email" id="honeybadger_feedback_email" value="{{ auth()->user()->email ?? '' }}">
74+
</p>
75+
76+
<p class="honeybadger-feedback-comment">
77+
<label for="honeybadger_feedback_comment">{{ __('honeybadger::feedback.labels.comment') }}</label><br>
78+
<textarea name="comment" id="honeybadger_feedback_comment" cols="50" rows="6" required></textarea>
79+
</p>
80+
81+
<p class="honeybadger-feedback-submit">
82+
<input type="submit" id="honeybadger_feedback_submit" value="{{ __('honeybadger::feedback.submit') }}">
83+
</p>
84+
</form>
85+
86+
<p><a id="honeybadger_feedback_link" href="https://www.honeybadger.io/" target="_blank" title="Exception, uptime, and performance monitoring for PHP.">Powered by Honeybadger</a></p>
87+
</div>
88+
@endif

resources/views/informer.blade.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@if(session('honeybadger_last_error'))
2+
<div class="{{ $class }}">
3+
{{ $text }} {{ session('honeybadger_last_error') }}
4+
</div>
5+
@endif

src/HoneybadgerLaravel.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,16 @@
66
use Honeybadger\Exceptions\ServiceException;
77
use Honeybadger\Honeybadger;
88
use Illuminate\Support\Facades\Log;
9+
use Symfony\Component\HttpFoundation\Request;
10+
use Throwable;
911

10-
class HoneybadgerLaravel
12+
class HoneybadgerLaravel extends Honeybadger
1113
{
1214
const VERSION = '3.6.0';
1315

14-
/**
15-
* Honeybadger factory.
16-
*
17-
* @param array $config
18-
*
19-
* @return \Honeybadger\Contracts\Reporter
20-
*/
21-
public function make(array $config): Reporter
16+
public static function make(array $config): Reporter
2217
{
23-
return Honeybadger::new(array_merge([
18+
return static::new(array_merge([
2419
'notifier' => [
2520
'name' => 'Honeybadger Laravel',
2621
'url' => 'https://github.com/honeybadger-io/honeybadger-laravel',
@@ -31,4 +26,17 @@ public function make(array $config): Reporter
3126
},
3227
], $config));
3328
}
29+
30+
public function notify(Throwable $throwable, Request $request = null, array $additionalParams = []): array
31+
{
32+
$result = parent::notify($throwable, $request, $additionalParams);
33+
34+
// Persist the most recent error for the rest of the request, so we can display on error page.
35+
if (app()->bound('session')) {
36+
// Lumen doesn't come with sessions.
37+
session()->now('honeybadger_last_error', $result['id'] ?? null);
38+
}
39+
40+
return $result;
41+
}
3442
}

src/HoneybadgerServiceProvider.php

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Honeybadger\HoneybadgerLaravel\Commands\HoneybadgerTestCommand;
1313
use Honeybadger\HoneybadgerLaravel\Contracts\Installer as InstallerContract;
1414
use Illuminate\Console\Scheduling\Event;
15+
use Illuminate\Support\Facades\Blade;
1516
use Illuminate\Support\ServiceProvider;
1617

1718
class HoneybadgerServiceProvider extends ServiceProvider
@@ -28,10 +29,19 @@ public function boot()
2829

2930
$this->publishes([
3031
__DIR__.'/../config/honeybadger.php' => base_path('config/honeybadger.php'),
31-
], 'config');
32+
], 'honeybadger-config');
33+
$this->publishes([
34+
__DIR__.'/../resources/views' => resource_path('views/vendor/honeybadger'),
35+
], 'honeybadger-views');
36+
$this->publishes([
37+
__DIR__.'/../resources/lang' => resource_path('lang/vendor/honeybadger'),
38+
], 'honeybadger-translations');
3239
}
3340

34-
$this->registerMacros();
41+
$this->registerEventHooks();
42+
$this->loadViewsFrom(__DIR__.'/../resources/views', 'honeybadger');
43+
$this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'honeybadger');
44+
$this->registerBladeDirectives();
3545
}
3646

3747
/**
@@ -42,7 +52,7 @@ public function register()
4252
$this->mergeConfigFrom(__DIR__.'/../config/honeybadger.php', 'honeybadger');
4353

4454
$this->app->singleton(Reporter::class, function ($app) {
45-
return (new HoneybadgerLaravel)->make($app['config']['honeybadger']);
55+
return HoneybadgerLaravel::make($app['config']['honeybadger']);
4656
});
4757

4858
$this->app->alias(Reporter::class, Honeybadger::class);
@@ -57,7 +67,7 @@ public function register()
5767
throw $e;
5868
};
5969

60-
return (new HoneybadgerLaravel)->make($config);
70+
return HoneybadgerLaravel::make($config);
6171
});
6272

6373
$this->app->singleton('honeybadger.isLumen', function () {
@@ -115,9 +125,9 @@ private function bindCommands()
115125
/**
116126
* @return void
117127
*/
118-
private function registerMacros()
128+
private function registerEventHooks()
119129
{
120-
/** @param string|array|null $environments */
130+
/** @param string|array|null $environments */
121131
Event::macro('thenPingHoneybadger', function (string $id, $environments = null) {
122132
return $this->then(function () use ($id, $environments) {
123133
if ($environments === null || app()->environment($environments)) {
@@ -126,7 +136,7 @@ private function registerMacros()
126136
});
127137
});
128138

129-
/** @param string|array|null $environments */
139+
/** @param string|array|null $environments */
130140
Event::macro('pingHoneybadgerOnSuccess', function (string $id, $environments = null) {
131141
return $this->onSuccess(function () use ($id, $environments) {
132142
if ($environments === null || app()->environment($environments)) {
@@ -135,4 +145,26 @@ private function registerMacros()
135145
});
136146
});
137147
}
148+
149+
private function registerBladeDirectives()
150+
{
151+
// Views are not enabled on Lumen by default
152+
if (app()->bound('blade.compiler')) {
153+
Blade::directive('honeybadgerError', function ($options) {
154+
if ($options === '') {
155+
$options = '[]';
156+
}
157+
158+
$defaults = "['class' => 'text-gray-500 text-sm', 'text' => 'Error ID:']";
159+
160+
return "<?php echo \$__env->make('honeybadger::informer', $options, $defaults)->render(); ?>";
161+
});
162+
163+
Blade::directive('honeybadgerFeedback', function () {
164+
$action = rtrim(Honeybadger::API_URL, '/').'/feedback';
165+
166+
return "<?php echo \$__env->make('honeybadger::feedback', ['action' => '$action'])->render(); ?>";
167+
});
168+
}
169+
}
138170
}

src/Installer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function sendTestException(): array
4343
public function publishLaravelConfig(): bool
4444
{
4545
return Artisan::call('vendor:publish', [
46-
'--provider' => HoneybadgerServiceProvider::class,
46+
'--tag' => 'honeybadger-config',
4747
]) === 0;
4848
}
4949

tests/Commands/InstallerTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Honeybadger\Contracts\Reporter;
66
use Honeybadger\HoneybadgerLaravel\Exceptions\TestException;
7-
use Honeybadger\HoneybadgerLaravel\HoneybadgerServiceProvider;
87
use Honeybadger\HoneybadgerLaravel\Installer;
98
use Honeybadger\Tests\TestCase;
109
use Illuminate\Support\Facades\Artisan;
@@ -93,17 +92,15 @@ public function publishes_config_for_laravel()
9392

9493
Artisan::shouldReceive('call')
9594
->once()
96-
->with('vendor:publish', [
97-
'--provider' => HoneybadgerServiceProvider::class,
98-
])->andReturn(0);
95+
->with('vendor:publish', ['--tag' => 'honeybadger-config'])->andReturn(0);
9996

10097
$installer = new Installer($honeybadger);
10198

10299
$this->assertTrue($installer->publishLaravelConfig());
103100
}
104101

105102
/** @test */
106-
public function publish_should_be_configed()
103+
public function config_should_be_published()
107104
{
108105
$honeybadger = $this->createMock(Reporter::class);
109106

0 commit comments

Comments
 (0)