我喜欢尽可能简化我的控制器。在处理 API 时,我有时会使用服务类(存储库?)方法,该方法需要一些输入以及
RedirectResponse
,如下所示:
use App\Http\Controllers\Controller;
class MyController extends Controller
{
public function create(Request $request)
{
$validated = $request->validate([...]);
return MyService::createWithResponse(
input: $validated,
response: back()
);
}
}
我可以在这里专注于I/O。
MyService::createWithResponse
将处理所有存储库逻辑,但它也将处理错误/成功消息传递:
use \Illuminate\Http\RedirectResponse;
class MyService
{
public static function createWithResponse(array $input, RedirectResponse $response)
{
// ...repository logic dealing with the third-party API
if (/* the API sends me an error */) {
return $response->with(['error' => $some_error]);
}
$resourceId = /**/;
return $response->with(['success' => 'Your resource has been created!']);
}
}
好吧,假设我有:
Route::get('/resources/{resourceId}', ...)->name('resources.show');
并且我正在尝试找到一种使用
createWithResponse
来调用 response()->redirectToRoute('resources.show')
的方法,但我想稍后传递路由参数(即 $resourceId
);在运行存储库逻辑之前,我还不知道 resourceId
。
我不能只将路由名称字符串传递到
createWithResponse
中,因为预期的 RedirectResponse
可能不是用于命名路由,或者我可能在传递它之前已经向 RedirectResponse
添加了参数。 (无论如何,MyService
应该是不可知的,并且该信息应该保留在控制器中。)
我如何传递按名称检索的
Route
,然后附加参数?或者还有其他方法可以做到这一点吗?几周来我一直在断断续续地寻找解决方案。
一种选择是将成功/失败回调传递给您的服务方法。回调闭包可以接受结果中的数据作为参数。
考虑:
use \Illuminate\Http\RedirectResponse;
class MyService
{
public static function create(
array $input,
callable $onSuccess,
callable $onFailure
)
{
// ...repository logic dealing with the third-party API
if (/* the API sends me an error */) {
return $onFailure($some_error);
}
$resourceId = /**/;
return $onSuccess($resourceId);
}
}
use App\Http\Controllers\Controller;
class MyController extends Controller
{
public function create(Request $request)
{
$validated = $request->validate([...]);
return MyService::create(
input: $validated,
onSuccess: fn(string $resourceId) => response()
->redirectToRoute('resources.show', $resourceId)
->with(['success' => 'Your resource has been created!']),
onFailure: fn(string $errorMsg) => back()
->with(['error' => $errorMsg])
);
}
}
这将 I/O 逻辑完全保留在控制器中。服务方法不需要知道响应应该是什么类型,让控制器定义它。现在应用程序的其他部分可以使用该服务方法并定义自己的输出。
此外,您可以使用一些 PHPDoc“泛型”(
@template
) 语法糖来帮助您的 IDE 并使这一点更加明显:
class MyService
{
/**
* @template TSuccess of mixed
* @template TFailure of mixed
* @param array $input
* @param callable(string):TSuccess $on_success
* @param callable(string):TFailure $on_failure
* @return TFailure|TSuccess
*/
public static function create(
array $input,
callable $onSuccess,
callable $onFailure
)
{
...