should we forcefully unload a model loaded via loadModel() - cakephp

Is there a function like unloadModel in cakePHP that should be called to unload a model that was loaded using loadModel() function?
I found an unload method,
http://api20.cakephp.org/file/Cake/Model/BehaviorCollection.php#method-BehaviorCollectionunload
But it seems to be used for Behavior. Im new to cake. Is there a function like that or does it get automatically unloaded when the called action loses scope?
One more doubt; is using loadModel against MVC's normal conventions? Does it have any adverse effects?

You do not need to unload your model. If you're going to use the model throughout the entire Controller, then use the $uses variable:
public $uses = array('MyModel', 'AnotherModel');
If you're going to just use it in a specific action(s), use loadModel:
$this->loadModel('MyModel');
That's it - no unloading necessary.
And no, it's not against MVC imo and I have seen no adverse effects.
It's VERY common to load a model. Example - most of my projects require a few "homepages" that have greatly-varying data from nearly ever model. In that case, I create a "DashboardsController", which doesn't even have a table - then I load each model when I need to access it's data. (Or with $uses if I'm going to use it's data in all the actions).

no, behaviors and models are two different things.
behaviors add functionality through hooks. Meaning: they alter the way other methods in models work. So if you want to geocode your data automatically, you use a geocoder behavior. Or if you want your results to be decrypted upon find, you add the decrypt behavior.
So there you NEED the option to detach/unload behaviors because you might not want this functionality there at some point.
Models are just access to the database or provide wrapper methods. They don't have to be removed in order for the rest of the site to function as they do not alter the way other methods work.
loadModel is just a way to dynamically load models that are not automatically related. its totally fine to do that from controller actions where you need those models.

Related

What's the preferred way to go about using backbone with non-crud resources?

New to backbone/marionette, but I believe that I understand how to use backbone when dealing with CRUD/REST; however, consider something like results from a search query. How should one model this? Of course the results likely relate to some model(s), but they are not meant to be tied to said model(s).
Part of me thinks that I should use a collection using a model that doesn't actually sync with a data store through the server, but instead just exists as a means of a modeling a search result object.
Another solution could be to have a collection with no models and just override parse.
I assume that the former is preferred, but again I have no experience with the framework. If there's an alternative/better solution than those listed above, please advise.
I prefer having one object which is responsible for both request and response parsing. It can parse the response to appropriate models and nothing more. I mean - if some of those parsed models are required somewhere in your page, there is something that keeps reference to this wrapper object and takes models from response it requires via wrapper methods.
Another option is to have Radio (https://github.com/marionettejs/backbone.radio) in this wrapper - you will not have to keep wrapper object in different places but call for data via Radio.

CakePHP multiple controllers using same method

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');

Modify contained models at runtime

I'm in the process of building a plugin that includes a behavior and several related models. My goal is to make this as easy as possible for the developer using the behavior. My perfect world has the dev simply attaching the behavior to any relevant models and configuring it.
The behavior interacts directly with one of the models and a hasOne association is being created on the fly, but the other models contain supporting data that is important. What I'd like to do is to have that model pull in its related data by modifying the Containable models.
In short:
MyModel (which actsAs the behavior) gets bound to top level model during the behavior's setup method.
The supporting models are directly associated to the top level model
In MyBehavior::beforeFind, I'd like to ensure that supporting model data is returned without the user having to know to ask for it when calling MyModel::find( ... ).
I haven't found the right keys that will allow me to modify these things at runtime. Maybe it's not even possible given that I want to essentially interact with another behavior (Containable).
Any thoughts would be appreciated.
This code automatically adds some contains to the find before it is run, you just have to make sure that your behavior is attached before the containable behavior or it will not work. The beforeFind callback for a behavior is only run once, so once containable has been called adding something like this does nothing. Took me a while to get it going because of that.
https://github.com/infinitas/infinitas/blob/dev/core/contents/models/behaviors/contentable.php#L65

What is the best way to access another CakePHP's Model in a Controller?

Say I got two Controllers like this Table1sController, and Table2sController.
With corresponding models: Table1sModel, Table2sModel.
In the Table1sController, I got this:
$this->Table1sModel->action();
Say I want to access some data in Table2sModel.
How is it possible to do something like this in Table1sController?
I have tried this in Table1sController:
$this->Table2sModel->action();
But I received an error message like this:
Undefined property: Table1sController::$Table2sModel
There are a few ways to go here.
If your models have defined associations (hasMany, etc.), then you can access that model's methods (assuming you're in Model1Controller) with:
$this->Model1->Model2->method();
If there is no model association between the two models, but you want to be able to use the Model2's methods, you can add an entry in the $uses attribute of model1Controller. See http://book.cakephp.org/2.0/en/controllers.html#components-helpers-and-uses
Finally, if it's a transitory connection (you don't want the overhead of loading other models every time, because you're only rarely going to access model2), check out the manual's section on creating / destroying associations on the fly, at http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Something is inherently wrong with what you are doing.
In any controller, you can specify $uses = array('Table1sModel', 'Table2sModel', 'LolModel') and use each Model you need in your controller. You are not calling another controller to access a Model. Models are for data access, you access the needed ones directly from any controller.
I understand, that many MVC examples are almost always show you one page of one controller with one model which is horribly wrong as 99% of the cases you have one site from one controller using many different parts of different models.
(If you really need to call an action, use $this-requestAction())

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