Best Laravel coding practices
Laravel is one of the most popular and widely used PHP framework worldwide as it provides lots of features like elegant and simple syntax, Laravel ORM, large developer community, Integrated testing feature and many more. Writing code is okay but writing code with efficiency and best coding standard is what matters.
Developers mostly choose Laravel for development due to its powerful features like rapid development of API's, Database interactions and code quality assurance. In this article we are going interact with some best Laravel development practices every developer should follow.
Best Laravel Development Practices ( Summarized ) :
- Follow MVC Pattern.
- Use Eloquent ORM.
- Use of Validations and Middlewares.
- Write database migrations.
- Write Unit test.
- Use of Eager Loading.
- Use Helper functions.
- Do not use .env variables directly.
- Follow service-repository pattern.
- Use constants and lang files.
- Use chunk for large data processing.
- Use jobs and queues.
Follow MVC Pattern:
Use Eloquent ORM:
ORM basically stands for Object Relational Mapping. It basically provides us powerful feature to interact database operations where we provide table details inside Model file and write our eloquent queries on those models. Eloquent makes it very easier to write table operation queries instead of writing complicated raw SQL queries.
Eloquent queries are very efficient, readable and safe from sql injection. So it is recommended to use Eloquent queries over raw SQL queries.
Use of Validations and Middlewares:
Laravel provides built-in validations to validate request/inputs before getting into database. It allow us to make our custom rules and validate inputs as per the requirement and we can provide custom messages for different rules.
<?php namespace Modules\User\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Http\JsonResponse; use Illuminate\Validation\ValidationException; use Illuminate\Contracts\Validation\Validator; class LoginRequest extends FormRequest { /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'email' => 'required|string|email|max:255', 'password'=> 'required', ]; } /** * Custom message for validation * * @return array */ public function messages() { return [ 'email.required' => trans('user::validation.signIn.email'), 'email.email' => trans('user::validation.signIn.email_email'), 'password.required' => trans('user::validation.signIn.password'), ]; } /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * @param Validator $validator */ protected function failedValidation(Validator $validator) { $errors = (new ValidationException($validator))->errors(); $validationErr = reset($errors)[0]; throw new HttpResponseException( response()->json( [ 'response' => [ 'code' => config('constants.statusCode.validationError'), 'message' => $validationErr, 'description' => 'Validaton Error' ] ] ) ); } }
Coming to Middleware, Middleware works as a filter between incoming request and the response. Like whenever we need to check some validations or other user verifications before proceeding to our route and controller, in such cases we use middleware.
Some examples are like, before accessing the controller system need to check whether the user is logged-in or not or the user is more than 18+ age or not. In such cases we can use middleware. It is very simple to create and implement.
<?php namespace App\Http\Middleware; use Closure; class CheckAgeMiddleware { public function handle($request, Closure $next) { if ($request->age < 18) { return redirect('home'); } return $next($request); } }
Write database migrations:
Laravel provides database migration functionality to work working database tables. Migrations allows us to keep track of database table changes time to time. With the use of migrations we don't need to run manual sql queries to change table structure in our different environments like ( development, staging and production ). Migration allow us to maintain the same table structures in all our environments.
It makes our deployment more faster and efficient and allow us to maintain database consistency and reduces chances of error.
Write Unit Test and Feature Test:
In any development process, we should follow unit testing features. Laravel provides built-in testing features those are Unit Testing and Feature Testing. Here we basically write Unit Testing to test classes and Models where as we write Feature Testing to test our codebase.
Writing test case allow us to monitor and check that how our code base works in different scenarios as well as it allows other developers to understand the functionalities. So basically writing test cases allow us to ensure code quality and the need of user satisfying or not.
Use of Eager Loading:
Eager Loading is a feature of Laravel which allow us to write efficient and optimize queries and relationships and solves N+1 query problem. Here are some of the benefits of eager loading above lazy loading.
- Solves N+1 query problem.
- If we use lazy loading, while fetching large amount data, Some data might be updated, deleted or inserted in between the queries. Here Eager loading helps us to avoid this problem.
- Eager loading reduces queries as well as server load.
- It helps in code readability and maintainability.
Use Helper functions:
Helper functions are basically used for writing common code which we need in our routing development. So that instead of writing of that routine code again and again we can simply call that helper function and make use of it.
It also improves productivity and code readability as you just have to provide a well explained name to that helper function regarding what the function does. Other developers can simply understand the behaviors of the function by its name only.
Do not use .env variables directly:
Mostly what we do is like storing our common variable in .env file and access it directly throughout our application whenever needed and its very easy and handy to use, but this is not a recommended way to access variables directly as it can produce security concerns.
So instead of accessing variables directly from .env file, we can use config() to get env data. To elaborate it a little more, what we are going to do is , we will define variables in .env file but while accessing those variable , we will access through config files. Here is an example.
MAIL_SENDER="hello@thedevnerd.com"
Let's say inside my config/constants.php looks something like this.
<?php return [ 'mail_sender' => env('MAIL_SENDER', 'hello@thedevnerd.com'), ];
this is the following way to access this variable.
config('constants.main_sender');
Follow service-repository pattern:
While developing a small application we basically perform our CRUD operation in our controller , starting from database query to implementing business logic . For small application it is ok to write your code inside controller but in future due to client requirement you might need to grow the application functionality .
In such cases while developing a bigger application it will be very difficult to manage your codes present inside your controller , in that case service and repository architecture pattern will be very helpful .
In bigger application you need to make lots of API's where you have to send different success and error JSON responses and to manage all this service and repository architecture pattern is one of the best approach rather than writing your whole code inside your model .
We already have a in-depth article regarding this service-repository pattern, you can checkout here.
Use constants and lang files:
Use of constants and lang files are very simple concepts with huge impact in your application. It basically improves your code readability and maintainability. Constants are used to give a meaningful name to a set of texts or messages. Lang files allow us to store all of our project texts or messages in a single place.
Storing all the texts and messages at a single place helps in maintaining our code base. whenever we need to change any message or text , we just need to update it in one place and it will reflect in throughout our application.
Apart from this, in lang files you can translate the texts and messages to different languages very effectively.
Use of chunk for large data processing:
In Laravel you can use chunk() method to process large amount of data. Here are some reasons for using chunk() method for large data processing.
- It is memory efficient. The major work of chunk() is that it process the data in batch wise. Let's say you need to process 1 Million records at a time, if you use normal queries it will consume lots of memory and might slow down you server. Here chunk() method comes into help. chunk() method will break down your data let's say , it will pick 500 data out of 1 Million records at a time and process it, then again it will fetch next 500 data and process it and so on. So in this way it will be so memory efficient.
- It prevents timeouts. As we discussed in above point if we process 1 Million records directly it might exceed the execution time and break our query. So if we use chunk() it will process batch wise and will prevent timeouts.
Use jobs and queues:
Jobs and queues in Laravel allow us to perform a task asynchronously. Here are some use cases and benefits of using jobs and queues.
- It improves performance, Whenever you think a perticular task or process might take more time to process, we can add it to jobs and queues. So that it will not wait the user and process the time consuming task in the background.
- It's asynchronous behaviour. As it process the task in background, the API response time becomes more faster and your application can now receive other API request to handle.
- Apart from this basic behaviour of jobs and queues , it also provides some advance features also like job batching and error handling. If any job failed it will retry that after sometime. so that the application flow keeps on running.
You can read more about jobs and queues in Laravel here.