I have two types of data that are similar but different. They have some pieces of presentational code that they share but some that they implement differently.
I was thinking that I would have a factory function in a helper (Tracker is a TrackerHelper) like so;
$this->Tracker->getInstance("boolean"); // Returns a BooleanTrackerHelper
But I'm not sure how to return another helper from within another helper. I don't think I can just do a return new BooleanTrackerHelper() since CakePHP probably has it's own routines it wants to go through, and besides; that would force me to place all the classes in the same file.
There is a function in the manual that allows you to load a helper from within a view ($this->Helpers->load()) but I want to load a helper from another helper.
More generally; What do you do if you don't want to repeat in a bunch of different views that if data is of type A use helper A and if it's of type B use helper B, and where helpers A and B share some pieces of code.
There might be a brighter way of solving this, if so; please feel free to share!
If you simply want to use one helper from within another helper, just include it in the $helpers array where you want to use it:
class TrackerHelper extends AppHelper {
public $helpers = array('BooleanTracker');
public function someMethod() {
// Using the other helper
$this->BooleanTracker->someOtherMethod();
}
}
Related
Sorry for this basic question. The following are the codes presented in my Userscontroller.php
public function register()
{
//Setting some data
$this->User->create();
$this->User->save($this->request->data)
}
public function edit()
{
//Setting some data
$this->User->save($this->request->data)
}
public function admin_add()
{
//Setting some data
$this->User->create();
$this->User->save($this->request->data)
}
public function admin_edit()
{
//Setting some data
$this->User->save($this->request->data)
}
One of my senior reviewed this code and said that the above code not met the CAKEPHP Standard..Business logic need to move to model
like as follows in model
<?php
class User extends AppModel {
//Validation parts
public functions savingData($data =array(), $id=false)
{
if($id == false)
{
$this->create();
}
$this->User->save($data)
}
}?>
And in controllers he is asking to call this savingData function for Create and update options
in MVC, business rules goes to model.
but in your example there is no any business logic so your code is correct to be in controller.
I suggest to use cakephp console to create controller and model and you can get it by yourself.
Usually any method which has validations or save data to other tables or any extra functionality that makes the actions bigger than one page you need to consider it (break the function to smaller functions) and you can put this function base on your need and access into a Model or Component. I can say fat model concept and Component is used for this kind of situation.
I believe that methods shouldn't be more than one page this make the application maintainable for the next developer.
Also any static methods can be inside Utility as a class which can be called from controllers or views ... easily.
Bear in mind that Cake has lots of model behaviours which contained in all models. like beforeSave(), afterSave(), initiate(), before and after delete() ,...
At the end it is entirely up to you how you implement OOP, tidy and maintainable application.
Other example imagine a Car.
All the engine and complected stuff is inside box where you can't see it you can call it Model .
Controller stuff is in front of your hand so you can Controller it. Controller
Hope it helps if any one can add more option to this answer for others to learn.
Generally speaking your boss is correct in that the goal is fat models - skinny controllers. The reason for this is that if at your work they are doing Unit testing ( which I hope they are ) this makes things MUCH easier on you. Testing in the controller is a pain in the rear.
With that being said though the code in your controller is negligible so don't know if what he is asking is "neccessary" exactly, just technically not consistent with current standards ( which will change with time anyway ). Bottom line if you are bothered that he/she made this criticism, try not to be. Things like this are not written in stone and are left up to interpretation for the most part.
I'm writing a variety of Model Tests in CakePHP (PHPUnit)
In TravisCI, I get something like: "Base table or view not found: 1146 Table 'test.events'
In Cake's test runner I get an assertion failure.
The problem I am having is there are methods in my ModelClasses that I am trying to test which call other models with App::uses. For example:
Method on User model:
public function getOtherData() {
App::uses('Event', 'Model');
$this->Event = new Event;
return $this->Event->find('all');
}
And the test:
public function testGetOtherData() {
$result = $this->User->getOtherData();
$this->assertTrue(!empty($result));
}
Note the above example is just that. An example, simplified to show the problem. I understand that the above example has better 'cake' ways of doing it.
Also, I am using defining required fixtures and they work just fine. (I know this by another method in the model which uses a join in the find, instead of App::Uses())
EDIT:
The code when run works, BUT the UnitTest is looking for the other models data (When using App::uses) in the default database, and not the test database. Why doesn't it use the test database? Am I missing something?
LAST NOTE
Using App::uses() and then instantiating the class will work at runtime. But during testing it will fail, as it attempts to use the default database connection, instead of the test database connection.
Per the selected answer, rather than using App::uses, Cakes built in class registry, ClassRegistry::init('Model', true);, you can include a Model from inside another model method.
It's not generally a good idea to instantiate an object in the middle of your functions using the new statement. This is why -- there's no way to block or redirect that call. Also, it's not necessarily easy to get the right parameters to the object's constructor when it's in the middle of another function, so it's best to keep that code separate.
The right way to do this is to use a different method call to get your object. If you use Cake's ClassRegistry::init() to create model objects, they should use the test database.
If you need to create other non-Cake objects, it's best to create them using some other function, e.g. $this->fetchMeOneOThemEventThingies(). Then, during testing, you can mock out that function and have it return something else. Or, you could use some other DI container like pimple, which will take the same role as Cake's ClassRegistry.
If you need a mock model object for testing, be sure to pass the appropriate arguments to the model's constructor as the third parameter to getMock(), or it may use the production database.
i am working on a Cakephp 2.3 ..In my modals i am doing encryption an decryption in these two functions beforeSave and afterFind .. as again and again i have to write this
Security::rijndael($text, Configure::read('constants.crypt_key'), 'encrypt');
so i decided to make a function so i have done this
static public function encrypt($text) {
return Security::rijndael($text, Configure::read('constants.crypt_key'), 'encrypt');
}
static public function decrypt($text) {
return Security::rijndael($text), Configure::read('constants.crypt_key'), 'decrypt');
}
but i want to know where should i write these function.. should it be in app/lib/utility or app/vendors directory and also after suggesting, do tell me how can i access the function in the Model ..how can i import the class in Model..thanks in advance
To use a common function on controller side you have to declare it in 'AppController.php'
While to use function in view files you can mention it in 'AppHelper.php' And for model you can put it in 'Appmodel.php'
It depends where you want to be calling them from. If you're only calling them from your model (which I think makes sense in your case), then you should place them in AppModel.php, which all your models inherit from.
however, having seen your previous question, if you're having to write the encrypt/decrypt function "again and again", then you're probably not designing your app very well.
Really, you should only need to call encrypt once, in your beforeSave, and decrypt once, in your afterFind. If you have to call them in one or two other places... OK. But if you're having to call them all over the place, you're going about things the wrong way.
And also, there should be no need to make it a static function.
I have some "global" functions not directly related to a model that need to be called from different controllers.
Where can i put them and how can they be correctly called from a controller?
It depends on what your functions do. CakePHP has two generic classes: AppController and AppModel. Every controller should extend AppController and every model should extend AppModel so the methods in these to classes should be available to you in every controller.
Another alternative is to package the functions as behaviors and have all models actAs them.
Depending on semantics you may want to choose one over the other options.
I would like to suggest you to create your own helper class if you want to use in views OR create your own component to use in controllers.
And group the related function in a single and give a meaningful name.
Such that you can use it in your any project just by copying them to your project.
Just add those files to your code wherever required by using the global array var $helpers = array('your_helper1','helper2'); and for components you can use var $components = array('your_component1','component2');
it sounds like a behavior to me if the data is model related.
if it is just some general method, use a component instead.
can you be more specific about the methods you want to use globally?
Iv got a method in a model that I want to be executed everytime a page is requested so I think I need to call it from the app_controller but can't seem to get it to work. The model i want to use is called Blacklist and it has a method in it called check_blacklist() which is what I want to run every time a page is requested. Does anyone know how I should do it?
Thanks
Well, one way to do that would be adding:
var $uses = array('Blacklist');
In your AppController class.
Perhaps a better solution is using a CakePHP built-in method called: loadModel, like this:
$this->loadModel('Blacklist');
If you add Blacklist in the $uses array in your AppController, it will be available in all of your controllers, loadModel just loads the Model for a specific task.
Try to avoid using the $uses array as it adds some overhead to all actions, whether or not the model is used in that action.
As Pawel says, you can use $this->loadModel('Blacklist'); It should be located in the action, say view, just before $this->Blacklist->check_blacklist()
e.g.
function view($id)
{
if($id)
{
$this->loadModel('Blacklist');
$this->Blacklist->check_blacklist();
...
}
}
If this is very widely used, I'd probably write the function on app_model.
Edit:
Use of loadModel is covered here: http://book.cakephp.org/view/845/loadModel
$ModelName = ClassRegistry::init('ModelName');
$ModelName->find();
Unfortunately, due to bug #858, your best bet is to avoid using loadModel() in AppController for now, unless you aren't using any plugins (quite possible). The solution I used to replace $uses was along the lines of:
$this->Blacklist = ClassRegistry::init('Blacklist');
$this->Blacklist->check_blacklist();
Note that you should put this in your beforeFilter() or beforeRender() (see the cookbook) - depending on when you want it executed...
If you'd like to use that same code in other sites, or have it fire earlier in the loading chain, you might consider a Component - putting the same code in your Component initialize() function, or startup() function if the point in the load chain is less critical.