phplaravel-5dynamiceloquentauto-populate

Efficient way to populate drop-down dynamically in laravel


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.


Solution

  • 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.