Laravel SQL Query. Help me - mysql

I have a table name "Offers" with 3 (public, request, private ) types of data. Now I want to show directly to the user end public and request offers. and private offers not be shown but when admin will add user_id and offer_id in a new table (offer_access) then the private offer should be available to user end for only these users.
$offer = Offer::where('status', 'public')->orWhere('status', 'request')->latest()->get();
I wrote this one and getting public and private offers for user end. Now I want to show private offers to a user when it available on "OfferAccess" table.
So now, How can I write the SQL query for that?

You can try blow:
$offer = Offer::whereIn('status', ['public', 'request'])
->orWhere(function($query) {
$query->where('status', 'private')
->whereHas('OfferAccess', function($qry) {
$qry->where('user_id', auth()->user()->id);
});
})->get();
If you need only the latest results can use ->latest()->get() instead of only ->get().
Also if you need to get it for any other user than the current logged in user, then you need to pass user_id to closure function. so you need to use updated orWhere like as:
->orWhere(function($query) use ($user_id) {
$query->where('status', 'private')
->whereHas('OfferAccess', function($qry) use ($user_id) {
$qry->where('user_id', $user_id);
});
})
It should give you the desired results.

Related

Laravel - Query builder with subquery

So i have a pivot table like the following :
match id
player id
score
And i want to query to get the number of wins/losses for a given user id. (wins based on user id with the highest score for a game)
In sql i would write this like :
SELECT user_id, score
from match_user matchu1
where score = (select max(score) from match_user matchu2 where matchu1.match_id = matchu2.match_id)
How would i express this query in laravel, or is there a better method of doing this that i am missing ?
There are multiple ways to achieve this. The easiest and cleaniest way to me is defining
a relationship with pivot.
class Match extends Model
{
public function players()
{
return $this->belongsToMany(User::class, 'match_user')->withPivot('score');
}
public function winner()
{
return $this->players
->sortByDesc(function ($player) {
return $player->pivot->score;
})
->first();
}
}
Then you can simply get the winner by saying:
$match->winner();
This is to answer your true intention of asking this question, which is to get the number of wins for a single user, as you commented on my answer. The following the the best solution that I can think of for now:
class Match extends Model
{
public function scopeWonBy($query, User $user)
{
return $query->selectRaw('matches.id, max(match_user.score) AS max_store, match_user.player_id AS player_id')
->join('match_user', 'matches.id', '=', 'match_user.match_id')
->groupBy('matches.id')
->having('player_id', $user->id);
}
}
Later on, you can say:
$matches = Match::wonBy($user);
$count = Match::wonBy($user)->count();
I'm not going to write your query for you as I don't want to provide an untested solution but the following code example should give you a good idea of how to implement subqueries with the query builder.
$q->where('price_date', function($q) use ($start_date)
{
$q->from('benchmarks_table_name')
->selectRaw('min(price_date)')
->where('price_date', '>=', $start_date)
->where('ticker', $this->ticker);
});

Laravel Join Query returning empty column

I have a member table with some entries. Each member can create a user account in laravel's users table.
They each have a field called "person_id" and that's how the connection is made.
I have a search that returns a list with all of them. I have a checkbox "Search only registered" that means it returns only members that have users account, otherwise if the check doesn't check, return a mix with all of them.
The thing is, no matter if the checkbox is checked or not, the person_id must be pulled for each one.
if($reg == 'on') {
$Members = $Members->rightJoin('users', 'users.person_id', '=', 'members.person_id');
}
else {
$Members = $Members->leftJoin('users', 'users.person_id', '=', 'members.person_id');
}
I tried with leftJoin but person_id comes empty
at first look if you are using Eloquent i can tell you are missing the "->get();" at the end of each query.
Hope this helps.
Use relation in member model:
public function user()
{
return $this->belongsTo('App\User', 'person_id', 'person_id' );
}
public function getMemberWithUser()
{
return $this->select('*')->with('user')->get()->toArray();
}
and use (new Member)->getMemberWithUser(); in controller. That will return you member detail with user.
Neverming guys I found it out.
Most members don't have yet a user account, only 2. And the select wasn't specifying which table to take the person_id from. And with most members missing an user account, it was trying to get it from users.
I did this:
$Participants = Member::select(
'members.first_name',
'members.last_name',
'members.person_id',
'members.email'
);

Use a column value in an other table with laravel query builder

I have two table witch named users & Inbox
In the Inbox table I have a column named sender_id that have the user_id of the sender
I want to show this message in the view. I need a query to get the sender_id from the inbox table and use that to select a certain user from the users table
I need to do this with all messages and all users.
Laravel is basicly straith foward when you use eloquent. You can always customise it.
First, almost all the time, I create a model and a migration at the same time using this : php artisan make:model Something --migration
I know you already make some models and/or migrations, but I'll go step by step to help you understand it.
So, in your case, it'll be php artisan make:model User --migration and php artisan make:model Inbox --migration. Doing this, you get two model named User and Inbox and two migration named date_create_users_table.php and date_create_inboxs_table.php. Maybe you already did the default user table with php artisan make:auth. If it's the case, don't remake one.
I'm not sure about how laravel will name the Inbox model migration... Since, I think, Laravel 5.3, the plurialisation changed and don't always just add an "S" at the end.
Then, now you got your models and migrations, let's add some line into your migration files. Since you want to do a one to many relationship. You don't need to touch the user one. Only the Inbox migration. Each Inbox is related to one User and Users can have many Inboxs. Add something like this in your migration:
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
all other columns...
});
}
There, you can change the column's name if you need to have a sender, a recipient, etc... Do this instead :
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('sender_id');
$table->foreign('sender_id')->references('id')->on('users');
$table->integer('recipient_id');
$table->foreign('recipient_id')->references('id')->on('users');
all other columns...
});
}
What we just did, it's creating the Foreign key that Laravel will use to build the query. There is one last part before the fun one. We need to create the relation in our Model. Begin with the user one:
App/User.php
public function inboxs() {
return $this->hasMany(Inbox::class);
}
And now into the App/Inbox.php model:
public function user() {
return $this->belongsTo(User::class);
}
If you need to have a Sender/Recipient/etc... go this way instead:
public function sender() {
return $this->belongsTo(User::class);
}
public function recipient() {
return $this->belongsTo(User::class);
}
Note that each of your function need to be writen in the same way it's into your migration. sender_id need a relation named sender().
Now, that our relations are done, we can simply call everything using eloquent.
$inboxs = Inbox::with('sender')->get();
This will return an array of all your Inbox into the inboxs table. You can access the sender this way: $inboxs[0]->sender();
You need the id, do this: $sender_id = $inboxs[0]->sender_id;
The sender name : $sender_name = $inboxs[0]->sender->name;
If you want to get one Inbox and you have the id, just do this $inbox = Inbox::with('sender')->find($id);
This way you don't get an array, only one result and can access the sender directly using $sender_name = $inbox->sender->name; instead of having to add [0] or using a foreach loop.
You can get all messages sended by a user using something like this:
$inboxs = Inbox::where('sender_id', $sender_id)->get();
Finally, you can pass your data to the view using:
return view('path.to.view')->with('inbox',$inbox);
Into the view you do this to show the sender's name:
//If view.blade.php
{{$inbox['sender']['name']}} //work a 100%
{{$inbox->sender->name}} //I'm not sure about this one
//If not using blade
<?php echo $inbox['sender']['name']; ?>
There is a lot of thing you can do using Eloquent and you can add as much condition you want. The only thing I suggest you to really do if you want to use Eloquent, be aware about the n+1 problem. There is a link where I explain it. Look for the EDIT section of my answer.
If you need some documentation:
Laravel 5.3 Relationships
Laravel 5.3 Migrations
Laravel 5.3 Eloquent
I think you should update your code like:
$user_messages = DB::table('messages')
->select('messages.id as msgId','messages.message as message','users.id as userId','users.user_name as user_name')
->join('messages','messages.user_id','=','users.id')
->where('messages.user_id',$user_id)
->get();
return view("view.path")
->with('messages',$user_messages);
Hope this work for you!
In Model :
namespace App;
use Illuminate\Database\Eloquent\Model;
class Messages extends Model
{
protected $table = 'table_name';
public function sender()
{
return $this->belongsTo('App\User', 'sender_id', 'id');
}
}
In Controller :
public function functionName($user_id){
$messages = Messages::where('sender_id', $user_id)->get();
return view("view.path")
->with('messages',$messages);
}
In view, you can access seder details like this $message->sender->name for name for id $message->sender->id

Laravel Request ip address for login users

i made login_history table with fields user_id foreign for users table , ip_address and created_at i need to very time to login user save it in login_history table now i'm using
Listeners or last_login users using laravel 5.2 with this code
public function handle(Login $event)
{
$user = \Auth::user();
$data = new LoginHistory();
$event->user->$data->user_id = $user->id;
$event->user->$data->created_at = Carbon::now();
$event->user->$data->ip_address = Request::getClientIp();
$event->user->$data->save();
}
**but this not i want
please any one can help for changing this code i have model created
class LoginHistory extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
and i get this error
Cannot use Illuminate\Foundation\Auth\User as User because the name is
already in use
thanks
Considering you have a Model for the LoginHistory pivot table. In any controller method, you can use the following code.
$user = auth()->user();
LoginHistory::create(['user_id'=>$user->id,'ip_address' => Request::getClientIp(), 'created_at'=>Carbon::now()]);
And if you don't have the model, you can use the DB facade to do the same.
You can create a Middleware in laravel in handle method you can insert the data
$event->user->$data->ip_address = \Request::ip(),

Querying Relationship Existence using multiple MySQL database connections in Laravel 5.2

I am dealing with the following situation: I have two models, an Employee with id and name fields and a Telephone with id, employee_id and flag fields. There is also an one-to-many relationship between these two models, that is an employee may have many telephones and a telephone may belong to a single employee.
class Employee extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
}
class Telephone extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
The Employee model references a table employees that exists in database schema named mydb1, while the Telephone model is related to a telephones table that exists in a different database schema named mydb2.
What I want is to fetch only the employees with at least one telephone of a specific flag eager loaded, using Eloquent and (if possible) not the query builder
What I tried so far without success is:
1) use the whereHas method in the Controller
$employees = Employee::whereHas('telephones', function ($query) {
$query->where('flag', 1); //Fetch only the employees with telephones of flag=1
})->with([
'telephones' => function ($query) { //Eager load only the telephones of flag=1
$query->where('flag', 1);
}
])->get();
What I try to do here is first to retrieve only the employees that have telephones with flag=1 and second to eager load only these telephones, but I get the following query exception because of the different db connections used:
Base table or view not found: Table mydb1.telephones doesn't exist (this is true, telephones exists in mydb2)
2) Eager load with constrains in the Controller
$employees = Employee::with([
'telephones' => function ($query) {
$query->where('flag', 1);
},
])->get();
This method eager loads the telephones with flag=1, but it returns all the employee instances, which is not what I really want. I would like to have a collection of only the employee models that have telephones with flag = 1, excluding the models with telephones = []
Taking into account this post, this post and #Giedrius Kiršys answer below, I finally came up with a solution that fits my needs, using the following steps:
create a method that returns a Relation object in the Model
eager load this new relationship in the Controller
filtered out the telephones of flag != 1 using a query scope in the Model
In Employee model
/**
* This is the new relationship
*
*/
public function flaggedTelephones()
{
return $this->telephones()
->where('flag', 1); //this will return a relation object
}
/**
* This is the query scope that filters the flagged telephones
*
* This is the raw query performed:
* select * from mydb1.employees where exists (
* select * from mydb2.telephones
* where telephones.employee_id = employee.id
* and flag = 1);
*
*/
public function scopeHasFlaggedTelephones($query, $id)
{
return $query->whereExists(function ($query) use ($id) {
$query->select(DB::raw('*'))
->from('mydb2.telephones')
->where('telephones.flag', $flag)
->whereRaw('telephones.employee_id = employees.id');
});
}
In the Controller
Now I may use this elegant syntax a’la Eloquent
$employees = Employee::with('flaggedTelephones')->hasFlaggedTelephones()->get();
which reads like "Fetch all the employees with flagged telephones eager loaded, and then take only the employees that have at least one flagged telephone"
EDIT:
After dealing with the Laravel framework for a while (current version used 5.2.39), I figured, that in fact, whereHas() clauses do work in case of the relationship model exists in a different database using the from() method, as it is depicted below:
$employees = Employee::whereHas('telephones', function($query){
$query->from('mydb2.telephones')->where('flag', 1);
})->get();
#Rob Contreras credits for stating the use of the from() method, however it looks like the method requires to take both the database and the table as an argument.
Not sure if this will work but you can use the from method to specify your database connection within the closure:
$employees = Employee::whereHas('telephones', function($query){
$query->from('mydb2')->where('flag', 1);
})->get();
Hope this helps
Dirty solution:
Use whereExists and scope for better readability.
In Your Employee model put:
public function scopeFlags($query, $flag)
{
$query->whereExists(function ($q) use ($flag) {
$q->select(\DB::raw(1))
->from('mydb2.telephones')
->where('telephones.flag', $flag)
->whereRaw('telephones.employee_id = employees.id');
});
}
Then modify your query like so:
$employees = Employee::flags(1)->get();