I have one model Portfolio in which I have define join like
public $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
now when I am using code in controller like:
$this->Portfolio->recursive = 0;
$this->paginate = array(
'fields' => array('Portfolio.id', 'Portfolio.application_name','Portfolio.category_id','Portfolio.description','Portfolio.screenshots','Portfolio.icon','Portfolio.bg_color_code','Portfolio.created','Category.title','Category.id'),
'limit' => 10,
'order' => array(
'Portfolio.id' => 'asc'
)
);
so its working fine on my window 7 but its giving me error on linux server like:
Database Error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Category.title' in 'field list'
SQL Query: SELECT `Portfolio`.`id`, `Portfolio`.`application_name`, `Portfolio`.`category_id`, `Portfolio`.`description`, `Portfolio`.`screenshots`, `Portfolio`.`icon`, `Portfolio`.`bg_color_code`, `Portfolio`.`created`, `Category`.`title`, `Category`.`id` FROM `portfolios` AS `Portfolio` WHERE 1 = 1 ORDER BY `Portfolio`.`id` asc LIMIT 10
Notice: If you want to customize this error message, create app/View/Errors/pdo_error.ctp
and my category model contains
var $hasMany = array(
'Portfolio' => array(
'className' => 'Portfolio',
'foreignKey' => 'category_id',
)
);
my table
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`parent_id` int(11) NOT NULL DEFAULT '0',
`status` enum('1','2') NOT NULL COMMENT '''1''=active,''2''=inactive',
PRIMARY KEY (`id`)
)
I have tested in debug result its showing
Included Files
Include Paths
0/home/reviewpr/public_html/imobdevnew/lib
2/usr/lib/php
3/usr/local/lib/php
4-> /home/reviewpr/public_html/imobdevnew/lib/Cake/
Included Files
core
app
Config
Controller
Model
0APP/Model/AppModel.php
Other
0APP/webroot/index.php
plugins
where in local its showing
Included Files
Include Paths
0C
1\wamp\www\imobdevnew\lib;.;C
2\php\pear
3-> C:\wamp\www\imobdevnew\lib\Cake\
Included Files
core
app
Other
0APP/webroot\index.php
1APP/Config\core.php
2APP/Config\bootstrap.php
3APP/Config\config.php
4APP/Config\routes.php
5APP/Controller\PortfoliosController.php
6APP/Controller\AppController.php
7APP/Model\portfolio.php
8APP/Model\AppModel.php
9APP/Config\database.php
10APP/Model\category.php
plugins
that means its not loading models.
Please help me...
Linux is case-sensitive
Ominously showing up in the included-files on your windows install are these files:
7APP/Model\portfolio.php
...
10APP/Model\category.php
These files are the wrong case - so on linux they are not included, instead your models will be AppModel instances.
This will be the direct cause of the problem as without the model files being loaded, there will be no model associations either.
To fix the problem just ensure that all your files follow conventions - this means:
APP/Model/portfolio.php -> APP/Model/Portfolio.php
APP/Model/category.php -> APP/Model/Category.php
The filename, and other conventions, are sumarized in the documentation.
It seems to me that there is something wrong with your database, and not Linux. Is your database properly linked?
$this->Portfolio->recursive = 0;
$this->paginate = array(
'fields' => array('Portfolio.id', 'Portfolio.application_name','Portfolio.category_id','Portfolio.description','Portfolio.screenshots','Portfolio.icon','Portfolio.bg_color_code','Portfolio.created','Category.id'),
'limit' => 10,
'order' => array(
'Portfolio.id' => 'asc'
)
);`
Related
I need some help with CakePHP 2.2.3.
What I have
I have the following setup at the moment:
Post hasMany Attachment
It works fine and the page is generated with 2 queries:
SELECT *, `Post`.`id`
FROM `posts` AS `Post`
WHERE 1 = 1
ORDER BY `Post`.`created` DESC
SELECT
`Attachment`.`id`,
`Attachment`.`post_id`,
`Attachment`.`created`
FROM
`attachments` AS `Attachment`
WHERE
`Attachment`.`post_id` IN (1, 2, 3, ..., n)
What I want
I want to extend the relation to be as follows:
Post hasMany Attachment; every Attachment belongsTo Type
And I don't know hot to make CakePHP follow it.
Basically, what I need is:
SELECT *, `Post`.`id`
FROM `posts` AS `Post`
WHERE 1 = 1
ORDER BY `Post`.`created` DESC
SELECT
`Attachment`.`id`,
`Attachment`.`post_id`,
`Attachment`.`created`,
`Type`.`title`, `Type`.`icon`
FROM
`attachments` AS `Attachment`
LEFT JOIN
`types` AS `Type`
ON (`Attachment`.`type_id`=`Type`.`id`)
WHERE
`Attachment`.`post_id` IN (1, 2, 3, ..., n)
Note the LEFT JOIN types added.
So I get the corresponding type data in the second query. I know I could get the data in a loop or using a ->query() call, but I want this to be as much effective and flexible as possible.
The problem
I tried the Containable, Model Unbinding trick (and this one) but no success. I tried different combinations of the options, I believe I've even removed joins. Here's what my PostsController looks like now.
class PostsController extends AppController {
public function index() {
$this->Post->unbindModel(array('hasMany' => array('Attachment')));
$this->Post->Attachment->unbindModel(array('belongsTo' => array('Type')));
$this->Post->bindModel(array(
'hasMany' => array(
'Attachment' => array(
'className' => 'Attachment',
// when uncommented, throws the "Unknown column Post.id" SQLSTATE error
// 'conditions' => array('Post.id' => 'Attachment.post_id'),
'foreignKey' => false,
),
),
));
$this->Post->Attachment->bindModel(array(
'belongsTo' => array(
'Filetype' => array(
'className' => 'Filetype',
// 'conditions' => array('Type.id' => 'Attachment.type_id'),
'foreignKey' => false,
),
),
));
$all = $this->Post->find('all', array(
'joins' => array(
array(
'table' => 'users',
'prefix' => '',
'alias' => 'User',
'type' => 'INNER',
'conditions' => array(
'User.id = Post.user_id',
)
),
),
'contain' => array('Attachment', 'Type'),
'conditions' => array(),
'fields' => array('*'),
'order' => 'Post.created ASC'
));
var_dump($all);exit;
}
}
But it just runs an extra query per each iteration in a loop and gets all the attachments:
SELECT `Attachment`.`id`, ...
FROM `attachments` AS `Attachment`
WHERE 1 = 1
When I uncomment the condition for this association, it throws me the SQLSTATE "Column Post.id not found error" - I guess because there's no Post table joined here.
I need a hand in setting this up.
Please help! Thanks
UPDATE
I've changed the controller as follows. Please note there's no bindModel/unbindModel code, the relation is set in the models classes (is that correct in this case?).
class PostsController extends AppController {
public function index() {
$options = array(
'contain' => array(
'Post',
'Type'
),
'order' => 'Post.created DESC',
'conditions' => array(
// 'Post.title LIKE' => 'my post'
)
);
// The following throws "Fatal error: Call to a member function find() on a non-object"
// $posts = $this->Attachment->find('all', $options);
// So I had to use $this->Post->Attachment instead of $this->Attachment
$posts = $this->Post->Attachment->find('all', $options);
$this->set(compact('posts'));
}
}
This is the Attachment model:
class Attachment extends AppModel {
public $belongsTo = array(
'Type' => array(
'className' => 'Type',
'foreignKey' => 'type_id',
),
'Post' => array(
'className' => 'Post',
'foreignKey' => 'post_id',
),
);
}
The above code runs this query:
SELECT
`Attachment`.`id`, `Attachment`.`type_id`, `Attachment`.`post_id`, `Attachment`.`created`,
`Type`.`id`, `Type`.`title`,
`Post`.`id`, `Post`.`text`, `Post`.`created`
FROM
`attachments` AS `Attachment`
LEFT JOIN `types` AS `Type` ON (`Attachment`.`type_id` = `Type`.`id`)
LEFT JOIN `posts` AS `Post` ON (`Attachment`.`post_id` = `Post`.`id`)
WHERE
1 = 1
ORDER BY
`Post`.`created` ASC
Everything is about the attachments here. I mean the posts are joined to attachments, so if the post has no attachments, it's not returned. This is probably because the call is Attachment->find() so it's from the attachment's point of view. I guess it just should be:
// ...
FROM
`posts` AS `Post`
LEFT JOIN `attachments` AS `Attachment` ON (`Attachment`.`post_id` = `Post`.`id`)
LEFT JOIN `types` AS `Type` ON (`Attachment`.`type_id` = `Type`.`id`)
// ...
But it's not going to work, is it? You see there are posts, attachments and types, but they do have the different relation types. Originally, I've posted those two separate queries CakePHP runs - there must be reasons for that.
UPDATE2
I still believe that it's all about changing the second query to the Attachment model in the initial setup (please see the What I Want section). So I will get attachments types along with attachments themselves. I mean in that case LEFT JOINing the types table to attachments is not going to break any database relation logic, is it?
I just want to make sure there's no way to do that with one complex, but single find() call.
Whenever Cake sees a hasMany relationship, it will automatically create multiple queries to pull the data. While constructing those queries, it looks for relationships that can be LEFT joined to it (hasOne and belongsTo).
Since Cake can't do this for you, you will need to merge them yourself.
public function index() {
$posts = $this->Post->find('all');
// get all attachments for all found posts
$attachments = $this->Post->Attachment->find('all', array(
'contain' => array('Type'),
'conditions' => array('Post.id' => Set::extract('/Post/id', $posts)
));
// now join them to the posts array
foreach ($posts as $key => $data) {
$postId = $data['Post']['id'];
// append any data related to this post to the post's array
$posts[$key] += Set::extract("/Attachment[post_id=$postId]/..", $attachments);
}
$this->set(compact('posts'));
}
This is not the most efficient way to do it since you'll iterate through the $attachments array multiple times, but I'm sure you get the idea.
Try the finderQuery in hasMany.
Eg:
In the Post model,
public $hasMany = array(
'Attachment' => array(
'className' => 'Attachment',
'foreignKey' => 'post_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '
SELECT
`Attachment`.`id`,
`Attachment`.`post_id`,
`Attachment`.`created`,
`Type`.`title`,
`Type`.`icon`
FROM
`attachments` AS `Attachment`
LEFT JOIN
`types` AS `Type`
ON (`Attachment`.`type_id`=`Type`.`id`)
WHERE
`Attachment`.`post_id` IN (1, 2, 3, ..., n)
',
'counterQuery' => ''
)
I want to create in cake php application with users, games and games platforms (for ex PS3)
I got tables:
userGames (game have one platform)
id, name, platform_id
users (users can have many platforms)
id, username
platforms
id, name
users_platforms
id, platform_id, user_id
And now i want to select all user id=1 platforms, and list it for select tag.
Here is sql query:
SELECT platforms.name, platforms.id FROM platforms LEFT JOIN platforms_users ON platforms_users.platform_id=platforms.id WHERE platforms_users.user_id=1
But i dont know what to list this by find('list') function in cakePHP
I try type in users controller:
$this->User->Platform->find('list', array('conditions', array('User.id'=>'1')));
But this returns sql problem (undefinded User.id)
Anyone can help me?
please try this
$this->loadModel('UserPlatform');
$this->UserPlatform->bindModel(array(
'belongsTo' => array('Platform')
));
$this->UserPlatform->find('list', array(
'fields' => array('Platform.id','Platform.name'),
'conditions' => array('UserPlatform.user_id'=>'1'),
'recursive' => 1
));
you must apply find function on join table
Your find must same as this:
$this->PlatformUser->find('list',array('fields'=>
array('Platform.name','Platform.id'),'conditions'=> array('PlatformUser.id' => 1)));
Your PlatformUser Model must have:
public $belongsTo = array(
'Platform' => array(
'className' => 'Platform',
'foreignKey' => 'platform_id',
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
),
);
What you are trying to do is actually a HasAndBelongsToMany Association.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
hasAndBelongsToMany (HABTM)
We’ll need to set up an extra table in the database to handle HABTM associations. This new join table’s name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ ). The contents of the table should be two fields that are foreign keys (which should be integers) pointing to the primary keys of the involved models. To avoid any issues, don’t define a combined primary key for these two fields. If your application requires a unique index, you can define one. If you plan to add any extra information to this table, or use a ‘with’ model, you should add an additional primary key field (by convention ‘id’).
HABTM requires a separate join table that includes both model names.
(This would be the UserPlatform-table if I got that right.)
Make sure primary keys in tables cakes and recipes have “id” fields as assumed by convention. If they’re different than assumed, they must be changed in model’s primaryKey.
class Recipe extends AppModel {
public $hasAndBelongsToMany = array(
'Ingredient' =>
array(
'className' => 'Ingredient',
'joinTable' => 'ingredients_recipes',
'foreignKey' => 'recipe_id',
'associationForeignKey' => 'ingredient_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => ''
)
);
}
I've got three tables
posts
tags
posts_tags
I need to write some controller logic that selects and sets all posts that have the tag work
This means querying the tags to find the id for the queried tag, checking in the associated posts_tags table to find matches, using the post_id to return the correct posts from the posts table.
I'm not sure how to even begin this query, I'm new to CakePHP and could use a hand... Please?
If it helps, here's my posts model relationship:
var $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'posts_tags',
'foreignKey' => 'posts_id',
'associationForeignKey' => 'tag_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
My Tag table is made up of two fields: id and tag
My PostsTag table is made up of three fields: id, tag_id and post_id
My Posts table is made up of four fields: id, title, body and created
I found some code on the CakePHP Book that shows the below code:
$this->Recipe->Tag->find('all', array('conditions'=>array('Tag.name'=>'Dessert')));
They suggested that it was a similar idea, so I attempted to adapt:
$this->Post->Tag->find('all', array('conditions'=>array('Tag.tag'=>'work')));
However, this has not worked. This returns all Posts without filtering.
I took the advice of #Leo and tried to adapt his code to mine:
function getArticleByTagSql($tag) {
$dbo = $this->getDataSource();
$subQuery = $dbo->buildStatement(
array(
'fields' => array('DISTINCT(ArticlesTag.article_id)'),
'table' => "articles_tags",
'joins' => array(
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'INNER',
'conditions' => array('ArticlesTag.tag_id = Tag.id')
)
),
'alias' => "ArticlesTag",
'conditions' => array("Tag.tag" => $tag),
'order' => null,
'group' => "ArticlesTag.article_id",
'limit' => null
),
$this
);
$subQuery = ' Article.id IN (' . $subQuery . ')';
return $dbo->expression($subQuery);
}
Controller:
$this->set('articles', $this->paginate(array(
'conditions' => $this->Article->getArticleByTagSql('work')
)));
However, whatever I type in the paginate() method as a key - in this case 'conditions' appears in the query and I can't figure out why - I keep getting unknown column 'conditions' errors. The error is with the paginate function, the data returns correctly without it, but I cannot use the paginator without it. It's like a catch 22
Cheers,
Dan
if you use:
$this->Post->Tag->find('all'...
you're telling him to find all Tags work... and since its recursive, each tag will contain the related posts..
try doing this instead:
$this->Post->find('all'...
hopefully cake will be smart enough (and if you have correctly set your models relations) to only select posts that have the "work" tag.. and if that doesnt work, you could always set the joins "manually" using a complex find condition
Good Luck
Daniel this question is actually answered in the Cake documentation when describing the HABTM relationship betweens Receipe/Tag
I answered this question for someone who had a similar issue with an Article/Tag models, that answer used a subquery
I had same problem, but I tried this query and it worked for me...May be it will work for you too :)
$claims = $this->Claim->query("SELECT DISTINCT Claim.id,Claim.title, Claim.description FROM
claims as Claim
LEFT JOIN claim_tags as ClaimTag ON Claim.id = ClaimTag.claim_id
LEFT JOIN tags as Tag ON Tag.id =ClaimTag.tag_id
WHERE Tag.id = '$id'");
I have been fighting with this code:
function getNextActionFObyBalance($when) {
$theQuery = $this->find('first', array(
'fields' => array(
'Contract.id',
'Contract.start_balance'
),
'conditions' => array(
'AND' => array(
'Status.next_action_by' => 'frontoffice',
'Status.status_type' => 'active',
'Status.visibility' => 'frontoffice',
'OR' => array(
'Contract.next_action_on' => null,
'Contract.next_action_on <=' => $when
)
)),
'order' => 'Contract.start_balance DESC',
'recursive' => 0,
));
return $theQuery;
}
I have enabled logging on the MySQL server at this is what the server indicates that CakePHP is requesting:
SELECT `Contract`.`id`, `Contract`.`start_balance` FROM `contracts` AS `Contract` LEFT JOIN `statuses` AS `Status` ON (`Contract`.`status_id` = `Status`.`id`) LEFT JOIN `users` AS `User` ON (`Contract`.`user_id` = `User`.`id`) WHERE ((`Status`.`next_action_by` = 'frontoffice') AND (`Status`.`status_type` = 'active') AND (`Status`.`visibility` = 'frontoffice') AND (((`Contract`.`next_action_on` IS NULL) OR (`Contract`.`next_action_on` <= '2010-09-13 10:13:04')))) ORDER BY `Contract`.`start_balance` DESC LIMIT 1
if I use that in the phpmyadmin tool, I get exactly what I was expecting 1 record with two fields. BUT CakePHP just gives me an empty result set.
Can anyone enlighten me?
PS the code was working but I can figure out what changed!
The problem was with a stub to do some post processing afterFind. The problem is that I have completely forgotten to return $results;
I found the error by doing a step by step debugging down the find method in model.php. Found that the after find was called at some point and went to check my afterFind.
Took my about 4 hours for a simple error but I am learning!
Presumably this method is defined in models/contract.php?
The recursive = 0 statement looks a bit suspect to me. Are the models correctly related in their respective model files?
Have you tried loadModel in case the associations aren't working properly?
It would be useful to see the relationship definitions from the respective models.
--EDIT--
I've formatted the code from your comment here as I can't edit your OP
var $belongsTo = array(
'Status' => array(
'className' => 'Status',
'foreignKey' => 'status_id',
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
)
);
var $hasMany = array(
'Transaction' => array(
'className' => 'Transaction',
'foreignKey' => 'contract_id',
'dependent' => false,
)
);
I am getting an error in my view:
Warning (512): SQL Error: 1054: Unknown column 'Model.id' in 'where clause' [CORE\cake\libs\model\datasources\dbo_source.php, line 525]
$sql = "SELECT Model.model_id, Model.pic_location, Model.model_name FROM models AS Model WHERE Model.id = '20' LIMIT 1"
$error = "1054: Unknown column 'Model.id' in 'where clause'"
$out = null
My model is unfortunately named "Model", due to the legacy database I am working with. I have used debug and determined that it is using primaryKey of 'id' (as also displayed in the SQL above), despite my model code (see below) explicitly setting the primaryKey to 'model_id'.
The database table is models with a primary key of model_id, so I can only assume the system is using an autoModel.
My model code is 'model.php':
<?php class Model extends AppModel {
var $name = 'Model';
var $primaryKey = 'model_id';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $hasMany = array(
'Pic' => array(
'className' => 'Pic',
'foreignKey' => 'model_name',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);}?>
I originally created the by hand, and when I hit this error, I baked it... with identical results (except I didn't include the empty fields in the hasMany relationship).
I have turned application level caching off temporarily, and cleared the cache, but nothing helps. How can I make it use my model code?
I'm afraid you'll have to rename your Model model to something else. Your Model class extends AppModel, which in turn extends the base model class, which is also called Model. You're bound to get into trouble this way.
If you have a legacy database, just set the $useTable attribute to use a table with a name different from your model.