cakephp calling different controllers in one view? - cakephp

I can't seem to find a method to call different controller in the same view. The closest thing I've found is $html->link("Register User",array('controller' => 'users', 'action'=>'register')).
So I did the cakephp's blog tutorial. I have a posts_controller.php, and now I want to add in a star rating system. I googled some stuff and got this nifty-already-been-done rating system you can download: http://www.reversefolds.com/articles/show/rating2
Now I have two controllers, rating_controller.php and post_controller.php.
My base route, '/', is pointing to post controller's index action. My post's view.ctp is showing one blog entry, I want to add in the rating system within this view. And to use the rating I need to call the helper like so:
echo $rfRating->ratingBar($ratingInfo);
When I do this in post's view.ctp file. It complains. I've tried messing around with var $helpers = array('blah') but it didn't work, I just end up merging the rating controller in the post_controller, which I think is stupid. I can use the rating system for other stuff too.
So... I don't know what to do. Actually that's a lie, I think I two idea how to tackle this. But I need critiques and other solutions that my google skills have failed.
Should I just implement the whole rating system into the app_controller.php instead? So that every controller inherit this rating system? Sounds stupid because I don't think my user registration needs the rating system.
I've googled up another solution, requestAction('blab'). I think what this enable me to do is... to call another controller within a controller. But this is frown upon cause it kills performance. And I don't exactly know how to do this haha or if it works. I call the rating controller but what about its helper function? Maybe it'll recognize it if I add a var $helpers = array('rating');
Anyway, thank you all in advance for taking the time to read this. Please point me in the right direction.

Have the ratings_controller extend the posts_controller.
This gives you the ability to selectively decide which pages need the ratings module.

Related

Cakephp: How to re-use code in different controller

I have some controller, It use same code idea, only different when call model
ex:
In bookscontroller:
public function abc(){ $this->Book->find(....); }
In categoriescontroller:
public function abc(){ $this->Category->find(....); }
I think it too waste. So, please teach me how to write only one function, but it can call in any controller and load same model.
Thank a lot :)
If you think you need to DRY (dont repeat yourself) that, use components.
They can share code between controllers.
In your case you might also want to look into the crud plugin which takes basic CRUD one step further.
I think it too waste. So, please teach me how to write only one
function, but it can call in any controller and load same model.
You answered half of your question already: DON'T put the code in a controller. Everything related to data manipulating and fetching should go into a model, not a controller.
Assuming you are in your books controller and book belongs to category you can simply call from there:
$this->set('someCategoryData', $this->Book->Category->yourCustomMethod());
$this->set('categories', $this->Book->Category->find('list'));
Need a book from the categories controller?
$this->set('book', $this->Category->Book->view($bookId));
You should fetch the data through the associations and have model methods for your data retrival and manipulation tasks.
A component that calls 1000 models with the logic inside the component is clearly the wrong approach. Read about SoC.

Cakephp how should you manage controllers and views

I am completely new to CakePHP, therefore I am fairly confused on how the management of different controls/views/elements works.
The Problem:
I am attempting to create my home page, which has PageController and view home.ctp. Now, I have another controller, IdeaController, which contains function to load all the ideas from the DB.
public function index() {
$this->set('title_for_layout', 'Ideas');
$this->set('ideas', $this->Idea->find('all'));
}
Now, I need to access this Idea Controller from multiple(up to 3) different views. What is the best way to go about doing so?
Thank-you
You're going the other way around...
Views don't "have access" to the controller. The controller receives a request, tells the models what info it need from them, and passes all necessary data to the views. Views are like little dolls you can put clothes on, but nothing more, they don't speak or play or ask random questions to you.
Generally speaking, there's just one view per action in a controller. If you need to "access" the controller from different views, you may be a little confused with cake.
Without knowing the exact reason you need to do this, I'm going to assume you want to "access" the controller from 3 different views only to get all ideas from the BD. If that's the case, the standard way is:
1) Create a function in the appropriate model:
//Idea Model
public function getAll() {
return $this->Idea->find('all');
}
Well, you don't actually need to do that function, since it's so simple, but for more complex cases where you want to get only the ideas of the logged in user and in a certain order, encapsulating that in the model is a mentally-sane way to go.
2) In every action in the controller that the view will need that data, you do
public function randomAction() {
$this->set('ideas', $this->Idea->getAll());
}
3) In every view you receive the data as
pr($ideas);
And that's it.
The views never "access" the controller, so your question turns out to be a bit confusing. Maybe you meant having 3 views associated to the same action, but there's little reason to do that also... Or maybe you meant to have a "view" in a lot of other "views", like the "info" bar on stackoverflow, that repeats everywhere so you need to have it in a lot of views. If that was the case, then you have to do that in an element to reutilize that "view"-code inside other views.
If you clarify a little more what you want, I can probably answer a lot better, but I hope at least I gave you some direction on where to look or how to go about what you want to do.
Each View has to have it's own method in the Controller.
Say, if you want an ideas/index, ideas/view/x and ideas/add pages, you need to create the following methods:
class IdeasController extends AppController
{
public function index()
{
/* index stuff */
}
public function view($id)
{
/* view stuff */
}
public function add()
{
/* add stuff */
}
}
For the sake of understanding the framework, is advisible to do the blog tutorial, as you after that will be very familiar with the core concepts: http://book.cakephp.org/2.0/en/getting-started.html#blog-tutorial
Good luck!

Data logic on load using a component - cakePHP

I have a project I'm developing which includes articles that can be commented on (comments stored in separate table of course). I want to perform pre logic on a field from each comment, wherever they are loaded through-out the app. The data logic I want to performed is from a custom written component.
The logical place to me that this could be achieved globally is from the comment model, but I could be wrong.
I'm not even 100% if I can use a component from a model, but I've been trying to do this logic using the afterFind() call-back function:
function afterFind($results) {
foreach ($results as $key => $val) {
if (isset($val['Comment']['created'])) {
$results[$key]['Comment']['created'] = $this->Dateconvert->howLongAgo($val['Comment']['created']);;
}
}
return $results;
}
I have tried echoing from inside this function and it doesn't actually seem to be getting called but searching hasn't revealed any functions that do, but I believe afterFind() is best to illustrate what I'm trying to achieve.
So I am looking for a solution where I can performed the post-load logic on articles comments, whether they are being loaded from other controllers with associations to comments or in the comments controller. Basically a global one hit solution :D
cakephp indicates that components are for controllers and behaviours for models and helpers for view...
knowing that first, you may also know that you can use any part of it wherever you want because cake still php, though is not recomended... if is a library of functions you may want to put it inside the libs folders and access it from there.
how, easy use App::import('component', 'nameComponent'); component can be lib, controller, etc..
Having said that, afterFind is a good place to do after load things, remember that this function is call ONLY when a find is used, if you use, any other like query or save or update it won't be called.
hope this helps you :)

Loading CakePHP Helpers

This is a multi part question.
Background:
I'm building my first site using CakePHP, and I like it so far. I've got a DB setup, initial data loaded, and a few models, views, and controllers to interface with the data.
I've created a globally accessible function to create Add/Edit/Delete type image links in various areas. It will be used across multiple views, so I need it accessible, essentially, everywhere. The function is defined in /app/config/bootstrap.php. I was hoping to use the HTML Helper's $html->image() and $html->link() methods to facilitate this, but they're not available in bootstrap.php and I'm not sure how to load/access the HTML Helper where I've defined my function.
Questions:
1) Is this a reasonable/idiomatic place to define a function of this sort?
2) If this isn't the correct place to define the function, where should I define it?
3) If this is the correct place to define the function, how can I go about loading various CakePHP helpers?
Again, I am new to CakePHP, so please let me know if my question is unclear, and forgive my ignorance. I've read/searched through a fair amount of the CakePHP documentation and while I can find plenty of references to loading helpers within Controllers via App::import(...); or $helpers = array(...);, I do not seem to have access to the App object and the $helpers member is specific to the AppController class, I assume. I assume I'm going about this incorrectly, so please help me understand the Cake way of accomplishing this.
No, that is not the correct place for such a function (or more accurately, it goes against the MVC paradigm). A better approach would be to create your own helper for the function. Depending on the complexity of the links you could also use elements.
As a rule of thumb only functions that are completely independent of anything else in the app should be in bootstrap.php, and even most of those would often be better somewhere else.

Is using the RequestHandlerComponent in a model possible?

I'm new to PHP and decided to use the cakePHP framework to help me get started.
I can't figure out one thing though, I want to call methods on the RequestHandlerComponent class to update a users last used IP address and other information, I figured the best place to put this would be in the beforeSave() method on the User model.
I can't figure out how to call the getClientIP method though.
The normal code that would otherwise go in the controller doesn't work. Is there another way to call this class if you're in the model and not the controller?
Class Level:
var $components = array('RequestHandler');
And in the function:
$this->data['User']['lastActiveIP'] = $this->RequestHandler->getClientIP();
Gives:
Undefined property: User::$RequestHandler
Call to a member function getClientIP() on a non-object
Components, by design, aren't available to models (without bypassing MVC convention - which you can do, of course). If you chose to force it to be available, look into ClassRegistry::init(). A better solution, I think, would be to employ the RequestHandler component in your controller (where it's meant to be used), set the lastActiveIp value in the controller (exactly as you've shown in your own example code) and pass the entire data array along to the model.
Now your component is being used where it should be and the model gets to remain ignorant about where it gets its data. At the risk of oversimplification, all the model should know is what to do with the data once it arrives; let the controller worry about collecting and packaging the data.
In addition to Rob's answer, maybe it's enough to put a bit of code together yourself that uses the general env('REMOTE_ADDR') or similar variables. Look at the RequestHandler code, it's not doing anything terrifically complicated.
You may even be able to call the component statically, which is slightly better than instantiating it in the model (still in violation of MVC though). Untested, but should work:
App::import('Component', 'RequestHandler');
RequestHandlerComponent::getClientIp();

Resources