Skip to main content

InvalidReactionSourceException

The InvalidReactionSourceException is thrown when attempting to create a reaction without a valid reactor or device identifier.

Namespace

JobMetric\Reaction\Exceptions\InvalidReactionSourceException

Overview

This exception is thrown during reaction creation when neither a reactor (user) nor a device_id is provided. Reactions must have at least one identifier to track who or what made the reaction.

When It's Thrown

The exception is thrown in the Reaction model's creating event when:

  • No reactor (user) is provided (reactor_type and reactor_id are both null/empty)
  • No device identifier is provided (device_id is null/empty)
  • Both conditions are true (no way to identify the source of the reaction)

Exception Details

Message

The exception message is retrieved from the translation file:

trans('reaction::base.exceptions.invalid_reaction_source')

HTTP Status Code

Default HTTP status code: 400 (Bad Request)

How to Avoid

Provide a Reactor

$article->addReaction('like', $user); // ✅ Valid - user provided

Provide a Device ID

$article->addReaction('like', null, ['device_id' => 'device-123']); // ✅ Valid - device_id provided

Invalid Usage

// ❌ This will throw InvalidReactionSourceException
$article->addReaction('like'); // No reactor, no device_id
$article->addReaction('like', null); // No reactor, no device_id
$article->addReaction('like', null, []); // No reactor, no device_id

Handling the Exception

Try-Catch Block

use JobMetric\Reaction\Exceptions\InvalidReactionSourceException;

try {
$article->addReaction('like');
} catch (InvalidReactionSourceException $e) {
// Handle the exception
return response()->json([
'error' => 'A reactor or device identifier is required',
], 400);
}

In Controllers

use JobMetric\Reaction\Exceptions\InvalidReactionSourceException;

public function like(Article $article)
{
try {
$user = auth()->user();
$deviceId = request()->header('X-Device-ID');

if ($user) {
$article->addReaction('like', $user);
} elseif ($deviceId) {
$article->addReaction('like', null, ['device_id' => $deviceId]);
} else {
throw new InvalidReactionSourceException();
}

return response()->json(['success' => true]);
} catch (InvalidReactionSourceException $e) {
return response()->json([
'error' => $e->getMessage(),
], 400);
}
}

Global Exception Handler

use JobMetric\Reaction\Exceptions\InvalidReactionSourceException;

public function register(): void
{
$this->renderable(function (InvalidReactionSourceException $e, $request) {
if ($request->expectsJson()) {
return response()->json([
'error' => 'A reactor or device identifier is required to add a reaction',
], 400);
}

return redirect()->back()->with('error', $e->getMessage());
});
}

Complete Examples

Safe Reaction Addition

public function react(Article $article, string $reaction)
{
$user = auth()->user();
$deviceId = request()->header('X-Device-ID');

try {
if ($user) {
$article->addReaction($reaction, $user);
} elseif ($deviceId) {
$article->addReaction($reaction, null, ['device_id' => $deviceId]);
} else {
throw new InvalidReactionSourceException();
}

return response()->json(['success' => true]);
} catch (InvalidReactionSourceException $e) {
return response()->json([
'error' => 'Please log in or provide a device identifier',
], 400);
}
}

Middleware for Device ID

class EnsureDeviceId
{
public function handle($request, Closure $next)
{
if (!auth()->check() && !$request->header('X-Device-ID')) {
return response()->json([
'error' => 'Device identifier required for anonymous reactions',
], 400);
}

return $next($request);
}
}

When to Use

This exception helps ensure data integrity by requiring that every reaction has a source identifier. Use it to:

  • Validate Input: Ensure reactions always have a source
  • Data Integrity: Prevent orphaned reactions without identifiers
  • Security: Ensure proper tracking of reaction sources
  • Analytics: Ensure all reactions can be tracked and analyzed