Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ErikThiart's avatar

How would you implement a search, the laravel way

So, I picked up laravel a few weeks ago as many of you know, I love it - but still lots to learn regarding how to use the relationship aspect better, I decided to thumb suck a project I can try build in laravel as a learning experience.

Now I build a business directory of sorts and it works like a bomb, but it feels dirty. Do any of you mind explaining how you would approach this to make it more laravel(sque).

Logic (what makes it dirty is I'm trying to use the same view to do all out comes and keeping the SEO side in tact.

    /*
     * The search is POSTed, I then form a GET url for SEO
     * This produces a url like: /search/{business_type}/{business_town}
     */
    public function redirectBusiness(Request $request)
    {
        if(is_numeric($request->business_town)) {
            $town = Town::find($request->business_town);
            return Redirect('search/' . Str::lower($request->business_type) . '/' . Str::lower($town->town));
        }

        return Redirect('search/' . Str::lower($request->business_type) . '/' . Str::lower($request->business_town));
    }
    /*
     * Get the businesses that match a search term in a particular town
     * This is for /search/{business_type}/{business_town}
     */
    public function getBusinesses($business_type, $business_town)
    {
        // get the town ID
        $town_id = (new \App\Town)->getIdFromTown($business_town);

        // bail if the town does not exist
        if (!$town_id) {
            // get the most popular categories
            $categories = Category::withCount('businesses')
                ->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(25);
            // get a list of towns
            $locations = Town::all()->random(25);
            // display the no search result page
            return view('no-search-result')
                ->with('search_type', $business_type)
                ->with('search_town', $business_town)
                ->with('categories', $categories)
                ->with('locations', $locations);
        }
        // get the the collection of businesses
        $businesses = DB::table('businesses')
            ->select('businesses.*')
            ->join('towns', 'towns.id', '=', 'businesses.town_id')
            ->join('categories', 'categories.id', '=', 'businesses.category_id')
            ->where(static function ($query) use ($business_type) {
                // format each of search keywords into the db query to be run
                $keywords = explode(' ', $business_type);
                foreach ($keywords as $word) {
                    $query->orwhere('businesses.title', 'LIKE', '%' . $word . '%')
                          ->orWhere('categories.name', 'LIKE', '%' . $word . '%')
                          ->orWhere('businesses.description', 'LIKE', '%' . $word . '%');
                }
            })
            ->where(static function ($query) use ($town_id) {
                $query->where('towns.id', '=', $town_id);
            })
            ->limit(25)
            ->paginate(5);

        // bail if there are no businesses
        if ( $businesses->isEmpty() ) {
            $meta_description = 'There are no '.$business_type.' businesses near or in '.$business_town.' yet - list your business for free.';
            $categories = Category::withCount('businesses')->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(25);
            $locations = Town::all()->random(25);
            return view('no-search-result')
                ->with('meta_description', $meta_description)
                ->with('search_type', $business_type)
                ->with('search_town', $business_town)
                ->with('categories', $categories)
                ->with('locations', $locations);
        }

        // Create the search result set
        $town = Town::find($town_id);
        $categories = Category::withCount('businesses')->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(10);
        $meta_description = 'There are '.$businesses->count().' '.$business_type.' businesses near'.' '.$town->full_name.' - list your business for free.';
        // Town ID was found and a collection of matching businesses, display it.
        return view('search-results')
            ->with('meta_description', $meta_description)
            ->with('businesses', $businesses)
            ->with('search_type', $business_type)
            ->with('town', $town)
            ->with('categories', $categories);
    }
    /*
     * Get ALL the businesses in a particular location
     * This is for /location/{town_name}
     */
    public function getBusinessesByLocation($location)
    {

        // get the town ID
        $town_id = (new \App\Town)->getIdFromTown($location);

        // bail if the town does not exist
        if (!$town_id) {
            $categories = Category::withCount('businesses')->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(25);
            $areas = Town::all()->random(25);
            $meta_description = 'There are no businesses near or in '.$location.' yet - list your business for free';
            return view('no-search-result')
                ->with('meta_description', $meta_description)
                ->with('search_type', 'All Businesses')
                ->with('search_town', $location)
                ->with('categories', $categories)
                ->with('locations', $areas);
        }

        // get the the collection of businesses
        $businesses = DB::table('businesses')
            ->select('businesses.*')
            ->join('towns', 'towns.id', '=', 'businesses.town_id')
            ->join('categories', 'categories.id', '=', 'businesses.category_id')
            ->where(static function ($query) use ($town_id) {
                $query->where('towns.id', '=', $town_id);
            })
            ->limit(200)
            ->paginate(5);

        // bail if there are no businesses
        if ( $businesses->isEmpty() ) {
            $categories = Category::withCount('businesses')->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(25);
            $areas = Town::all()->random(25);
            $meta_description = 'There are no businesses near or in '.$location.' yet - list your business for free';
            return view('no-search-result')
                ->with('meta_description', $meta_description)
                ->with('search_type', 'All Businesses')
                ->with('search_town', $location)
                ->with('categories', $categories)
                ->with('locations', $areas);
        }

        // create the town
        $town = Town::find($town_id);
        $categories = Category::withCount('businesses')->having('businesses_count', '>=', 1)->get()->sortByDesc('businesses_count')->take(10);
        $meta_description = 'There are '.$businesses->count().' businesses near'.' '.$town->full_name.' - list your business for free and be seen by millions.';
        return view('search-results')
            ->with('meta_description', $meta_description)
            ->with('businesses', $businesses)
            ->with('search_type', 'All Businesses')
            ->with('town', $town)
            ->with('categories', $categories);
    }

I am also unsure how you would handle filters /search/business_type/business_area?nearby=1 or any other kind of filter without then repeating the above.

0 likes
4 replies
ederson's avatar

the first thing i'd do would be to use scopes ....

1 like
martinbean's avatar

@erikthiart Well, the “Laravel way” is to use the official package, Scout.

By default, it’s heavily tied to Algolia, but you can use or create other drivers for other search engines, such as Elastic Search.

ErikThiart's avatar

Don't need to use scout for this, that's overkill imo. (and cost additional money)

Please or to participate in this conversation.