Weird try/catch behavior with Collection's sole method. Here's a code snippet to illustrate my confusion :
use Illuminate\Support\ItemNotFoundException;
dump(ItemNotFoundException::class);
// Illuminate\Support\ItemNotFoundException
try {
$search = collect([['id' => 1], ['id' => 2]]);
$id = $search->where('id', 3)->sole();
} catch (ItemNotFoundException $e) {
dd('Catch ItemNotFoundException');
} catch (Exception $e) {
dd('Catch Exception');
}
You would think that code would execute the first catch block but it goes into the generic Exception catch.
If I instead put the full namespace of the ItemNotFoundException in the catch block, then it triggers as excepted.
Anyone has an idea of what is going on here?
Function \Illuminate\Database\Eloquent\Builder::sole() throws \Illuminate\Database\Eloquent\ModelNotFoundException and \Illuminate\Database\MultipleRecordsFoundException, not \Illuminate\Support\ItemNotFoundException
upd: sorry, I see you call sole() on a collection not a query bulider...
Your code behaves exactly as it should on Laravel 12.19:
C:\nastroim\pipka>php artisan app:test-command
"Illuminate\Support\ItemNotFoundException" // app\Console\Commands\TestCommand.php:122
"Catch ItemNotFoundException" // app\Console\Commands\TestCommand.php:129
What Laravel version you have?
Maybe you have another ItemNotFoundException in use statements?
@Glukinho Thanks for taking the time to look into this.
I'm running Laravel version 12.20.0 and PHP 8.4.7.
I tried running the code both in my app and in isolation in a Tinkerwell session. My colleague also tried and got the same behavior.
Weirdly enough, when I test the code within a command, I do get the expected behavior where it catches the ItemNotFoundException exception.
@FrankMawn I created a new command just for this case, it gives normal result too:
C:\nastroim\pipka>php artisan app:test-sole-command
"Illuminate\Support\ItemNotFoundException" // app\Console\Commands\TestSoleCommand.php:19
"Catch ItemNotFoundException" // app\Console\Commands\TestSoleCommand.php:26
One thing I fixed in your code, it should be catch (\Exception $e) (backslash before "Exception"). It doesn't seem to affect catching other exception.
TestSoleCommand.php:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\ItemNotFoundException;
class TestSoleCommand extends Command
{
protected $signature = 'app:test-sole-command';
protected $description = 'Command description';
public function handle()
{
dump(ItemNotFoundException::class);
// Illuminate\Support\ItemNotFoundException
try {
$search = collect([['id' => 1], ['id' => 2]]);
$id = $search->where('id', 3)->sole();
} catch (ItemNotFoundException $e) {
dd('Catch ItemNotFoundException');
} catch (\Exception $e) {
dd('Catch Exception');
}
}
}
I have PHP 8.3.10.
@FrankMawn Tinker gives proper result too:
C:\nastroim\pipka>php artisan tinker
Psy Shell v0.12.8 (PHP 8.3.10 — cli) by Justin Hileman
> $search = collect([['id' => 1], ['id' => 2]]);
= Illuminate\Support\Collection {#7271
all: [
[
"id" => 1,
],
[
"id" => 2,
],
],
}
> $id = $search->where('id', 3)->sole();
Illuminate\Support\ItemNotFoundException
>
It might be a glitch with Tinkerwell then. You are right that running the code within a command or controller does seem to work as expected.
Thank you for taking the time, I guess I'll move on lol
Please sign in or create an account to participate in this conversation.