I have a HABTM relationship in both my models.
Person.php
public $hasAndBelongsToMany = array(
'Tag' =>
array(
'className' => 'Api.Tag'
));
Tag.php
public $hasAndBelongsToMany = array(
'Person' =>
array(
'className' => 'Api.Person',
));
PeopleController.php
public function edit(){
$results = $this->Person->saveAll($this->request->data);
}
_
(
[id] => 554d92e1-7920-409a-b348-080e2773a233
[firstname] => George
[lastname] => Jones
[Company] => Array
(
[id] => 554995a3-f880-4a02-b971-9ac82773a233
[title] => xxxx
)
[Tag] => Array
(
[0] => Array //this is an existing tag
(
[id] => 530e487c-44bc-4ffe-ae2b-152f4056922c
[title] => monkey
[PeopleTag] => Array
(
[id] => 554e741d-a98c-48d0-8a52-080c2773a233
[tag_id] => 530e487c-44bc-4ffe-ae2b-152f4056922c
[person_id] => 554d92e1-7920-409a-b348-080e2773a233
[created] => -62169987600
[modified] => 1431207117
)
)
[1] => Array //this is a new tag that's not being added
(
[title] => rocketship
)
[2] => Array //this is a new tag that's not being added
(
[title] => houses
)
)
)
When I manually set tags in the database I'm able to read them back out into my app correctly and when I delete existing tags, they get removed from the database. The problem is though that nothing gets added when I try to use cakephp to add them.
My data array looks a little funky because I'm actually using this plugin to transform things.
http://friendsofcake.com/crud/docs/listeners/api-transformation.html
my CakePHP app is getting this data below, but it's not adding my new tags nor is it adding my associations in the people_tags join table. Any idea on what I'm doing wrong?
Related
I have Three tables Projects, Tasks and Tags. Projects.id is the primary key of the first table, Tasks.id is the PK of the second table and Tags.id is the PK of Third table.
Projects Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tasks' => array('className' => 'Tasks','foreignKey' => 'project_id')
);
Tasks Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tags' => array('className' => 'Tags','foreignKey' => 'task_id')
);
The below query return some unexpected result.
$data = $this->Projects->find('all', array(
'recursive' => 2,
'contain' => array(
'Tags' => array(
'conditions' => array('Tags.tag_name =' => "Driver")
)
)
));
The response data i am getting is
[Projects] => Array
(
[id] => 1
[project_id] => 1234
[project_name] => XYZ
)
[Tasks] => Array
(
[0] => Array
(
[id] => 1
[project_id] => 1
[task_id] => 12
[task_name] => task1
[Tags] => Array
(
[0] => Array
(
[id] => 1
[task_id] => 1
[tag_id] => 3444
[tag_name] => Driver
)
)
)
[1] => Array
(
[id] => 2
[project_id] => 1
[task_id] => 343242
[task_name] => task2
[Tags] => Array
(
)
)
See i am even getting tasks without tag as Driver. How i can exclude tasks without tag Driver?
In another word task1 do have Tag as Driver, so that should be there. But task2 don't have any tag, even then the return data contain task2. How to fix it?
You cannot limit the results of the main or parent model based on conditions on child models because "contain" actually creates separate queries for each contain model.
To get the proper result you must use join.
I apologize if this ends up being a newbish PHP misunderstanding, but anyway, I have the following Vip.php file:
<?php
class Vip extends AppModel {
public $useTable = 'vips';
public $hasOne = 'VipCredential';
public $belongsTo = array('User', 'MasterExhibitor');
public $validate = array();
}
class InviteVipForm extends Vip {
}
class AccreditVipForm extends Vip {
}
So, both InviteVipForm and AccreditVipForm classes should inherit every model attributes from their parent, right? This doesn't happen. I loaded InviteVipForm in the controller and printed. Everything is empty or set to default (useTable, for example, is set to invite_vip_forms, which is of course a table which doesn't exist).
AppModel Object ( [useDbConfig] => default [useTable] => invite_vip_forms [id] => [data] => Array ( ) [schemaName] => [table] => invite_vip_forms [primaryKey] => id [_schema:protected] => [validate] => Array ( ) [validationErrors] => Array ( ) [validationDomain] => [plugin] => [name] => InviteVipForm [alias] => InviteVipForm [tableToModel] => Array ( [invite_vip_forms] => InviteVipForm ) [cacheQueries] => [belongsTo] => Array ( ) [hasOne] => Array ( ) [hasMany] => Array ( ) [hasAndBelongsToMany] => Array ( ) [actsAs] => [Behaviors] => BehaviorCollection Object ( [modelName] => InviteVipForm [_methods:protected] => Array ( ) [_mappedMethods:protected] => Array ( ) [_enabled:protected] => Array ( ) [_loaded:protected] => Array ( ) [defaultPriority] => 10 ) [whitelist] => Array ( ) [cacheSources] => 1 [findQueryType] => [recursive] => 1 [order] => [virtualFields] => Array ( ) [_associationKeys:protected] => Array ( [belongsTo] => Array ( [0] => className [1] => foreignKey [2] => conditions [3] => fields [4] => order [5] => counterCache ) [hasOne] => Array ( [0] => className [1] => foreignKey [2] => conditions [3] => fields [4] => order [5] => dependent ) [hasMany] => Array ( [0] => className [1] => foreignKey [2] => conditions [3] => fields [4] => order [5] => limit [6] => offset [7] => dependent [8] => exclusive [9] => finderQuery [10] => counterQuery ) [hasAndBelongsToMany] => Array ( [0] => className [1] => joinTable [2] => with [3] => foreignKey [4] => associationForeignKey [5] => conditions [6] => fields [7] => order [8] => limit [9] => offset [10] => unique [11] => finderQuery ) ) [_associations:protected] => Array ( [0] => belongsTo [1] => hasOne [2] => hasMany [3] => hasAndBelongsToMany ) [__backAssociation] => Array ( ) [__backInnerAssociation] => Array ( ) [__backOriginalAssociation] => Array ( ) [__backContainableAssociation] => Array ( ) [__safeUpdateMode] => [_insertID:protected] => [_sourceConfigured:protected] => [findMethods] => Array ( [all] => 1 [first] => 1 [count] => 1 [neighbors] => 1 [list] => 1 [threaded] => 1 ) [_eventManager:protected] => [_validator:protected] => )
Could anybody tell me why this is happening? The classes don't need to be in separate files, do they?
That's not how things work, each model has to be placed in a separate file, otherwise CakePHP might not be able to find/load them, and then you'll end up with an instance of the AppModel class being used, which is what you are experincing.
The AppModel instance of course won't have any of the properties or methods that you've defined on your extending class.
This behavior is also mentioned in the Cookbook, see http://book.cakephp.org/2.0/en/models.html
CakePHP will dynamically create a model object for you if it cannot find a corresponding file in /app/Model. This also means that if your model file isn’t named correctly (for instance, if it is named ingredient.php or Ingredients.php rather than Ingredient.php), CakePHP will use an instance of AppModel rather than your model file (which CakePHP assumes is missing). If you’re trying to use a method you’ve defined in your model, or a behavior attached to your model, and you’re getting SQL errors that are the name of the method you’re calling, it’s a sure sign that CakePHP can’t find your model and you need to check the file names, your application cache, or both.
[0] => Array
(
[Host] => Array
(
[id] => 2821
[user_id] => 7090
)
[Review] => Array
(
[0] => Array
(
[id] => 852
[host_id] => 2821
[user_id] => 6592
)
[1] => Array
(
[id] => 853
[host_id] => 2821
[user_id] => 6532
)
)
[1] => Array
(
[Host] => Array
(
[id] => 2221
[user_id] => 7390
)
[Review] => Array
(
)
)
I want to show order of pagination result on basis of count review of host.I am trying to use concept of virtual fields to sort.
Please help me to suggest this ..
Refer to Cakephp websie
The implementation of virtualFields has a few limitations. First you
cannot use virtualFields on associated models for conditions, order,
or fields arrays.
However workaround is something along the lines with:
Review Model:
public $virtualFields = array('rw_count' => COUNT(Review.host_id));
Host Model:
class Host extends Model{
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->virtualFields['rw_count'] = $this->Review->virtualFields['rw_count'];
}
}
Hosts Controller
public $paginate = array(
'limit' => 25,
'order' => array(
'rw_count' => 'desc'
)
);
Given that I don't have full details of your schema, this is what I presume what you could use but the concepts remain the same
I have two tables in my database Members and Memberitems. I created two models for it. one is, Member and another is Memberitem
Member model has hasMany relation to Memberitem, and Memberitem model has belongsTo relations with my Member model.
Memberitem entries has specific categorization based on color, like, Red, Pink, Green, etc.
Now I want to select all the members who has atleast one Pink color memberitem using pagination.
Currently I am using:
$this->paginate = array(
'limit' => 5,
'contain' => array(
'Memberitem' => array(
'conditions' => array('Memberitem.color' => 'Pink')
)
)
);
But its showing all the Members.
output is this:
Array
(
[0] => Array
(
[Member] => Array
(
[id] => 1
[first_name] => fh
[last_name] => g
)
[Memberitem] => Array
(
[0] => Array
(
[id] => 1
[name] => item2
[color]=> Pink
)
)
)
[1] => Array
(
[Member] => Array
(
[id] => 2
[first_name] => ad
[last_name] => vd
)
[Memberitem] => Array
(
)
)
[2] => Array
(
[Member] => Array
(
[id] => 3
[first_name] => ae
[last_name] => sdi
)
[Memberitem] => Array
(
[0] => Array
(
[id] => 3
[name] => item1
[color]=> Pink
)
)
)
)
Its showing this result. Member of empty memberitem is still there. I want only 1st and 3 record in result.
This is a classic :-) It takes a while to get it though.
The Cake manual has an excellent peace on this. You should read: http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#containing-deeper-associations
So if you want only Members with certain MemberItems, you should query on the MemberItems and contain the Member Model. You can actually do this from Member Model:
$this->Member->Memberitem->find('all', array(
'conditions' => 'Memberitem.color = "Pink"',
'contain' => 'Member',
));
or maybe a bit more catered to you app:
$this->paginate['Memberitem'] = array(
'contain' => array('Member'),
'conditions' => array(
'Memberitem.color' => 'Pink',
),
);
$items = $this->paginate('Memberitem');
Hope that helps!
I have the following model relationships defined:
class Publication extends AppModel {
var $name = 'Publication';
var $hasAndBelongsToMany = array(
'Author'=>array(
'className'=>'Author'
)
);
}
class Author extends AppModel {
var $name = 'Author';
var $hasAndBelongsToMany = array(
'Publication'=>array(
'className'=>'Publication'
)
);
var $belongsTo = array(
'College' => array (
'className' => 'College'
)
);
}
class College extends AppModel {
var $name = 'College';
var $hasMany = array(
'Department'=>array(
'className'=>'Department'
)
);
}
class Department extends AppModel {
var $name = 'Department';
var $belongsTo = array(
'College'=>array(
'className'=>'College'
)
);
}
The database tables are set up correctly (join tables for the HABTM, etc.). I am trying to find the one DB query to rule them all. I want to create a query that will find all of the publications with the associated authors, colleges, departments, etc. After getting data from a form, I have tried to run queries like this:
$conditions = array(
"Author.id" => $this->data['authors'],
"Publication.year" => $this->data['year']
);
$publications = $this->Publication->find('all', array('conditions' => $conditions));
This throws SQL errors saying that Author.id is not a valid field. Now, this is because a join with the 'authors' db table has not been completed by the time Author.id is being searched for. BUT, if I do this:
$pubs = $this->Publication->find('all', array('conditions' => $conditions));
then I get an array that has all of the Publications with all of the associated Authors (though, not the associated Colleges for some reason).
My question is this: what do I need to do to make the tables join before Author.id is searched for? I've attempted to use bindModel, containable, subqueries, but cannot get those to work for some reason (probably a ID10T error).
Thanks for any advice!
Edit:
The result of the following call:
$this->Publication->recursive = 2;
$pubs = $this->Publication->find('all');
are as follows:
Array (
[0] => Array (
[Publication] => Array ( [id] => 1 [title] => TestArticle [year] => 2011 [type_id] => 3 )
[Type] => Array ( [id] => 3 [type_name] => Journal Articles )
[Author] => Array (
[0] => Array ( [id] => 2 [firstname] => Jeremy [lastname] => Gustine [middle] => A [faculty] => 0 [college_id] => 4 [AuthorsPublication] => Array ( [id] => 3 [author_id] => 2 [publication_id] => 1 )
[College] => Array ( [id] => 4 [college_name] => Letters, Arts, and Sciences ) )
[1] => Array ( [id] => 3 [firstname] => George [lastname] => Obama [middle] => A [faculty] => 0 [college_id] => 6 [AuthorsPublication] => Array ( [id] => 2 [author_id] => 3 [publication_id] => 1 )
[College] => Array ( [id] => 6 [college_name] => School of Public Affairs ) )
[2] => Array ( [id] => 2 [firstname] => Jeremy [lastname] => Gustine [middle] => A [faculty] => 0 [college_id] => 4 [AuthorsPublication] => Array ( [id] => 1 [author_id] => 2 [publication_id] => 1 )
[College] => Array ( [id] => 4 [college_name] => Letters, Arts, and Sciences ) ) ) )
[1] => Array (
[Publication] => Array ( [id] => 2 [title] => TestBook [year] => 2010 [type_id] => 1 )
[Type] => Array ( [id] => 1 [type_name] => Books )
[Author] => Array (
[0] => Array ( [id] => 7 [firstname] => Sony [lastname] => Stuff [middle] => L [faculty] => 0 [college_id] => 5 [AuthorsPublication] => Array ( [id] => 4 [author_id] => 7 [publication_id] => 2 )
[College] => Array ( [id] => 5 [college_name] => Nursing and Health Science ) ) ) ) )
Hopefully that is somewhat readable...
Your second find is correct
i.e. $pubs = $this->Publication->find('all', array('conditions' => $conditions));
just above that try using recursive 2 (below code) to get related College too.
$this->Publication->recursive = 2;