yii active record join models - activerecord

Using Yii framework.
I have 3 models.
Articles - table articles(id, name)
ArticlesToAuthors - table articles_to_authors (id, article_id, author_id, type)
Authors - table authors (id, name)
I need to get authors.*, article_to_authors.type for specific article_id.
I was trying to make relation in ArticlesToAuthors model like that:
'authors' => array(self::HAS_MANY, 'Authors', array('id' => 'author_id'), ),
then i made query:
$authors = ArticlesToAuthors::model()->with('authors')->findAll(array('condition' => 'article_id=2217') );
foreach($authors as $a)
{
//this is not working
#var_dump($a->authors->name);
#var_dump($a->name);
//this works fine
foreach($a->authors as $aa)
{
var_dump($aa->name);
}
}
Can i get all active record object in one and not to do foreach in foreach?
I need an analogue to sql "SELECT atoa., a. FROM articles_to_authors atoa LEFT JOIN authors a ON atoa.author_id=a.id WHERE atoa.article_id=:article_id"
Am i doing right?
p.s. - sorry for my bad english.

It looks like you need the following relations:
in your ArticlesToAuthors table:
'author' => array(self::BELONGS_TO, 'Authors', 'author_id'),
'article' => array(self::BELONGS_TO, 'Articles', 'article_id'),
and, for completeness, in your Authors table:
'articlesToAuthors' => array(self::HAS_MANY, 'ArticlesToAuthors', array('id' => 'author_id'), ),
This should allow you to access $a->author->name. Not tested, that's just off the top of my head.

Related

Yii - find records with zero related records

There are two models: Auteurs and Books. Auteurs model contains following relations:
public function relations() {
return array(
'books' => array(self::MANY_MANY, 'Books','a_liens(id_auteur,id_book)'),
'booksCount' => array(self::STAT, 'Books', 'a_liens(id_auteur,id_book)'),
);
}
How to write criteria to get all Auteurs with zero booksCount?
Instead of counting books, you may just find Auteurs models without any book - result is the same, but question is different. You may achieve this by using LEFT JOIN and finding records with missing books:
$auteurs->with([
'books' => [
'together' => true,
'select' => false,
'joinType' => 'LEFT JOIN',
'condition' => 'books.id IS NULL',
],
]);

Laravel relationship with method "with" returns null

Today I wanted to do some clean code so just started selecting columns for with relationship. With this code:
\App\Genre::with([
'family'
])->where([
'slug' => $slug,
'is_active' => true
])->first();
everything is working fine. But when I start selecting columns for "with" method:
\App\Genre::with([
'family' => function ($query) {
$query->select('name_pl', 'name_lat');
}])->where([
'slug' => $slug,
'is_active' => true
])->first();
I got that family is null (but it should be an object with columns: name_pl, name_lat). What I am doing wrong?
family method in Genre class looks like this:
public function family () {
return $this->belongsTo(Family::class);
}
I am using Laravel 5.4
Pretty sure you need to add a related column to the list of selected columns, otherwise Laravel won't b able to match the data to eager-load.
Assuming that Genre has a family_id and Family has an id primary key column specified, you need this:
$query->select('id', 'name_pl', 'name_lat'); // See the id added here?
Should do the trick.
For clarity, the matching I mentioned is this one:
select * from genre
select * from family where id in (1, 2, 3, 4, 5, ...)
-- where the comma-separated list of IDs consists of the unique family_id values retrieved in the first query.
Why don't you try:
\App\Genre::with('family:name_pl,name_lat')->where([
'slug' => $slug,
'is_active' => true
])->first();

How I can add column before another column in dbforge?

I want to add column that name 'accept_loc', type 'VARCHAR' to 3 database tables (use dbforge library from codeigniter) Assum they are named t1,t2,t3.
t1 structure:
id
bla_bla
pick_up_loc
....
t2 structure:
id
pick_up_loc
....
t3 structure:
id
bla_bla
pick_up_loc
....
if I used this code below in my migration up function:
$fields = array(
'accept_lat' => array(
'accept_loc' => 'VARCHAR',
'constraint' => '50',
'after' => 'id',
),
);
$this->dbforge->add_column('t1',$fields);
$this->dbforge->add_column('t2',$fields);
$this->dbforge->add_column('t3',$fields);
result:
t1 structure:
id
accept_loc
bla_bla
pick_up_loc
....
t2 structure:
id
accept_loc
pick_up_loc
....
t3 structure:
id
accept_loc
bla_bla
pick_up_loc
....
it's not a good looking structure. How can I add column before 'pick_up_loc' to all of them (n database tables).
Please try to put the after in uppercase, that is 'AFTER', there was a bug in that after key and mentioned got fixed here.
$fields = array(
'accept_lat' => array(
'accept_loc' => 'VARCHAR',
'constraint' => '50',
'AFTER' => 'id'
)
);
The third argument in add_column() is $after_field. So you can't add the column before another column but you can do this:
$this->dbforge->add_column('t1', $fields, 'bla_bla');
$this->dbforge->add_column('t2', $fields, 'id');
$this->dbforge->add_column('t3', $fields, 'bla_bla');
Also, you seem to be naming the field 'accept_lat' and then using 'accept_loc' instead of the 'type' element which is confusing things.
Late to the party but to clarify your code, on t1 for example, should look like this:
$fields = array(
'accept_lat' => array('type' => 'TEXT')
);
$this->dbforge->add_column('t1', $fields, 'id');
So accept_lat will be added after the id column in table t1.

Relation between tables without primary key

Two tables 1 and 2, where id_schedule in 2 table is not primary key:
Task is to get the dates from table 2. I have the following code:
public function relations()
{
return array(
'scheduleTitles' => array(self::BELONGS_TO, 'ObjectScheduleTranslate', 'id'),
'scheduleDates' => array(self::BELONGS_TO, 'ObjectScheduleDate', array('id' => 'id_schedule'))
);
}
OK, first relation works well, second (for this task, exactly) returns only one record (this one 2013-12-30 00:00:00)which is first in screen.
Trying to use another approach, I coded the relation in first model:
'scheduleDates' => array(self::BELONGS_TO, 'ObjectScheduleDate', 'id')
at second model:
'scheduleDatesId' => array(self::HAS_MANY, 'ObjectSchedule', 'id_schedule')
which returns my empty set.
What am I doing wrong ?

Yii CGridview - search/sort works, but values aren't being displayed on respective cells

I am semi-frustrated with this Yii CGridView problem and any help or guidance would be highly appreciated.
I have two related tables shops (shop_id primary) and contacts (shop_id foreign) such that a single shop may have multiple contacts. I'm using CGridview for pulling records and sorting and my relation function in shops model is something like:
'shopscontact' => array(self::HAS_MANY, 'Shopsmodel', 'shop_id');
On the shop grid, I need to display the shop row with any one of the available contacts. My attempt to filter, search the Grid has worked pretty fine, but I'm stuck in one very strange problem. The respective grid column does not display the value that is intended.
On CGridview file, I'm doing something like
array(
'name' => 'shopscontact.contact_firstname',
'header' => 'First Name',
'value' => '$data->shopscontact->contact_firstname'
),
to display the contact's first name. However, even under circumstances that searching/sorting are both working (I found out by checking the db associations), the grid column comes out empty! :( And when I do a var_dump
array(
'name' => 'shopscontact.contact_firstname',
'header' => 'First Name',
'value' => 'var_dump($data->shopscontact)'
),
The dump shows record values in _private attributes as follows:
private '_attributes' (CActiveRecord) =>
array
'contact_firstname' => string 'rec1' (length=4)
'contact_lastname' => string 'rec1 lsname' (length=11)
'contact_id' => string '1' (length=1)
< Edit: >
My criteria code in the model is as follows:
$criteria->with = array(
'owner',
'states',
'shopscontacts' => array(
'alias' => 'shopscontacts',
'select' => 'shopscontacts.contact_firstname,shopscontacts.contact_lastname',
'together' => true
)
);
< / Edit >
How do I access the values in their respective columns? Please help! :(
Hmm, I have not used the with() and together() methods much. What's interesting is how in the 'value' part of the column, $data->shopscontacts loads up the relation fresh, based on the relations() definition (and is not based on the criteria you declared).
A cleaner way to handle the array output might be like this:
'value' => 'array_shift($data->shopscontacts)->contact_lastname'
Perhaps a better way to do this, though, would be to set up a new (additional) relation, like this in your shops model:
public function relations()
{
return array(
'shopscontacts' => array(self::HAS_MANY, 'Shopsmodel', 'shop_id'), // original
'firstShopscontact' => array(self::HAS_ONE, 'Shopsmodel', 'shop_id'), // the new relation
);
}
Then, in your CGridView you can just set up a column like so:
'columns'=>array(
'firstShopscontact.contact_lastname',
),
Cheers
Since 'shopscontact' is the name of the has-many relation, $data->shopscontact should be returning an array with all the shops related... did you modify the relation in order to return only one record (if I didn't get you wrong, you only need to display one, right?)? If you did it, may I see your filtering code?
P.S. A hunch to get a fast but temporal solution: have you tried 'value' => '$data->shopscontact['contact_firstname']'?

Resources