Can anyone suggest me why when there are no translation for a field it is returned empty, and not with the default translation?
I will appreciate all suggestions...
Can`t tell what part of my code you want to see, because it is all straight forward from www.book.cake.org. So i pasting some code:
Model definition:
<?php
class Article extends AppModel
{
var $useTable = 'nc_articles';
var $name = 'Article';
var $actsAs = array(
'Translate' => array(
'title', 'content', 'meta_key_words','meta_description'
)
);
// Use a different model
var $translateModel = 'ArticlesI18n';
// Use a different table for translateModel
var $translateTable = 'nc_articles_i18ns';
var $belongsTo = array(
'Author' => array('className' => 'User',
'foreignKey' => 'author_id',
'conditions' => '',
'fields' => array(),
'order' => '',
'counterCache' => ''),
'Modifier' => array('className' => 'User',
'foreignKey' => 'modifier_id',
'conditions' => '',
'fields' => array(),
'order' => '',
'counterCache' => ''),
'Category' => array('className' => 'ArticlesCategory',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => array(),
'order' => '',
'counterCache' => ''),
'Layout' => array('className' => 'Layout',
'foreignKey' => 'layout_id',
'conditions' => '',
'fields' => array(),
'order' => '',
'counterCache' => ''),
);
var $hasMany = array(
'Comments' => array(
'className' => 'ArticlesComment',
'foreignKey' => 'article_id',
'conditions' => array(),
'order' => '',
'limit' => '',
//'dependent'=> true When dependent is set to true, recursive model deletion is possible. In this example, Comment records will be deleted when their associated User record has been deleted.
)
);
}
?>
And then the function where I am changing Language:
function setLanguage($languageCode='pol')
{
$this->Session->write('Config.language', $languageCode);
$this->redirect($this->referer());
}
Would you like to see something more?
Let me answer my own question. There were few more things I had to write more. First of all I had to declare my Config.language in core.php then for Every model which is translated I had to declare a local variable which is an array of language codes
$this->Article->array('en','pol');
And that's how I managed the problem. But now queries for translation are very long and I am facing an optimization problem.
Related
I am using the CakeDc Users plugin 2.0 and on the plugins admin_index view I would like to see the associated Books for the users.
I have added $hasMany to User.php Model
public $hasMany = array(
'Book' => array(
'className' => 'Book',
'foreignKey' => 'user_id',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => 'order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
And in the UserController.php I added 'contain'
protected function _setupAdminPagination() {
$this->Paginator->settings = array(
'limit' => 20,
'order' => array(
$this->modelClass . '.created' => 'desc'),
'contain' => array('Book')
);
}
public function admin_index() {
$this->Prg->commonProcess();
unset($this->{$this->modelClass}->validate['username']);
unset($this->{$this->modelClass}->validate['email']);
$this->{$this->modelClass}->data[$this->modelClass] = $this->passedArgs;
if ($this->{$this->modelClass}->Behaviors->loaded('Searchable')) {
$parsedConditions = $this->{$this->modelClass}->parseCriteria($this->passedArgs);
} else {
$parsedConditions = array();
}
$this->_setupAdminPagination();
$this->Paginator->settings[$this->modelClass]['conditions'] = $parsedConditions;
$this->set('usersList', $this->Paginator->paginate());
$this->layout = 'btst';
}
However I do not get the associated books in the view, I still just the array of users. This should work?
UPDATE:
debug ($this->Paginator->settings);
Output
array(
'limit' => (int) 20,
'order' => array(
'User.created' => 'desc'
),
'contain' => array(
(int) 0 => 'Book'
),
'User' => array(
'conditions' => array()
)
)
Debug $this->Paginator->settings before calling $this->Paginator and try
'contain' => array('Book')
However it is bad practice to modify plugins directly, you won't be able to update them anymore without trouble (merge conflicts, API changes...) in the worst case. The plugins documentation comes with a lot documentation that explains how to extend the plugin instead of modinfy it directly.
Edit: This was actually a bug in the plugin, fixed it in https://github.com/cakedc/users/commit/73aa350
I have a pretty typical Comment model where Comment belongsto many other models such as Article, Review, Photo, etc and in turn each of those models hasmany Comment. Here is how I built the relationship on the Comment model...
<?php
App::uses('AppModel', 'Model');
class Comment extends AppModel {
var $name = "Comment";
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Article' => array(
'className' => 'Article',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Photo' => array(
'className' => 'Photo',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Review' => array(
'className' => 'Review',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
This works like a charm wherein if I'm viewing a particular article then I can retrieve all comments from that article and it works the same for the other models. What I'm trying to do is show ALL recent comments with the original post's title no matter what model the original post is coming from (Article, Review, Photo, etc) in the format of $comment['Original']['title']. I thought adding the below code within the belongsto of the Comment model would work but it does not....
'Original' => array(
'className' => 'Article',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 3),
'fields' => '',
'order' => ''
),
'Original' => array(
'className' => 'Review',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 2),
'fields' => '',
'order' => ''
),
'Original' => array(
'className' => 'Photo',
'foreignKey' => 'post_id',
'conditions' => array('Comment.module_id' => 8),
'fields' => '',
'order' => ''
),
Unfortunately this only shows the correct title if the recent comment was on a photo (Comment.module_id = 8).
You can use CakePHP's Containable Behavior and do this:
//within a method of the Comment model
$recentComments = $this->find('all', array(
'contain' => array(
'Article',
'Photo',
'Review',
'User'
),
'limit' => 10,
'order' => $this->alias . '.created DESC'
));
Then, you'll get back the comments and any of their parents, regardless of which model it's in. After that, as you repeat through each comment, you can either do a case statement, or an if(!empty()) kinda thing to determine which model has content that you want to display.
(side note: not a good idea to create multiple associations with the same name per your attempt with "Original")
It's not surprising that you got comments only with conditions Comment.module_id = 8. You have made a basic PHP mistake. By using the same key Original multiple times you are effectively overwriting it's value each time. Choose unique aliases (array keys) for each association.
I have 2 models Profiles and Messages. When i try to get all messages in its controller, cake doesn`t return any profiles in result array.
In Message controller:
$this->Message->recursive=3;
$m=$this->Message->find('all');
Models:
class Message extends AppModel {
var $name = 'Message';
var $primaryKey = 'id';
var $useTable = 'messages';
var $belongsTo = array(
'Profile' => array(
'className' => 'Profile',
'foreignKey' => 'author_id',
'conditions' => '',
'fields' => '',
'order' => ''
));
And
class Profile extends AppModel {
var $name = 'Profile';
var $primaryKey = 'id';
var $useTable = 'profiles';
var $belongsTo = array(
'Account' => array(
'className' => 'Account',
'foreignKey' => 'account_id',
'conditions' => '',
'fields' => '',
'order' => ''
));
var $hasMany = array(
'Message' => array(
'className' => 'Message',
'foreignKey' => 'Author_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
));
P.S. I cant wait 7 hours for answer option.
I found solution eventually, my Message model filename was messageS.php, as soon as i renamed it to message.php, got everything i needed. I it helps someone
Per your answer, (but also relevant to other people), if you're pretty sure your associations are correct, the next step is to check your filenames to make sure they fit the conventions (singular model).
Another note, if you're using recursive 3, (wasn't aware it went higher than 2, but apparently it does), you're probably better off using CakePHP's Containable Behavior. Even using recursive of 2 is usually excessive.
write in Message.php model file:
var $belongsTo = array(
'Profile' => array(
'className' => 'Profile',
'foreignKey' => 'author_id',
'conditions' => '',
'fields' => '',
'order' => ''
));
write in Profile.php model file:
var $hasMany = array(
'Message' => array(
'className' => 'Message',
'foreignKey' => 'Author_id', // Hear you "Author_id" should change as "author_id"
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
));
Controller:
$m=$this->Message->find('all');
Now its working fine...Enjoy..
<?php
class Product extends AppModel {
var $name = 'Product';
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'Category' => array(
'className' => 'Category',
'foreignKey' => 'category_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Brand'
);
var $hasOne = array(
'PhotoSmall' => array(
'className' => 'Photo',
'foreignKey' => 'product_id',
'dependent' => true,
'conditions' => 'PhotoSmall.tipo = "small"',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
var $hasMany = array(
'PhotoBig' => array(
'className' => 'Photo',
'foreignKey' => 'product_id',
'dependent' => true,
'conditions' => 'PhotoBig.tipo = "big"',
'fields' => '',
'order' => 'PhotoBig.order',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'Rating' => array(
'className' => 'Rating',
'foreignKey' => 'product_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
I need all my finds (except in the admin area) to retrieve only products with images.
In the case of PhotoSmall is easy, I can do PhotoSmall.id IS NOT NULL in a condition because CakePhp generates a left join, but i can not find a way to require a least on PhotoBig because CakePhp does two queries to return its results.
The requirement is the following, I can only show products with a PhotoSmall and a least one PhotoBig system wide (except for the admin section of the site), the solution should work with CakePhp pagination
I've tried the following code without success, it only returns product data, not photo data:
$this->Product->recursive = -1;
$conditions = array('Product.category_id'=> $cats);
$joins = array(
array('table' => 'photos',
'alias' => 'PhotoBig',
'type' => 'INNER',
'conditions' => array(
'Product.id = PhotoBig.product_id',
)
),
array('table' => 'photos',
'alias' => 'PhotoSmall',
'type' => 'INNER',
'conditions' => array(
'Product.id = PhotoBig.product_id',
)
)
);
$this->paginate = array(
'limit' => 12,
'conditions' => $conditions,
'joins' => $joins,
);
you need to additionally use contain - at least that worked for me
(due to your recursive=-1):
'contain' => array('PhotoSmall', 'PhotoBig'),
the joins are only the setup configuration. without specifying your data you will only get the one model's data.
do you use the containable behavior? would be the easiest solution.
if not, try to set recursive to 0 or 1.
PS: and your second alias is wrong inside the 'conditions' (should be PhotoSmall there).
Well firstly you're setting recursive to -1 which should just give you Product data no matter what kind of find you do.
Why don't you do an AND condition in a find on the Product model like so:
$this->Product->find('all', array('recursive' => 1, 'conditions' => array(
"NOT" => array('PhotoSmall.id' => NULL, 'PhotoBig.id' => NULL))));
Note: recursive will need to be at least one because you want related data.
Another noob question - using v1.2.1.8004 of CakePHP, I think...
I have 3 tables, broker (B), quote_site (QS) and broker_quote_site (BQS) that links them together.
B has many BQS (it belongs to B)
QS has many BQS (it belongs to QS)
I am trying to retrieve quote sites, that are linked to a specific broker, but CakePHP is not doing the joins to the tables behind the scenes.
Here is my query:
$quote_sites = $this->QuoteSite->find('all', array(
'conditions' => array(
'Broker.company_id' => $company_id,
'BrokerQuoteSite.is_active' => true
),
'contain' => array(
'BrokerQuoteSite' => array(
'Broker'
)
)
));
Here are the related models:
<?php
class QuoteSite extends AppModel
{
var $name = 'QuoteSite';
//$validate set in __construct for multi-language support
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $hasMany = array(
'BrokerQuoteSite' => array(
'className' => 'BrokerQuoteSite',
'foreignKey' => 'quote_site_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
?>
Broker:
<?php
class Broker extends AppModel
{
var $name = 'Broker';
//$validate set in __construct for multi-language support
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $hasMany = array(
'BrokerQuoteSite' => array(
'className' => 'BrokerQuoteSite',
'foreignKey' => 'broker_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
?>
And the last one:
<?php
class BrokerQuoteSite extends AppModel
{
var $name = 'BrokerQuoteSite';
//$validate set in __construct for multi-language support
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'Broker' => array(
'className' => 'Broker',
'foreignKey' => 'broker_id',
'conditions' => '',
'fields' => '',
'order' => '',
) ,
'QuoteSite' => array(
'className' => 'QuoteSite',
'foreignKey' => 'quote_site_id',
'conditions' => '',
'fields' => '',
'order' => '',
)
);
}
?>
Thanks in advance for any tips/tricks.
Chris why don't you define Broker as a HABTM relationship then a simple find will retrive the desired results?
class Broker extends AppModel {
var $name = 'Broker';
var $hasAndBelongsToMany = array(
'QuoteSite' =>
array(
'className' => 'QuoteSite',
'joinTable' => 'broker_quote_sites',
'foreignKey' => 'broker_id',
'associationForeignKey' => 'quote_site_id'
)
);
}
http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM
Nice question and what I thought is to make it two steps
$this->Broke = ClassRegistry::init("Broke");
$brokeids = $this->Broke->find("list",array("conditions"=>array('Broker.company_id' => $company_id))); //get all B ids
$this->QuoteSite->Behaviors->attach('Containable'); //use containable behavior
$quote_sites = $this->QuoteSite->find('all',array(
'contain'=>array(
'BrokerQuoteSite'=>array(
'conditions'=>array(
"BrokerQuoteSite.broke_id"=>$brokeids,
"BrokerQuoteSite.is_active" => true
)
)
)
)
);
The code is NOT tested yet,maybe some syntax mistakes out there.Hope it helps.
update
$this->Broke = ClassRegistry::init("Broke");
$this->Broke->recursive=2;
$brokes = $this->Broke->find("all",array("conditions"=>array("Broke.company_id"=>$comany_id)));
the QS information you need shall be found if you view the result with debug($brokes); .What you need to do is extracting them from the array.
Cheers.