Laravel Eloquent HasManyThrough returning empty array - php

I am having trouble getting a query from HasManyThrough relation in Eloquent.
These are my tables
PAGES
id
columns
slideshow_fk
SLIDESHOWS
id
columns
SLIDES
id
columns
slideshow_id
My Page model:
class Page extends Model
{
public function slideshow_id(){
return $this->belongsTo(Slideshow::class);
}
public function slides(){
return $this->hasManyThrough('App\Slide','App\Slideshow','id','slideshow_id','slideshow_fk');
}
}
Controller
$page=Page::where("slug","=",$slug)->with('slides')->first();
Query log: I am not Page ID:3 with slideshow_fk:1, [? = 1]
select `slides`.*, `slideshows`.`id` from `slides` inner join `slideshows` on `slideshows`.`id` = `slides`.`slideshow_id` where `slideshows`.`id` in (?)
page->slides array:
[]
PhpMyAdmin SQL copy/paste:
http://prntscr.com/e0hy4e
Which are the correct 3 slides I need for my page.
Why do I get an empty array?

You cannot you hasManyThrough() here as your implementation doesn't support the need for one.
Say you have three models A, B and C and A want to connect to C via B.
Then if you want to use hasManyThrough()
B needs to have A's primary key as a foreign key
C needs to have B's primary key as a foreign key
That is A <- B <- C
If I put this to your example, what you have is
A have B's primary key as a foreign key
C have B's primary key as a foreign key
Which is A -> B <- C.
What you can do here is define models like this.
class Pages extends Model
{
public function slideshow()
{
return $this->belongsTo(Slideshow::class);
}
}
class Slideshow extends Model
{
public function slides()
{
return $this->hasMany(Slides::class);
}
}
class Slides extends Model
{
}
And query like
$pags = Pages::with('slideshow.slides')->where('slug', $slug)->first();
I suggest using proper naming conventions.

Related

Yii2 GridView shows "(not set)" if dataProvider contains GROUP BY and INNER JOIN

I have show (only show, not compleate CRUD) the result of a query which is built as following:
SELECT SUM(a) AS ab, b, COUNT(*) as C
FROM x
INNER JOIN y
ON y.a = x.a
WHERE b=123
GROUP BY b
so I built this query with ActiveRecord in SearchModels search() method.
In the model of table a I added a hasOne()-relation.
To display the data of this query, I'm using GridView. In it's columns array I use y.b and so on...
My problem: The columns from table x are displayed correct, but for every "joined column" from table y it displays (not set).If I print the by ActiveRecord builded query, and execute it in my sql client, it displays all data. I guess this is depending on the Models primaryKey() function, but I can't change it to get the table work properly. Does somebody know a solution for my problem or why dataProvider/GridView takes care of the selected model's (in this case model of table x) primaryKey() method (or how to make dataProvider/GridView ignore the primaryKey()?
In model you should create relation method with relation model.
For example:
class Patient extends ActiveRecord
{
public function getOrders()
{
return $this->hasMany(Order::class, ['patient_id' => 'id']);
}
}
class Order extends ActiveRecord
{
public function getPatient()
{
return $this->hasOne(Patient::class, ['id' => 'patient_id']);
}
}
For access data:
// SELECT * FROM `patient` WHERE `id` = 1
$patient = Patient::findOne(1);
$orders = $patient->orders;

Speed up query through laravel relationships

There are 3 models:
First (first_id)
Connection (connection_id, first_id, product_id)
Second (second_id, product_id)
I would like to connect the three models together using laravel relationships
First->joined to Connection though first_id
Connection->joined to First through first_id, & joined to Second through product_id
Second -> joined to Connection through product_id
So: First joined to Second through Connection first_id, product_id
Is this possible to do using something like HasManyThrough?
Thanks for your time
On your First model:
public function second () {
return $this->hasManyThrough(
Second::class,
Connection::class,
'product_id', // Foreign key on connection table
'product_id', // Foreign key on second table
'first_id', // Local key on first table
'first_id' // Local key on connection table
);
}
Based on your description the column names should work.
In tinker you can validate if it's hooked up correctly by doing something like First::first()->second.
It depends on what type of relationship Your first model and second model shares as well as what type of relation second and third model shares.
if consider your first model First and second model Second shares a one-to-one relation, as well as Second model and Third models shares one-to-one relationships.
It will be $first->second->third; //no has many through relationship requires
If your First model and Second models shares as hasMany-belongs to relation than you need to use hasManyThrough relationship
example from doc
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}
You can try using nested relationships.
Nested Eager Loading
To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement:
$books = App\Book::with('author.contacts')->get();
Book Model:
public function author()
{
return $this->hasOne('App\Author');
}
Author Model:
public function contacts()
{
return $this->hasMany('App\Author');
}
Documentation:
https://laravel.com/docs/5.8/eloquent-relationships

Eloquent ORM Many-to-many relationship

I've just started using Eloquent ORM (Without Laravel) and I am having issues with the many to many relationships.
I have a table where I store Families (Article categories), another one for the Articles, and a third one as a "pivot". I want to be able to get all the articles a Family has, and all the families an article belongs to. So I have coded this models.
Families
class Families extends Model {
public $table = 'Families';
public function Articles() {
return $this->belongsToMany('Articles', 'articles_families', 'families_id', 'articles_id');
}
}
Articles
class Articles extends Model {
public $table = 'Articles';
public function Families() {
return $this->belongsToMany('Families', null, 'articles_id', 'families_id');
}
}
Then I am trying to retrieve the data like this:
$families = Families::all();
echo $families[1]->Articles;
However, it just returns an empty array, when it should return a couple of articles. I have tripled checked that all the values are correct in the three tables. If I echo the Eloquent query debugger I can see that it is looking for a null value and I'm pretty sure that's the problem, but I don't quite know how to fix it. Here:
{"query":"select * from `Families`","bindings":[],"time":49.13},{"query":"select `Articles`.*, `articles_families`.`families_id` as `pivot_families_id`, `articles_families`.`articles_id` as `pivot_articles_id` from `Articles` inner join `articles_families` on `Articles`.`id` = `articles_families`.`articles_id` where `articles_families`.`families_id` is null","bindings":[],"time":38.93}
The null value is at the end of the last query.
I just found the solution myself. As my primary key columns are called Id, and Eloquent by default assumes the primary key is called id, I needed to override that by adding a class property protected $primaryKey = "Id"; and it now retrieves the data properly.

Eloquent ORM query -- newbie

I am just starting with ORM. I had a question, this is my tabel --
table a - (aid, aname, atag);
table b - (bid, aid, bname, .. );
It is One to Many relationship - that is One aid can belong to many bid but one bid can belong to only one aid.
So I was trying out this code, In the out put I want -- (bname,aname) for all the records.
A model --
class A extends Eloquent {
protected $table = 'a';
protected $primaryKey = 'aid';
public function brelation() {
$this->belongsToMany('B','aid');
}
}
B model --
class B extends Eloquent {
protected $table = 'b';
protected $primaryKey = 'bid';
public function getANames() {
$this->hasOne('A','aid');
}
}
In Controller --
foreach(B::with('getANames')->get() as $b_item){
echo $b_item->bname." , ".$b_item->aname;
}
Couple of points to clarify --
1) I have to specify the foreign key to make sure they map. Because in my actual case they are named differently.
2) I am using Laravel 4.
Can someone show me what I did wrong and how I can get the desired result.
===== Update =====
class A extends Eloquent {
protected $table = 'a';
protected $primaryKey = 'aid';
public function brelation() {
$this->belongsTo('B','aid');
}
}
I still cannot access the aname column i.e ($b_item->aname) in the controller.
A couple of things you should be aware of:
If you have a custom primary key, you need to set the $primaryKey property on your eloquent models to the primary keys you have in the DB.
You can't mix and match belongsToMany relationships with anything other than belongsToManys. A belongsToMany is exclusively for the case where you have two tables that are connected by a pivot table. In your case, B belongsTo A, and A hasMany B.

Laravel/Eloquent - Eager Load using other than Primary Key

Eager Loading uses Primary Keys from the parent table inside the IN(...) clause, as clearly stated in Laravel's documentation:
select * from books
select * from authors where book_id in (1, 2, 3, 4, 5, ...)
Is it possible not to use the Primary Key for this, but another key from the books table? Or even a key retrieved from a pivot table?
Yeah we can do eager loading on non-primary columns. For this you need to define db-data relationships in models:-
Define your models Book & Author like this:-
class Books extends Eloquent {
public static $table = 'books';
public function bookauthors(){
return $this->has_many('authors','book_id');
}
}
class Authors extends Eloquent {
public static $table = 'authors';
public function books()
{
return $this->belongs_to('books','book_id');
}
}
Now you can use following line of code to eager load books with authors on a key "book_id":-
$books = Books::with(array('bookauthors'))->get();
I hope this helps you...i haven't tested on my local or test db. But had used similar eager loading for posts-tags relationship.

Categories