Skip to content

Commit 054e0d6

Browse files
authored
Add reporter for Model::preventAccessingMissingAttributes() (#824)
1 parent 25e1cd2 commit 054e0d6

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

src/Sentry/Laravel/Integration.php

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Sentry\Laravel;
44

5+
use Illuminate\Database\Eloquent\MissingAttributeException;
56
use Illuminate\Database\Eloquent\Model;
67
use Illuminate\Database\LazyLoadingViolationException;
78
use Illuminate\Foundation\Configuration\Exceptions;
@@ -240,6 +241,55 @@ public static function captureUnhandledException(Throwable $throwable): ?EventId
240241
return SentrySdk::getCurrentHub()->captureException($throwable, $hint);
241242
}
242243

244+
/**
245+
* Returns a callback that can be passed to `Model::handleMissingAttributeViolationUsing` to report missing attribute violations to Sentry.
246+
*
247+
* @param callable|null $callback Optional callback to be called after the violation is reported to Sentry.
248+
*
249+
* @return callable
250+
*/
251+
public static function missingAttributeViolationReporter(?callable $callback = null): callable
252+
{
253+
return new class($callback) {
254+
use ResolvesEventOrigin;
255+
256+
/** @var callable|null $callback */
257+
private $callback;
258+
259+
public function __construct(?callable $callback)
260+
{
261+
$this->callback = $callback;
262+
}
263+
264+
public function __invoke(Model $model, string $attribute): void
265+
{
266+
SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($model, $attribute) {
267+
$scope->setContext('violation', [
268+
'model' => get_class($model),
269+
'attribute' => $attribute,
270+
'origin' => $this->resolveEventOrigin(),
271+
'kind' => 'missing_attribute',
272+
]);
273+
274+
SentrySdk::getCurrentHub()->captureEvent(
275+
tap(Event::createEvent(), static function (Event $event) {
276+
$event->setLevel(Severity::warning());
277+
}),
278+
EventHint::fromArray([
279+
'exception' => new MissingAttributeException($model, $attribute),
280+
'mechanism' => new ExceptionMechanism(ExceptionMechanism::TYPE_GENERIC, true),
281+
])
282+
);
283+
});
284+
285+
// Forward the violation to the next handler if there is one
286+
if ($this->callback !== null) {
287+
call_user_func($this->callback, $model, $attribute);
288+
}
289+
}
290+
};
291+
}
292+
243293
/**
244294
* Returns a callback that can be passed to `Model::handleLazyLoadingViolationUsing` to report lazy loading violations to Sentry.
245295
*
@@ -263,7 +313,7 @@ public function __construct(?callable $callback)
263313
public function __invoke(Model $model, string $relation): void
264314
{
265315
// Laravel uses these checks itself to not throw an exception if the model doesn't exist or was just created
266-
// See: https://github.com/laravel/framework/blob/438d02d3a891ab4d73ffea2c223b5d37947b5e93/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L563
316+
// See: https://github.com/laravel/framework/blob/438d02d3a891ab4d73ffea2c223b5d37947b5e93/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L559-L561
267317
if (!$model->exists || $model->wasRecentlyCreated) {
268318
return;
269319
}
@@ -273,6 +323,7 @@ public function __invoke(Model $model, string $relation): void
273323
'model' => get_class($model),
274324
'relation' => $relation,
275325
'origin' => $this->resolveEventOrigin(),
326+
'kind' => 'lazy_loading',
276327
]);
277328

278329
SentrySdk::getCurrentHub()->captureEvent(

0 commit comments

Comments
 (0)