I have a several functions which are quite large, and are only used in one controller function each, and I'm wondering where to put these? They are not displaying any views, but instead crunching some numbers.
If I'm not wrong, there are 4 possible places where i could put these function: in my controller, in a helper, in a library or in a model. But none of these seem appropriate, since I don't want the code to be loaded every time a user uses the controller, and model should be used to do database stuff, and helpers and libraries should contain code that can be used over and over again.
If it is business logic, the best place to put it is in the controller as a private method, then you can call that method from within the controller.
Just as a note, helpers aren't always loaded unless you autoload them or load them in the constructor of your controller. So, as an alternative, you can make these methods of a helper then just load the helper in the controller action you wish to use them. That way they only get loaded when you need them.
CodeIgniter comes with helpers that you probably might not use (doesn't load unless you specify it in the application/config/config.php file) and I don't think its a problem having functions that you only use once stored there (application/helpers ). For example I might use a random password generator once only, but its still there and won't be loaded unless I call it.
$this->load->helper('my_string_generators');
Related
I have a very big AppController. Nearly 75 functions and 130 kilobytes. It seems like that slows my system. Therefore I need to put those functions inside another file, and include that file, when some other controller needs it.
Options are creating a new controller or a new component. I'm trying to make a selection. What would be the advantages or disadvantages?
My points are:
I don't plan to use these functions inside another project. These functions will only be used by this project.
Inside my AppController I use these files, models, components. So they should be accessible by new structure.
App::import('Vendor', 'MyFancyVendor', array('file' => 'MyFancyVendor.php'));
App::uses('CakeEmail', 'Network/Email');
public $uses = array('Mytable1', 'Mytable2', 'Mytable3', 'Mytable4');
public $components = array('Session');
public $helpers = array('Session','Html');
Edit: Although using a huge new controller/component seems like the same with the old structure, difference is: Say it MyController12 and MyController13 doesn't use the methods of these huge functions inside AppController. But because of MyController12 is created from AppController it loads models, components and other things that it doesn't need. If I put of these logic out of my AppController, MyController12 will not load all that logic.
Follow this pattern:
Gather all related functionality in libraries.
Move all the data logic in the models.
Move all the view logic int the views (remember views are not templates)
For whatever else left, create some helpers
This will make your controller thinner. Creating other controllers should be your last chance, considering that you really don't want to use these kind of functionality in any other projects or part of the website.
The number of functions and the size of the files has absolutely no impact on the time code takes to execute.
Example: this has over 50 plugins loaded, 100ish controllers, 84k lines of code and the pages load reasonably fast.
You need to look at the queries being run. I suspect you are using queries with recursive set to 1 or 2. You should use containable at the very least.
Also look at the explain for your selects. If you are using mysql check that, or what ever is similar for your engine.
You can also install debug kit which displays a lot about what is taking time and can be sped up.
From what i can read, maybe its best that you think about dividing your AppController into multiple different files. Without seeing what your AppController it seems like it is assuming a lot of different roles.
Maybe its better to use different controllers for Mytable1, MyTable2, Mytable3, Mytable4, and use Components to share any information between them.
To answer your question, it is to use BOTH, and also to use Libs, and Helpers. Controllers where necessary, and Components where necessary. There's no point in changing your huge AppController into a huge Component. Split your files where you see something in common. Such as a ImageController, or Postcontroller, both however will use the Session Component.
Edit: What about changing the $helpers, $components, and $uses, from the AppController to the Individual controllers? Use relationships so that CakePHP can find the models. And make sure controllers aren't loading extra models / classes, as i doubt a big controller would cause sluggishness ( unless its your code )
After reading a fair few posts on Stack, and also some material recommended to me on line, the MVC pattern is quite open to interpretation, so please don't answer with another explanation. Thanks!
I'm reaching the end of designing my own PHP MVC now, and have two possible ways to move forward with the views.
But first, my controllers are currently quite dumb, not containing any classes and simply call public methods from the suitable models, and render the appropriate view.
Views are included as necessary, so naturally the objects are available to them via the constructors, along with all the methods (inc delete/update etc).
My first option is to get data using something like this in the view
foreach($object->fetchData() as $data)
and then looping through the results. However some people do not agree with this, and have suggested that such methods should be excluded from the view. Instead it has been recommended that I assign this to a variable in the constructor, and then use this variable in the view
//constructor
$fetched_data = $object->fetchData()
// view
foreach($featched_data as $data)
I don't like this very much, as it seams messy and unnecessary.
With all my critical methods being made available to the view, could this be considered a problem?
So here's the question. Do I keep it how it is, and create new methods in the MODEL for rendering data (as above) OR can I create a class in the constructor, extend the model into it, protect the critical functions in the model, and then create my read only public methods in the CONSTRCUTOR?
Thanks!
I would create a class in the constructor. Not only would extending the model be a much safer approach, but it'd also minimize the calling of functions in the views. Am assuming you'll have several views, it's much easier to get access the constructor data than calling method functions each time in each view.
You can add classes to your controllers that will call the method functions and pass the data directly into the views, instead of clustering your constructor or bootstrap.
When trying to adhere to established best practices like avoiding singletons, registry, static properties and base controllers, how I can populate my layout(and partials used by the layout) with data that is only used by the layout and common across all actions?
The typical scenario is menu which is built on variable data, like an database. Keeping separation of concerns in mind, the views/layout should never talk to an backend directly, but rather be told what to contain.
Using a front controller plugin is simply not possible without using the singleton "feature" in Zend_Layout. The plugin only knows the request and response object, neither has access to controllers, views or the layout.
Zend's action helpers have init/preDispatch/postDispatch methods. One can add action helpers to the HelperBroker (ex. using the bootstrap) and these will be executed in the normal application flow.
Using the init-method to inject data into the view is not possible since it's trigged before the controller/view is ready. preDispatch/postDispatch is possible, but not perfect, since these methods are always triggered when executing a controller action.
That means that all uses of the Zend_Controller_Action::_forward() will also execute the preDispatch/postDispatch in all action helpers. This doesn't have any big implications for the code except speed, I really do not want to be setting a view (or an view helper) variable several times. One can code around this issue using some sort of $firstRun variable, but I really don't want to track this in my own code.
Another method is doing this in the bootstrap, but in my opinion it really does not belong there.
So, how can I populate my layout/view helper with data from the database, doing it only once and still keep a good separation of concerns?
I've followed the ActionHelper approach, setting the view variables on the preDispatch method. It was the most logical place, in my opinion. In addition, my projects weren't using Zend_Controller_Action::_forward(), so I didn't have any speed concerns about multiple triggering of the helper.
Hope that helps,
You could go with Action Helpers as stated in this answer (take a look at the question too, its pretty much similar to yours)
I'd use action helpers too. Just fill the view variables and display them using plain PHP/partials/render/viewHelper (depending on complexity).
Your problem with multiple runs using preDispatch could be solved using
if (!($this->view->myVar)) { // or array_key_exist or isset - depending on your use case
$this->view->myVar = $someModel->getSomeData();
}
Which is just fine IMO.
I am solving a kind of architectural problem inside CI.
I need to be able to instantiate other controllers and their methods in main controller.
E.g.
*main.php/function index():*
$controller2 = new Controller2();
$data['pre_loaded_data'] = $controller2 ->ajax_get_some_view(array('static'=>true));
The goal behind this approach is to build ajax application which loads some screen parts
statically at first load, as part of main html page, but later these parts are updated with ajax methods to from various other controllers(at this time with array('static'=>false) param), e.g as reponse to onclick event on main page.
The problem is that CI doens't seem to be design to support multiple controllers and throws various loader-related errors reporting that some class is not loaded even when it's loaded.
What would be the best approach to pre-load data from other controllers in the main controller?
You might want to make base classes that controllers will inherit. You can also consider trying with HMVC by using Modular Extensions.
Here's a great read on base classes by Phil Sturgeon and how to implement them.
Try putting functions like get_some_data() on a library, then you'll be able to include and call them from every controller and every function without problems, sending the results formatted in a partial view (static case) or back to the browser after an ajax call.
Always remember to deal with data only on models and libraries. This way you'll not have to worry about conficting controllers.
// main/index
$this->load->library('your_library');
$data['foo'] = $this->your_library->get_foo();
// controller2/get_some_ajax_data
$this->load->library('your_library');
echo $this->your_library->get_foo() || '';
I've been using the CodeIgniter framework for PHP and am enjoying it, but I notice that it seems to require a controller for every view. I'm wondering if there is a way to call a specific model from the view itself, rather than route through a controller. I understand that use of a controller is best practice in most cases, especially where the data from the model needs to be modified in some way, but I have cases where I just need to do a strict data pull to the view (which is loaded via ajax), and setting up a controller for that seems superfluous.
Any thoughts? Thanks in advance!
You're fundamentally misunderstanding MVC, at least as implemented in CI.
All URLs on your site (at least those that utilize the CI framework) are mapped to functions (methods) within controllers.
http://myCIsite.com/controller/method[/var1][/var2]...
It doesn't matter whether the URL is accessed via regular HTTP or via AJAX. This is always a one to one mapping. Because of this, you should think of the controller/method combination as the "web page". Do not think of the view as the web page.
Models and views are subordinate to controllers. The controller delegates specific responsibilities to them - database interaction for models, and page output to views.
Because models and views only serve to perform delegated responsibilities, their use is not required in any given controller/method. Help pages, for example, generally have no need to interact with a database, so there is no model utilized by the controller/method combination that serves a given help page. Likewise, form handlers frequently redirect to another page upon completion of processing. As such, there is no view corresponding to the form handler (but there is (likely) a view called from the controller/method in the redirected to page).
Furthermore, models and views do not necessarily correspond on a one to one basis with individual controllers/methods. Any given model can be loaded and used from within several controllers. Similarly, a controller could have a single monolithic view that is used by all methods, or each method could be assigned its own view. (Or, as I just said, a given controller/method could utilize no view at all.)
Finally, CI does not enforce strict MVC separation. You can interact with the database and echo HTML all from within the controller and CI will not complain. Nevertheless, this separation and delegation of responsibility is followed because logically separating the responsibilities makes the code easier to read and helps you follow the DRY principle in your coding.
The fundamental Understanding is that the "web page" corresponds to the controller/method. The view and model, when used, handle delegated responsibilities for the controller/method.
I'm wondering if there is a way to
call a specific model from the view
itself, rather than route through a
controller.
That's not possible as of what I know, the main abstract class of the CI controller imposes restriction to use a controller otherwise you will get a fatal error.
And actually what you say will break the best practice of MVC design pattern. You got to go to model through a controller not view.
I'm a bit confused as to exactly what you're trying to achieve. The controller's value, aside from just being a clean way to handle incoming requests, is to manage the interaction between the models and the views and to determine which views to load. It's also entirely reasonable to load model data directly from your views, but how did you get to your view in the first place?
I guess I'm just having a hard time seeing the context here..
To run a query via Ajax you still need to provide a URL / path in the javascript call. You can not get around the fact that a controller function has to "catch" this call; you can not map a url directly to a model. All you need is 3-4 lines of code in your controller.
Via URI routing you can map a URL to a different controller, so you don't "require a controller for every view". I always create a controller called "ajax" to handle those requests.
A basic ajax call with jquery can be something like this
$('#prod_img').load( "http://domain.com/ajax/get_img", {'color': 'blue', 'url_title': 'bla' } )
You can echo stuff in your controller, so rather than trying to bypass the controller you should be looking into how to do away with the views. This will actually be easy, you can load the db class in the controller just as you can in a model.
But if you really don't want to use MVC perhaps Codeigniter is not the framework for you.
You should read more into the principles of MVC.
Views are strictly for presentation of data, the model shouldn't communicate with views directly.
But still if that's what you want then just pass $this->db from the controller to the view and use it in the view.
Then again, this is NOT a good practice.