I have multiple database tables which each one of them populates a dropdown, The point is each dropdown effects next dropdown.
I mean if I select an item from the first dropdown, the next dropdown values change on the selected item, which means they are related and they populate dynamically on each dropdown item change.
I know this is not efficient and need refactoring so I'd be glad to point me out to the right way of populating those dropdowns.
This is the controller code:
<?php
use App\Http\Controllers\Controller;
use App\Models\County;
use App\Models\OutDoorMedia;
use App\Models\Province;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class FiltersController extends Controller
{
protected static $StatusCode = 0;
protected static $Msg = '';
protected static $Flag = false;
public function index(Request $request)
{
try {
$validator = Validator::make($request->all(), [
'province_id' => 'exists:province,id',
'county_id' => 'exists:county,id',
'media_type' => Rule::in([MEDIA_TYPE_BILLBOARD, MEDIA_TYPE_OUTDOOR_MONITOR, MEDIA_TYPE_INDOOR_MONITOR, MEDIA_TYPE_STAND, MEDIA_TYPE_STRABOARD, MEDIA_TYPE_BRAND_BOARD]),
'media_status' => Rule::in([MEDIA_STATUS_AVAILABLE, MEDIA_STATUS_NEGOTIATING, MEDIA_STATUS_ASSIGNED, MEDIA_STATUS_ARCHIVE]),
'category_id' => 'exists:category_list,id',
]);
if ($validator->fails()) {
abort(400, $validator->errors()->first());
} else {
//############################# Input Filters ####################################
$province_id = $request->has('province_id') ? $request->province_id : null;
$county_id = $request->has('county_id') ? $request->county_id : null;
$media_type = $request->has('media_type') ? $request->media_type : null;
$location = $request->has('location') ? $request->location : null;
$media_status = $request->has('media_status') ? $request->media_status : null;
$category_id = $request->has('category_id') ? $request->category_id : null;
//this flag is for detecting if user is requesting from "advertiser my order" to ignore some concitions
$advertiser_my_orders = ($request->has('my_orders') && $request->my_orders == 'true') ? true : false;
$province_ids = [];
$county_ids = [];
//############################# Media Owner Filters ####################################
//offline section filters
if (!is_null($province_id) && Province::whereId($request->province_id)->exists()) {
//check correction of county id
if (!is_null($county_id) && County::whereId($county_id)->whereProvinceId($province_id)->exists()) {
$media_owner_ODM_Provinces = Province::whereHas('media')->get()->toArray();
$media_owner_ODM_Provinces_Counties = County::whereProvinceId($province_id)
->whereHas('county_media')->get()->toArray();
foreach ($media_owner_ODM_Provinces as $key => $province) {
if ($province['id'] == $province_id) {
$media_owner_ODM_Provinces[$key]['county'] = $media_owner_ODM_Provinces_Counties;
}
}
$media_owner_ODM_locations = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereProvinceId($province_id)->whereCountyId($county_id)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
} else {
$media_owner_ODM_Provinces = Province::whereHas('media')->with(['county' => function ($query) {
$query->whereHas('county_media');
}])->get()->toArray();
$media_owner_ODM_locations = OutDoorMedia::whereProvinceId($province_id)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereProvinceId($province_id)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereProvinceId($province_id)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
}
} else {
$media_owner_ODM_Provinces = Province::whereHas('media')->with(['county' => function ($query) {
$query->whereHas('county_media');
}])->get()->toArray();
foreach ($media_owner_ODM_Provinces as $province) {
$province_ids[] = $province['id'];
foreach ($province['county'] as $county) {
$county_ids[] = $county['id'];
}
}
$media_owner_ODM_locations = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->groupBy('location')->pluck('location')->toArray();
$media_owner_ODM_media_types = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->whereIn('location', $media_owner_ODM_locations)->groupBy('media_type')->pluck('media_type')->toArray();
$media_owner_ODM_media_Status = OutDoorMedia::whereIn('province_id', $province_ids)->whereIn('county_id', $county_ids)->whereIn('media_type', $media_owner_ODM_media_types)->groupBy('status')->pluck('status')->toArray();
}
$media_owner_offline = [
'provinces' => $media_owner_ODM_Provinces,
'media_status' => $media_owner_ODM_media_Status,
'location' => $media_owner_ODM_locations,
'media_type' => $media_owner_ODM_media_types,
];
$filters['media_owner']['offline'] = $media_owner_offline;
self::$StatusCode = 200;
self::$Msg = $filters;
self::$Flag = true;
}
} catch (\Exception $e) {
//=========== Get Error Exception Message ============
self::$StatusCode = 400;
self::$Msg = $e->getMessage();
self::$Flag = false;
return $this->CustomeJsonResponse(self::$Flag, self::$StatusCode, self::$Msg);
//=========== Get Error Exception Message ============
} finally {
return $this->CustomeJsonResponse(self::$Flag, self::$StatusCode, self::$Msg);
}
}
}
FYI: I'm using laravel 5.3 framework.
Here are something that you should be aware of them.
first of all, if you validate province_id, so there is no need to double check it in your code. so you should remove
Province::whereId($request->province_id)->exists()
Second one is, Laravel has ->when eloquent method that helps you reduce if else statements for null values, if we have a null value for given parameter, it will not effect the query. https://laravel.com/docs/5.8/queries#conditional-clauses
Third one, I suggest you to use Laravel Resources in order to transform your fetched data from database in API. https://laravel.com/docs/5.8/eloquent-resources
This is better version of small portion of your code, I think with suggested tips and this code, you can refactor it:
class TestController extends Controller
{
const DEFAULT_COUNTRY_ID = '10';
public $request;
public function something(Request $request)
{
// Put Validations ...
$this->request = $request;
OutDoorMedia::when('province_id', function ($query) {
return $query->where('province_id', $this->request->province_id);
})
->when('country_id', function ($query) {
// if country_id exists
return $query->where('country_id', $this->request->country_id);
}, function ($query) {
// else of above if (country_id is null ...)
return $query->where('country_id', self::DEFAULT_COUNTRY_ID);
})
->get();
}
}
This is just a sample, You can use this way to refactor your code base.