Alright, I have some issues understanding how the associations are working, particularly belongsTo here is my setup:
Articles can have multiple Categories
Categories can belong to multiple Articles
so in my database i have 3 tables:
articles, categories and a join table articles_categories
Table/ArticlesTable.php:
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
$this->table('articles');
$this->belongsTo('Users');
$this->belongsToMany('Categories', [
'through' => 'ArticlesCategories',
'alias' => 'Categories',
'foreignKey' => 'article_id',
'joinTable' => 'articles_categories',
'targetForeignKey' => 'category_id'
]);
}
Table/CategoriesTable.php:
public function initialize(array $config)
{
$this->table('categories');
$this->displayField('name');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsToMany('Articles', [
'through' => 'ArticlesCategories',
'alias' => 'Articles',
'foreignKey' => 'category_id',
'joinTable' => 'articles_categories',
'targetForeignKey' => 'article_id'
]);
}
Table/ArticlesCategoriesTable.php:
public function initialize(array $config)
{
$this->belongsTo('Articles');
$this->belongsTo('Categories');
}
Now inside in the view action CategoriesController.php i can overview a particular category and i need to retrieve some articles related to that category.
What is the right way to do such a thing? Here is what i have:
public function view($id = null)
{
$category = $this->Categories->find('all',['limit'=>1])->where(['Categories.id' => $id])->contain(['Articles']);
$this->set(['category'=> $category]);
}
It kinda does the job but I'd also need to be able to limit the number of related articles..
you can modify the query object used to load the associated models:
$category = $this->Categories->find('all',['limit'=>1])
->where(['Categories.id' => $id])
->contain(['Articles' => function($q) {
$q->limit(10);
return $q;
}
]);
edit: or you can do
$category = $this->Categories->get($id,
[
'contain' => [
'Articles' => function($q) {
$q->limit(10);
return $q;
}
]);
or maybe if you want the Articles without the Category data you can use matching
$articles = $this->Categories->Articles->find()
->matching('Categories', function ($q) use $id{
return $q->where(['id' => $id])
->limit(10);
I did not tested the last one but I think something like that should work
But as you can see the complexity is more o less the same
Related
I am using CakeDC Users and as part of the registration I would like the registrant to choose some checkbox values that correspond to another Model in the application. I am able to get the form to load the choices just fine, but I am unable to get it to save to the join table even though I have added all of the associations and accessibilities where it would seem relevant. The form is displaying in a similar way to other areas where I am saving the same type of association with a different model.
TypesTable.php
{
public function initialize(array $config): void
{
//$this->addBehavior('Timestamp');
$this->setDisplayField('type');
$this->setPrimaryKey('id');
$this->belongsToMany('Words');
$this->belongsToMany('Users');
$this->belongsTo('Languages', [
'foreignKey' => 'language_id',
'joinType' => 'INNER',
]);
}```
UsersTable.php (in the plugin folders)
```class UsersTable extends Table
{
...
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('users');
$this->setDisplayField('username');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->addBehavior('CakeDC/Users.Register');
$this->addBehavior('CakeDC/Users.Password');
$this->addBehavior('CakeDC/Users.Social');
$this->addBehavior('CakeDC/Users.LinkSocial');
$this->addBehavior('CakeDC/Users.AuthFinder');
$this->hasMany('SocialAccounts', [
'foreignKey' => 'user_id',
'className' => 'CakeDC/Users.SocialAccounts',
]);
$this->hasMany('Types', [
'foreignKey' => 'user_id', 'targetForeignKey' => 'type_id',
'joinTable' => 'types_users']);
}```
In order for a "belongsToMany" association to work in this instance, both *Table.php files must have the relations listed as belongsToMany. Don't forget to make the field accessible in the Entities as well.
One also needs to place the associated array in the patchEntity function in the RegisterBehavior.php file.
UserTable.php (in CakeDC users)
public function initialize(array $config): void
{
...
$this->belongsToMany('Types', [
'foreignKey' => 'user_id', 'targetForeignKey' => 'type_id',
'joinTable' => 'types_users']);
}
TypesTable.php (in app)
class TypesTable extends Table
{
public function initialize(array $config): void
{
....
$this->belongsToMany('Users');
$this->belongsTo('Languages', [
'foreignKey' => 'language_id',
'joinType' => 'INNER',
]);
}
RegisterBehavior.php
$user = $this->_table->patchEntity(
$user,
$data,
['validate' => $validator ?: $this->getRegisterValidators($options), 'associated' => ['Types']]
);
I have two tables category and product. I want to get details of product whose id are passed in conditions array of find query. The problem is when i pass condition as an array, it returns
Cannot convert value to integer
Secondly, if i debug it by passing only one id it returns category record, but it should return product record. Please help to solve my issue.
My code is as follows:
public function display()
{
$ids = array(1,2,3,4,5);
$c_List = $this->Products->Categories->find('all',array('conditions'=>array('Categories.category_id'=>$ids)));
$data = $c_List->toArray();
debug($data);
die();
}
Model - ProductsTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('products');
$this->setDisplayField('product_id');
$this->setPrimaryKey('product_id');
$this->belongsTo('Products', [
'foreignKey' => 'product_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER'
]);
}
Model - CategoriesTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('categories');
$this->setDisplayField('category_id');
$this->setPrimaryKey('category_id');
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER'
]);
}
When you are finding the records based on an array of ids, use IN in the condition clause.
public function display()
{
$ids = array(1,2,3,4,5);
$c_List = $this->Products->Categories->find('all',array('conditions'=>array('Categories.category_id IN'=>$ids)));
$data = $c_List->hydrate(false)->toArray();
pr($data);
die();
}
I am trying to show number of users present in a room. But when I try to do that, I get error.
This is the relationship.
Rooms has many users.
Rooms belong to groups.
public function initialize(array $config)
{
parent::initialize($config);
$this->table('rooms');
$this->displayField('name');
$this->primaryKey('id');
$this->belongsTo('Groups', [
'foreignKey' => 'group_id'
]);
$this->hasMany('Users', [
'foreignKey' => 'room_id'
]);
}
To achieve this, I wrote a controller function which looks like this:
public function index()
{
$this->loadComponent('Prg');
$this->Prg->commonProcess();
$params = $this->Prg->parsedParams();
$this->paginate = [
'limit' => 25,
'order' => ['id' => 'ASC'],
'finder' => ['RoomsList' =>['filter'=> $params]],
'sortWhitelist' => ['Rooms.id','Rooms.name'],
'extraOptions' =>['params' => $params]
];
$rooms = $this->paginate($this->Rooms);
$this->set(compact('rooms'));
$this->set('_serialize', ['rooms']);
}
This function paginates the list of rooms available. This is working fine but now when I try to show the count of users in each room, it throws error.
I modified my model function like this:
public function findRoomsList(Query $query, array $options)
{
$query->select(['id','name','modified','created'])
->contain([
'Groups'=> function ($query) {
return $query->select(['id','name']);
},
'Users' => function($query){
return $query->select(['status','full_name']);
//want to fetch total number of users
}
]);
echo $query;
return $query;
}
Now I'm getting this error:
You are required to select the "Users.room_id" field(s)
Can anyone tell me the mistakes I made here? I'm new to CakePHP3.
I wanna make assoc with Locations via locations_ways join table what contain order and point (start / middle / end) of way.
In end I wanna get assoc
locations - all locations
end_location ONLY end location
start_location ONLY start location
Now for end_location and start_location I have array what containe one record. But I dont want write some like this: $way->end_location[0]->name;
How to process it?
class WaysTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Locations', [
'through' => 'LocationsWays',
'sort' => ['LocationsWays.position ASC'],
]);
$this->belongsToMany('LocationStartPoint', [
'className' => 'Locations',
'foreignKey' => 'way_id',
'targetForeignKey' => 'location_id',
'through' => 'LocationsWays',
'conditions' => ['LocationsWays.point' => 'start'],
]);
$this->belongsToMany('LocationEndPoint', [
'className' => 'Locations',
'foreignKey' => 'way_id',
'targetForeignKey' => 'location_id',
'through' => 'LocationsWays',
'conditions' => ['LocationsWays.point' => 'end'],
]);
}
}
class LocationsTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Ways', [
'through' => 'LocationsWays',
]);
}
}
class LocationsWaysTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Ways', [
]);
$this->belongsTo('Locations', [
]);
}
}
Fetching func.
public function getWayById($id, $locale = 'uk')
{
I18n::locale($locale);
$item = $this->find()
->where(['Ways.id' => $id])
->contain(['Locations', 'LocationStartPoint', 'LocationEndPoint'])
->cache(function (Query $q) {
return 'way-' . md5(serialize($q->clause('where')));
}, 'orm')
->first();
return $item;
}
I would like to join two controllers.
I have a controller Articles with a view function :
public function view($id = null)
{
$article = $this->Articles->get($id, [
'contain' => []
]);
$this->set('article', $article);
$this->set('_serialize', ['article']);
}
Each article has an associated user. So I have a controller Users.
Now I can have the user_id for the article (in database).
Is it possible to access the username in the User table with the user_id in the Articles table? With a get() function.
For example I know how to do it with find() :
$this->set('articles', $this->Articles->find('all')->contain(['Users']));
But is it possible with get()? For a particular article.
Thanks!
if you have username field in users table:
class UsersTable extends Table
{
public function initialize(array $config)
{
$this->displayField('username');
}
}
Articles table
class ArticlesTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
}
}
In your Articles controller:
public function view($id = null)
{
$article = $this->Articles->get($id, [
'contain' => ['Users']
]);
$this->set('article', $article);
$this->set('_serialize', ['article']);
}
in your articles view
<?= $article->has('user') ? $this->Html->link($article->user->username, ['controller' => 'Users', 'action' => 'view', $article->user->id]) : '' ?>
In the get() function, just add Users to the contain array:
'contain' => ['Users']