作为初学者Laravel开发人员 - 编写清洁控制器至关重要。根据我的经验,我遇到了许多Laravel项目,其中控制器长1000行。不必这样。
编写可维护和高效的控制器并不难。您只需要知道如何组织代码库即可。在本文中,我们将探讨基本技巧,以帮助您编写清洁器控制器。
清洁器Laravel控制器的3个提示:
-
具有单个责任的较小方法
-
用表单请求类验证
-
雄辩的API资源
我们将使用电子商务产品管理系统的简单示例来解释每个点。因此,让我们潜入!
1-单一责任的较小方法
控制器方法应具有一项责任。处理特定的HTTP请求并返回适当的响应。
您应该避免将复杂的逻辑添加到控制器方法中。将应用程序的请求处理部分从复杂的业务逻辑中解脱出来。您的控制器应仅负责“控制”执行流程。
让我们以一个示例理解这一点:
class ProductController extends Controller
{
// ...
public function update(UpdateProductRequest $request, $id)
{
$product = Product::findOrFail($id);
$data = $request->validated();
$product = Product::findOrFail($id);
if ($request->hasFile('image')) {
$image = $request->file('image');
$imagePath = 'uploads/products/' . $image->hashName();
$image->storeAs('public', $imagePath);
$product->image = $imagePath;
}
$product->name = $request->input('name');
$product->price = $request->input('price');
$product->category_id = $request->input('category_id');
$product->description = $request->input('description');
$product->save();
return redirect()->route('products.index')->with('success', 'Product updated successfully.');
}
// ...
}
这里的update
方法是负责多件事。它还处理文件上传和存储图像,这不是其主要关注点。它应该只关注“更新”产品数据。
让我们看看如何清理update
方法
class ProductController extends Controller
{
private $productService;
public function __construct(ProductService $productService)
{
$this->productService = $productService;
}
// ...
public function update(UpdateProductRequest $request, $id): RedirectResponse
{
$product = Product::findOrFail($id);
$data = $request->validated();
if ($request->hasFile('image')) {
$image = $request->file('image');
$data['image'] = $this->productService->storeProductImage($image);
}
$this->productService->updateProduct($product, $data);
return redirect()->route('products.index')->with('success', 'Product updated successfully.');
}
}
请注意,我们仍然必须更新Product
模型并上传图像。但是我们在处理这些特定操作的单独类ProductService
中这样做。
创建服务类或操作以处理复杂的业务逻辑
这是一个非常简单的示例,但是您可以想象一个更复杂的功能,该功能可能涉及基于请求和模型的5种不同操作。它可能很快变得非常复杂。
关键要点:
-
坚持每个控制器动作的单一责任
-
保持您的方法集中和简洁,执行特定任务
-
将复杂操作分解为较小的可重复使用方法
2-表单请求类验证
验证传入请求数据对于确保数据完整性和安全性至关重要。但是,如果您不小心 - 验证逻辑可能会使代码变得不可读。
您可以创建自定义表单请求类,以保持控制器清洁。这将验证逻辑与控制器本身分开。 Laravel提供了一种克服此类课程的好方法。
让我们探索这个。首先,考虑ProductController
的store
方法。这是您在控制器操作中实现的典型验证逻辑。
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Product;
class ProductController extends Controller
{
public function store(Request $request)
{
// Validate the request data
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'description' => 'required|string',
'price' => 'required|numeric|min:0',
'quantity' => 'required|integer|min:0',
'category_id' => 'required|exists:categories,id',
'brand_id' => 'required|exists:brands,id',
'color' => 'required|string|max:50',
'size' => 'required|string|max:20',
'weight' => 'required|numeric|min:0',
'images' => 'required|array',
'images.*' => 'required|image|max:2048',
]);
// Create a new product ...
}
}
这样做验证的缺点:
-
代码膨胀并降低可读性
-
跨控制器操作的代码重复
-
测试挑战并降低可检验性
因此,让我们看看如何使用Request
类重写,并使其更清洁,可重复使用,更可测试
使用工匠命令创建请求类:
php artisan make:request CreateProductRequest
这将在app/Http/Requests
目录中生成一个新的CreateProductRequest
类。打开生成的文件并使用验证规则更新其rules
方法:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateProductRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'required|string|max:255',
'description' => 'required|string',
'price' => 'required|numeric|min:0',
'quantity' => 'required|integer|min:0',
'category_id' => 'required|exists:categories,id',
'brand_id' => 'required|exists:brands,id',
'color' => 'required|string|max:50',
'size' => 'required|string|max:20',
'weight' => 'required|numeric|min:0',
'images' => 'required|array',
'images.*' => 'required|image|max:2048',
];
}
}
现在,在您的ProductController
中,您可以使用新的请求类,这样:
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\CreateProductRequest;
use App\Models\Product;
class ProductController extends Controller
{
public function store(CreateProductRequest $request)
{
// Retrieve the validated data
$validatedData = $request->validated();
// Create a new product ...
}
}
如果可能的话,最好将请求类重复使用请求类。但是,如果您愿意,也可以为update
操作创建不同的请求类。您可以根据需要创建尽可能多的自定义请求类。
关键要点:
-
使用自定义表单请求与控制器单独的验证逻辑。
-
在其他控制器/方法中重复使用请求类
3-雄辩的API资源
当您为API编写控制器时,格式化JSON
响应非常常见。
如果您需要的响应格式与模式不同,则格式化逻辑也可以使您的控制器肿,并且很难阅读。有时您可能需要在多个API端点中重复使用相同的响应格式。
这是您可以利用雄辩的API资源来保持响应一致的地方,使您的格式可重复使用,并且控制器清洁
让我们看一个在控制器方法中格式化的API响应的示例:
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ProductController extends Controller
{
public function index(Request $request)
{
$products = Product::with('brand', 'categories', 'features')->get();
// Transform the product list with required attributes
$transformedProducts = $products->map(function ($product) {
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'description' => $this->description,
'brand_name' => $product->brand->name,
'brand_image' => $product->brand->image,
'categories' => $product->categories->map(function ($category) {
return [
'name' => $category->name,
'alias' => $category->alias,
'image' => $category->image,
];
}),
'features' => $product->features->map(function ($feature) {
return [
'title' => $feature->title,
'description' => $feature->description
];
})
];
});
return response()->json(['products' => $transformedProducts], Response::HTTP_OK);
}
}
现在让我们看一下如何提取此逻辑并将其放入Resource
类
首先,创建ProductResource
类
php artisan make:resource Product
让我们将逻辑移至此类
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'description' => $this->description,
'brand_name' => $this->brand->name,
'brand_image' => $this->brand->image,
'categories' => $this->categories->map(function ($category) {
return [
'name' => $category->name,
'alias' => $category->alias,
'image' => $category->image,
];
}),
'features' => $this->features->map(function ($feature) {
return [
'title' => $feature->title,
'description' => $feature->description
];
})
];
}
}
现在我们可以在控制器中使用它
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Resources\ProductResource;
class ProductController extends Controller
{
public function index(Request $request)
{
$products = Product::with('brand', 'categories', 'features')->get();
$productResource = ProductResource::collection($products);
return response()->json(['products' => $productResource], Response::HTTP_OK);
}
}
您可以看到这种方法,与原始的index
方法相比,我们的控制器要干净得多。它也可以重复使用。假设您有一个客户订单端点,希望在其中提供产品以及订单对象(非常常见的API要求),您可以重复使用相同的资源/集合
关键要点:
-
使用雄辩的API资源使控制器更可读
-
通过将数据转换逻辑与控制器分开
,提高代码的可重复性和可维护性
在Laravel中编写清洁控制器对于构建可维护和高效的应用至关重要。养成编写清洁代码的习惯,而作为开发人员的生活将变得更加容易。与所有良好的习惯一样,它将需要进行故意的思考和实践。
通过练习这些原则并将其纳入您的开发工作流程中,您将在Laravel编写清洁剂和更有条理的控制器的方式中。
我还发表了一个关于getting started with background jobs in laravel的博客
我希望您能发现这很有价值 - 如果与他们相关的话,很棒的ð与您的人们分享。如果您有任何建议/评论,请自由。
快乐编码!