cakephp3- unable to show count of values - php

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.

Related

Cannot search based on multiple id in find query in Cakephp 3

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

CakePHP 3: How to make assoc with one record?

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

Cakephp hasOne relationship with finder

In the initialize function of OrdersTable.php, I have
$this->hasOne('CurrentReview', [
'className' => 'Reviews',
'finder' => 'latest',
'foreignKey' => 'order_id
]);
and in ReviewsTable.php, I have
public function findLatest(query $q)
{
return $q->orderDesc('id')->limit(1);
}
I am trying to get only the latest review associated with the order, but I am only ever able to get the first one.
$order = $this->Orders->get($id, ['contain' => [
'CurrentReview'
]]);
What am I missing?
I am almost getting what I need with
$order = $this->Orders->get($id, ['contain' => [
'Reviews' => function ($q) {
return $q->find('latest');
}
]]);
but it's inside an array that I don't want

CakePHP 3 join table associations

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

How to paginate joined many-to-many table with where clause in cakephp?

I have two tables that is joined by another one. tables are:
PostsTable:
$this->belongsToMany('Categories', [
'through' => 'CategoryPost'
]);
CategoriesTable:
$this->belongsToMany('Categories', [
'through' => 'CategoryPost'
]);
CategoryPostTable:
$this->belongsTo('Categories', [
'foreignKey' => 'category_id'
]);
$this->belongsTo('Posts', [
'foreignKey' => 'post_id'
]);
I want to show posts that are in a specific category. for example posts in "design" category.
the route is defined as:
$routes->connect('/blog/archive/:safe_name', ['controller' => 'Posts', 'action' => 'category'], ['pass' => ['safe_name']]);
The category action in Posts controller is defined like this:
class PostsController extends AppController
{
...
public function category($safe_name = null)
{
$this->paginate = [
'contain' => ['Photos', 'Categories']
];
$posts = $this->Posts->find()->matching('Categories', function ($q) {
return $q->where(['Categories.safe_name' => $safe_name]);
});
$this->set('posts', $this->paginate($posts));
$this->set('_serialize', ['posts']);
}
...
}
but what I get is:
Undefined variable: safe_name [APP/Controller\PostsController.php, line 188
could anyone help me about this problem! and how can I do that?
sorry for bad English.
and BTW my cakephp version is 3.0.
Closures in php do not inherit variables in a higher scope
The code responsible for the error message is this:
$posts = $this->Posts->find()->matching('Categories', function ($q) {
return $q->where(['Categories.safe_name' => $safe_name]);
});
Because within the closure, the variable $save_name isn't defined. To fix that error, use use
$posts = $this->Posts->find()->matching('Categories', function ($q) use ($safe_name) {
return $q->where(['Categories.safe_name' => $safe_name]);
});

Categories