cake php tree model join tables - sql

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');

Related

How to wp-query posts by category using the sql AND and OR operator

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
);

Yii: A HAS_MANY B, B HAS_MANY C, find count of C belonging to A

Basically, I have 3 tables.
house_table
===========
house_id
floor_table
===========
floor_id
house_id
room_table
===========
room_id
floor_id
is_occupied
A house has many floor, a floor has many rooms. A room belongs to one floor, a floor belongs to one house. The corresponding models created automatically by gii are HouseTable, FloorTable, RoomTable.
What I need is to findAll() houses that have rooms that are not occupied.
How do I do that? Something like this?
class HouseRecord extends CActiveRecord {
public function relations() {
return array(
'FREE_ROOM_COUNT' => array(self::STAT ...???...),
);
}
}
Sure, I could do it with SQL, but it needs to be done this way, because the result of findAll() is used as a data provider in a grid.
UPDATE
Following tinybyte's advice, here's what finally worked.
public function relations() {
return array(
'FREE_ROOM_COUNT' => array(
self::STAT ,
'FloorTable',
'house_id',
'select' => 'COUNT(rt.floor_id)',
'join' => 'INNER JOIN room_table rt ON t.floor_id = rt.floor_id',
'condition' => 'rt.is_occupied = 0',
),
);
}
And to be used as so:
$criteria = new CDbCriteria;
$criteria->with = array('FREE_ROOM_COUNT');
$criteria->together = true;
$provider = new CActiveDataProvider(HouseTable::model(), array(
'criteria'=>$criteria,
'pagination' => array(
'pageSize' => 1,
),
));
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$provider,
'itemView'=>'house',
));
Unfortunately it turns out one can not use these STAT relations as conditions! (Confirmed here: Using STAT relation in CActiveDataProvider criteria).
I think this should do the trick
'FREE_ROOM_COUNT' => array(
self::STAT ,
'Floor' ,
'house_id'
'select' => 'count(rt.floor_id)' , // or count(rt.room_id)
'join' => 'Inner join room_table rt ON Floor.floor_id = rt.floor_id' ,
),

Cakephp: Group by foreign key id and order by published date

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'),
),
),
);

Restricting a category for a certain country in Prestashop 1.5

I need to restrict a category to a set of countries in Prestashop 1.5.
This restriction would prevent the shipping of a product belonging to such a category; as such, the users would still be able to see the products but they would not be able to buy them.
Ideally, I wanted to develop a module that would insert a list of countries (checkbox style, as in the Modules -> Payment page (AdminPayment)) inside a category's edit page, but I haven't been able to do so.
Why can't i simply paste the following code inside the renderForm() function?
Only the description is visible if i do so...
array(
'items' =>Country::getCountries(Context::getContext()->language->id),
'title' => $this->l('Country restrictions'),
'desc' => $this->l('Please mark the checkbox(es) for the country or countries for which you want to block the shipping.'),
'name_id' => 'country',
'identifier' => 'id_country',
'icon' => 'world',
),
EDIT:
I managed to get the list of countries working:
array(
'type' => 'checkbox',
'label' => $this->l('Restricted Countries').':',
'class' => 'sel_country',
'name' => 'restricted_countries',
'values' => array(
'query' => Country::getCountries(Context::getContext()->language->id),
'id' => 'id_country',
'name' => 'name'
),
'desc' => $this->l('Mark all the countries you want to block the selling to. The restrictions will always be applied to every subcategory as well')
),
Now, I can save these values by checking if the value "submitAddcategory" is being submitted in the postProcess function and by running an insert query there. Similarly, I can also load the IDs of the blocked countries from the database, but how can I tick the respective select boxes in the list of countries?
My initial "quick and dirty" idea was to use jQuery selectors inside a document.ready(), but the code gets inserted before everything else and, as such, it won't work because jQuery isn't even loaded yet.
How can this be done?
Cheers
I solved it by using the following code right before the end of the renderForm() function.
The Pièce de résistance was $this->fields_value, as sadly I didn't known of its existence.
public function getRestrictedCountries($obj)
{
// Loading blacklisted countries
$country = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT DISTINCT id_country
FROM `'._DB_PREFIX_.'category_country_restriction`
WHERE id_category = ' . (int)Tools::getValue('id_category') . ';');
$blacklisted_countries = array();
if (is_array($country))
foreach ($country as $cnt)
$blacklisted_countries[] = $cnt['id_country'];
// Global country list
$c_todos = Country::getCountries(Context::getContext()->language->id);
// Crossmatching everything
foreach ($c_todos as $c)
$this->fields_value['restricted_countries_'.$c['id_country']] = Tools::getValue('restricted_countries_'.$c['id_country'], (in_array($c['id_country'], $blacklisted_countries)));
}
PS: The table I am reading from is basically an associative table between 'category' and 'country'

Yii Many to Many saving issue

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/