В настоящее время я работаю над проектом, в котором мы пытаемся создать RESTful API.Этот API использует некоторые классы по умолчанию, например ResourceController
, для базового поведения, которое может быть перезаписано при необходимости.
Допустим, у нас есть маршрут ресурса API:
Route::apiResource('posts', 'ResourceController');
Этот маршрутбудет использовать ResourceController
:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Repositories\ResourceRepository;
class ResourceController extends Controller
{
/**
* The resource class.
*
* @var string
*/
private $resourceClass = '\\App\\Http\\Resources\\ResourceResource';
/**
* The resource model class.
*
* @var string
*/
private $resourceModelClass;
/**
* The repository.
*
* @var \App\Repositories\ResourceRepository
*/
private $repository;
/**
* ResourceController constructor.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
public function __construct(Request $request)
{
$this->resourceModelClass = $this->getResourceModelClass($request);
$this->repository = new ResourceRepository($this->resourceModelClass);
$exploded = explode('\\', $this->resourceModelClass);
$resourceModelClassName = array_last($exploded);
if (!empty($resourceModelClassName)) {
$resourceClass = '\\App\\Http\\Resources\\' . $resourceModelClassName . 'Resource';
if (class_exists($resourceClass)) {
$this->resourceClass = $resourceClass;
}
}
}
...
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, $this->getResourceModelRules());
$resource = $this->repository->create($request->all());
$resource = new $this->resourceClass($resource);
return response()->json($resource);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$resource = $this->repository->show($id);
$resource = new $this->resourceClass($resource);
return response()->json($resource);
}
...
/**
* Get the model class of the specified resource.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
private function getResourceModelClass(Request $request)
{
if (is_null($request->route())) return '';
$uri = $request->route()->uri;
$exploded = explode('/', $uri);
$class = str_singular($exploded[1]);
return '\\App\\Models\\' . ucfirst($class);
}
/**
* Get the model rules of the specified resource.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
private function getResourceModelRules()
{
$rules = [];
if (method_exists($this->resourceModelClass, 'rules')) {
$rules = $this->resourceModelClass::rules();
}
return $rules;
}
}
Как вы можете сказать, мы не используем привязку к маршруту модели, и мы используем репозиторий для выполнения нашей логики.
Как вы также можете видеть, мы используем некоторую грязную логику, getResourceModelClass()
, для определения класса модели, необходимого для выполнения логики в / с.Этот метод не очень гибкий и накладывает ограничения на структуру каталогов приложения (очень неприятно).
Решением может быть добавление некоторой информации о классе модели при регистрации маршрута.Это может выглядеть так:
Route::apiResource('posts', 'ResourceController', [
'modelClass' => Post::class
]);
Однако, похоже, что это невозможно.
Есть ли у кого-нибудь какие-либо предложения о том, как сделать эту работу или как сделать нашу логику более чистой и гибкой?,Важными факторами являются гибкость и простота использования.