getFilterData($filterData); $query = $this->getRestaurantQuery(); if (! $filter['with_deleted']) { $query->whereNull("{$this->table}.deleted_at"); } if (isset($filter['search']) && strlen($filter['search']) > 0) { $query = $this->filterSearchQuery($query, $filter['search']); } return $query ->orderBy($filter['orderBy'], $filter['order']) ->paginate($filter['perPage']); } protected function getFilterData(array $filterData = []): array { $defaultArgs = [ 'perPage' => 10, 'search' => '', 'orderBy' => 'id', 'order' => 'desc', 'with_deleted' => false, ]; return array_merge($defaultArgs, $filterData); } private function getRestaurantQuery(): Builder { return $this->getQuery() ->leftJoin('users as owner', 'restaurants.owner_id', '=', 'owner.id') ->leftJoin('users as assigned', 'restaurants.assigned_to', '=', 'assigned.id') ->leftJoin('themes', 'restaurants.theme_id', '=', 'themes.id') ->select([ 'restaurants.id', 'restaurants.owner_id', 'owner.first_name as owner_name', 'restaurants.assigned_to', 'assigned.first_name as assigned_name', 'restaurants.name', 'restaurants.email', 'restaurants.address', 'restaurants.restaurant_type', 'restaurants.phone', 'restaurants.domain', 'restaurants.platform', 'restaurants.last_active_time', 'restaurants.logo', 'restaurants.status', 'restaurants.theme_id', 'themes.name as theme_name', 'restaurants.created_at', 'restaurants.deleted_at', ]); } protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder { $searchable = "%$searchedText%"; return $query->where('restaurants.name', 'LIKE', $searchable) ->orWhere('restaurants.email', 'LIKE', $searchable) ->orWhere('restaurants.restaurant_type', 'LIKE', $searchable) ->orWhere('restaurants.phone', 'LIKE', $searchable) ->orWhere('restaurants.domain', 'LIKE', $searchable); } /** * @throws Exception */ public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object { $user = $this->getRestaurantQuery() ->where($columnName, $columnValue) ->first(); if (empty($user)) { throw new Exception( $this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE), Response::HTTP_NOT_FOUND ); } return $user; } public function getCount(array $filterData = []): int { $filter = $this->getFilterData($filterData); $query = $this->getQuery(); if (! $filter['with_deleted']) { $query->whereNull("{$this->table}.deleted_at"); } return $query->count(); } /** * @throws \Exception */ public function create(array $data): object { try { return DB::transaction(function () use ($data) { // Step 1: Prepare data for DB (handles file uploads, default timestamps, owner_id, etc.) $data = $this->prepareForDB($data); // Step 2: Insert restaurant and get the ID $restaurantId = $this->getQuery()->insertGetId($data); $restaurant = Restaurant::find($restaurantId); // Step 3: Owner info from currently authenticated user $authUser = Auth::user(); $ownerData = [ 'name' => $authUser->first_name, 'email' => $authUser->email, 'phone' => $authUser->phone, 'avatar' => $authUser->avatar, 'package_id' => $data['package_id'] ?? null, 'price' => $data['price'] ?? null, ]; // Step 4: Setup restaurant (owner assignment, settings, subscription, domain) RestaurantSetupService::setup($restaurant, $ownerData, false); // Step 5: Return the restaurant object return $restaurant; }); } catch (Exception $exception) { // Rollback is automatic on exception in transaction closure throw new Exception($exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR); } } /** * @throws Exception */ public function prepareForDB(array $data, ?object $item = null): array { $data = parent::prepareForDB($data, $item); if (empty($item)) { $data['created_at'] = now(); $data['owner_id'] = getUserId(); $data['assigned_to'] = $this->getCurrentUserId(); $data['created_by'] = $this->getCurrentUserId(); $data['status'] = 1; if (! empty($data['logo']) && $data['logo'] instanceof \Illuminate\Http\UploadedFile) { $data['logo'] = fileUploader('restaurants/', 'png', $data['logo']); } } else { if (! empty($data['logo']) && $data['logo'] instanceof \Illuminate\Http\UploadedFile) { $data['logo'] = fileUploader('restaurants/', 'png', $data['logo'], $item->logo); } $data['updated_at'] = now(); } return $data; } /** * @throws Exception */ public function update(int $id, array $data): ?object { try { $restaurant = Restaurant::find($id); $data = $this->prepareForDB($data, $restaurant); parent::update($id, $data); return $this->getById($id); } catch (Exception $exception) { throw new Exception($exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR); } } protected function getExceptionMessages(): array { $exceptionMessages = parent::getExceptionMessages(); $userExceptionMessages = [ static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Restaurant does not exist.', static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Restaurant could not be deleted.', ]; return array_merge($exceptionMessages, $userExceptionMessages); } }