Cakephp Self referring Model Not working - php

I have a table
Medias:
ID,
PARENT_ID
PATH
TITLE
Items:
ID
medias
Title
description
Models
class ImageGallery extends AppModel {
public $name = 'ImageGallery';
public $useTable = "medias";
var $belongsTo = array(
'Parent' =>
array('className' => 'ImageGallery',
'foreignKey' => 'parent_id',
'dependent' => false,
),
);
var $hasMany = array(
'Children' =>
array('className' => 'ImageGallery',
'foreignKey' => 'parent_id',
'dependent' => false,
),
);
}
class Item extends AppModel {
public $useTable = "items";
public $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
);
public $belongsTo = array(
'Gallery' => array(
'className' => 'ImageGallery',
'foreignKey' => 'medias'),
);
public $hasMany = array(
'ItemMeta' => array( 'className' => 'ItemMeta'),
);
}
The media table contains gallery information. Images are stored in parent_id relation.
When I request Item->find('all'); I am getting only one entry from Media table, but I want to get all its children too. :(
I can get its children by using $this->ImageGallery->findById(10);, but I want to get them with the Item Model.

Use the containable behavior to specify which associated models you want the query to get. http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
$this->Item->find('all', array('contain' => array('ImageGallery' => array('Children'))));
If you're looking to go deeper than just the child level, like if you want to get the rest of the tree, then you'll need to either write something to recursively fetch the children, the children's children, etc., or perhaps you can alter your code and models to make use of CakePHP's Tree Behavior. See http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html and http://www.dereuromark.de/2013/02/17/cakephp-and-tree-structures/

Related

CakePHP Multidimensional Model - Joining in wrong place

I'm having an issue with Cake joining tables in the wrong place :(
I have three tables - CC_PLAYLIST, CC_PLAYLISTCONTENTS, and CC_FILES.
I'd like to get a list of all playlists, with all of their contents, and then the relevant file information for each piece of playlist content.
I.E
Playlist 1
-- Playlist Content 1
---- File Info
-- Playlist Content 2
---- File Info
-- Playlist Content 3
---- File Info
Playlist 2
-- Playlist Content 123
---- File Info
In my Model (AirtimePlaylist) I get this data with
$result = $this->find('all', array(
'contain' => array(
'AirtimePlaylistContent' => array(
'fields' => array('AirtimePlaylistContent.id', 'AirtimePlaylistContent.playlist_id', 'AirtimePlaylistContent.file_id'),
'AirtimeFile' => array(
'fields' => array('AirtimeFile.id', 'AirtimeFile.track_title', 'AirtimeFile.artist_name')
)
),
),
'conditions' => array('AirtimePlaylist.id' => 5),
'fields' => 'AirtimePlaylist.id', 'AirtimePlaylist.name'
));
It seems however that the join between CC_PLAYLISTCONTENTS and CC_FILES is not quite playing ball. CC_PLAYLISTCONTENTS should join CC_FILES with CC_PLAYLISTCONTENTS.file_id = CC_FILES.id but it seems to be doing CC_PLAYLISTCONTENTS.id = CC_FILES.id
AirtimePlaylist.php
class AirtimePlaylist extends AppModel {
public $useTable = 'cc_playlist';
public $actsAs = array('Containable');
public $hasMany = array('AirtimePlaylistContent' => array(
'className' => 'AirtimePlaylistContent',
'foreignKey' => 'playlist_id'
));
AirtimePlaylistContent.php
class AirtimePlaylistContent extends AppModel {
public $useTable = 'cc_playlistcontents';
public $hasOne = array('AirtimePlaylist' => array(
'className' => 'AirtimePlaylist',
'foreignKey' => 'id'
),'AirtimeFile' => array(
'className' => 'AirtimeFile',
'foreignKey' => 'id'
));
AirtimeFile.php
class AirtimeFile extends AppModel {
public $useTable = 'cc_files';
public $hasMany = array('AirtimeFileAttribute' => array(
'className' => 'AirtimeFileAttribute',
'foreignKey' => 'track_id'
));

Cakephp Model association with user id

I have the following model in Cakephp:
class Post extends AppModel {
var $name = 'Post';
var $belongsTo = array(
"User" => array(
'className' => 'User',
'foreignKey' => 'user',
'fields'=>array('id', 'username', 'last_action', 'type', 'status', 'country')
),
);
var $hasOne = array(
"Follower" => array(
'className' => 'Follower',
'foreignKey' => false,
'fields'=>'target',
'conditions' => array('Follower.target = Post.user', 'Follower.user = 21')
),
);
}
This model gets the posts from the database and includes the basic user information. My goal is to include in the same query if the user who is retrieving the data is following or not whoever created that post.
For this reason I am trying to associate the table followers. But in order to get the appropriate result I should submit the user id, (in this case 21). The problem is that I don't know how to pass the logged user ID variable.
Does anybody know how to do it or how this model should be written?
Thanks
Remove the $hasOne code within the Post model. Immediately before executing your find, use the bindModel
For example, this would be called from a method within the Post model (changing the 21 to your logged in user's id) prior to the find:
$this->bindModel(
array('hasOne'=>array(
'Follower' => array(
'className' => 'Follower',
'foreignKey' => false,
'fields'=>'target',
'conditions' => array(
'Follower.target' => 'Post.user',
'Follower.user' => '21')
)
))
);

How do I traverse CakePHP relations?

I'm trying to traverse the relations on CakePHP models.
This is the database:
I can access product attributes (product->attributes) on a product model but I cannot access the product attributes on Ad model (ad->product->attributes).
Here is my code:
//Product Model
class Product extends AppModel {
public $useTable = 'products';
public $displayField = 'name';
public $hasAndBelongsToMany = array(
'Attributes' =>
array(
'className' => 'Attribute',
'joinTable' => 'product_has_attributes',
'foreignKey' => 'products_id',
'associationForeignKey' => 'attributes_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'product_has_attributes'
)
);
public $hasMany = array(
'Ads' => array(
'className' => 'Ad',
'foreignKey' => 'Products_id',
'conditions' => '',
'order' => '',
'limit' => '',
'dependent' => true
)
);
//Ad Model
class Ad extends AppModel {
public $displayField = 'Name';
public $belongsTo = array(
'Product' => array(
'className' => 'Products',
'foreignKey' => 'products_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
//Attribute Model
class Attribute extends AppModel {
public $displayField = 'name';
public $hasAndBelongsToMany = array(
'Products' =>
array(
'className' => 'Product',
'joinTable' => 'product_has_attributes',
'foreignKey' => 'attributes_id',
'associationForeignKey' => 'products_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'with' => 'product_has_attributes'
)
);
// Products controller -> Action View
class ProductsController extends AppController {
public function view($id = null) {
if (!$this->Product->exists($id)) {
throw new NotFoundException(__('Invalid product'));
}
$options = array('conditions' => array('Product.' . $this->Product->primaryKey => $id));
$this->set('product', $this->Product->find('first', $options));
}
}
// Ads controller -> Action View
class AdsController extends AppController {
public function view($id = null) {
if (!$this->Ad->exists($id)) {
throw new NotFoundException(__('Invalid ad'));
}
$options = array('conditions' => array('Ad.' . $this->Ad->primaryKey => $id));
$this->set('ad', $this->Ad->find('first', $options));
}
And here is what I do in the views:
//Products Views: snipet of view.ctp
print_r ($product);
// this prints rhe product and all associated attributes
//Ads Views: snipet of view.ctp
print_r ($ad['Product']);
//this will print only the product fields, but not the attributes associated to the product
What is wrong? How do I access the relation Ad->product->attribute from my Ad model?
I can think of a couple of simple ways to accomplish this.
First:
class AdsController extends AppController {
if (!$this->Ad->exists($id)) {
throw new NotFoundException(__('Invalid ad'));
}
$options = array(
'conditions' => array('Ad.' . $this->Ad->primaryKey => $id),
'recursive' => 1, // or more
);
$this->set('ad', $this->Ad->find('first', $options));
}
That would be the simplest code change to make sure you get attributes that are related to the product that is returned.
Otherwise, you alluded to this in your question. You can access related Models through the model, so:
$this->Ad->Product->find(...);
I have had issues with Cake not liking my find conditions when using related models in conditions, and I'm not sure of the proper syntax, but if you wanted to pursue that, I'm sure you can track it down through the docs or by experimentation.
Finally, I would advise you to check into the ContainableBehavior, which will allow you to fine tune which fields are actually returned in the results. I hope this answers your question!
Perhaps the problem could be that you're not using CakePHP's conventions.
From the docs:
"new join table’s name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ )."
So, your join table should be named attributes_products.
Also, check your foreign keys. They should be in singular form.
attributes_products.id
attributes_products.product_id
attributes_products.attribute_id
Hopefully that solves the problem.
References:
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm
http://book.cakephp.org/2.0/en/getting-started/cakephp-conventions.html#model-and-database-conventions

How to find data through foreign key in cakephp?

Product Plan ProductPlan
id |name id |name id | product_id | plan_id
1 aplha 1 a 1 1 2
2 bravo 2 b
3 charlie
I want to find Product name and Plan name against ProductPlan, if product id and plan id for product exist in ProductPlan then the name of plan and product will show, I tried a lot, the relation b/w tables are correct but i didn't get the exact data, query which i used that is
$p_plan = $this->ProductPlan->find('all',array(
'conditions'=>array(
'ProductPlan.product_id'=>'Product.product_id'
)
)
);
$this->set('p_plan', $p_plan);
if some body help me , i'll very thaksful to him. Thanks in advance.
Relation
For Plan
class Plan extends AppModel{
public $primaryKey='plan_id';
public $hasMany = array(
'ProductPlan'=>array(
'className' => 'ProductPlan',
'foreignKey' => 'plan_id'
)
);
Product
class Product extends AppModel{
public $primaryKey='product_id';
public $hasMany = array(
'ProductsUser'=>array(
'className' => 'ProductsUser',
'foreignKey' => 'product_id'
),
'ProductsUserNode'=>array(
'className' => 'ProductsUserNode',
'foreignKey' => 'product_id'
),
'ProductPlan'=>array(
'className' => 'ProductPlan',
'foreignKey' => 'product_id'
)
);
for Product Plan
class ProductPlan extends AppModel{
var $primaryKey='product_plan_id';
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id'
),
'Plan' => array(
'className' => 'Plan',
'foreignKey' => 'plan_id'
)
);
public $hasMany = array(
'ProductPlansUserNode'=>array(
'className' => 'ProductPlansUserNode',
'foreignKey' => 'product_plan_id'
),
);
}
You should simply be able to use 'contain':-
$p_plan = $this->Product->find('all', array(
'contain' => array('Plan')
));
This will return all your products, with their associated plans. Your Product and Plan models need a hasAndBelongToMany relationship. There is no need to define a model for your joins table.
class Product AppModel {
...
public $hasAndBelongsToMany = array('Plan');
...
}
class Plan AppModel {
...
public $hasAndBelongsToMany = array('Product');
...
}
As a side note I'd personally avoid overriding CakePHP's default way of handling primary keys. It is better to stick with convention and use id.

Using Cakephp, how can I get a multi-select element or checkboxes for a hasMany relationship in my scaffolded add, edit views?

I've run through the Cakephp documentation on linking models together (creating associations), and I can get a single select dropdown in the scaffolded add and edit views by defining a $hasOne member one model and a corresponding $belongsTo in the other. Now, for a $hasMany relationship, I'm trying to get some kind of form input (either a multi-select dropdown, or checkboxes ... preferably checkboxes) in my scaffolded add and edit views that lets the user choose the associated advertisements for a given rental. But with the below code I get no mention of Advertisements in the Rental add and edit views :'( Am I missing something? Is this even possible? I've seen this done in RoR and Grails but can't get it working with CakePHP. Thanks for any help!
Rental model (app/Model/Rental.php)
<?php
class Rental extends AppModel {
var $name = 'Rental';
var $belongsTo = array(
'Agent' => array(
'className' => 'User',
'foreignKey' => 'agent_id'
),
'Bedroom',
'Landlord' => array(
'className' => 'Landlord',
'foreignKey' => 'landlord_id'
)
);
var $hasMany = array(
'Advertisement' => array(
'className' => 'Advertisement',
'foreignKey' => 'rental_id',
//'conditions' => array('Comment.status' => '1'),
'order' => 'Advertisement.created DESC',
'limit' => '5',
'dependent'=> false
)
);
public $validate = array(
'title' => array(
'rule' => 'notEmpty'
),
'description' => array(
'rule' => 'notEmpty'
)
);
public function isOwnedBy($rental, $user) {
return $this->field('id', array('id' => $rental, 'user_id' => $user)) === $rental;
}
}
Rentals Controller (app/Controller/RentalsController.php)
<?php
class RentalsController extends AppController {
public $scaffold;
}
Advertisement model (app/Model/Advertisement.php)
<?php
class Advertisement extends AppModel {
var $name = 'Advertisement';
var $belongsTo = array(
'Rental' => array(
'className' => 'Rental',
'foreignKey' => 'rental_id'
),
'Author' => array(
'className' => 'User',
'foreignKey' => 'author_id'
)
);
}
Advertisements Controller (app/Controller/AdvertiesementsController.php)
<?php
class AdvertisementsController extends AppController {
public $scaffold;
}
Cake's scaffold views don't show anything from the hasMany side of the relationship. They assume you want to pick it from the model that has the belongsTo.
Frankly, doing it as a multi-select is a little odd for this relationship, IMHO. Multi-selects are normally used for hasAndBelongsToMany relationships. If you want to do it, you'll need to do the work yourself, and not use Cake's scaffolding.

Categories