adding hasMany association causes find() to not work well - php

OK, I am a little bit lost...
I am pretty new to PHP, and I am trying to use CakePHP for my web-site.
My DB is composed of two tables:
users with user_id, name columns
copies with copy_id, copy_name, user_id (as foreign key to users) columns.
and I have the matching CakePHP elements:
User and Copy as a model
UserController as controller
I don't use a view since I just send the json from the controller.
I have added hasMany relation between the user model and the copy model see below.
var $hasMany = array(
'Copy' => array(
'className' => 'Friendship',
'foreignKey' => 'user_id'
)
);
Without the association every find() query on the users table works well, but after adding the hasMany to the model, the same find() queries on the users stop working (print_r doesn't show anything), and every find() query I am applying on the Copy model
$copy = $this->User->Copy->find('all', array(
'condition' => array('Copy.user_id' => '2')
));
ignores the condition part and just return the whole data base.
How can I debug the code execution? When I add debug($var) nothing happens.

I'm not an expert, but you can start with the following tips:
Try to follow the CakePHP database naming conventions. You don't have to, but it's so much easier to let the automagic happen... Change the primary keys in your tabel to 'id', e.g. users.user_is --> users.id, copies.copy_id -->copies.id.
Define a view, just for the sake of debugging. Pass whatever info from model to view with $this->set('users', $users); and display that in a <pre></pre> block
If this is your first php and/or CakePHP attempt, make sure you do at least the blog tutorial
Make CakePHP generate (bake) a working set of model/view/controllers for users and copies and examine the resulting code
There's good documentation about find: the multifunctional workhorseof all model data-retrieval functions

I think the main problem is this:
'condition' => array('Copy.user_id' => '2')
It should be "conditions".
Also, stick to the naming conventions. Thankfully Cake lets you override pretty much all its assumed names, but it's easier to just do what they expect by default.
The primary keys should be all named id
The controller should be pluralised: UsersController

First off, try as much as possible to follow CakePHP convention.
var $hasMany = array(
'Copy' => array(
'className' => 'Friendship',
'foreignKey' => 'user_id'
)
);
Your association name is 'Copy' which is a different table and model then on your classname, you have 'Friendship'.
Why not
var $hasMany = array(
'Copy' => array('className'=>'Copy')
);
or
var $hasMany = array(
'Friendship' => array('className'=>'Friendship')
);
or
var $hasMany = array(
'Copy' => array('className'=>'Copy'),
'Friendship' => array('className'=>'Friendship')
);
Also, check typo errors like conditions instead of condition

Your table name might be the problem too. I had a table named "Class" and that gave cake fits. I changed it to something like Myclass and it worked. Class was a reserved word and Copy might be one too.

Related

cakephp 3 query is not executing

I am new in cakephp3. I am trying to execute below query but its showing me error.
$lifeinsurances = TableRegistry::get('LifeInsurances')->find("all");
$life_insurances = $lifeinsurances->find()
->join([
'table' => 'institutions',
'alias' => 'institutions',
'type' => 'LEFT',
'conditions' => 'institutions.id = LifeInsurances.institute_id',
]);
I have fixed previous query. Now I am getting only one table data.
EDIT
Now I created association using cake bake. But a new error showing this time. Below is my code.
public function index() {
$this->paginate = [
'contain' => ['Institutions']
];
$lifeInsurances = $this->paginate($this->LifeInsurances);
$this->set(compact('lifeInsurances'));
$this->set('_serialize', ['lifeInsurances']);
}
Internal server error
if I remove
$this->paginate = [
'contain' => ['Institutions']
];
$lifeInsurances = $this->paginate($this->LifeInsurances);
error stop showing
If you have your table associations set up correctly (which they should be automatically if you used bake to create your code), you should be able to simply say:
$lifeinsurances = TableRegistry::get('LifeInsurances')
->find('all')
->contain(['Institutions']);
If you want contain to work , you need to define associations in your respective Models (lies in Table Folder in case of cakephp 3.x).
Since you are saying that you have baked the models, Ensure that relationships are defined in the respective models.
That may be the reason that it is throwing error.
Normally when you have created all the tables in your database , then you should bake the models. Because adding table after you have baked the models do not define relationships in the new models and you have to explicitly define it.
Have a look at this -
How associations get defined when code is baked in Cakephp
Also check the naming conventions of the foreign keys defined in the tables. Cakephp use this naming conventions to define the relationships between models.
Furthermore it would be great if you can post the error log, so as to find out more exact solution to your problem.

CakePHP: How to specify models while retrieving data?

I want to retrive data with recursive level 3. The problem is that It adds all 8 linked models but I need data from only three data models. Is there any way to ignore some models or specifically asked some models but not all. something like useModel('Model1', 'Model2')?
It's better to use the Containable behavior, which will allow you to specify find conditions like this:
$this->Post->find('all', array(
'contain' => array(
'Tag',
'Comment' => array(
'User')
)
)
);
Also, in conjunction with this, it's good to set $recursive to -1 in your AppModel.
class AppModel extends Model {
var $recursive = -1;
var $actsAs = array('Containable');
}
This will give you the finer control you need and ensure that your queries don't bloat as more relationships get added to your models over time.

CakePHP HABTM Filtering

I've got two tables - users and servers, and for the HABTM relationship, users_servers. Users HABTM servers and vice versa.
I'm trying to find a way for Cake to select the servers that a user is assigned to.
I'm trying things like $this->User->Server->find('all'); which just returns all the servers, regardless of whether they belong to the user.
$this->User->Server->find('all', array('conditions' => array('Server.user_id' => 1))) just gives an unknown column SQL error.
I'm sure I'm missing something obvious but just need someone to point me in the right direction.
Thanks!
Your table names are right. There are many ways to do this:
Use the Containable behavior
In your AppModel, set the following:
var $recursive = -1;
var $actsAs = array('Containable');
Then, use the following code to query your servers:
$userWithServers = $this->User->find('all', array(
'conditions' => array('User.id' => 1),
'contain' => array('Server')
));
Note that we are querying the User model, instead of the Server model to accomplish this.
Use bindModel
$this->Server->bindModel(array('hasOne' => array('UsersServer')));
$this->Server->find('all', array(
'fields' => array('Server.*'),
'conditions' => array('Server.user_id' => 1)
));
I personally don't recommend using bindModel a lot. Eventually, your code becomes a bit unmanagable. You should try using the Containable behavior whenever possible. The code looks cleaner and simpler. More on the bindModel method can be found here.
HTH.
I think you're supposed to name tour table user_servers.

Saving with HABTM in CakePHP

I am creating multiple associations in one go and there are a few problems when it comes to saving.
I have the following code:
<?php
foreach($userData as $user) {
$data = array('User' => array('id' => $user['id']), 'Site' => array('id' => $user['site_id']));
$this->User->save($data);
}
?>
I have experimented with formatting the data array in different ways although I always encounter the same problems. Either the previous entries get moved when a new one is inserted or the current one gets updated.
I could just use the following although I need a behavior to trigger.
$this->User->SiteUser->save($data);
Edit: Also $this->User->create(); doesn't seem to do much.
The IRC helped work out what was wrong, once the unique key was set to false everything was able to save correctly.
//In the user model
var $hasAndBelongsToMany = array(
'Site' => array(
'className' => 'Site',
'unique' => false
)
);
Try resetting the id before a new save(), possibly on both models:
$this->User->id = null;
Cake decides whether to update or insert entries based on the set id, and save() sets an id automatically. Not sure why create() doesn't take care of this for you.
Also, if you want to save HABTM data, you should need to use saveAll() instead of save(). Also see this question.

CakePHP displayField usage

Can you tell me how to use CakePHP's displayField directive? I can not figure out how to use it.
So, in a model file, I have following code:
<?php
class Task extends AppModel {
var $name = 'Task';
var $displayField = 'projectName';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
...
How can I use this, to display field projectName in select form field?
So, you have Task belongsTo Project (FK: project_id). You want to make a project select box in tasks/add and tasks/edit views.
The problem is that the projects table doesn't have a field called name or title so the select box is empty. You wouldn't have any problems if there was a name or a title field, right?
Well, here's the solution, in the Project model add this:
var $displayField = 'projectName';
http://book.cakephp.org/view/71/Model-Attributes
So you were going in the right direction, just messed up the models a bit. I hope you understand it now ;]
You can basically do this (in controller):
$this->set('tasks', $this->Task->find('list'));
And make an input with name task_id, and make sure to force it to be a select box, so (in views):
echo $form->input('task_id', array('label' => 'youLabelHere', 'type' => 'select'));
displayField gives you a chance to choose which field will be used as a displayed option (one of) in the select box, if it's not provided in model the script will look for 'name' or 'title'.
If you wan't to display projects in the users forms (add, edit option) then your associations aren't right. Always make sure that there is an association (with good, conventional tables and keys names) between two model when you want to make a select box, Cake makes it as easy as can it gets.

Categories