Eloquent Relations With Multiple Columns - php

So I have the following match table which contains the numbers of the teams that participated in that match. I want to set up a relationship with the teams which looks something like this:
Teams Table
| id | number | name | etc |
| 1 | 1234 | Example | etc |
| 2 | 2345 | Example | etc |
etc...
Matches Table
| id | match | red1 | red2 | blue1 | blue2 |
| 1 | 1 | 1234 | 1710 | 673 | 2643 |
| 2 | 2 | 2345 | 1677 | 4366 | 246 |
etc...
I want to have something like $this->match->where("match", "=", "2")->first()->teams();.
I have tried using hasMany() but I can't seem to get to use the red1, red2, blue1, blue3 columns.
What I have tried:
class Matches extends Model
{
protected $table = "match_table";
protected $fillable = [
"match_id",
"time",
"bluescore",
"redscore",
"red1",
"red2",
"red3",
"blue1",
"blue2",
"blue3",
];
public function teams()
{
return $this->hasMany("App\Models\Teams", "number", ["red1", "red2", "blue1", "blue2"]);
}
}

What I ended up doing was just looping through each column I wanted and then just returning a new Collection with the results in it.
public function teams()
{
$result = [];
foreach($this::$teamColumns as $column) {
$result[] = $this->hasMany("App\Models\Teams", "number", $column)->first();
}
return new Collection($result);
}

Related

How can I write a relation for pivot table in Laravel?

Here is my table structure:
// tickets
+----+------------+----------------------+--------+---------+-------------------+
| id | subject | content | closed | user_id | unique_product_id |
+----+------------+----------------------+--------+---------+-------------------+
| 1 | subject1 | question1 | 0 | 123 | 2 |
+----+------------+----------------------+--------+---------+-------------------+
// unique_product
+----+---------------+------------+
| id | serial_number | product_id |
+----+---------------+------------+
| 1 | 2342rd34fc | 3 |
| 2 | fg34gt4r5t | 1 |
| 3 | 34ffvv4et6 | 3 |
+----+---------------+------------+
// products
+----+--------------+
| id | name |
+----+--------------+
| 1 | Router-rb51 |
| 2 | Switch-sfx2 |
| 3 | Router-rb300 |
+----+--------------+
Now I have a collection of tickets like this:
$tickets = tickets::where(user_id, "$user_id")->get();
foreach( $tickets as $ticket ){
$ticket->{I need to get the name of product here}
}
I can write a relation in the tickets model like this:
public function unique_product()
{
return $this->hasOne(unique_product::class, 'id', 'unique_product_id');
}
And I need one more relation to the products table for getting the name of product (i.e. Switch-sfx2). How should I write that relation?
$tickets = tickets::where(user_id, "$user_id")->with('unique_product.product')->get();
You can take advantage eager loading using with().
but for using with('unique_product.product') You have to define the relation ships between unique_products and products.
In your UniqueProduct model create a new relationship
public function product()
{
return $this->BelongsTo(Product::class, 'id', 'product_id');
}
After that you can access the column of a name like
foreach( $tickets as $ticket ){
$ticket->unique_product->product->name
}

Laravel impossible where query

I'm working on a filter for some products. I have the majority of it working however I am encountering an error with an impossible where clause.
The table contains multiple rows for a single product and I am trying to match multiple criteria per product, which is causing it to fail.
If you have an opinion on this, or possibly a way to fix this, I would greatly appreciate it.
The database table looks like this:
--------------------------------------------
|id | FilterKey | filterValue | product_id |
--------------------------------------------
|1 | Colour | Gunmetal | 1 |
|2 | Colour | Silver | 1 |
|3 | Size | 750cc | 1 |
|4 | Size | 1000cc | 1 |
|5 | Colour | Red | 2 |
|6 | Colour | Blue | 2 |
|7 | Size | 750cc | 2 |
|8 | Size | 1000cc | 2 |
--------------------------------------------
And the filter looks like this:
public function scopeFilterProduct($query, $filters)
{
$this->filters = $filters;
if (count ($this->filters) === 1 && isset($this->filters[0]))
{
return $query;
}
$query->join('product_filters', 'products.id', '=', 'product_filters.product_id')->Where(function($query){
foreach ($this->filters as $filter => $vals)
{
$this->filter = $filter;
$this->vals = $vals;
$query->Where(function ($query){
$query->Where('filterKey', $this->filter);
$query->Where(function($query){
foreach ($this->vals as $val){
$query->orWhere('filterValue', $val);
}
$this->vals = null;
});
});
$this->filter = null;
};
});
return $query;
}
This then outputs the following SQL statement:
select
distinct
`products`.`id`
, `product_id`
from
`products`
inner join
`product_filters`
on
`products`.`id` = `product_filters`.`product_id`
where
(
(`filterKey` = 'Colour' and (`filterValue` = 'gunmetal'))
and
(`filterKey` = 'Size' and (`filterValue` = '750cc'))
)
and
`products`.`deleted_at` is null
If selected, as in the screenshot, then only 'product one' should be present on the page.
The scope you have added in my opinion is wrong. Even your database structure is incorrect in my opinion. Here is how i would structure this:
Filters Table
This model will hold all the filter values. For example, Colour, Size etc. Here is how the filter table will be structured:
-----------------
|id | name |
-----------------
|1 | Colour |
|2 | Size |
-----------------
So your eloquent model become something like this:
class Filter extends Model
{
protected $fillable = ['id', 'name'];
public function products()
{
return $this->belongsToMany(Product::class, 'products_filters');
}
}
Products Table
Your product models becomes:
class Product extends Model
{
public function filters()
{
return $this->belongsToMany(Filter::class, 'products_filters');
}
}
products_filters Table
After the above changes, here is how the table will be structured:
--------------------------------------------
|id | filter_id | filterValue | product_id |
--------------------------------------------
|1 | 1 | Gunmetal | 1 |
|2 | 1 | Silver | 1 |
|3 | 2 | 750cc | 1 |
|4 | 2 | 1000cc | 1 |
|5 | 1 | Red | 2 |
|6 | 1 | Blue | 2 |
|7 | 2 | 750cc | 2 |
|8 | 2 | 1000cc | 2 |
--------------------------------------------
Now you can simply query the filters table, then get associated products for all filters. After that you simply need to compile a list of unique products.
Unqiue products based on selected filters.
$ids = [];
$products = new \Illuminate\Support\Collection();
foreach($filters as $filter) {
foreach($filter->products as $product) {
if(!in_array($product->id, $ids)) {
$ids[] = $product->id;
$products->push($product);
}
}
}
return view('results', compact('products'));
In your view, you need to write:
#foreach($products as $product)
// Your product block HTML
#endforeach

Eloquent selfreferencing hierachie to json

I'm trying Eloquent now with high expectations.
I have a category tree.
Everything works fine. But now I want to return the whole tree as json. Therefore I'm doing:
$categories = Category::whereNull('parent_id')->get()->toJson();
And only get the adam and eve nodes.
[{"category_id":1,"name":"Boats","slug":"boats","parent_id":null},
{"category_id":2,"name":"Paddles","slug":"paddles","parent_id":null}]
Which is good basically. How to integrate the childs recursivly? No "native" eloquent way for that?
Tree like this:
select * from categories;
+-------------+----------------+----------------+-----------+
| category_id | name | slug | parent_id |
+-------------+----------------+----------------+-----------+
| 1 | Boats | boats | NULL |
| 2 | Paddles | paddles | NULL |
| 3 | Kayaks | kayaks | 1 |
| 4 | Canoes | canoes | 1 |
| 5 | Carbon Paddles | carbon-paddles | 2 |
| 6 | Vajda K1 | vajda-k1 | 4 |
| 7 | Dagger RPM | dagger-rpm | 3 |
| 8 | Kober Viper | vober-viper | 2 |
+-------------+----------------+----------------+-----------+
8 rows in set (0.03 sec)
and a model like that
class Category extends Eloquent {
protected $table = 'categories';
protected $primaryKey = 'category_id';
protected $fillable = array("name", "slug", "parent_id");
public $timestamps = FALSE;
// each category has many subcategories
public function childs() {
return $this->hasMany('Category');
}
// each category belogs to one parent category
public function parent() {
return $this->belongsTo('Category');
}
}
AS far as I know there is no native way to get a recursive result from eloquent directly.
For the first level you would use:
$categories = Category::whereNull('parent_id')->with('childs')->get()->toJson();
For the next level (and likewise further on):
$categories = Category::whereNull('parent_id')->with(['childs' => function ($query) {
$query->with('childs');
}])->get()->toJson();
Using Lazy Eager Loading you'll be able to build your own PHP giveMeMyCatTree() methode.
Does this help?

Finding sum through eager loading

I've a table schema as follows:
+----+---------------+------------+--------+
| id | crowd_fund_id | email | amount |
+----+---------------+------------+--------+
| 1 | 11 | jj#xx.com | 200 |
| 2 | 11 | sd#ff.com | 250 |
| 3 | 12 | jj#xx.com | 150 |
| 4 | 12 | abc#cc.com | 230 |
+----+---------------+------------+--------+
And a Entries table:
+----+---------+----------+------+
| id | user_id | crowd_id | name |
+----+---------+----------+------+
| 1 | 6 | 11 | Abc |
| 2 | 6 | 12 | Xyc |
| 3 | 8 | 18 | ijn |
+----+---------+----------+------+
In the Backer's Model
public function entry()
{
return $this->belongsTo('App\Entries', 'crowd_fund_id', 'crowd_id');
}
and in the Controller I've called:
$var = Backers::with('entry')->where('email', $user->email)->get();
This works fine. Now I wanted to get the sum also through the eager loading.
That means I need to call something like
Backers::with('entry')->with('sum')->where('email', $user->email)->get();
The sum will calculate the total of all the amount where crowd_fund_id is equal to the raw where email = $user->email.
That means when I call
Backers::with('entry')->with('sum')->where('email', $user->email)->get();
I should be getting :
1 raw for the backer's details with crowd_fund_id
1 raw for the corresponding entry where crowd_fund_id = crowd_id
1 sum of all amount where crowd_fund_id = crowd_fund_id from the backer's details.
How can I get this?
Could you try something along these lines (in your Backers model):
public function backersSum()
{
return $this->hasOne('App\Backer')
->selectRaw('crowd_fund_id, sum(amount) as aggregate')
->groupBy('crowd_fund_id');
}
Doing it this way allows you to eager load it like any relationship. Then you could do something like this to access it:
public function getBackersSumAttribute()
{
if ( ! $this->relationLoaded('backersSum'))
$this->load('backersSum');
$related = $this->getRelation('backersSum');
return ($related) ? (int) $related->aggregate : 0;
}

Laravel getting results from model belongsToMany relationship back to controller

I'm using Laravel 5 and Eloquent, I have 3 tables setup:
photos
+----+---------------+------------------+
| id | photo_name | photo_location |
+----+---------------+------------------+
| 1 | kittens.jpg | C:\kittens.jpg |
| 2 | puppies.jpg | C:\puppies.jpg |
| 3 | airplanes.jpg | C:\airplanes.jpg |
| 4 | trains.jpg | C:\trains.jpg |
+----+---------------+------------------+
photo_set (pivot table)
+------------+----------+
| set_id | photo_id |
+------------+----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
+------------+----------+
sets
+----+----------------+
| id | description |
+----+----------------+
| 1 | cute animals |
| 2 | transportation |
+----+----------------+
I created a belongsToMany relationship in my photos and sets models to link these two together.
class Photo extends Model {
public function sets()
{
return $this->belongsToMany('App\Set');
}
}
and
class Set extends Model {
public function photos()
{
return $this->belongsToMany('App\Photo');
}
}
However I'm trying to reference the $Sets->photos() model function in my controller, so that given a set of id=1, I can return the photo_location value for each row [C:\kittens.jpg,C:\puppies.jpg], but I don't know how to access it..
Also, I can "sort of" access this information in the view with:
#foreach($sets as $set)
{{$set->images}}
#endforeach
but it looks like it only iterates through once and returns a json (?) of the necessary information, though I'm not sure how to parse that to regular HTML either.
So in short, I'm having trouble accessing this data (photo_location) from both the controller and the view
Use Collection::lists()
$locations = Set::find(1)->photos->lists('photo_location');
It will return an array ['C:\kittens.jpg', 'C:\puppies.jpg']
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Collection.html#method_lists
In your controller try this :
$result = PhotoSet::where('set_id', $set_id)
->with('sets')
->with('photos')
->get();
$photo_location = $result->photos->photo_location;
here PhotoSet is the model for photo_set table, because it is a pivot table we will be able to access both sets and photos table from it.

Categories