I have these models:
class Prefix extends AppModel {
public $displayField = 'prefix';
public $hasMany = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'prefix_id',
'dependent' => false,
),
);
}
class State extends AppModel {
public $displayField = 'name';
public $belongsTo = array(
'Prefix' => array(
'className' => 'Prefix',
'foreignKey' => 'prefix_id',
),
);
}
Then I have this admin_add method, from the automatic scaffolder:
public function admin_add() {
if ($this->request->is('post')) {
$this->Peefix->create();
if ($this->Prefix->save($this->request->data)) {
$this->redirect(array('action' => 'index'));
} else {
// Error message
}
}
$states = $this->Prefix->State->find('list');
$this->set(compact('states'));
}
I also have the list of them in my form:
<?php echo $this->Form->input('State', array('multiple' => 'checkbox', 'type' => 'select',)); ?>
Now I can set the States for the Prefix. However, when I submit the form, the selection disappears. It is not saved in the database.
What did I do wrong?
You linked the models as if there is only one state per prefix, and many prefixes "assigned" to one state. That means you cannot use 'multiple' => 'checkbox'. So either remove this or change model associations to HABTM.
First, both foreign keys for hasMany and belongsTo must be the same. If in the parent model you provided invoice_circle_id as the key, then the same must be provided in the child model also. Obviously, that field must exist in the child table. See this for more info http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Second - you might want to use the saveAll() or saveAssociated() method for linked model data saving. Again - http://book.cakephp.org/2.0/en/models/saving-your-data.html contains all the ifnormation you need.
As for naming the input fields for hasMany, you name them like this:
$this->Form->input('ParentModel.fieldname');
$this->Form->input('ChildModel.0.fieldname');
Related
I have 3 tree like connected tables. Their schemas as follows:
Member{
//Some column
}
Transactions{
member_id :: foreign key of member table
//Some other column
}
TransactionItems{
transaction_id :: foreign key of Transaction table
//Some other column
}
I define models like this:
class Members extends AppModel {
public $primaryKey = 'id';
public $hasOne = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'member_id',
'dependent' => true
)
);
}
class Transactions extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Members');
public $hasOne = array(
'TransactionItems' => array(
'className' => 'TransactionItems',
'foreignKey' => 'transaction_id',
'dependent' => true
)
);
}
class TransactionItems extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Transactions');
public $belongsTo = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'transaction_id'
)
);
}
I have a Data Array which I want to save into database. My scheme is:
Array(
[Members] = [],//Array
[Transactions] = [],//Array
[TransactionItems] = []//Array
)
The problem is that whenever I run $this->Members->saveAll($data). It save data in Member and Transactions table. But do not create data in TransactionItems table. I want to save in all 3 tables at a time.
Any help would be grateful.
Second level (and above) associations must be nested, ie the data structure needs to be:
array(
'Members' => array(),
'Transactions' => array(
'TransactionItems' => array()
)
)
A bit awkward, but that's how it works in 2.x. You can always refer to the structure that is being returned when reading data, it needs to be the same when saving it.
Furthermore you must set the deep option to true in order to be able to save second level and above associations (by default only first level associations are being saved):
$this->Members->saveAll($data, array('deep' => true));
See also
Cookbook > Models > Saving Your Data > Model::saveAssociated()
I'm working with CakePHP to develop a web application that has a few tables and some relationships between them. In this instance I have a series of meetings which reference a calendar year, a department and the relevant school however the model fails to grab the associated table information when data is returned from the controller to the view.
There is already existing $belongsTo relationships between staff and the department and school they belong to and I also managed to grab the associated meeting when the calendar array is returned on the calendar index but ideally I want to be able to list all the meetings with the names of calendars, departments and schools rather than the id field stored in the meetings table.
Here are my tables:
dbo.meetings
id (int) *primary key*
calendar_id (int)
department_id (int)
school_id (int)
created (datetime2(7))
modified (datetime2(7))
dbo.calendar
id (int) *primary key*
name (nvarchar(50))
startdate (datetime2(7))
enddate (datetime2(7))
created (datetime2(7))
modified (datetime2(7))
dbo.schools
id (int) *primary key*
name (nvarchar(255))
(other fields)
dbo.departments
id (int) *primary key*
name (nvarchar(255))
(other fields)
Here is the controller for Meetings:
<?php
App::uses('AppController','Controller');
class MeetingsController extends AppController {
public $helpers = array('Form');
public function beforeFilter() {
parent::beforeFilter();
}
public function index() {
$this->set('meetings', $this->Meeting->find('all'));
}
}
?>
Here is the model for Meeting:
<?php
App::uses('AppModel','Model');
class Meeting extends AppModel {
public $primaryKey = 'id';
public $recursive = -1;
public $belongsTo = array(
'Calendar' => array(
'className' => 'Calendar',
'foreignKey' => 'calendar_id'
),
'School' => array(
'className' => 'School',
'foreignKey' => 'school_id'
),
'Department' => array(
'className' => 'Department',
'foreignKey' => 'department_id'
)
);
}
?>
Currently the index.ctp file in /View/Meetings just contains <?php echo var_dump($meetings); ?> which is printing out the array until I can get the association working and then I will restyle it as required.
Here is what the array looks like atm:
array(1) {
[0]=>
array(1) {
["Meeting"]=>
array(6) {
["id"] => string(1) "1"
["calendar_id"] => string(1) "1"
["department_id"] => string(2) "33"
["school_id"] => string(1) "1"
["created"] => NULL
["modified"] => NULL
}
}
}
For some reason it just won't fetch the calendar, department and school details that it should and I want it to. Can anyone help?
Edit: Model for School
<?php
App::uses('AppModel','Model');
class School extends AppModel {
public $validate = array(
'name' => array(
'required' => array(
'rule' => 'notBlank',
'message' => 'A school name is required.'
)
)
);
}
?>
Make sure that you are enabling the Containable behaviour for your model's using public $actsAs = ['Containable'];:-
App::uses('AppModel','Model');
class Meeting extends AppModel {
public $recursive = -1;
public $actsAs = array('Containable');
public $belongsTo = array(
'Calendar',
'School',
'Department'
);
}
To apply Containable to all models set it in AppModel so that each model inherits the behaviour. Also, as long as you stick to CakePHP naming conventions you don't need to specify the className and foreignKey of your associations.
Now $this->Meeting->find('all') in your MeetingsController should return all the associated data along with the meeting. If you only want it to return some of the associated data you can pass the contain option to the find. For example:-
$this->Meeting->find(
'all',
array(
'contain' => array(
'School',
'Department'
)
)
);
I have a problem with querying associated data from a Model in CakePHP. I wrote an example to show the behavior:
TestController.php:
class TestController extends AppController
{
public $uses = array(
'User',
'Upload',
'Detail'
);
public function test(){
$result = $this->Upload->find('all', array(
'recursive' => 2,
'conditions' => array('Detail.id' => 1)
));
print_r($result);
}
}
Upload.php:
class Upload extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
}
Detail.php:
class Detail extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
}
User.php:
class User extends AppModel {
public $hasOne = 'Detail';
public $hasMany = array(
'Upload' => array(
'className' => 'Upload',
'foreignKey' => 'user_id',
)
);
}
When I remove the condition I get back an array with Details included. But with the condition I get the following error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Detail.id' in 'where clause'
Looking at the SQL Queries it seems like he is not joining the tables correctly when I add the condition. Without the condition he is joining all three tables.
Is this a bug in CakePHP or am I doing anything wrong?
No, it is not a bug with CakePHP. It's simply the way it's designed, using conditions during a find on associated models will often create an invalid query. You should be using containable behavior or manually joining to use conditions on associated models.
Also, I suspect that you will not get the results you are looking for doing this way anyways. CakePHP by default uses left joins. Therefore, your results will not be limited by those associated with the desired Detail ID, but rather, it will get all uploads, all users associated with those uploads, and then only those details associated with those users that have the correct ID. The simplest way then to get what you're probably looking for is to do the query from the opposite direction:
$result = $this->Detail->find('all', array(
'recursive' => 2,
'conditions' => array('Detail.id' => 1)
));
EDIT: If you do want to do left joins, then make your query this way:
$result = $this->Upload->find('all', array(
'contain' => array('User' => array('Detail' => array('conditions' => array('Detail.id' => 1))),
));
I have a model class in CakePHP defined like this:
class Programme extends AppModel {
public $hasOne = array(
'ProgrammeLikes' => array(
'className' => 'ProgrammeLikes',
'fields' => array('likes'));
}
When retrieving my models from the database they are returned as an array with an array keyed to 'Programme' and a separate array keyed to 'ProgrammeLikes' (which contains the 'likes' value correctly). In order to reduce the changes necessary to existing code I want the 'likes' value to be within the 'Programme' array.
Is this possible?
Thanks in advance
Use virtualFields here to get this thing to be done.
class Programme extends AppModel {
public $hasOne = array(
'ProgrammeLikes' => array(
'className' => 'ProgrammeLikes',
'fields' => array('likes')
);
public $virtualFields = array(
'likes' => 'SELECT likes FROM programme_likes AS ProgrammeLikes WHERE ProgrammeLikes.id = Programme.programme_likes_id'
);
// Where programme_likes_id is the foriegnkey for Programme model
}
Note: I assumed programme_likes is your table name for ProgrammeLikes Model and programme_likes_id is the foriegnkey for
Programme Model, so you can arrange the query in your own way that suits your requirement.
I'm Using cakePHP 2.3.8
I have two tables: application, computer_application. The relationship is one application hasMany computer_application, foreign key is application_id
in my ComputerApplication model:
class ComputerApplication extends AppModel{
public $name = "ComputerApplication";
public $useTable = "computer_application";
var $belongsTo = array(
'Computer' => array(
'className' => 'Computer',
'foreignKey' => 'computer_id',
'dependent' => true
),
'Application' => array(
'className' => 'Application',
'foreignKey' => 'application_id',
'dependent' => true
)
);
}
In my ComputerApplication controller. HERE I INITIALIZE THE POPULATION OF DROPDOWN in **add** function
public function add($id=null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('computerApplications',
$this->ComputerApplication->Application->find('list',
array('fields' => array('description') ) ) );
}
Now In my Add View
echo $this->Form->create("computerApplication");
echo $this->Form->input('application_id',array('empty'=>''));
echo $this->Form->end('Save Post');
My problem is that it won't populate the select input. This is the first time I used 2 words in table [computer_application] using cake since I don't have problem populating other table with just one word. Just help me identify which I need to tweak for it to populate.
$this->set('applications', ...
and not
$this->set('computerApplications', ...