Defining query areas within the Laravel model

Little background ...

I have two models in my application that are "local". I could very easily write a query in the repository to return what I need, however I am sure that this can be done much better with Laravel Scopes and Traits, etc. (Maybe I'm wrong).

So, I came up with the following solution:

An example of an abstract model

abstract class AbstractModel extends Model implements SomeOtherStuff{
    public function scopeNearby(Builder $query){
        return $query->selectRaw('
                (
                    6373000 * acos(
                        cos( radians( ' . $this->location->latitude . ' ) )
    
                        * cos( radians( X(' . $this->location->table . '.location) ) )
    
                        * cos( radians( Y(' . $this->location->table . '.location) ) - radians( ' . $this->location->longitude . ' ) )
    
                        + sin( radians( ' . $this->location->latitude . ' ) )
                        * sin( radians( X(' . $this->location->table . '.location) ) )
                    )
                ) AS distance
           ')
            // I wanted to use ->with('location') below instead of ->join() but it didn’t work
            ->join($this->location->table, $this->location->primaryKey, '=', $this->primaryKey);
    }

    // All other Abstract stuff here
}

User Model Example

class User extends AbstractModel implements SomeOtherStuff
{
    
    /**
     * Get the location of the user.
    
     */
    public function location()
    {
    
        return $this->hasOne(‘App\Models\User\Location', 'user_id');
    
    }

    // All other model stuff here
}

User Controller Example

class UserController extends AbstractController{
    /**
     * Return the nearby users.
     *
     * @return \Illuminate\Http\JsonResponse
     */public function nearby()
    {
        $users = $this->shield->user()->nearby()->toSql();

        // Print out the query to ensure it is structured correctly
        echo $users;
    
    }
}

My problems

The above solution works, however, it is very wrong (in my opinion)! The area nearby()should be available only for models that are "local." Naturally, I thought the best solution would be to implement Trait as follows:

trait Locatable
{
    /**
        
     * Scope a query to include the distance from the current model.
        
     *
     * @param   \Illuminate\Database\Eloquent\Builder $query
     * @return  \Illuminate\Database\Eloquent\Builder
        
     */public function scopeNearby(Builder $query){
        // Same as above implementation
    }
    
}

, , , protected Trait...

()

, , . :

  • , , , - ?
  • , ->with('location') ? ? , , ...
+4
1

trait Locatable {

  /**
   * Scope a query to include the distance from the current model.
   *
   * @param   \Illuminate\Database\Eloquent\Builder $query
   * @return \Illuminate\Database\Eloquent\Builder
   */
  public function scopeNearby($query)
  {
    if(!$this->location) {
      return $query;
    }

    return $query->whereHas('location',
      function($query) {
        $query->selectRaw('
                    //Your query for distance (Use the getTable() function wherever required...)
                  ) AS distance
                ')
              ->having('distance', '<', 25);
      }
    );
  }
}

.

  • . whereHas() .

  • , , WHERE EXISTS(), . ... .......

( , ... )

dd($user->with('locations')->toSql());

, ...:)

+1

Source: https://habr.com/ru/post/1663330/


All Articles