CodeIgniter doesn't like methods in views? - php

I'm playing around with CodeIgniter; hoping to convert some of my old, ugly PHP into a more maintainable framework. However, I've come across a rather frustrating roadblock - I can't seem to define methods in my views. Any time I try I get a completely blank page, and when I look in the debug log the processing seemed to stop after the view was loaded. Can I define methods within views? If not, why, and what workarounds would you suggest?
Note: The method has to do with formatting output strings.

Define your functions in a helper and load them from the controller. That way you can reuse the functions in other views, as well.

I'm not familiar with CodeIgnitor, but it could be including your templates multiple times. Try wrapping your function in a check:
if (!function_exists('myfunc'))
{
function myfunc() {}
}
CodeIgnitor is probably swallowing errors, so you could also try flushing buffers immediately before your function:
while(ob_end_flush()){}
error_reporting(E_ALL);
ini_set('display_errors', 1);
In reality though, you should probably make your string formatting code a bit more general. Your template is not really a good place to start adding functions. You'll begin duplicating code, and it defeats the purpose of having templates at all. I'd suggest experimenting with CodeIgnitor's Helpers and Plugins

Views are not meant to call controller actions. Reverse your logic, call that function in the controller and set it to a variable you sent to the view. Then you can have the if statement check that variable in your view template.
If that doesn't work for you, maybe a helper is what you need: http://codeigniter.com/user_guide/general/helpers.html

Related

Static classes and global variables

I'm using FuelPHP 1.6.1 with a lot of static classes, this seems to work out quite nice. Now I have a Menu generator that loads some data
$menu = Menu::generate();
It loads some data and stores this in static::$data
How would I go for another class to load just that? I'm getting null results, probably because I'm doing something wrong, but I dont see what I'm doing wrong at the moment.
Also, yes, the Menu::$data is declared public static $data
Any tips?
Using FuelPHP's Session::set() does the job, but only after a reload, I need the data straight away in other classes, and loading it again results into double queries (which I dont want)
PHP's $_SESSION is not used, nor will be used.
Turns out, in my way of showing views and menu, menu::generate() came after the other classes that needed it, put it at the start and using FuelPHP's Session::set() did the job

How can I populate Zend_Layout variables with backend data?

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.

Beginner CodeIgniter concepts - Reusable view code, where to go? (Helper?)

I am a beginner with CodeIgniter still struggling to get a complete grasp on how to use the MVC ideology most cleanly.
I am writing a basic CMS system with the ability to vote on entries and follow people etc, consequently, I have found myself using the same or similar pieces of code across multiple views here and there consisting of various pieces of html and logic such as:
Voting panel
Follow/Unfollow panel
Login/Logout panel
Code to check if a user is logged in etc...
I am wondering where to put this code so it can be unified? I am thinking a helper is the way to go? If I declare the helper in the controller, it can be called from the corresponding view right?
Some of the elements are dynamic - such as a follow/unfollow button - It would need to check if you are already following the user or not and display the appropriate button, which would require a model to check. What I have now is that all the logic is in the controller and it returns an appropriate button, but it seems weird to be returning formed html code in a controller return as well. Should it be more like:
controller checks if you are following someone
the controller passes a boolean to the view
the view calls the helper with this value to draw the appropriate button
Also, as a secondary question, I have been doing a fair bit of looping through mysql arrays in foreach loops to process mysql results returned from the view. It seems like my views are getting somewhat complicated, but I can't think of another way to do it, although perhaps this should be done in another helper as well?
Apologies if this is a naive or repetitive question, there is indeed a lot of discussion surrounding this subject but it is not always easily relatable to another project.
Helpers are certainly one way to modularize anything that isn't DRY. Another is to use Partial Views. CodeIgniter looks like it supports partial views. Here's a good breakdown - not PHP specific but the discussion should be agnostic.
As far as handling user logins is concerned, you will probably want to use a static class and the singleton design pattern, which will allow you to check to see if a particular user is logged in or not anywhere in your application. There is a good tutorial here
http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login
Loading the helper, I don't believe loading it in your controller will automatically load it in your view. I think you have to re load the helper in your view file, or you have to autoload the helper. (cant remember off top of head but Im pretty sure).
Regarding looping through the mysql results, you should be using a model for this, always. Any functions which are grabbing or sorting information from your applicaiton, should be done within the model. Then, in your view file you loop through the results and format the data how you choose to.
When developing http://newspapair.com which has the vote functionality you mentioned I used helpers and custom classes to spread the functionality across multiple views.
Helper - has functions without a class. So a standalone function or group of functions can be placed in a file and saved as a helper.
For instance I used a helper with generic form processing functions for NewsPapair, instead of a static class. But this is not the "best practices" thing to do. I did it this way because I already had the functions from a previous project.
As far a looping through MySQL results, try to write a query that allows the DB Server to do the heavy lifting. This will make your code more efficient. Perhaps ask a question about a specific query with example code. Plus do all of the data gathering in your Model.

CodeIgniter: invoking multiple controllers in one call

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

Database calls in Smarty/views/templates

Today at work someone tried to convince me that:
{$obj->getTableInfo()}
is fine for smarty/mvc/templating because it is using an objects method. I argued that because it makes a call to the database it has no place being there and it should be in the controller (we don't actually use MVC). Am I right in my understanding of the logical separations that are used in MVC and generally in templating? Or is there something that I am missing?
You're right. He's wrong.
Database calls, no matter in what form, should live in the controller if you want to do MVC right.
Obviously people piss all over what it should be and do stuff like that, but it's not the correct way.
Well, there are no "official" rules or anything, but I think something like that belongs in the controller. I don't do anything in my view code except display variables, nothing more complex than an if or a foreach-type loop is allowed. Certainly not calling functions that access the database. That should all be loaded by the controller, the view should only decide whether it needs to display it or not.
Depends on its context and scope really.
Is $obj the controller or the model layer? That should answer whether or not it is valid in my opinion.
In response to reading the other answers.
The functions name in itself pertains it to being a simple getter method. It may make a call to the db through a controller layer. Which I would say is ok. Especially if it used some form of caching in memory. (ie the getter is the setter as you only want to cache it when it is used once.)

Categories