लारवेल के साथ DRY सिद्धांत

एक साधारण मॉड्यूल पर विचार करें जो नए उपयोगकर्ताओं को जोड़ने के लिए जिम्मेदार है।

और उसके उदाहरण से हम देखेंगे कि DRY सिद्धांत के अनुप्रयोग की क्या संभावनाएँ हैं।

मेरे लिए, DRY का सिद्धांत (खुद को दोहराएं नहीं) हमेशा दो मूल परिभाषाओं में सन्निहित है:

  1. ज्ञान का दोहराव हमेशा सिद्धांत का उल्लंघन है
  2. कोड दोहराव हमेशा सिद्धांत का उल्लंघन नहीं है

आइए नियंत्रक के साथ शुरू करें जिसमें तर्क की न्यूनतम राशि है।

class UserController
{
    public function create(CreateRequest $request)
    {
        $user = User::create($request->all());
        
        return view('user.created', compact('user'));
    }
}

class UserApiController
{
    public function create(CreateRequest $request)
    {
        $user = User::create($request->all());
        
        return response()->noContent(201);
    }
}

प्रारंभिक चरण में, कोड की ऐसी पुनरावृत्ति हानिरहित लगती है।
लेकिन हमारे पास पहले से ही ज्ञान का दोहराव है, और ज्ञान का दोहराव निषिद्ध है।
ऐसा करने के लिए, हम उपयोगकर्ता सेवा वर्ग में उपयोगकर्ता निर्माण को सामान्य करते हैं

class UserService
{
    public function create(array $data): User
    {
        $user = new User;
        $user->email = $data['email'];
        $user->password = $data['password'];
        $user->save();

        return $user;
    }
    
    public function delete($userId): bool 
    {
        $user = User::findOrFail($userId);
 
        return $user->delete();
    }    
}

मॉडल के साथ काम करने के सभी तर्क को सेवा में स्थानांतरित करने के बाद, हमें नियंत्रक में इसके दोहराव से छुटकारा मिलता है। लेकिन हमें एक और समस्या है। मान लें कि हमें उपयोगकर्ता बनाने की प्रक्रिया को थोड़ा जटिल करना है।

class UserService
{
    protected $blogService;
    
    public function __construct(BlogService $blogService)
    {
        $this->blogService = $blogService;
    }

    public function create(array $data): User
    {
        $user = new User;
        $user->email = $data['email'];
        $user->password = $data['password'];
        $user->save();
        
        $blog = $this->blogService->create();
        $user->blogs()->attach($blog);

        return $user;
    }
    
    //Other methods
}

धीरे-धीरे, उपयोगकर्ता सेवा वर्ग बढ़ने लगेगा और हम बड़ी संख्या में निर्भरता के साथ एक सुपर वर्ग प्राप्त करने का जोखिम उठाते हैं।

CreateUser सिंगल एक्शन क्लास


इस तरह के परिणामों से बचने के लिए, आप सेवा को एकल कार्रवाई की कक्षाओं में तोड़ सकते हैं।

इस वर्ग के लिए बुनियादी आवश्यकताएं:

  • प्रदर्शन करने की क्रिया का प्रतिनिधित्व करने वाला नाम
  • एक एकल सार्वजनिक विधि है (मैं __inoke मैजिक विधि का उपयोग करूंगा )
  • सभी आवश्यक निर्भरताएँ हैं
  • अपने भीतर सभी व्यावसायिक नियमों का अनुपालन सुनिश्चित करता है, उनका उल्लंघन होने पर अपवाद उत्पन्न करता है

class CreateUser
{
    protected $blogService;

    public function __construct(BlogService $blogService)
    {
        $this->blogService = $blogService;
    }

    public function __invoke(array $data): User
    {
        $email = $data['email'];
        
        if (User::whereEmail($email)->first()) {
            throw new EmailNotUniqueException("$email should be unique!");
        }
        
        $user = new User;
        $user->email = $data['email'];
        $user->password = $data['password'];
        $user->save();

        $blog = $this->blogService->create();
        $user->blogs()->attach($blog);

        return $user;
    }
}

हमारे पास CreateRequet वर्ग में पहले से ही एक ईमेल फ़ील्ड की जाँच है, लेकिन यहाँ भी चेक जोड़ना तर्कसंगत है। यह अधिक सटीक रूप से उपयोगकर्ता बनाने के व्यापार तर्क को दर्शाता है, और डिबगिंग को भी सरल करता है।

नियंत्रक निम्नलिखित रूप लेते हैं

class UserController
{
    public function create(CreateRequest $request, CreateUser $createUser)
    {
        $user = $createUser($request->all());

        return view('user.created', compact('user'));
    }
}

class UserApiController
{
    public function create(CreateRequest $request, CreateUser $createUser)
    {
        $user = $createUser($request->all());

        return response()->noContent(201);
    }
}

परिणामस्वरूप, हमारे पास उपयोगकर्ता बनाने के लिए पूरी तरह से अलग तर्क है। यह संशोधित करने और विस्तार करने के लिए सुविधाजनक है।

अब देखते हैं कि यह दृष्टिकोण हमें क्या लाभ देता है।

उदाहरण के लिए, उपयोगकर्ताओं को आयात करने के लिए एक कार्य है।

class ImportUser
{
    protected $createUser;
    
    public function __construct(CreateUser $createUser)
    {
        $this->createUser = $createUser;
    }
    
    public function handle(array $rows): Collection
    {
        return collect($rows)->map(function (array $row) {
            try {
                return $this->createUser($row);
            } catch (EmailNotUniqueException $e) {
                // Deal with duplicate users
            }
        });
    }
}

हमें कोड :: मैप () विधि में एम्बेड करके कोड को पुन: उपयोग करने का अवसर मिलता है। और हमारी जरूरतों के उपयोगकर्ताओं के लिए भी प्रक्रिया करते हैं जिनके ईमेल पते अद्वितीय नहीं हैं।

ड्रेसिंग


मान लीजिए हमें प्रत्येक नए उपयोगकर्ता को एक फ़ाइल में पंजीकृत करने की आवश्यकता है।

ऐसा करने के लिए, हम स्वयं CreateUser वर्ग में इस क्रिया को एम्बेड नहीं करेंगे, लेकिन डेकोरेटर पैटर्न का उपयोग करेंगे।

class LogCreateUser extends CreateUser 
{
    public function __invoke(array $data)
    {
        Log::info("A new user has registered: " . $data['email']);
        
        parent::__invoke($data);
    }
}

फिर, लारवेल IoC कंटेनर का उपयोग करके , हम LogCreateUser वर्ग को CreateUser वर्ग के साथ जोड़ सकते हैं , और पहली बार हर बार लागू किया जाएगा जब हमें दूसरे की आवश्यकता होगी।

class AppServiceProvider extends ServiceProvider
{

    // ...

    public function register()
    {
        $this->app->bind(CreateUser::class, LogCreateUser::class);
    }

हमारे पास कॉन्फ़िगरेशन फ़ाइल में एक चर का उपयोग करके उपयोगकर्ता निर्माण सेटिंग करने का अवसर भी है।

class AppServiceProvider extends ServiceProvider
{

    // ...

    public function register()
    {
         if (config("users.log_registration")) {
             $this->app->bind(CreateUser::class, LogCreateUser::class);
         }
    }

निष्कर्ष


ये रहा एक सरल उदाहरण। जटिलता बढ़ने पर वास्तविक लाभ दिखाई देने लगते हैं। हम हमेशा जानते हैं कि कोड एक जगह पर है और इसकी सीमाओं को स्पष्ट रूप से परिभाषित किया गया है।

हमें निम्नलिखित लाभ मिलते हैं: दोहराव को रोकता है, परीक्षण को सरल करता है
और अन्य सिद्धांतों और डिजाइन पैटर्न के आवेदन का मार्ग खोलता है।

All Articles