I'm having trouble saving a many to many relation. My database schema are as below:-
articles
- id (PK)
- content
tags
- id (PK)
- name
article_tag
- article_id (PK)
- tag_id (PK)
My Article model has the following relation:-
'tags' => array(self::MANY_MANY, 'Tag', 'article_tag(tag_id, article_id)'),
However, when I saw using a Yii behavior, I get the following error:-
Table "tags" does not have a column named "article_tag(tag_id, article_id)".
I have run through everything from schema to relation and I can't seem to figure out the problem. I have tried using other extensions as well and none of them seem to save to the m:n table.
Am I missing something here?
Additional Information
Here is my CManyManyRelation Object; the foreignKey just doesn't look right.
CManyManyRelation Object ( [limit] => -1 [offset] => -1 [index] => [through] => [joinType] => LEFT OUTER JOIN [on] => [alias] => [with] => Array ( ) [together] => [scopes] => [name] => tags [className] => Tag [foreignKey] => restaurant_tag(restaurant_id, tag_id) [select] => * [condition] => [params] => Array ( ) [group] => [join] => [having] => [order] => [_e:CComponent:private] => [_m:CComponent:private] => )
In the Many-Many relation in the Article class you should put first the id of the Article and then the id of the tag:
'tags' => array(self::MANY_MANY, 'Tag', 'article_tag(article_id, tag_id)'),
Then in the class Tag you should have:
'articles' => array(self::MANY_MANY, 'Article', 'article_tag(tag_id, article_id)'),
Edit: My bad I didn't realize it was saving the related model that causes the problem.
There is no build-in possibility to save the related record in Yii
For me the best solution to save a related models is the extension activerecord-relation-behavior. The extension will be handling all the HAS_MANY and MANY_MANY relations.
I've been using yii-manymanyactiverecord extension to help simplify the process, you can find it here: http://www.yiiframework.com/extension/yii-manymanyactiverecord/
Related
I would like to create basically a sql statement to the effect:
Select all posts from table where post has the following assigned categories as follows: (has category==7, or has category ==8 or has category ==9) and has both categories (category ==10 and category=33) using wp-query. Note: numbers represent category ID.
I tried various wp-query category parameters.
$args = array(
'post_type' => 'post',
'category__and' => array(10,33),
'category__in' => array(7,8,9),
'order' => 'ASC',
'posts_per_page'=> '-1', // overrides posts per page in theme settings
);
Not errors just incorrect posts chosen
Thanks for your response. This worked for me
$args = array(
'post_type' => 'post',
'category__and' => array(10,33),
'cat' => 7,8,9
'order' => 'ASC',
'posts_per_page'=> '-1', // overrides posts per page in theme settings
);
public function index() {
$this->paginate = array(
'order'=>array('published_date'=>'desc'),
'group'=>'book_id',
'conditions'=>array('Chapter.published'=>1,'Chapter.published_date <= NOW()')
);
$chapters = $this->paginate();
$this->set('chapters',$chapters);
}
My database have table Book, Chapter. Each book has many chapter
Table Chapter has field '*book_id*', that is foreign key reference table Book primary key (id).
Here is my index page. The idea is to get latest chapter from each book and order by published date.In controller ChapterController, I use group by statement but it didn't get the latest chapter, it get the first chapter form each book.
So,please help me fix it. Thanks a lot
I believe that group by will use the first row that is naturally in your results, and I do not think there is a simple way to sort your results before the group by is applied. But I think the following query will get you the results you want:
SELECT * FROM books INNER JOIN (SELECT * FROM chapters WHERE chapters.published = 1 AND chapters.published_date <= NOW() ORDER BY chapters.published_date DESC) AS Chapter ON Chapter.book_id = books.id GROUP BY books.id
I think the following is how the CakePHP should look (I'm assuming you're paginating Book):
$this->Book->recursive = -1; //Join manually instead
$this->paginate = array(
'order' => array('published_date' => 'desc'),
'group' => 'Book.id',
'joins' => array(
array(
'table' => '(SELECT * FROM chapters)',
'alias' => 'Chapter',
'conditions' => array(
'Chapter.book_id = Book.id',
'Chapter.published' => 1,
'Chapter.published_date <= NOW()',
),
'type' => 'inner',
'order' => array('published_date' => 'desc'),
),
),
);
I am new in CakePHP, but I use Rails. I would like to do something like this in CakePHP:
class Manager < ActiveRecord::Base
has_many :employees
end
and ask then the object like this:
m = Manager.find(1)
# Sends SQL query SELECT COUNT * FROM EMPLOYEES WHERE MANAGER_ID = 1
count = m.employees.count
# Sends SQL query SELECT * FROM EMPLOYEES WHERE MANAGER_ID = 1
m.employees.each do |e|
puts e.name
end
I have this code in CakePHP...
class Manager extends AppModel {
public $hasMany = array(
'Employee' => array(
'className' => 'Employee',
'order' => 'Employee.created DESC'
)
);
}
class Employee extends AppModel {
public $belongsTo = 'Manager';
}
How can I do implementation of these (above) functionality (which is in RoR easy made by its ORM) in CakePHP?
Thanks for help...
Myth Rush
Your question boils down to "How can I retrieve the Manager with id=1 and find his Employees.
In CakePHP you would issue the following find query to retrieve the desired manager entry:
$manager = $this->Manager->findById(1);
// or
$manager = $this->Manager->find('first', array(
'conditions' => array(
'Manager.id' => 1
)
);
The above find calls fetch the manager with id=1 from the database and because you set up the relationship Manager hasMany Employee, the result will also contain all employees for the manager ordered by Employee.created DESC.
The resultset would look something like this:
Array
(
[Manager] => Array
(
[id] => 1
[field1] => value1
)
[Employee] => Array
(
[0] => Array
(
[id] => 2
[manager_id] => 1
[name] => Bar
)
[1] => Array
(
[id] => 1
[manager_id] => 1
[name] => Foo
)
)
)
As you can see, CakePHP uses an array format for returned results and not an object as in Ruby on Rails. Therefore you have to access your related data within the resulting array.
Another important difference between CakePHP and Ruby on Rails(RoR) is, that in CakePHP the queries to the db are executed the moment you call them, whereas in RoR they are lazily executed the moment you try to access the results.
To complement your RoR example for accessing employees here is the CakePHP version:
$employee_count = count($manager['Employee']);
foreach ($manager['Employee'] as $e) {
echo $e['name'];
}
I hope this clears up some confusion.
I think you are looking for the containable behavior of CakePHP.
It is important to attach the containable behavior to your model(s), otherwise it won't work.
I have three tables: books, books_categories and categories.
books:
...
categories:
id, name, parent_id
books_categories:
id book_id category_id
So one book might be in many categories and one category might have many books.
And categories are a tree - each category has parent (or NULL) (and virtually children).
The problem is that if we have categories: a > b > c and book belongs to category a, it doesnt mean that it belongs to subcategories b or c... And I want to get all books from category a even from subcategories.
For now I get all books from specified category like this:
$options['joins'] = array(
array('table' => 'books_categories',
'alias' => 'BookCategory',
'type' => 'inner',
'conditions' => array('Book.id = BookCategory.book_id')
),
array('table' => 'categories',
'alias' => 'Category',
'type' => 'inner',
'conditions' => array('BookCategory.category_id = Category.id')
));
$options['conditions'] = array('Category.id' => '5');
$this->set('books', $this->Book->find('all', $options));
And this correctly finds all books from category of id = '5'. And I need also books from child categories of '5' - is it possible in single query? Or I have to get all parent child categories (how) and then in conditions set 'Category.id' => '5' OR 'Category.id => '6' and so on?
Try this :
$allCategories = $this->Book->find('threaded');
In my code I have three classes as follows: Forum, Forum::Thread and Forum::Post
What I want to do is create a belongs_to-relationship from the Forum::Post class to the Forum class and vice versa with a has_many, preferably without creating a custom function for it. (This is admittedly more of an intellectual exercise than a technical limitation or actual problem, but if it is possible, I would much like to know.)
The commented out lines contain my intention with the relationships, but in their current form, they fail to work. I've poked around in the documentation, but cannot find anything relevant to this specific case.
Any pointers?
The forum class:
package Schema::Result::Forum;
use Moose;
extends qw/DBIx::Class/;
__PACKAGE__->load_components (qw/Core/);
__PACKAGE__->table ('forum');
__PACKAGE__->add_columns (
id => {
is_auto_increment => 1,
data_type => 'integer',
},
);
__PACKAGE__->set_primary_key ('id');
__PACKAGE__->has_many (threads => 'Schema::Result::Forum::Thread');
#This is the interesting line
#__PACKAGE__->has_many (posts => 'threads' => 'forums' );
1;
The thread class:
package Schema::Result::Forum::Thread;
use Moose;
extends qw/DBIx::Class/;
__PACKAGE__->load_components (qw/Core/);
__PACKAGE__->table ('forum_thread');
__PACKAGE__->add_columns (
id => {
is_auto_increment => 1,
data_type => 'integer',
},
forum => {
data_type => 'integer',
},
);
__PACKAGE__->set_primary_key ('id');
__PACKAGE__->belongs_to (forum => 'Schema::Result::Forum');
__PACKAGE__->has_many (posts => 'Schema::Result::Forum::Post');
1;
The post class:
package Schema::Result::Forum::Post;
use Moose;
extends qw/DBIx::Class/;
__PACKAGE__->load_components (qw/Core/);
__PACKAGE__->table ('forum_post');
__PACKAGE__->add_columns (
id => {
is_auto_increment => 1,
data_type => 'integer',
},
thread => {
data_type => 'integer',
},
);
__PACKAGE__->set_primary_key ('id');
__PACKAGE__->belongs_to (thread => 'Schema::Result::Forum::Thread');
#This is the other interesting line
#__PACKAGE__->belongs_to (forum => 'thread' => 'forum');
1;
PS: Additional columns to hold actual content were omitted for brevity.
It looks like nested relationships aren't possible. has_many takes a single foreign class, which has a foreign key to the calling class.
The good news is $forum->threads->posts returns a single DBIx::Class::Resultset. It is not translated into SQL until needed, so when you call $forum->threads->posts->all() or even something like $forum->search_related('threads',{},{rows=>25})->posts->all(), it only runs a single query.
If your goal is to have a $post->forum, it can always be a method: sub forum{$_[0]->thread->forum}
What database and engine-type are you using? If you don't have foreign keys (like, for instance, with myisam tables in MySQL) then you'll have to provide the column names in your relationship statements.