There were issues that some controllers are using DboSource methods and I added the
App::uses('DboSource', 'Model/DboSource');
line to the class file of some base controllers from which other controllers are inherited. However, I wonder whether there is a way in Cake to make sure that a class is loaded by every controller. My current solution works, I just intend to improve it. Is this possible? Thanks!
You can add this to your app/Config/bootstrap.php file and it will be loaded on every request.
Related
I have a custom plugin called "MyApps". In MyApps I have Lib/MyCustomHelper.php.
I'm trying to access MyCustomHelper from a model function. I have no problem accessing in a controller.
In a controller, I would do this:
App::uses('MyCustomHelper', 'MyApps.Lib');
And then I could use it like this:
$myhelper = new MyCustomHelper();
Can anyone tell me how I can accomplish the same thing, but in a model class?
I could copy the whole text from my answer to this question How to load a component in console/shell and just replace component with helper. The answer would be the same, so please read it.
If you want to - and your text sounds like you already do - use helpers inside a controller you have a fundamental misunderstanding of how MVC works. They're not used inside a model nor a controller. They're supposed to work only inside the view layer.
If you can't get your current code to work without misusing the helper in the wrong context, your application architecture is already broken by design and you're on your way to create a pretty messy code base. You should fix your understanding of the MVC design pattern and then refactor the code.
This is for CakePHP 3.0
I want to encapsulate some nontrivial php logic to be called (reused) several times within one .ctp file for one controller action. I'm trying to figure out the most elegant way of doing it.
I have a few thoughts, none of which seem very elegant:
$this in the CTP file execution context is class View. Put methods on the View class to call as $this->function() within the .ctp file. This seems like the wrong division of labor, especially since helpers seem designed for this. Plus the functions would be exposed to all ctp files.
Create a helper. This seems like the "best" way to go, but that helper is always loaded and exposed to all .ctp files, which seems like it violates containment since the logic is only relevant to one action's view. In the absence of a better solution, this is the route I'm taking.
Create a subclass of View for this element/model and put the logic there, to be accessed as in (1). This seems like the most elegant solution, but it appears that subclassing View is intended for alternate media (eg PDF), and I can't see how to direct Cake to use that class when manufacturing the view for a given controller's action.
Shove the function inline in the .ctp file. I'm not even sure if this will work correctly, and it seems ugly to put functions in a .ctp file.
Any advice?
Well, you're not explaining what kind of super complex logic you want to use there so I would say go for 3). It is very well possible, you can load helpers in a view files:
$this->loadHelper('MyFancyLogic');
You can also checkout view cells. But again, you're not explaining what problem exactly you try to solve it's hard to recommend anything specific. So I would say it's a helper or a view cell.
I have an admin controller that I would like to utilize functions in other controllers (these functions do not represent pages that someone would load in their browser), but it cannot utilize those functions because the functions in the other controllers are private. They are private because I don't want the public to access them. Is there a way to make a controller function not accesible to the public without making the function private or protected?
public function __blah(){
// function that can't be accessed from outside, but can be called from other functions
}
Based on what I've read in the comment of the answer Piotr gave you:
You don't use an admin controller. You want to use admin prefixes:
http://book.cakephp.org/view/950/Prefix-Routing
And authentication:
http://book.cakephp.org/view/1250/Authentication
If you call - and thats how your comment sounds like - one controller from another you're doing something totally wrong in an MVC framework. If it should be re-usable code it should go into components if it's about admin action use the prefix routing and admin_* methods, auth component and protected methods for what you call "helper" methods.
Yes.
You have a lot of information in the CakePHP Book about ACL (access control list) and that is exactly what you're looking for.
Or you may use Auth component.
I see three possible solutions (they can also be combined):
The first solution is to move the code you want to reuse to components (as mentioned by burzum).
The second solution depends on your code. It's possible that you do stuff in the controller which should be done in the model. In this case, move the respective code to the model.
The third solution is to put the code you want to reuse into plain old PHP classes and load them as vendor files.
We had an outsourced engineer work on a quick feature DELETING items listed in our database. He says that the code is difficult because the "controller" is missing. Is there a pre-loaded controller for every function like that in cake, or is it weird that he is expecting a controller to be there for a feature we didn't have yet.
There is a generic AppController, but that's more of an abstract class in practice (you generally derive your other controllers from that).
It's not that weird at all that he's expecting a controller -- after all, you won't be able to call methods in the models (which is how I'm guessing you're doing delete) unless you have a point of control to call them from. In this case, the point of control is the controller.
So you can just create a controller. Here's a template to start from:
class SomeController extends AppController {
function delete() {
$this->Some->delete();
}
}
Then access /somes/delete (remember, URLs are generally /controller/action).
Now, he could be talking about the Cake Bake CLI app. That will take your DB tables, and walk you through an initial basic setup for your app. Generally it creates a basic skeleton for CRUD actions.
Either way, you need to create a controller (manually, or via Bake).
When you use the Cake bake function, it'll create all the controllers for you. When you don't use it, you'll need to create them manually. It makes no sense to make all the controllers at the begin, just make them when you really gonna write them would be good.
If you do not have a controller in CakePHP when you visit a page (http://www.youraddress.com/Newfeature) you receive a missing controller error:
Error: NewfeatureController could not be found.
Error: Create the class NewfeatureController below in file: app\controllers\newfeature_controller.php
You cannot get or delete data from the database without controllers - Understanding Model-View-Controller. You do not need the controller only for static pages in CakePHP.
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();