Я не вижу проблем с использованием исключений для вашего сценария.
<?php
namespace App\Services;
use App\User;
class UserService
{
public function getUserById($id)
{
$user = User::find($id);
if (!$user) {
throw UserNotFoundException('User not found');
}
if ($user->role === 'admin') {
throw EditAdminException("You can't edit admin.");
}
return $user;
}
}
Где эти исключения - ваши собственные пользовательские исключения, определенные в app\Exception
, если хотите.Тогда метод getUserById()
может только вернуть User
, в противном случае исключение всплывает и возвращает JSON-ответ клиенту.
Laravel также уже имеет простой способ обработки первого исключения.Вы можете сделать это:
<?php
namespace App\Services;
use App\User;
class UserService
{
public function getUserById($id)
{
$user = User::findOrFail($id);
if ($user->role === 'admin') {
throw EditAdminException("You can't edit admin.");
}
return $user;
}
}
И Laravel будет обрабатывать бросок Illuminate\Database\Eloquent\ModelNotFoundException
, если User
не может быть найден.
Таким образом, вам не нужно беспокоиться осоздание ResponderService
для того, что исключения могут уже сделать для вас.
Если вы хотите стандартизировать ответы своих ресурсов, вы можете использовать Eloquent Resources, который работает как слой преобразования для вашего API: https://laravel.com/docs/5.7/eloquent-resources
Наконец, если вы обнаружите, что вы удаляете ресурс из более чем одного места и не хотите дублировать ответ, вы можете поместить ответ внутри события: https://laravel.com/docs/5.7/eloquent#events
В документации показан извилистый способ обработки событий, но я лично сделаю это только тогда, когда ваша модель начнет чувствовать себя раздутой.
Вы можете сделать это в качестве более простой альтернативы созданию классов Event и Observer:
public static function boot()
{
parent::boot();
static::deleted(function ($model) {
return response()->json([], 204);
});
}
Этот метод подходит только для вашей модели User.И я обнаружил, что, кстати, заглянув в черту HasEvents
на Eloquent\Model
.
Теперь, после всего сказанного, я бы фактически поместил всю логику удаления в вашу * 1034.* и переименуйте метод с getUserById
на deleteById
.Альтернатива немного странная, потому что вы говорите, что не хотите получать пользователя по идентификатору, если это администратор.
На самом деле вы пытаетесь инкапсулировать логику удаленияпользователь, поэтому просто перенесите все это в метод службы, или, что еще лучше, просто используйте событие delete
в модели и поместите всю логику туда.Таким образом, вам даже не нужно вводить услугу.
Редактировать
Исходя из вашего комментария ниже, я думаю, что вы, возможно, неправильно понимаете, как использовать исключения в Laravel..
В новом проекте Laravel в app\Exeptions\Handler
есть класс, который перехватывает все необработанные исключения в вашем приложении.Этот класс сначала проверяет, является ли Exception значение ModelNotFoundException
, а затем возвращает ответ json.
В противном случае он передает перехваченное исключение методу render
своего родителя.
Таким образом, в основномкогда вы хотите создать пользовательское исключение, вы просто создаете класс, который расширяет Exception
и реализует метод handle
.
Вот пример класса исключений:
<?php
namespace App\Exceptions;
use Exception;
class TicketNotPayableException extends Exception
{
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render()
{
return response()->json([
'errors' => [
[
'title' => 'Ticket Not Payable Exception',
'description' =>
'This ticket has already been paid.'
],
],
'status' => '409'
], 409);
}
}
Теперь ответполностью пригоден для повторного использования, и мне не нужно связывать блоки try-catch в моем коде.Обработчик исключений Laravel перехватит его и вызовет метод render
.
Так что, если я хочу инкапсулировать логику оплаты билета внутри службы, мне просто нужно throw App\Exceptions\TicketNotPayableException;
и затем мой контроллернужно всего лишь сделать что-то вроде: $ticketPaymentService->pay($ticket);
, и нет необходимости в перехвате.Если исключение генерируется, оно всплывает, перехватывается обработчиком, и вызывается метод render
, который возвращает соответствующий ответ JSON - для Responder
.
нет необходимости.