Laravel Eloquent how to override the base query? - laravel

I have 2 models shared a same table.
Table name: books, I separate normal book & novel by an attribute called type
Book model
class Book extends \Illuminate\Database\Eloquent\Model
{
protected $table = 'books';
}
Novel model
class Novel extends Book
{
protected $table = 'books';
// Is such a method available?
protected function someMethodToOverride()
{
$this->where('type', 'novel');
}
}
What I want to achieve here is
$results = Novel::where('title', 'LIKE', '%' . $title . '%')->get();
from this query, I want it to pre-set the condition
where('type', 'novel')
Is there any function I can override to achieve this?

use Anonymous Global Scopes and add this boot method in Novel Model
protected static function boot()
{
parent::boot();
static::addGlobalScope('type', function (\Illuminate\Database\Eloquent\Builder $builder) {
$builder->where('type', 'novel');
});
}
now it will automatically add query
$results = Novel::where('title', 'LIKE', '%' . $title . '%')->get();
now If you would like to remove a global scope for a given query, you
may use the withoutGlobalScope method.
Novel::withoutGlobalScope('type')->get();
for more information read this article

In Model You can use scope:
public function scopeOfType($query, $type)
{
return $query->where('type', $type);
}
And pass the parameters when calling the scope:
Model::ofType('novel')
->where('title', 'LIKE', '%' . $title . '%')
->get();
refer link Laravel Scope

Related

issue in laravel relationship search data

I want to search for usernames from the user's table.
I have used the Laravel relationship(eloquent). I don't search for usernames from users' tables. My code is Below and here I Explain the relationship with All Tablets
I have a query write inside the group controller
public function getGroupsData(Request $request){
$group = Group::with(['memberscount', 'getusername'])->where('groupName', "like", "%" . $request->searchText . "%")
->whereHas('getusername.user', function ($query) use ($request) {
return $query->where('name', 'like', '%'. $request->searchText . '%');
})
->get();
}
memberscount and getusername relationship write-in group model my group model is below
class Group extends Model
{
public function memberscount(){
return $this->hasMany('App\Models\Members', 'group_id', 'id')->where('memberStatus', 'Joined');
}
public function getusername(){
return $this->hasOne('App\Models\Members', 'group_id', 'id')->where('isOwner', 0);
}
}
And user's table relationship in members models. members model is below
class Members extends Model
{
public function user(){
return $this->hasOne('App\User', 'id', 'user_id');
}
/**get group name */
public function group(){
return $this->hasOne('App\Models\Group', 'id', 'group_id');
}
}
I have search user's data this(user) relationship. But I can't search data in a multilevel relationship.
OK, I'm the first step is to rename name relationships in class Group
I think it was more logical names
memberscount -> members
getusername -> owner
And the second step is to search. I write like this:
$group = Group::whereHas('owner', function ($query) use ($request) {
return $query->where('groupName', 'like', '%'. $request->searchText . '%');
})->get();
or more effective and clear code we can save in scope us query like that:
$group = Group::whereHas('owner', function ($query) use ($request) {
return $query->haveGroupName($request->searchText);
})->get();
In the Group model class write code like that:
/**
* Scope a query to only have groupName.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #param string $param
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeHaveGroupName($query, $param)
{
return $query->where('groupName', 'like', '%' . $param . '%');
}

Laravel cannot use where on a table connected using belongsToMangy

I have the following model file which has a belongsToMany relation with the portal_users table.
class Role extends Model
{
use HasFactory;
protected $table = 'portal_roles';
protected $hidden = array('created_at', 'updated_at','deleted_at');
public function users()
{
return $this->belongsToMany(User::class, 'portal_user_roles');
}
}
I am trying to find details of all the users that fits into a particular role using the following query
$recordobj = Role::find(15)->users->where('firstname', 'like', '%' . $searchstring . '%')->get()->keyBy('id');
It is returning empty resultset even though there are users who is having the role id as 15. Can anyone please tell me what is the problem here?
Change users to users():
$recordobj = Role::find(15)->users()->where('firstname', 'like', '%' . $searchstring . '%')->get()->keyBy('id');

Or with And Statement in Eloquent livewire

I am using Laravel Livewire dataTables and while searching I am getting an error.
Object of class Illuminate\Database\Eloquent\Builder could not be
converted to string
my method for searching is
public static function search($QUERY)
{
return empty($QUERY) ? static::QUERY()
: static::WHERE(function ($QUERY) {
$QUERY->WHERE('name', 'like', '%' . $QUERY . '%')
->orWhere('email', 'like', '%' . $QUERY . '%');
});
}
Livewire render method
public function render()
{
//$this->roles = ROLE::WHERE('company_id', SESSION('company_id'))->paginate(5);
return VIEW('livewire.users', [
'users' => USER::search($this->search)
->WITH(['role', 'company'])
->WHERE('company_id', SESSION('company_id'))
->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')
->paginate($this->perPage),
]);
}
Instead of having the actual method search(), you can make a scope, which will be rendered the same, but will also have some Laravel-magic helping you.
Replace your search() method on your User model with this scopeSearch() method. You do not change the query where its being used.
/**
* Scope a query to search for users name and email
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeSearch(Builder $query, string $search)
{
return $query->where('name', 'like', '%'.$search.'%')
->orWhere('email', 'like', '%'.$search.'%');
}
And import that Builder class, by adding the following line to the top of your User model class,
use Illuminate\Database\Eloquent\Builder;
The trick here is the scope prefix, with a capital S in "search". See the official documentation for more details.

Getting specific value when using eloquent from Laravel

I am using Laravel 5.2 and I need to get specific values from the database with a leftjoin. The code I am using is as follow:
public function commentList(Request $request)
{
$inputs = $request->all();
$commentList = Comment::select(
'projects_comments.id as comment_id',
'u.name as user_name',
'projects_comments.comment as comment',
'projects_comments.created_at as created_at'
);
$commentList->leftjoin('users AS u', 'projects_comments.user_id', '=', 'u.id');
if (!empty($inputs['project_ids'])) {
$commentList->where(function ($query) use ($inputs) {
foreach ($inputs['project_ids'] as $i) {
$query->orWhere('projects_comments.project_id', $i);
}
});
};
$data = $commentList->get();
return $data;
}
It works fine but I would like to know if there is a better way to do this using eloquent but I can't really understand how to write this for eloquent to work. I need to get all the comments from an array of project ids.
I have the following model for Comment:
class Comment extends Model
{
protected $table = 'projects_comments';
public $timestamps = true;
protected $guarded = ['id'];
public function project()
{
return $this->belongsTo('App\Project', 'project_id');
}
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
}
I assume what you want is to get Comments (with their users) that belongs to specific Projects provided by the user as an array of IDS
Comment::whereIn('project_id', $inputs['project_ids'])->with('user')->get();
And if you only want the id and name of the user associated with the comment, pass the fields to the with function like so
Comment::whereIn('project_id', $inputs['project_ids'])
->with('user:id,name')->get();

Get onlyTrashed() does not exist in query builder

I am trying to get trashed rows from table messages:
public function trash() {
return $this->onlyTrashed()
->where('user_id', '=', $this->_u)
->orWhere('receiver', '=', $this->_u)
->orderBy('deleted_at', 'desc')->get();
}
I get this error:
Method Illuminate\Database\Query\Builder::onlyTrashed does not exist.
I checked up Builder and SoftDeletes files for onlyTrashed method and it does not exist, how can I look up to trashed messages from message table?
The only way I think about is to create method that doesn't return messages where delete_at is not null and for trashed to return only those where it is not null. But I am still wondering why this doesn't work since it is in documentation at this url:
https://laravel.com/docs/5.6/eloquent#soft-deleting
MORE INFO
Yes it is inside model and yes I added use SoftDeletes:
use Illuminate\Database\Eloquent\SoftDeletes; - on top
use SoftDeletes; after opening the class
Let me paste entire model here:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
class Messages extends Model
{
use SoftDeletes;
protected $fillable = [
'user_id', 'subject', 'text', 'receiver'
];
public $_u;
protected $dates = ['deleted_at'];
public function __construct() {
$this->_u = auth()->user()->user_id; //or some id as string
}
public function trash() {
return $this->onlyTrashed()
->where('user_id', '=', $this->_u)
->orWhere('receiver', '=', $this->_u)
->orderBy('deleted_at', 'desc')->get();
}
public static function trashed() {
return self::onlyTrashed();
}
}
And controller has:
public function __construct() {
$this->middleware('auth');
}
public function index($field = 'trash') {
if ($field !== "new") {
$messages = (new Msg)->$field();
$user = auth()->user();
return view('pages.messages', compact('messages', 'user'));
}
return view('pages.messages.new', compact('messages', 'user'));
}
I tried calling static as well and I tried doing it from tinker and still keep getting:
onlyTrashed() doesn not exist
You have to call the parent constructor:
public function __construct() {
parent::__construct();
$this->_u = auth()->user()->user_id;
}
I think what you want is to define the trash method static:
public static function trash() {
return self::onlyTrashed()
->where('user_id', '=', $this->_u)
->orWhere('receiver', '=', $this->_u)
->orderBy('deleted_at', 'desc')->get();
}
Then call this function by:
$messages = Messages::trash();
This should work
# YourModelController.php
/**
* Show only trashed
*
* #return \Illuminate\Http\Response
*/
public function trashed()
{
...
$trashed = YourModel::onlyTrashed()->get();
...
}
I have researched a little further and I got this:
From https://laravel.com/api/5.6/Illuminate/Database/Eloquent.html
I should have
SoftDeletesTrait
but I have
SoftDeletes
. In softdeletestrait we have onlyTrashed method but in SoftDeletes we do not.
So I copied that method from this page:
https://github.com/laravel/framework/blob/7d9e7068c49f945385673014d4cba4de28accd5e/src/Illuminate/Database/Eloquent/SoftDeletingTrait.php#L119
And added it to SoftDeletes class, now it works like it should. I haven't find why it doesn't exist inside SoftDeletes class so if anyone find out let us know!

Resources