DEV Community

Cover image for Laravel Best Practice [Coding Standards Part 02] ๐Ÿง‘โ€๐Ÿฆฐ๐Ÿ‘ฉโ€๐Ÿฆฐ
Lathindu Pramduitha
Lathindu Pramduitha

Posted on • Updated on

Laravel Best Practice [Coding Standards Part 02] ๐Ÿง‘โ€๐Ÿฆฐ๐Ÿ‘ฉโ€๐Ÿฆฐ

Hello friends, This is the second article of Laravel coding standards article series.

If you didn't see the first article, I recommend to read it for best practice.

Laravel Best Practice Article 01 => Click Here To Open Article

arraow

Article 02: Principles should adhere.โœŠ

Here I will talk about some principles which are developer should follow.

pK-gMzy3meGp1rdP21xe1TUB9Dde408OFq4S

01 Don't Use Validations Inside Controller ๐Ÿ‘ˆ

When I review my junior developer's code, I have seen there are bunch of validators in the controller. Some time they just google the issue and copy things from Stackowerflow or some where and put in the code without investigating about it. so that's the main problem which I seen with them.

Here You may see some Bad code which are used validator in controller.

    public function store(Request $request){
         Validator::make($request, [
            'first_name' => ['required', 'string', 'max:255'],
            'last_name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' =>['required', 'string', new Password, 'confirmed']
        ])->validate();
        return User::store($request->all());
    }
Enter fullscreen mode Exit fullscreen mode

so this is not a correct way to put validator.
we should use Customer Request to handle Validators.

01 Create Custom Request. ๐Ÿ‘ˆ
php artisan make:request UserCreateRequest
Enter fullscreen mode Exit fullscreen mode

above as a request name. you may use actual scenario . ex-: if you want to handle user update form request. You may create Request as UserUpdateRequest.

Once Created Request from the command. you can see UserCreateRequest inside your project root -> app -> Http -> Requests .

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserCreateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}

Enter fullscreen mode Exit fullscreen mode

In the class you may see two prebuilt functions called
authorize() and rules() .

02 Allow CSRF ๐Ÿ‘ˆ

in authorize() function you need to change return as true .

otherwise your request will not work.

03 Add Validation Rules. ๐Ÿ‘ˆ

You can add validation methods inside rules() function.

 public function rules()
    {
        return [
            'first_name' => ['required', 'string', 'max:255'],
            'last_name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' =>['required', 'string', new Password, 'confirmed']
        ];
    }

Enter fullscreen mode Exit fullscreen mode
04 Add Custom Validation Messages. ๐Ÿ‘ˆ

Then you can add custom validation messages for every input, every validation methods. here you need to override message() function from formRequest Trait.

and add messages by mentioning inputs and rules separating by dots.

    public function messages()
    {
        return [
            "first_name.required" => "User first name is required",
            "first_name.string" => "User first name type must be a string",
            "email.unique" => "This email is already used.",
        ];
    }
Enter fullscreen mode Exit fullscreen mode

Finally UserCreateRequest may be like this.

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserCreateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'first_name' => ['required', 'string', 'max:255'],
            'last_name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' =>['required', 'string', new Password, 'confirmed']
        ];
    }
    /**
     * Get custom messages for validator errors.
     *
     * @return array
     */
    public function messages()
    {
        return [
            "first_name.required" => "User first name is required",
            "first_name.string" => "User first name type must be a string",
            "email.unique" => "This email is already used.",
        ];
    }
}

Enter fullscreen mode Exit fullscreen mode

Now You Can use UserCreateRequest inside controller

function.

   /**
     * Store Customer
     *
     * @param  UserCreateRequest $request
     * @return User
     */
    public function store(UserCreateRequest $request){
        return User::store($request->all());
    }

Enter fullscreen mode Exit fullscreen mode

With this custom request you can have lot's of complex logics, rules inside it.

images

02 Use Config, Constants, Language Files without complexing code. ๐Ÿ‘ˆ

let's say you are adding users to database with number of status.

like ApprovalPending , Approved , Declined , ReSubmitted

This the Bad way which lot's of juniors are doing.


switch ($user->status) {
    case 1:
    // do the things for Pending status
        break;
    case 2:
    // do the things for Approved status
        break;
    case 3:
    // do the things for Declined status
        break;
    case 4:
    // do the things for Resubmitted status
        break;

}

Enter fullscreen mode Exit fullscreen mode

above you may see if we changed integer for related status, we must change the switch function also for correct the status, and also if comments deleted by some how, you don't know what happened in case 1, what happened in case 2 like this.

to avoid this we can use Constant Variable which is defined inside related model.


 CONST STATUS =[
        "ApprovalPending"=>1,
        "Approved"=>2,
        "Declined"=>3,
        "ReSubmitted"=>4,
    ];


Enter fullscreen mode Exit fullscreen mode

Then you can use STATUS variable inside the switch case anywhere.


switch ($user->status) {
    case User::STATUS['ApprovalPending']:
    // do the things for Pending status
        break;
    case User::STATUS['Approved']:
    // do the things for Approved status
        break;
    case User::STATUS['Declined']:
    // do the things for Declined status
        break;
    case User::STATUS['ReSubmitted']:
    // do the things for Resubmitted status
        break;
}

Enter fullscreen mode Exit fullscreen mode

identify_sqlitebrowser

03 Don't Execute Queries inside blade files. ๐Ÿ‘ˆ

lot's of junior developers are doing this thing without looking about it.


@foreach (Customer::all() as $customer)
    {{ $customer->address->street_address }}
@endforeach

Enter fullscreen mode Exit fullscreen mode

This code is fine there no any issue. but let's look in to deep. This will execute 1001 queries for 1000 customers .


$customers = Customer::with('address')->get();

@foreach ($customers as $customer)
    {{ $customer->address->street_address }}
@endforeach

Enter fullscreen mode Exit fullscreen mode

This is perfect. This will execute only 2 queries for 1000 of customers .

Above I talked about 3 main issues which junior developers are doing mostly.

I hope you find my post useful! Any feedback is greatly appreciated!

You may Find my Upwork Profile Here.

https://www.upwork.com/freelancers/lathindu

below I mentioned my other articles. you may also read them.

Other Articles ๐Ÿ‘ˆ๐Ÿ‘ˆ๐Ÿ‘ˆ

Here I'm Adding Public GitHub Repository which will store all of my tutorials. you may clone it and see every tutorials what I will publish ๐Ÿค—.

GitHub Repository

Thank You Very much.
--Lathindu Pramuditha--

GitHub Profile

GitHub logo lathindu1 / lathindu1

It's About Lathindu Pramuditha's Account

เถ†เถบเท”เถถเทเท€เถฑเทŠ (Welcome)๐Ÿ™๐Ÿป, I'm Lathindu Pramuditha Amarasekara!

Software Engineer at Speralabs

Linkedin: lathindu-pramuditha GitHub followers Waka Readme

A little more about me...

namespace App\Models
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Life;

class ProfileOfLathindu extends Life
{
    use HasFactory;
    const LANGUAGES = [
        'PHP' => 1,
        'JAVASCRIPT' => 2,
        'PYTHON' => 3,
        'SOLIDITY' => 4,
        'DART' => 5
    ];

    const FRAMEWORKS = [
        'LARAVEL' => 1,
        'FLUTTER' => 2,
        'DJANGO' => 3,
        'ANGULAR' => 4,
        'IONIC' => 5
    ];

    const EXPERIENCE = 'xxxxxxxxxx of hours from 2017';

    const MORE_EXPERIENCE = [
        'PAYPAL_API' => 1,
        'STRIPE_API' => 2,
        'PAYHERE_SDK' => 3,
        'UPHOLD_API' => 4,
        'VIMEO_SDK' => 5,
        'NMI_API' => 6,
        'SENDGRID_API' => 7,
        'AWEBER_API' => 8,
        'GETRESPOND_API' => 9,
        'REMIX' => 10,
        'BTCPAY_SERVER'
โ€ฆ
Enter fullscreen mode Exit fullscreen mode

Screenshot 2021-04-19 at 23.08.02

Top comments (12)

Collapse
 
bravemaster619 profile image
bravemaster619

I'd like to add a thing to 02.

I've seen many devs use env function.

Please avoid env and use config instead.

Because .env files can be cached via php artisan config:cache and you can't use env function after that. (it will return null)

So if any of the code uses env function, you can't config cache in the future.

Collapse
 
lathindu1 profile image
Lathindu Pramduitha

great @bravemaster619 it's better to use config instep of env. and also we can use both.

we can use real content inside config file and. if we have local only thing we can use them inside .env .

like

"paypal_secret" = env("PAYPAL_SECRET" , 'asdfthdnejs323jn23nk3jn2njk3n2'),

and for our sandbox in local we can use key's inside .env

PAYPAL_SECRET = "kjansjnaknjsnalhjsbljhslhjlhjsla"

otherwise we don't want to use env anyware.

Collapse
 
bravemaster619 profile image
bravemaster619

This.

Collapse
 
ionbazan profile image
Ion Bazan

Using $request->all() is worst thing you can do. You should always use $request->validated().

Collapse
 
bravemaster619 profile image
bravemaster619

03 is more like: Avoid N+1 query problem.

Collapse
 
theowlsden profile image
Shaquil Maria

Thank you for this post!๐Ÿ™
I am about to start developing a project in Laravel and these tips will come in handy!

Collapse
 
lathindu1 profile image
Lathindu Pramduitha

Thank you very much

Collapse
 
thuhtetdev profile image
Thu Htet Tun

Nice laravel tips, Lathindu.

Collapse
 
lathindu1 profile image
Lathindu Pramduitha

Thank you very much.

Collapse
 
bobbyiliev profile image
Bobby Iliev

Great post! Well done! Awesome to see some high-quality Laravel content on here!

Collapse
 
sajaddp profile image
Sajad DP

Thanks man :)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.