I came across a problem recently that I have to make a find(all) query in cakephp.
Problem is I was unable to call model function to cakephp controller & add a command in function that would allow me to make a find(all) function in cakephp and retrieve all rows in a database that I was looking for.
I would like to make a simple query to make a call to database table that is in database that retrieves rows in table that are matching query.
public function display(){
$query = $HouseParty->find('all', [
'conditions' => ['HouseParty.popular >' => 0],
'contain' => ['title', 'image', 'popular'],
'limit' => 6
]);
$results = $query->all();
var_dump($results);
}
Also what is code to make call to model in Cakephp Controller. So controller knows that we are making calls to models from controller. So we can interact with models from controller because I intend to make multiple calls to different models from same controller in future. Please be helpful looking for a response been stuck on this problem for days just making a question here that is relevant & resourceful for others as well. I would like to make a question come handy to other community members I would just need to get code apart from what I have mentioned above that what code should I write in order to make a call for calling models in one controller - call to multiple models from one controller. Is the above code correct and is so what makes it from giving an error as below. So what is code to make calls to models from database.
Error i get is below:
Call to a member function find() on null
I think you should start with a simple query based on your model.
I will assume your model is HouseParties (a database table named house_parties).
Then in your HousePartiesController, you can query:
$query = $this->HouseParties->find('all', [
'conditions' => ['popular >' => 0],
'limit' => 6
]);
I think you may be misusing 'contain' as a select. 'contain' is for related tables, not fields in the table you are querying.
If you go through the CMS tutorial in full https://book.cakephp.org/4/en/tutorials-and-examples.html it should be clear.
Related
I have 3 tables:
clients, traders and client_trader_relation
clients can have many traders, and traders can have many clients so this is a MANY-MANY relationship with a "pivot" table. The relation is defined in clients model like this:
$relations = array(
'traders' => array(self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'),
);
Now everything works correctly when displaying a listing of all clients in let's say CGridView, but I also want to be able to search for clients by a specific trader (so if one of the traders is let's say id 10, then return this client).
I have done it like this in model's search() function:
public function search()
{
$criteria=new CDbCriteria;
$criteria->with = 'traders';
$criteria->together = true;
$criteria->compare('traders.id', $this->search_trader);
}
search_trader is an additional variable added to the model & rules so it cna be used for searching.
While this works, it successfully returns all clients of specified trader, the result doesn't contain any other related traders, just the one I'm searching for. I can understand this behaviour, because that's the way the generated SQL works.
I'm curious though if there is any way to return all the traders from such search without having to make any additional queries/functions? If not, then what would be the correct way of doing such thing? As for now, I can only think of some function in the model like getAllTraders() that would manually query all the traders related to current client. That would work, I could use this function for displaying the list of traders, but it would produce additional query and additional code.
You can use this to disable eager loading:
$this->with(['traders' => ['select' => false]]);
But this will create separate query for each row, so with 20 clients in GridView you will get extra 20 queries. AFAIK there is no clean and easy way to do this efficiently. The easiest workaround is to define additional relation which will be used to get unfiltered traders using eager loading:
public function relations() {
return [
'traders' => [self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'],
'traders2' => [self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)'],
];
}
And then define with settings for eager loading:
$this->with([
'traders' => ['select' => false],
'traders2',
]);
Then you can use $client->traders2 to get full list of traders.
You can also define this relation ad-hoc instead of in relations():
$this->getMetaData()->addRelation(
'traders2',
[self::MANY_MANY, 'traders', 'client_trader_relation(client_id, trader_id)']
);
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.
I'm fairly new to Yii and so far I've managed to get by on my own but now I'm stuck.
I have a complex relational db (implemented in MySQL). I have the models for them and it's working properly my only problem is that I can't figure out how to make complex queries with CDbCriteria
The application is like an issue tracker so a user can report some problem and someone in charge of that type of problem will contact him/her.
Main tables relevant to the problem:
roles (multiple roles can be assigned to a user, e.g. a role can be 'accountant' or 'developer' )
issuetypes (a user with a role /e.g. accountant/ can create a new issue with a set of issue types /e.g. "printer problem"/
issues (every issue can only have one issue type)
A developer can create an issue like "new PHP version needed" but the accountant can't do that so I need to query the database for all the available issuetypes for a set of roles.
If the user have multiple roles (developer, tester) then I need the union of the issuetypes available for those roles.
So far it's working but when I need to take it a step further and query all the issues submitted with these issuetypes...I'm stuck.
Roughly I need to get the following query:
SELECT DISTINCT i.* FROM `issue` i
LEFT JOIN issuetype ON issuetype.id=i.issuetype_id
RIGHT JOIN role_has_issuetype rit ON rit.issuetype_id=issuetype.id
RIGHT JOIN role ON role.id=rit.role_id
WHERE role.role IN ('developer','tester') AND i.id IS NOT NULL
I know I could use the SQL query directly but the db backend will change in the future (most probably to Oracle) so I'd like to keep the abstraction as far as I could to avoid changing any hard-coded SQL statement and be "backend-independent".
The relevant parts of the models:
class Role extends CActiveRecord
{
public function relations()
{
return array(
'issuetypes' => array(self::MANY_MANY, 'Issuetype', 'role_has_issuetype(role_id, issuetype_id)'),
'users' => array(self::MANY_MANY, 'User', 'user_has_role(role_id, user_id)'),
);
}
}
class Issuetype extends CActiveRecord
{
public function relations()
{
return array(
...
'issues' => array(self::HAS_MANY, 'Issue', 'issuetype_id'),
'roles' => array(self::MANY_MANY, 'Role', 'role_has_issuetype(issuetype_id, role_id)'),
);
}
class Issue extends CActiveRecord
{
public function relations()
{
...
'issuetype' => array(self::BELONGS_TO, 'Issuetype', 'issuetype_id'),
);
}
}
I've tried something like this:
Issue::model()->with(
array(
'issuetype'=>array(
'select'=>false,
'joinType'=>'INNER JOIN',
'condition'=>'issuetype.roles IN ("developer","tester")',
)))->findAll();
It doens't work because issuetype has no column roles it's just a relation.
I've tried to do it in two steps. First get the issuetypes associated with the roles then get the issues.
The first part is working with this code:
$crit = new CDbCriteria();
$crit->addInCondition('roles.role',array('developer','tester'));
$crit->select = array('id');
$res=Issuetype::model()->with('roles')->findAll($crit);
But I don't know how to use the $res in another criteria.
(I'm not even sure this approach will work and even if will it's far from optimal)
I've read about a dozen SO answers and read the Yii forum together with the Yii docs but the examples I've found were not sufficient to solve this (at least I couldn't adopt those codes
to my problem)
I'm quite sure I'm just overlooking some obvious stuff but unfortunately I can't figure it out on my own.
Thanks
Sleeping on the problem helped :)
I've realized my mistake. I should have written this:
return Issue::model()->with(array(
'issuetype.roles'=>array(
'select'=>false,
'joinType'=>'INNER JOIN',
'condition'=>"roles.role IN ('developer','tester')",
)))->findAll();
I hope this will help someone in the future.
I'm working on the Admin view in Yii for my Project model.
One of the columns with a filter is user (owner) of the project.
I can do something like this:
'filter'=> CHtml::dropDownList('Project[user_id]', $model->user_id,
CHtml::listData(User::model()->orderAsc()->findAll(),
'id','username'),array('empty'=>'(select)')),
Which gives me a list of all users in the user table, but I'd like to create something that pulls the distinct users who own a project (I've got 200 users, but only a handful tend to create projects).
Project and User are related via:
'user' => array(self::BELONGS_TO, 'User', 'user_id')
I've tried a bunch of option in the findAll() method, but none worked, I'm not trying to do something with a scope.
So far I've tried this:
'filter'=> CHtml::dropDownList('Project[user_id]', $model->user_id,
CHtml::listData(Project::model()->with('user')->ownerUsernames()->
findAll(), 'id','username'),array('empty'=>'(select)')),
and my Scope is defined as:
'ownerUsernames' => array(
'with' => 'user.username',
'select' => 'user.username',
'distinct' => true,
),
I've tried so many iterations of the above I've lost count 'with'=>'username' 'select'=>'username' etc., but just can't seem to get it to work.
I've tried replace Project::model() with $model just because I thought it might have something to do with it, but no luck.
Any ideas are appreciated. Very new to Yii, but this seems like something it can do.
You have everything ready. Define for the project model a getter function like
public function getUsername()
{
return $this->user->name;
}
Now you should be able to use
CHtml::dropDownList('Project[user_id]', $model->user_id,
CHtml::listData(Project::model()->with('user')->ownerUsernames()->
findAll(), 'id','username'),array('empty'=>'(select)'))
The logic is that CHtml::listData will get the projects as a model, it will create the keys using $project->id and it will create the values using $project->username. Because you created the getted function it will know what $project->username is. Unfortunately CHtml::listData(Project::model()->with('user')->ownerUsernames()->findAll(), 'id','user.name') will not work because it cannot execute 'user.name' or anything like that.
actually you can do many things to accomplish that but some methods would be not appropriate due to time consumption. I prefer to tackle this problem as
Make a table in DB named user_project with attributes
id
user_id(fk to user table)
project_id(fk to project table)
When you create a project then also populate user_project with given fields.
Make its model and you will see relations in it. Now make a function like
public function getName()
{
return user->name;//here i have assumed that the relation name is user
}
Now query this table like
$user=UserProject::mode::findAll();
$list=CHtml::listData($user,'user_id','name');
and use this list to populate the dropDownList. The benefit of this method is that you dont need to query all users of the user table.
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.