简体   繁体   中英

laravel select raw not working on some models

I am caught in a very weird situation as there is something in my query that won't work if the value of whereHas is changed. To explain it better, first, look at this query:

$table_data = Pengelola::with('pekerjaan_aktif.cu','pendidikan_tertinggi')
->whereHas('pekerjaan', function($query) use ($id,$tipe){
    $query->where('tipe',$tipe)->where('id_tempat',$id)
    ->where(function($q){
        $q->where('sekarang','1')->orWhere('selesai','>',date('Y-m-d'));
    });
})->select('*',DB::raw('
    (SELECT name from pengelola_pekerjaan WHERE pengelola.id = pengelola_pekerjaan.id_pengelola) as pekerjaan_name,
    (SELECT tingkat from pengelola_pekerjaan WHERE pengelola.id = pengelola_pekerjaan.id_pengelola) as pekerjaan_tingkat,
    (SELECT name from pengelola_pendidikan WHERE pengelola.id = pengelola_pendidikan.id_pengelola) as pendidikan_name,
    (SELECT tingkat from pengelola_pendidikan WHERE pengelola.id = pengelola_pendidikan.id_pengelola) as pendidikan_tingkat
'))->get();

What it does is... I have 3 different table one is pengelola , pengelola_pendidikan that I called in with as pendidikan_tertinggi , pengelola_pekerjaan that I called in with as pekerjaan_aktif and in whereHas as pekerjaan .

and to more understand it here are my three models:

this is pengelola model

class Pengelola extends Model {

    use FilterPaginateOrder, LogsActivity;

    protected $table = 'pengelola';

    protected static $logFillable = true;

    public static $rules = [
        'nik'=>'required',
        'name'=>'required',
        'email' =>  'email'
    ];

    protected $fillable = [
        'nim','nik','name','tempat_lahir','tanggal_lahir','kelamin','agama','status','alamat','hp','email','gambar','darah','tinggi','berat','kontak'
    ];

    protected $filter = [
        'nim','nik','name','tempat_lahir','tanggal_lahir','kelamin','agama','status','alamat','hp','email','darah','tinggi','berat','kontak','created_at','updated_at'
    ];

    public function getNameAttribute($value){
        return !empty($value) ? $value : '-';
    }

    public static function initialize()
    {
        return [
            'nim' => '','nik' => '','name' => '','tempat_lahir' => '','tanggal_lahir' => '','kelamin' => '','agama' => '','status' => '','alamat' => '','hp' => '','email' => '','darah' => '','tinggi' => '','berat' => '','kontak' => ''
        ];
    }

    public function pendidikan(){
        return $this->hasMany('App\PengelolaPendidikan','id_pengelola','id');
    }

    public function pendidikan_tertinggi(){
        return $this->hasOne('App\PengelolaPendidikan','id_pengelola','id')->orderBy('tingkat','desc')->latest();
    }

    public function pekerjaan(){
        return $this->hasMany('App\PengelolaPekerjaan','id_pengelola','id');
    }

    public function pekerjaan_aktif(){
        return $this->hasOne('App\PengelolaPekerjaan','id_pengelola','id')->where('sekarang','1')->orWhere('selesai','>',date('Y-m-d'))->latest();
    }

    public function keluarga(){
        return $this->hasMany('App\PengelolaKeluarga','id_pengelola','id');
    }

    public function anggotacu(){
        return $this->hasMany('App\PengelolaAnggotaCU','id_pengelola','id');
    }

    public function organisasi(){
        return $this->hasMany('App\PengelolaOrganisasi','id_pengelola','id');
    }
}

this is pengelola_pendidikan

class PengelolaPendidikan extends Model {

    use FilterPaginateOrder, LogsActivity;

    protected $table = 'pengelola_pendidikan';

    protected static $logFillable = true;

    protected $fillable = [
        'id_pengelola','name','tingkat','tempat','mulai','selesai','sekarang'
    ];

    protected $filter = [
        'name','tingkat','tempat','mulai','selesai','sekarang','created_at','updated_at'
    ];

    public function getNameAttribute($value){
        return !empty($value) ? $value : '-';
    }

    public static function initialize()
    {
        return [
             'name' => '','tingkat' => '','tempat' => '','mulai' => '','selesai' => '','sekarang' => ''
        ];
    }

}

and here is pengelola_pekerjaan

class PengelolaPekerjaan extends Model {

    use FilterPaginateOrder, LogsActivity;

    protected $table = 'pengelola_pekerjaan';

    protected static $logFillable = true;

    protected $fillable = [
        'id_pengelola','id_tempat','tipe','name','tingkat','mulai','selesai','sekarang'
    ];

    protected $filter = [
        'id_tempat','tipe','name','tingkat','mulai','selesai','sekarang','created_at','updated_at'
    ];

    public function getNameAttribute($value){
        return !empty($value) ? $value : '-';
    }

    public static function initialize()
    {
        return [
            'id_tempat' => 0,'tipe' => '','name' => '','tingkat' => '','mulai' => '','selesai' => '','sekarang' => ''
        ];
    }

    public function pengelola(){
        return $this->belongsTo('App\Pengelola','id_pengelola','id');
    }

    public function lembaga(){
        return $this->belongsTo('App\Lembaga','id_tempat','id')->select(array('id','name'));
    }

    public function cu(){
        return $this->belongsTo('App\Cu','id_tempat','id')->select(array('id','no_ba','name'))->withTrashed();
    }

}

and as you can see in whereHas I am using 2 external variables which are $tipe and $id , so this query is working fine if my $tipe = 1 but when my $tipe is not 1 then it won't return anything.

and then if I change my $table_data query to be this (only remove select at pengelola_pendidikan ) then it will work for any $tipe

$table_data = Pengelola::with('pekerjaan_aktif.cu','pendidikan_tertinggi')
    ->whereHas('pekerjaan', function($query) use ($id,$tipe){
        $query->where('tipe',$tipe)->where('id_tempat',$id)
        ->where(function($q){
            $q->where('sekarang','1')->orWhere('selesai','>',date('Y-m-d'));
        });
    })->select('*',DB::raw('
        (SELECT name from pengelola_pekerjaan WHERE pengelola.id = pengelola_pekerjaan.id_pengelola) as pekerjaan_name,
        (SELECT tingkat from pengelola_pekerjaan WHERE pengelola.id = pengelola_pekerjaan.id_pengelola) as pekerjaan_tingkat
    '))->get();

So what is really happen? and for those who wonder why I need this kind of select, it is because I need to have a column alias that appears at the root of the returned json for my trait FilterPaginateOrder that handles searching, sorting, pagination. and to do that I need to have pekerjaan_name instead of pekerjaan_aktif.name (for example) for sorting purpose to this trait.

trait FilterPaginateOrder {

    protected $operators = [
        'equal_to' => '=',
        'not_equal' => '<>',
        'less_than' => '<',
        'greater_than' => '>',
        'less_than_or_equal_to' => '<=',
        'greater_than_or_equal_to' => '>=',
        'in' => 'IN',
        'not_in' => 'NOT_IN',
        'like' => 'LIKE',
        'between' => 'BETWEEN'
    ];

    public function scopeFilterPaginateOrder($query)
    {
        $request = request();

        $v = Validator::make($request->all(), [
            'column' => 'required|in:'.implode(',', $this->filter),
            'direction' => 'required|in:asc,desc',
            'per_page' => 'required|integer|min:1',
            'search_operator' => 'required|in:'.implode(',', array_keys($this->operators)),
            'search_column' => 'required|in:'.implode(',', $this->filter),
            'search_query_1' => 'max:255',
            'search_query_2' => 'max:255'
        ]);

        if($v->fails()) {

            //for debug
            // dd($v->messages());
        }

        return $query->orderBy($request->column, $request->direction)
            ->where(function($query) use ($request) {
                // check if search query is empty
                if($request->has('search_query_1')) {
                    // determine the type of search_column
                    // check if its related model, eg: customer.id
                    if($this->isRelatedColumn($request)) {
                        list($relation, $relatedColumn) = explode('.', $request->search_column);
                        return $query->whereHas($relation, function($query) use ($relatedColumn, $request) {
                            return $this->buildQuery(
                                $relatedColumn,
                                $request->search_operator,
                                $request,
                                $query
                            );
                        });
                    } else {
                        // regular column
                        return $this->buildQuery(
                            $request->search_column,
                            $request->search_operator,
                            $request,
                            $query
                        );
                    }
                }
            })
            ->paginate($request->per_page);
    }

    protected function isRelatedColumn($request)
    {
        return strpos($request->search_column, '.') !== false;
    }

    protected function buildQuery($column, $operator, $request, $query)
    {
        switch ($operator) {
            case 'equal_to':
            case 'not_equal':
            case 'less_than':
            case 'greater_than':
            case 'less_than_or_equal_to':
            case 'greater_than_or_equal_to':
                $query->where($column, $this->operators[$operator], $request->search_query_1);
                break;
            case 'in':
                $query->whereIn($column, explode(',', $request->search_query_1));
                break;
            case 'not_in':
                $query->whereNotIn($column, explode(',', $request->search_query_1));
                break;
            case 'like':
                $query->where($column, 'like', '%'.$request->search_query_1.'%');
                break;
            case 'between':
                $query->whereBetween($column, [
                    $request->search_query_1,
                    $request->search_query_2
                ]);
                break;
            default:
                throw new Exception('Invalid Search Operator', 1);
                break;
        }

        return $query;
    }
}

So what I need is a solution for having a root field that created from select as from relation table column ( pendidikan_name instead of pendidikan_tertinggi.name and also cu_name instead of pekerjaan_aktif.cu.name at my json return) for it to work with my FilterPaginateOrder trait.

To me this is more about joins and a SQL issue than Laravel Eloquent's problem.

Try to debug with DB::connection()->enableQueryLog(); at the begining of the code, and after the call to you model, you can use DB::getQueryLog() So this way you will be able to check the generated query and fix whatever is causing the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM