Please How to convert this raw sql query to laravel eloquent or query builder?

Issue

Hello Laravel Developers, Good day. Please how can I convert a raw sql query to laravel query builder or eloquent ORM.

I have the following models:

relationships

Model Server

  public function users()
    {
        return $this->belongsToMany(User::class,'server_users')->withPivot('spam','inbox');;
    }

    public function users_cancellation()
    {
        return $this->belongsToMany(User::class,'server_user_cancellations')->withPivot('spam','inbox');;
    }

Model User

   public function servers(): BelongsToMany
    {
        return $this->belongsToMany(Server::class, 'server_users');
    }

    public function servers_cancellation(): BelongsToMany
    {
        return $this->belongsToMany(Server::class, 'server_user_cancellations');
    }

tables

User

   $table->id();
            $table->string('full_name');
            $table->string('username')->unique();
            $table->string('password');
            $table->string('type');
            $table->boolean('is_active')->default(true);
            $table->rememberToken();
            $table->timestamps();
            $table->softDeletes();

Server

    Schema::create('servers', function (Blueprint $table) {
            $table->id();
            $table->string('name')->default('SM');
            $table->ipAddress('ip')->unique();
            $table->string('username')->default('root');
            $table->boolean('is_active')->default(true);
            $table->softDeletes();
            $table->timestamps();
        });

Server_user_cancellations

   Schema::create('server_user_cancellations', function (Blueprint $table) {
            $table->id();
            $table->foreignIdFor(Server::class)->constrained()->cascadeOnDelete()->cascadeOnUpdate();
            $table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
            $table->boolean('spam')->nullable();
            $table->boolean('inbox')->nullable();
            $table->timestamps();
        });

Server_users

  Schema::create('server_users', function (Blueprint $table) {
            $table->id();
            $table->foreignIdFor(Server::class)->constrained()->cascadeOnDelete()->cascadeOnUpdate();
            $table->foreignIdFor(User::class)->constrained()->cascadeOnUpdate()->cascadeOnDelete();
            $table->boolean('spam')->nullable();
            $table->boolean('inbox')->nullable();
            $table->timestamps();
        });

i want to convert this raw sql query to laravel eloquent or query builder?

if ($request->wantsJson()) {
  $servers = DB::select('
  SELECT 
    s.name,
    s.id,
    s.ip,
    (SELECT count(id) 
      FROM server_user_cancellations 
      where server_id = s.id and user_id=?
    ) as exist
  FROM servers s
  WHERE s.id IN
    (SELECT  distinct server_id from server_users  where user_id=?)
    AND s.is_active=true
    AND s.is_installed=true
    AND s."deleted_at" is null', 
  [auth()->id(), auth()->id()]
);

Solution

from query i assume Server can belong to many Users and User can have many Servers, and both has many ServerUserCancellation, so you need servers for current user with cancellations existence flag

first define relations that fits your database schema

// Server model
public function cancellations(){
  return $this->hasMany(ServerUserCancellation::class);
}

public function users(){
  return $this->belongsToMany(User::class);
}

// User model
public function servers(){
  return $this->belongsToMany(Server::class);
}

now you can count cancellations and filter servers which has current user according to users relation

$baseFilters = [
  'is_active' => true,
  'is_installed' => true,  
];
$result = Server::where($basicFilters)
  ->whereNull('deleted_at')
  ->whereHas('users', function($query){
      $query->where('user_id', auth()->id());
    })
  ->withCount(['cancellations as exists' => function($query){
      $query->where('user_id', auth()->id();
    }])
  ->select(['id', 'ip', 'name'])
  ->get();

//result strucure will be looking like this
array(
  [
    'id': 1,
    'ip': '127.0.0.1',
    'name': 'server 1 name',
    'exists': 0  
  ], 
  ...
) 

to make controller cleaner there is mechanism of soft deleting to skip whereNull('deleted_at') for each Server query and scopes to make code easy to read

// Server model
class Server extends Model {
  use SoftDeletes;

  public function scopeActive($query){
    return $query->where('is_active', true);
  }

  public function scopeInstalled($query){
    return $query->where('is_installed', true);
  }

  // ... other model code
}

and code will look like this

$result = Server::active()
  ->installed()
  ->whereHas('users', function($query){
      $query->where('user_id', auth()->id());
    })
  ->withCount(['cancellations as exists' => function($query){
      $query->where('user_id', auth()->id();
    }])
  ->select(['id', 'ip', 'name'])
  ->get();

Answered By – Ol D. Castor

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published