the first thing i'd do would be to use scopes ....
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.
Please or to participate in this conversation.