jeudi 24 juin 2021

Why use service container instead of new class

In what scenario should we use a service container instead of calling a new class directly? I read from Laravel official docs that it is mainly used for managing class dependency and performing dependency injection, however I am not sure if I understand it correctly.

For example payroll applications, we would have a Payroll class, Employee Class, Leave Class, Timesheet Class. So to process a monthly payroll, Payroll class would depends on

  • Employee Class (getBasicSalary)
  • Leave Class (getUnpaidLeaveCount)
  • Timesheet Class (getLateHoursCount)

Below is what I normally writes (without any design pattern)

Class PayrollProcessController 
{
    public function index(){
         $payrollObj = new Payroll();
         $payroll->setPayrollMonth('202106');
         $payroll->process();
    }
}

Class Payroll 
{
    private $payrollMonth;

    public function process()
    {
        // loop employee from database
        foreach ($employees as $employee_id){
             $salary = $this->calculateNetSalary($employee_id); 
             // save into db
        }
    }

    public function calculateNetSalary($employee_id)
    {
         $employee = Employee::find($employee_id);
         $basicSalary = $employee->getBasicSalary();
         $basicSalaryPerDay = $basicSalary / date('t');         
         $basicSalaryPerHour = $basicSalaryPerDay / 8;
         $leaveTakenDay = Leave::getUnpaidLeaveCount( $employee->getId(), $this->payrollMonth);
         $leaveDeductionAmount = $basicSalaryPerDay * $leaveTakenDay;
         $timesheetLateHours = Timesheet::getLateHoursCount($employee->getId(), $this->payrollMonth);
         $lateDeductionAmount = $basicSalaryPerHour * $timesheetLateHours;
         $netSalary = $basicSalary - $leaveDeductionAmount - $lateDeductionAmount;
         return $netSalary;
    }
}

If apply with service container concept,

Class PayrollProcessController 
{
    public function index(Payroll $payroll){  
          $payroll->setPayrollMonth('202106');        
          $payroll->process();
    }
}

Class Payroll 
{
    public function process()
    {
        // loop employee from database
        foreach ($employees as $employee_id){

            $employee = app(Employee::class);
            $employee = $employee->find($employee_id);
            $leave = app(Leave::class);
            $timesheet = app(Timesheet::class);

            $salary = $this->calculateNetSalary($employee, $leave, $timesheet); 
             // save into db
        }
    }

    public function calculateNetSalary(Employee $employee, Leave $leave, Timesheet $timesheet)
    {
         $basicSalary = $employee->getBasicSalary();
         $basicSalaryPerDay = $basicSalary / date('t');         
         $basicSalaryPerHour = $basicSalaryPerDay / 8;
         $leaveTakenDay = $leave->getUnpaidLeaveCount( $employee->getId(), $this->payrollMonth);
         $leaveDeductionAmount = $basicSalaryPerDay * $leaveTakenDay;
         $timesheetLateHours = $timesheet->getLateHoursCount($employee->getId(), $this->payrollMonth);
         $lateDeductionAmount = $basicSalaryPerHour * $timesheetLateHours;
         $netSalary = $basicSalary - $leaveDeductionAmount - $lateDeductionAmount;
         return $netSalary;
    }
}

Questions:

  1. Is the above concept correct?

  2. I checked again on the service container documentation https://laravel.com/docs/8.x/container#when-to-use-the-container, it is written:

    First, if you write a class that implements an interface and you wish to type-hint that interface on a route or class constructor, you must tell the container how to resolve that interface. Secondly, if you are writing a Laravel package that you plan to share with other Laravel developers, you may need to bind your package's services into the container.

    So can I say that unless we are publishing the payroll modules as a laravel package for others to use or to write unit testing, there is no point in using a service container?

  3. If we look at opencart's registry class, is that is similar to Laravel's service container? https://github.com/opencart/opencart/blob/e22ddfb060752cd8134abbfb104202172ab45c86/upload/system/framework.php#L9

  4. Take an example from opencart, so Language class is singleton design pattern, while registry is container design pattern?

    $language = new \Opencart\System\Library\Language($config->get('language_code'));
    $language->addPath(DIR_LANGUAGE);
    $language->load($config->get('language_code'));
    $registry->set('language', $language);
    

Aucun commentaire:

Enregistrer un commentaire