1

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.'); } 
9
  • The main question is why do you feel you should use the repository pattern? Commented Jul 16, 2019 at 8:03
  • 2
    I do think the repository pattern can make your controllers way more cleaner, but it all depends on how you implement it. In my own projects, I use repositories that return models or model collections and only that. So not a single query is in my controllers. Commented Jul 16, 2019 at 8:03
  • @RossWilson because i have a controller which is 800 line of code even after seperating the controllers i mean i can no longer seperate that to smaller controllers and i feel like i should make it smaller for making it readable and easy to debug Commented Jul 16, 2019 at 8:06
  • @Jerodev yes exacly i want to so some thing like that but i cant find a good source that talks about the repo pattern in laravel and how to implement that Commented Jul 16, 2019 at 8:07
  • Basic concept of implementing Repository Pattern in laravel is that controller only takes request from client and provide the response to client. All the business logic resides in the service layer and all database queries are placed in repository so that you can separate server logic in to different layers. Commented Jul 16, 2019 at 8:16

1 Answer 1

3

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!

Sign up to request clarification or add additional context in comments.

2 Comments

thank you i will implement the way you said after i read the service layer completely but one question remains here doesn't this service needs contracts ?? i mean this way how is it different than a helper ??
I don't really think it needs contracts however you're free to implement the way you want.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.