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.
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.
I have a method (the function in the controller, am I terming that correctly?) and view that I want to use in every controller on my site. Is there a way to make the method global across all controllers and the view .ctp file generic as well? I'd rather not have to copy-paste it everywhere.
This seems like something that should be obvious, so if I'm just searching for the wrong terms, let me know.
Thanks
Shared/Common Controller Code:
What you've described is a "Component":
Components are packages of logic that are shared between controllers.
If you find yourself wanting to copy and paste things between
controllers, you might consider wrapping some functionality in a
component.
See: http://book.cakephp.org/2.0/en/controllers/components.html
Shared/Common View Code:
As far as the View is concerned, there are a few options. If you want the entire view, you can just specify which view to render: $this->render('TestView/index');
Or, if you want a small chunk of code, you can try an Element.
All together:
If you find yourself creating a lot of the different "parts" (View, Controller/Component, Model/Behavior)...etc, all for the same general purposes (ie cropping a photo), you could think about creating a Plugin.
Side note:
Side note: Usually, I've heard the functions in Controllers referred to as "actions", and the functions in Models called "methods". They're all really methods (a function within a class/object), but - that's how they're commonly referred to.
You can put the method in AppController and make only one view.
You will use $this->render('/myview.ctp');
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 :)
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.
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();