My main model is Post, and it is populated with many different info fields (name, designation, status, created, modified, etc.), one of which is its relationship with the Category model. (Post belongs to Category, Category has many Posts.)
So far everything works as it should. I can save and edit the category_id, and I have an index for each category with each post that belongs to it. Everything is peachy.
Now I require to implement a special extra functionality, but all of my searches for a possible solution have been in vain. I have some ideas, but I don't know how to implement any of those, and I'm not sure what the best practice would be in this case.
What I need is to add a little "Similar/Related posts" module below the post's info in the view view, loading some basic info (name, designation, creation date, etc.) from 3 random posts from the same category as the current post.
I thought I could try a find('all') function in an element (loading the category_id as a variable from the view action).
This is my controller:
class PostsController extends AppController {
public function view($id) {
if (!$id) {
throw new NotFoundException(__('Invalid post.'));
}
$post = $this->Post->findById($id);
if (!$post) {
throw new NotFoundException(__('Post not found.'));
}
$this->set('post', $post);
}
}
In the Post model I have:
class Post extends AppModel {
public $belongsTo = array('Category');
}
And in the Category model I have:
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'category_id',
'dependent' => false
)
);
Currently I only need to load those "related posts" in the view view, but I'm not sure I won't be needing to do so later on. (That's why I'm thinking in an Element for the module.)
Its not good to write query in view, either you can use the helper or you can do it directly in the controller itself, in your controller you can try the below code :
class PostsController extends AppController {
public function view($id) {
if (!$id) {
throw new NotFoundException(__('Invalid post.'));
}
$post = $this->Post->findById($id);
if (!$post) {
throw new NotFoundException(__('Post not found.'));
}
$relatedPosts = $this->Post->find('all', array('conditions' => array('Post.category_id' => $post['Post']['category_id'], 'NOT' => array('Post.id' => $id)), 'limit' => 3));
$this->set('relatedPosts', $relatedPosts);
$this->set('post', $post);
}
}
And then in your view you can check !empty($relatedPosts) and within that you can loop on the $relatedPosts and show whatever fields you want to show.
Related
After setting up the simple Cakephp login concept I would like to let CakePHP use a different table to check the users and the login. I can't figure out how to change the table name within the Auth-component.
Below my basic Controller. How can I let Cakephp know it has to look into a different database table?
class AppController extends Controller {
public $components = array(
'Session',
'Auth'=>array(
'loginRedirect'=>array('controller'=>'users', 'action'=>'index'),
'logoutRedirect'=>array('controller'=>'users', 'action'=>'index'),
'authError'=>"You can't access that page",
'authorize'=>array('Controller')
)
);
public function isAuthorized($user) {
return true;
}
public function beforeFilter() {
//$this->Auth->allow('index', 'view');
$this->set('siteCategory', 'home');
$this->set('logged_in', $this->Auth->loggedIn());
$this->set('current_user', $this->Auth->user());
}
}
Best Solution:
This is something that's done in the User model with the useTable property.
I.e. in app/Model/User.php you should have something like this:
class User extends AppModel {
public $useTable = 'table_name';
//... rest of Model stuff here
}
Alternative:
Alternatively you can specify a different model to be used for the user, although I don't think that's what you're asking for. If I'm wrong there though, just set the userModel value like this:
public $components = array(
'Auth'=>array(
'authenticate'=>array(
'Form' => array('userModel' => 'ADifferentUserModel')
)));
Since a long time as per my knowledge I was using recursive to control my model relationship. If I make any relation between my models it would surely be autoconnected with paginate. To control that I need to use recursive. By default its value is 1 and to contro; that I have to use it as -1 or 0. Yes I read about Containable behaviour that how it automatically control fetching result from other Models Though relationships are made.
I went through same as writing
public $actsAs = array('Containable');
In my controller I wrote
$this->Album->Behaviors->load('Containable', array('autoFields' => false, 'recursive'=>false));
But then also my default paginate called data from other Model as well as fetch queries with other Models.
$this->paginate['Album'] = array('conditions' => $condition, 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
$this->set('albums', $this->paginate('Album'));
My default pagination code as per my expectation data would be only from Album Model and to get from other Model I have to describe it in Pagination but when I checked it in Debug Kit it shows this.
As well as fetch data from all variables.
What should I do ?? Where I am wrong ??
You don’t want the data of related models, correct me if I’m wrong.
For this you need to set contain property to false. This will only bring the data of Album model
$this->paginate['Album'] = array('conditions' => $condition,'contain' => false 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
$this->set('albums', $this->paginate('Album'));
Contain will be helpful when you want to attach multiple model with your query like
$this->paginate['Album'] = array('conditions' => $condition,'contain' => array('model1','model2'), 'limit' => '50', 'order' => array('Album.id' => 'DESC'));
I hope this will work for you. Thanks
Even if your model is set to be containable, you can still set the recursive to false to prevent the fetching of associated data.
Sample model:
<?php
class Article extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array('Category');
}
Sample controller:
<?php
class ArticlesController extends AppController {
public function index() {
$this->Article->recursive = 0;
$this->set('articles', $this->paginate('Article'));
}
public function view($id) {
$this->Article->recursive = 0;
$this->set('article', $this->Article->findById($id));
}
}
i am new to cake and using version 2.
i have models
hgcylinder.php
class HgCylinder extends AppModel {
//put your code here
var $name= "HgCylinder";
var $belongsTo = array('HgKeyGase');
}
hgkeygase.php
class HgKeyGase extends AppModel {
//put your code here
var $name= "HgKeyGase";
public $belongsTo = array(
'HgKeyColor' => array(
'className' => 'HgKeyColor',
'foreignKey' => 'hg_key_color_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
Controller HgCylindersController.php
<?php
class HgCylindersController extends AppController
{
var $name = "HgCylinders";
// var $scaffold;
function index()
{
$this->set('hey',$this->HgCylinder->find('all'));
}
public function edit($id = null) {
$this->HgCylinder->id = $id;
if ($this->request->is('post')) {
var_dump($this->request->data);
exit;
if ($this->HgCylinder->save($this->request->data)) {
$this->Session->setFlash(__('Cylinder has been updated successfull'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The cylinder could not be saved. Please, try again.'));
}
} else {
$this->request->data = $this->HgCylinder->read(null, $id);
}
$hg_key_gase_id = $this->HgCylinder->HgKeyGase->find('list');
$this->set(compact('hg_key_gase_id'));
}
}
?>
View : edit.ctp
<?php
echo $this->form->create('HgCylinder',array('action'=>'edit'));
echo $this->form->input('hg_key_gase_id',);
echo $this->form->input("capacityM3");
echo $this->form->input("weightEmpty");
echo $this->form->input("weightFilled");
echo $this->form->input("isFilled");
echo $this->form->end('Add');
?>
my problem is hg_key_gase_id is become select list with no options. if i changed the name to "hgKeyGas" in view and controller it shows the options from the hg_key_gases table. but on saving does not saving the value of hg_key_gase_id field in hg_cylinders table instead it stores null in this field.
second i want to know that it is necessary to have variable name passing to view from controller exactly same for as field in table.
try to stick to conventions.
so its
$hgKeyGases = $this->HgCylinder->HgKeyGase->find('list');
$this->set(compact('hgKeyGases'));
the pluralized form will be able to populate your select box (as documented in the cook book)
also use $this->Form->input() (note the capital F). $name is not necessary.
dont use read(), use find(first) instead. dont set the action (the form will post to itself by default).
and most importantly. ALWAYS respect the casing of files in your filesystem. especially if you plan on deploying on NIX systems (which are case sensitive).
so it would be HgCylinder.php and HgKeyGase.php as Model class files.
last tip: use baking (cake bake via shell console) to bake your crud files. this way you learn how its done the right way. it would have also answered your question itself by the way.
the documentation can be found here: http://book.cakephp.org/2.0/en/index.html
maybe you found an old outdated version, the 2.x one is the one you should have used.
this is my situation, I have a Post model that can belong to multiple Categories. This I figured out how to do:
class Post extends AppModel
{
var $hasAndBelongsToMany = array('Category');
}
And the Category model:
class Category extends AppModel
{
var $hasAndBelongsToMany = array ('Post');
}
Now, this all works fine and all that. But I just cannot figure out how to search for posts that belong to a certain category, for example "News" with the id of 1 to use in:
class CategoriesController extends AppController {
function view ($id = 0) {
// doesnt work
$this->Category->Video->find ('all', array('conditions' => array('category_id' => $id));
}
}
I've been trying to find an answer on Google and the CookBook but have found nothing yet. Does anyone know how this can be achieved?
Thank you.
You are performing a find on Video model, when you showed association on Category and Post models, not Video. Assuming this is a typo error:
If you want to search, as you stated, posts that are of "News" category do in posts_controller.php:
$this->Post->Category->find('all', array('conditions'=>array('Category.name'=>'News')) );
Or in the categories_controller.php
$this->Category->find('all', array('conditions'=>array('Category.name'=>'News')) );
Your easiest bet would be to search the Category itself, and allow the recursive level to also return associated Posts (or Videos, or whatever you're doing):
//in the category controller
$this->Category->find('all', array('conditions'=>array('Category.id'=>$id));
There are many options for searching against HABTM data, but the above is the easiest.
Here's the page in the CakePHP book that describes different ways to query against a HABTM relationship:
http://book.cakephp.org/1.3/view/1044/hasAndBelongsToMany-HABTM
You can do the following which should work:
$this->Category->bindModel(array(
'hasOne' => array(
'CategoriesVideo'
),
));
return $this->Video->find('all', array(
'conditions' => array(
'CategoriesVideo.category_id' => $id,
),
),
));
EDIT: Sorry, was looking at the wrong code. This should work.
On this page, a user would see a list of links which he himself/herself has posted, not including the rests which were posted by others. I'm in the middle of writing the function in one of my models, e.g. news
I am trying to use the idea of a dashboard: http://nuts-and-bolts-of-cakephp.com/2008/12/16/how-to-build-a-dashboard-for-your-application-in-cakephp/
I created my dashboards controller as:
function index () {
$this->set('news', ClassRegistry::init('News')->showmy());
}
// In my news::model I have a function called showmy()
function showmy() {
$userid = $this->Session->read('Auth.User.id');
$mynews = $this->News->find('all', array('conditions' => array('News.user_id' => '$userid')));
$this->set('mynews', $mynews);
}
//The error I get is as follow
Undefined property: News::$Session [APP\models\news.php, line 7]
Fatal error: Call to a member function read() on a non-object in C:\...\app\models\news.php on line 7
I know something is terribly wrong with the showmy function, can someone shed some light how do we write the function that only retrieves the posts by one user? or if the problems are minor, correct the function above?
Try this
You can't use Session from model so passit from controller
function index () {
$userid = $this->Session->read('Auth.User.id');
$this->set('news', ClassRegistry::init('News')->showmy($userid ));
}
function showmy($userid) {
return $this->find('all', array('conditions' => array('News.user_id' => $userid)));
}
My approach seems to be more documentation-like:
Let say you have PostsController with Post Model. When you do index on posts it's fine, you query for all posts. But for one user, I think you mean single index action in PostsController like:
class Post extends AppModel {
public $belongsTo = 'User'; // This way you're telling cakephp that one user can have many posts (he's posts' author)
}
class PostsController extends AppController {
public function viewByUser() {
$id = $this->Auth->user('id');
$posts = $this->Post->findAllById($id);
$this->set('posts', $posts);
}
}
And then, in your view, you build a table like for index action
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#magic-find-types