Laravel + Eloquent ORM: HasManyThrough OrderBy TableC.column2 - php

Table A = Inventory | Table B = ItemAssociation | Table C = ItemValue
I have Table A, B and C. A and B have a one-to-one relationship, B and C have a one to one relationship. I'm currently using the HasManyThrough relationship to arrive at this:
public function item(){
return $this->hasManyThrough('App\ItemValue','App\ItemAssociation','id','id');
}
And in my controller:
public function orm(){
$inventory = Inventory::getAssocBySteamID(76561198124900864)->get();
$i = 0;
foreach($inventory as $inv){
$this->data[$i] = $inv->item()->get();
$i++;
}
return $this->data;
}
Where Inventory::getAssocBySteamID:
public static function getAssocBySteamID($id){
return SELF::where('steamid64','=',$id);
}
This returns all the data I need, however, I need to order this by a column in Table C, the ItemValue model.
Any help would be greatly appreciated.

You can add ->orderBy('TableName', 'desc') to the getAssocBySteamID function.
Or to the query in the Orm() function before the ->get()
Also for Where clauses in Eloquent's QB you don't need the "="sign. You can just do where('steamid',$id)

Do not use static function use scopes. Try using join query like this:
// Inventory model method
public function scopeAssocBySteamID($query, $id) {
$query->where('steamid64', $id)
->join('ItemValue'. 'ItemValue.id', '=', 'Inventory.ItemValue_id')
->select('Inventory.*')
->orderBy('ItemValue.item_price')
}
And then:
public function orm(){
$inventory = Inventory::assocBySteamID(76561198124900864)->get();
$i = 0;
foreach($inventory as $inv){
$this->data[$i] = $inv->item()->get();
$i++;
}
return $this->data;
}
Check all table and field names befor testing this example.

Related

Order data by pivot table when try to use With

I have tables Polfzms <- Genes
Polfzm model have next relation
public function gene()
{
return $this->belongsTo('App\Gene');
}
I need get all data from Polfzms table with data from Genes table and order it by name from pivot table (Genes). I try next
$data = Polfzm::with([
'gene' => function ($query) {
$query->orderBy('name', 'asc');
},
])->get();
but it not order data by name. How can I do it?
You could try to set this in the relationship definition:
Polfzm.php
public function gene()
{
return $this->belongsTo('App\Gene')->orderBy('name', 'asc');
}
Then in your controller:
$data = Polfzm::with('gene')->get();
If I understand correctly, you could use a collection sortBy helper for this one.
An example could be:
$data = Polfzm::with('gene')
->get()
->sortBy(function ($polfzm) {
return $polfzm->gene->name;
});

Joining 3 tables in Laravel

I want to join this 3 tables.
delegations
delegations_id
delegation
delegates
delegates_id
delegatesname
delegations_id
meals
delegates_id
$meals = Meal::join('delegates', 'delegates.delegates_id', '=', 'meals.delegates_id')
->join('delegates', 'delegates.delegations_id', '=', 'delegates.delegations_id')
->get();
write following code in controller
use DB;
write following query inside of controller function
$meals=DB::select("SELECT delegations .*, delegates .*, meals.*
FROM delegations
JOIN delegates
ON delegates.delegations_id = delegations.delegations_id
JOIN meals
ON meals.delegates_id = delegates.delegates_id");
Why would you want to do it "manually" if your using laravel? check on this reference eloquent-relationship
in that case just define in models (these are concept examples, I cant be sure about your project structure):
Meal
function delegate(){
$this->belongsTo(Delegate::class);
}
Delegate
function delegation(){
$this->belongsTo(Delegate::class);
}
function meal(){
$this->hasOne(Meal::class);
}
Delegation
function delegates(){
$this->hasMany(Delegate::class);
}
and then you could just do:
$meals = Meal::all();
foreach ($meals as $meal){
$delegates = $meal->delegate;
$delegation = $mealt->delegate->delegation;
}
you can use it on the controller o on blades and then you'll have all the info you need for instance $delegate->name, $delegation->id an so on
You can do it by two ways:
1.- Raw querys
use DB;
public static function getRaw_data(){
return DB::select("SELECT d1.*, d2.*, m.*
FROM delegations d1, delegates d2, meals m
WHERE d1.delegations_id = d2.delegations_id AND d2.delegates_id = m.delegates_id );
}
2.-
use DB;
public static function getRaw_data(){
return DB::table('delegations')
->join('delegates','delegations.delegations_id','=','delegates.delegations_id')
->join('meals','delegates.delegates_id','=','meals.delegates_id')
->select('delegations.*','delegates.*','meals.*')
->get();
}

Relations with 4 tables [Laravel 5]

I have 4 tables:
projects: id, text
comments: id, text
comment_project: project_id, comment_id
project_group: project_id, user_id
My goal is to take all commets and user details for some project.
Currently I am able to get all comments for projects like this:
class Project extends Model {
public function comments(){
return $this->belongsToMany('App\Comment','comment_project');
}
}
and in controller I do like this:
$comments = Project::find(1)->comments()->get();
return $comments;
Any idea how to take only comments and user details for selected project if project_id and user_id exists in project_group table?
You'll need to set another relation method for project_group in your Model, then you should be able to get this like so:
$comments = Project::with(['comments','project_group'])
->whereHas('project_group',function($q){
$q->whereNotNull('user_id');
$q->whereNotNull('project_id');
});
dd($comments);
Model:
class Project extends Model {
public function comments(){
return $this->hasMany('App\Comment','comment_project');
}
public function project_group(){
return $this->hasMany('App\project_group','comment_project'); // < make sure this is the name of your model!
}
}
Try this:
$comments = Project::whereHas('groups',function($q){
$q->where('project_id',1);
})->whereHas('comments', function($q){
$q->where('user_id',Auth::id())->where('project_id',1);
})
->get();
return $comments;
Here is how I do this, if anyone has better idea pls comment...
Both methods are belongToMany()
$userCondition = function($q){
$q->where('user_id',Auth::id())->where('project_id',1);
};
$commentsCondition = function($q){
$q->where('project_id',1);
};
$comments = Project::with(['comments' => $commentsCondition,'groups' => $userCondition])
->whereHas('groups', $userCondition)
->whereHas('comments', $commentsCondition)
->get();
return $comments;

Laravel count related data

I have in my database:
Campaigns
hasMany Tasks
hasMany Links
hasMany LinkClicks
If I query
Campaign::find(1)->task->count();
It returns the correct number of tasks asigned to that campaign.
But how can I count link clicks from Campaign id?
Campaign Model:
public function task(){
return $this->hasMany('Task','campaign_id');
}
Task Model:
public function campaign(){
return $this->belongsTo('Campaign','campaign_id');
}
public function links(){
return $this->hasMany('Link','task_id');
}
Link Model:
public function task(){
return $this->belongsTo('Task','task_id');
}
public function clicks(){
return $this->hasMany('LinkClick', 'link_id');
}
public function user(){
return $this->belongsTo('User','user_id');
}
LinkClick Model:
public function link(){
return $this->belongsTo('Link','link_id');
}
So, I want to count linkClicks only for links under specific Campaign, no matter which Task or Link, ofcourse that task and link needs to be under specified Campaign.
Use hasManyThrough for the links:
// Campaign model
public function links()
{
return $this->hasManyThrough('Link', 'Task');
}
// then you can fetch the count either querying db:
$campaign->links()->count(); // SELECT COUNT(*) ...
// returns STRING '25'
// or from the collection of already loaded relation:
$campaign->links->count(); // counts collection items
// returns INT 25
This is not going to work further, for the LinkClicks, but there's easy way yuou can achieve that too:
// This is another way for the above:
$campaign = Campaign::with('tasks.links')->find($someId);
$campaign->tasks->fetch('links')->collapse()->count(); // INT 25
// and the LinkClicks:
$campaign = Campaign::with('links.clicks')->find($someId);
$campaign->links->fetch('clicks')->collapse()->count(); // INT 555
Since going down they are all 'hasMany' relations, you will need to iterate over all of the children at each level in order to generate the sum. Something like this ought to work for you:
$campaign = Campaign::find($campaignId);
$count = 0;
foreach($campaign->task as $task) {
foreach($task->link as $link) {
$count += $link->click->count();
}
}
echo 'Clicks for campaign id ' . $campaignId . ': ' . $count . "\n";
Or, you can skip all that and just issue a bare statement against the database:
$results = DB::select(
'SELECT \'a\' FROM campaign c
INNER JOIN task t ON t.campaign_id = c.id
INNER JOIN links l ON t.task_id = t.id
INNER JOIN link_clicks lc ON lc.link_id = l.id'
);
First idea is probably a better idea though.
Since you are using relationships; you can do something like this:
$count = 0;
$campaign_with_tasks = Campaign::with('tasks')->where('id','=',$campaign_id)->get();
foreach($campaign_with_tasks->tasks as $task){
$links = Links::where('task_id','=',$task->id)->get();
foreach($links as $link){
$count += LinkClicks::where('link_id','=',$link->id)->count();
}
}

Laravel Eloquent: Count items model relationship

I'm using Laravel and the Eloquent class. I have three models.
City.php:
public function itineraries() {
return $this->has_many('Itinerary', 'city_id');
}
Itinerary.php:
public function city()
return $this->belongs_to('City');
}
public function type()
{
return $this->belongs_to('Itinerarytype');
}
Itinerarytype.php:
public function itineraries()
{
return $this->has_many('Itinerary');
}
As you can see a city has many itineraries and an itinerary belongs to a city and an itinerary type. The itinerarytype model has many itineraries.
Using the with() method is it possible to get a count of itineraries grouped into itinerary type?
For instance here is what I have so far:
$city = City::with(array('itineraries'))->where_slug($city_slug)->first();
This gets the city which has that slug and all of it's itineraries.
I'd like to get a list like: (where the text is the itinerary type and the number is the count)
History: 10
Entertainment: 5
Outdoor: 6
...
You'd have to use join and a bit of raw sql to achieve that on a performant way:
$city = City::where_slug($slug)->first();
$types = ItineraryType::join('itineraries', 'itineraries.type_id', '=', 'itenerary_types.id')
->where('itineraries.city_id', '=', $city->id)
->group_by('itinerary_types.id')
->order_by('itinerary_count')
->get(array('itinerary_types.*', DB::raw('COUNT(itineraries.id) as itinerary_count')));
foreach ($types as $type) {
print($type->label . ': ' . $type->itinerary_count);
}

Categories