The problem of controller bloat can be solved by separating responsibilities: 1. Use Form Requests to extract verification logic; 2. Move complex business logic to Service class for processing; 3. Centrally manage the data access layer through Repository mode; 4. Use middleware to process pre-logic logic such as permissions and current limits; 5. Reasonably split the resource controller and hand it over to Blade or front-end components to process view logic. This keeps the controller simple and improves code maintainability and structural clarity.
In the Laravel project, if you find that the controller is getting bloated and full of various logic and database operations, you may have been trapped in the "Fat Controllers" problem. The core of solving this problem is to separate the code that does not belong to the controller, so that the controller is only responsible for receiving requests and returning responses.

Here are a few practical ways to help you keep your controller simple and clear.
Verify request data using Form Requests
Laravel provides a very convenient Form Request
feature that can pull verification logic out of the controller. This not only reduces the amount of controller code, but also makes verification rules more centralized and reusable.

For example: If you have an interface to create an article, there are multiple fields that need to be verified for type, length, uniqueness, etc. You can use php artisan make:request StoreArticleRequest
to create a Form Request class, and define rules and authorize methods.
Then your controller method can be simplified to:

public function store(StoreArticleRequest $request) { Article::create($request->validated()); return redirect()->route('articles.index'); }
After doing this, the controller no longer cares about verification details and has clearer responsibilities.
Move business logic into Service class
When a large number of if-else, loops or complex business judgments appear in the controller, it means that this part of the logic should be encapsulated into a special service class (Service).
For example, when handling order status updates, points calculations, user permission changes, etc., you can extract a separate class, such as OrderService
or UserService
. The controller only needs to call the method of this service class.
Let's give a simple structural diagram:
class OrderController extends Controller { protected $orderService; public function __construct(OrderService $orderService) { $this->orderService = $orderService; } public function updateStatus(Order $order, Request $request) { $this->orderService->updateStatus($order, $request->input('status')); return back(); } }
This approach not only makes the controller lighter, but also makes business logic easier to test and maintain.
Manage data access layer with Repository mode
If you find that direct model queries appear frequently in the controller, such as User::where(...)->get()
, and these queries may be reused in multiple places, it is a good idea to consider introducing the Repository pattern.
The role of Repository is to centrally manage data access logic to avoid excessive coupling between the controller and the model. You can create a corresponding Repository interface and implementation class for each main model.
for example:
interface ArticleRepositoryInterface { public function all(); public function find($id); public function create(array $data); } class EloquentArticleRepository implements ArticleRepositoryInterface { public function all() { return Article::all(); } // Other implementations... }
Then inject this interface into the controller:
public function __construct(ArticleRepositoryInterface $articleRepo) { $this->articleRepo = $articleRepo; } public function index() { $articles = $this->articleRepo->all(); return view('articles.index', compact('articles')); }
The advantage of this is that when changing the data source or adding a cache layer in the future, the controller needs little change.
Tips: Other places to optimize
- The middleware processing pre-login logic : login inspection, permission verification, current limiting, etc. should be completed through middleware as much as possible.
- Reasonable splitting of resource controllers : If a single controller assumes too many responsibilities, consider splitting into multiple small controllers by function.
- The view logic is handed over to Blade or front-end components : do not splice HTML or format output content in the controller.
Overall, the key to avoiding Fat Controllers is separation of responsibilities. The controller shouldn't do much, it's just a bridge between the request and the response. Leveraging verification, business logic, and data access to appropriate components separately will make the entire project structure clearer and later maintenance will be much easier.
Basically that's it.
The above is the detailed content of Avoiding 'Fat Controllers' in Laravel.. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

ToworkeffectivelywithpivottablesinLaravel,firstaccesspivotdatausingwithPivot()orwithTimestamps(),thenupdateentrieswithupdateExistingPivot(),managerelationshipsviadetach()andsync(),andusecustompivotmodelswhenneeded.1.UsewithPivot()toincludespecificcol

Laravelprovidesacleanandflexiblewaytosendnotificationsviamultiplechannelslikeemail,SMS,in-appalerts,andpushnotifications.Youdefinenotificationchannelsinthevia()methodofanotificationclass,andimplementspecificmethodsliketoMail(),toDatabase(),ortoVonage

Dependency injection automatically handles class dependencies through service containers in Laravel without manual new objects. Its core is constructor injection and method injection, such as automatically passing in the Request instance in the controller. Laravel parses dependencies through type prompts and recursively creates the required objects. The binding interface and implementation can be used by the service provider to use the bind method, or singleton to bind a singleton. When using it, you need to ensure type prompts, avoid constructor complications, use context bindings with caution, and understand automatic parsing rules. Mastering these can improve code flexibility and maintenance.

Laravel performance optimization can improve application efficiency through four core directions. 1. Use the cache mechanism to reduce duplicate queries, store infrequently changing data through Cache::remember() and other methods to reduce database access frequency; 2. Optimize database from the model to query statements, avoid N 1 queries, specifying field queries, adding indexes, paging processing and reading and writing separation, and reduce bottlenecks; 3. Use time-consuming operations such as email sending and file exporting to queue asynchronous processing, use Supervisor to manage workers and set up retry mechanisms; 4. Use middleware and service providers reasonably to avoid complex logic and unnecessary initialization code, and delay loading of services to improve startup efficiency.

Methods to manage database state in Laravel tests include using RefreshDatabase, selective seeding of data, careful use of transactions, and manual cleaning if necessary. 1. Use RefreshDatabasetrait to automatically migrate the database structure to ensure that each test is based on a clean database; 2. Use specific seeds to fill the necessary data and generate dynamic data in combination with the model factory; 3. Use DatabaseTransactionstrait to roll back the test changes, but pay attention to its limitations; 4. Manually truncate the table or reseed the database when it cannot be automatically cleaned. These methods are flexibly selected according to the type of test and environment to ensure the reliability and efficiency of the test.

LaravelSanctum is suitable for simple, lightweight API certifications such as SPA or mobile applications, while Passport is suitable for scenarios where full OAuth2 functionality is required. 1. Sanctum provides token-based authentication, suitable for first-party clients; 2. Passport supports complex processes such as authorization codes and client credentials, suitable for third-party developers to access; 3. Sanctum installation and configuration are simpler and maintenance costs are low; 4. Passport functions are comprehensive but configuration is complex, suitable for platforms that require fine permission control. When selecting, you should determine whether the OAuth2 feature is required based on the project requirements.

Laravel simplifies database transaction processing with built-in support. 1. Use the DB::transaction() method to automatically commit or rollback operations to ensure data integrity; 2. Support nested transactions and implement them through savepoints, but it is usually recommended to use a single transaction wrapper to avoid complexity; 3. Provide manual control methods such as beginTransaction(), commit() and rollBack(), suitable for scenarios that require more flexible processing; 4. Best practices include keeping transactions short, only using them when necessary, testing failures, and recording rollback information. Rationally choosing transaction management methods can help improve application reliability and performance.

The core of handling HTTP requests and responses in Laravel is to master the acquisition of request data, response return and file upload. 1. When receiving request data, you can inject the Request instance through type prompts and use input() or magic methods to obtain fields, and combine validate() or form request classes for verification; 2. Return response supports strings, views, JSON, responses with status codes and headers and redirect operations; 3. When processing file uploads, you need to use the file() method and store() to store files. Before uploading, you should verify the file type and size, and the storage path can be saved to the database.
