Farshad
Farshad

Reputation: 2000

how to implement Repository Pattern In Laravel

Although there Are some Tutorials on medium and some other sites about the Repository pattern for Laravel I read in some sites that repository pattern will duplicate the ORM and You won't need it in Laravel so now I have 2 questions: is it right to implement Repository pattern in Laravel ?? if yes What is the best source of tutorial because laracast I think has no tutorial on that neither do any good source done anything about it . and finally if not what is the best solution to make controller more beautiful and short

    public function bookingPhase2(Request $request)
    {
        // Requests
        $adults = $request->get('adults');
        $children = $request->get('children') ?? 0; // number of children
        $infants = $request->get('infants') ?? 0; // number of infants
        $extraBed = $request->get('extra_bed') ?? 0; // number of extra services (beds)
        $guestName = $request->get('guest_name'); //
        $guestLastName = $request->get('guest_last_name');
        $guestCellPhone = $request->get('guest_cellphone');
        $guestNationality = $request->get('guest_nationality'); // ['iranian', 'other']
        $guestNationalID = $request->get('guest_national_id');
        $accommodationBookingId = $request->get('accommodation_booking_id');
        $roomId = $request->get('room_id');

        Log::info(
            'The request for booking phase 2 is received with this data: ' . json_encode($request->all())
        );

        // Objects
        $accoBookingObject = AccommodationBooking::where('id', $accommodationBookingId)->first();
        $fromDate = Carbon::parse($accoBookingObject->from_date);
        $toDate = Carbon::parse($accoBookingObject->to_date);
        $numberOfStayingInDays = $fromDate->diffInDays($toDate);

        // get accommodationRoom for validating the request
        $accommodationRoom = AccommodationRoom::where('accommodation_id', $accoBookingObject->accommodation_id)->first();
        $message = '';

        $period = CarbonPeriod::create($accoBookingObject->from_date, $accoBookingObject->to_date);
        $fPrice = [];
        foreach ($period as $date) {
            $formattedDate = $date->format('Y-m-d');
            $roomprice = RoomPricingHistory::where('accommodation_room_id', $roomId)
                ->whereDate('from_date', '<=', $formattedDate)
                ->whereDate('to_date', '>=', $formattedDate)
                ->orderBy('created_at', 'desc')
                ->first();
            if (!$roomprice) {
                continue;
            }
            $lastPriceWithDiscount = $roomprice->sales_price - ($roomprice->sales_price * ($roomprice->discount_percent / 100));
            $fPrice[] = $lastPriceWithDiscount;
        }
        $totalRawPrice = collect($fPrice)->sum(); // SUm of prices for each night of staying without calculating any extra charges

        $pricePerNight = round($totalRawPrice / $numberOfStayingInDays, 2);

//        // get accommodationRoom for validating the request
//        $accommodationRoom = AccommodationRoom::where('accommodation_id', $accoBookingObject->accommodation_id)->first();
//        $message = '';

        if (
            $children > $accommodationRoom->childs_count
        ) {
            $message .= 'Invalid number of children which is ' . $accommodationRoom->childs_count;
        } elseif ($extraBed > $accommodationRoom->extra_bed_count) {
            $message .= 'Invalid number of extra bed which is ' . $accommodationRoom->extra_bed_count;
        } elseif ($adults > $accommodationRoom->bed_count) {
            $message .= 'Invalid number of adults which is ' . $accommodationRoom->bed_count;
        }

        if ($message !== '') {
            return $this->sendError(
                'Invalid Booking',
                $message
            );
        }

//        $accommodationObject = Accommodation::where('id', $accoBookingObject->accommodation_id)->first();
//        $childAge = $accommodationObject->child_age;
//        $infantAge = $accommodationObject->infant_age;;
        $extraPrice = 0;
        // the line below calculates the extra charges according to the children and infants during the staying nights
        $extraPrice += ($pricePerNight / 2) * $children * $numberOfStayingInDays;

        // extra bed price in the given period
        $pricingHistory = RoomPricingHistory::where('accommodation_room_id', $roomId)
            ->whereDate('from_date', '<', $fromDate)->whereDate('to_date', '>', $toDate)->first();
        $extraBedPrice = $pricingHistory->extra_bed_price ?? 0;
        $halfChargePrice = $pricingHistory->half_charge_price ?? 0;
        $halfBoardPrice = $pricingHistory->half_board_price ?? 0;
        $fullBoardPrice = $pricingHistory->full_board_price ?? 0;

        // final price is calculated by adding payable price and extra charge
        $finalPrice = (int) round(
            $totalRawPrice +
            $extraPrice +
            $extraBedPrice +
            $halfBoardPrice +
            $halfChargePrice +
            $fullBoardPrice,
            0
        );

        // Update payable price with the computed final price
        AccommodationBooking::where('id', $accommodationBookingId)->update(['payable_price' => $finalPrice]);

        // Add a log in accommodation_booking_accommodation_room
        try {
            DB::table('accommodation_booking_accommodation_room')
                ->insert([
                    'accommodation_booking_id' => $accommodationBookingId,
                    'accommodation_room_id' => $roomId,
                    'guest_national_number' => $guestNationalID,
                    'guest_first_name' => $guestName,
                    'guest_last_name' => $guestLastName,
                    'guest_cell_phone' => $guestCellPhone,
                    'guest_nationality_id' => $guestNationality,
                    'is_deleted' => 0,
                    'created_at' => Carbon::now(),
                    'updated_at' => Carbon::now()
                ]);
        } catch (\Exception $ex) {
            Log::error('Error during inserting accommodation_booking_accommodation_room: ' . $ex->getMessage());
            return $this->sendError(
                'Error during inserting accommodation_booking_accommodation_room',
                'Error during inserting accommodation_booking_accommodation_room.'
            );
        }

        return $this->sendResponse($finalPrice, 'final price retrieved successfully.');
    }

Upvotes: 1

Views: 1292

Answers (1)

Zeshan
Zeshan

Reputation: 2657

I would prefer to go with the following approach:

  1. Create a request class for data validation
  2. Create a service class for all the business logic and database interaction.

    You can also create repository per eloquent model to interact with database however I don't really see a benefit if you don't have a plan to replace Eloquent in future.

Let's see some code:

  1. Create request class
php artisan make:request BookingRequest

Place all your validation in the request class and then inject it in the controller.(more about request classes) i.e:

public function bookingPhase2(BookingRequest $request)
{
 // more code goes here
}

  1. Create a service class App\Services\BookingService and add all the business logic:
class BookingService
{
   public function bookRooms(array $data)
  {
    // place your business logic here.
    // you can create more private functions here to keep it more clean
    // return response to requester (ie controller)
  }
}

Call the service layer from controller:

public function bookingPhase2(BookingRequest $request, BookingService $bookingService)
{

  try {
      $response = $bookingService->bookRooms($request->validated());
      // return response
   } catch(\Exception $exception) {
       // log error message
       // throw exception
   }
}

// Inject the service class in controller's constructor 
// if you want to use it in other controller methods.

Read more about the service layer here

Hope it points you in a better direction!

Upvotes: 3

Related Questions