Can someone please tell me what the best way to pass values from a controller into a view would be? If anyone has played with codeignitor, they will know what I mean. I have looked at CIs code but can't find the file that handles this. I'd LOVE to know how this is done.
Thanks!
There's not necessarily a "best" way as far as I know, but there is a common method that I've seen used many times, and have used myself. It generally involves an associative array, and either the extract() function or variable variables.
Basically, all you do is set up your data into an associative array, using keys that will become your template variables.
//inside the controller
$data['name'] = 'my name';
$data['zip'] = '90210';
The $data array gets passed to the view somehow, either directly or indirectly, and extracted via extract() or using a loop of variable variables (same thing, really). The template can then be included, and the variables are in local scope.
//inside the view rendering process
extract($data);
//$name and $zip now exist
Code Igniter follows this exact procedure. Inside system\libraries\Loader.php in the most recent version (1.7.1) there's a function called view(), which is what you call in your CI controller to load a view/template (same thing really in CI). You pass a data array as the second parameter.
view() calls an internal function called _ci_load() in the same file, which extracts the data you passed it (and does some other wacky caching stuff). Your variables are ready to go after that in the local function scope, and can be manipulated inside the template after the subsequent include(), since everything happening in the included file exists in the local _ci_load() function scope as well.
I've used the exact same design in a quick-and-dirty homebrew MVC set up before. It's quite effective.
You might want to try CakePHP's 15-min blog sample. I haven't tried Code Igniter.
In Zend Framework, it's as simple as
class IndexController {
public function IndexAction {
$this->view->name='Name';
}
}
with the $this->view->xxxx setting the variable in the view.
Related
I undestand that would be considered a bad practice but my purpose is just for study, i wanna undestand if a function "render" with a include inside, can have this include to have access to outside variables or it will lose it anyway, even because that render is already the end of the application so wouldn't make sense to lose access to those variables and it's annoyng to pass it through the method then use a extract.
I tried using global but you need to inform the name of each variable, and wouldn't work on a greater scale.
Edit 1:
I'm adding a little more of informations (sorry it is my first question on stackoverflow)
so the code i was studying was from league/plates i was trying to do what i said above, but i found this snippet of code
public function render($data) {
extract($data);
ob_start();
include $this->path();
$content = ob_get_clean();
if (isset($this->layoutName)) {
$layout = $this->engine->make($this->layoutName);
$layout->sections = array_merge($this->sections, array('content' => $content));
$content = $layout->render($this->layoutData);
}
return $content;
}
So, in this code when the view is included all variables that were created before the call of render (inside a controller for example or anything like that) they can't be accessed from inside the view, of course i could pass then through the variable $data, but imagine if i had lots of variables and called render many times it wouldn't make much sense in my opinion. I thought maybe creating a functional facade of the render method but i don't if it's possible and how it would be done.
I am having problems with some legacy code that I am trying to add to a Yii project.
It has to do with global variables, which I am well aware should instead be passed as parameters, but since this old code and is used in other projects rewriting it is not really and option.
$testVar = '123';
function testOutput() {
global $testVar;
var_dump($testVar);
}
testOutput();
Now if I include this file in a plain php file it works and outputs
string '123' (length=3)
But if I include this file in a Yii controller or even in a template it output this
null
I have tried to search for this issue but I just get a bunch of results about people using global variables incorrectly. I am sure it is not actually a Yii issue but most likely a php_ini setting that Yii is setting, but I can't find anything when searching the code or the Yii docs that would explain this.
This example can be tested by just creating a file with my first code block and then include it into a Yii template or controller. I even tested it with a clean example Yii project.
I hope I didn't hurt my chances of figuring this out by tagging this questiong with Yii since I have a feeling that it is not just a Yii specific issue.
Any insights would be greatly appreciated.
If you do like this, it will work, I just tested with Yii controller
global $testVar;
$testVar = '123';
function testOutput() {
global $testVar;
var_dump($testVar);
}
testOutput();
As DCoder mentioned, if youre declaring them inside a class, function/method then they are not global. You can try assigning them to the $_GLOBALS array though:
$GLOBALS['testVar'] = 123;
However depending on the legacy code and how youre integrating it you may need to change all references in that legacy code to use $GLOBALS['thevar'] instead of $thevar or do an extract($GLOBALS) at the top of some or all of the legacy files.
Googled: Global Variables in Yii
I am passing a variable to a view script from a controller with Zend Framework. I want to know if there is anyway I can pre-filter the view so that I can change how the variable is retrieved in the view script.
For example. In the controller I have:
$this->view->name = 'Bob';
And in the view I have:
echo $this->name;
Which works fine no question! What I want is to occationally have the ability to change it so I can just use:
echo $name;
So basically, removing the $this statement. Is this possible? I am making a template and have other designers using the template system and want to make it easier for them then to type $this->array->name all the time.
I know in the view script I can simply add:
$name = $this->name;
But I would like to do that in the controller somewhere.
Thanks for your advice!
I'll say right up front that I think this is not a good idea to monkey around with the scope of your view's output variables. This works against the framework's MVC pattern by exposing the view's internals all over the global scope. But if you really insist on doing this, in the controller, you can probably assign them globally like this:
$GLOBALS['name'] = $this->view->name;
And access them later as $name or $GLOBALS['name'].
Note: depending on when the view's variables get populated versus when you assign them in the controller, you might need to assign references.
$GLOBALS['name'] = &$this->view->name;
Your idea is reasonable and seems quite easy to achieve. Just add this line to the beginning of your template:
<?php extract(get_object_vars($this)) ?>
Passing state to view by the means of global variables might not be considered a good idea by some, but this way is safe, as extract creates local variables, not global ones.
If you would like to reuse this method and prefer not to copy&paste, you could easily inherit from Zend_View, introduce this line to method (if I recall correctly) _run, and then in your bootstrap:
create an instance of the controller,
get the ViewRenderer action helper (using static method of Zend_Controller_Action_HelperBroker)
inject your view instance into ViewRenderer
This way all your views will present their public properties as variables.
I'm very new to MVC, and so I've been scouring the net in an attempt to build my own framework to get a real understanding on how the whole concept works.
Anyway, almost all tutorials out there that deal with MVC always seem to assign data that needs to be displayed in the view to an intermediary variable that is THEN used in the view.
My question is, why bother with that extra step?
Most MVC implementations end up including the view WITHIN the controller... so if that's the case, why waste time/memory/cpu cycles to create an intermediary variable/array that is then passed to the View when the View ends up being included with the controller at the end.
Would it not make more sense to simply use the Controller variables directly in the View itself?
Here's a code example to hopefully clarify what I mean:
class News_Controller
{
public function main(array $getVars)
{
$newsModel = new News_Model;
//get an article
$article = $newsModel->get_article($getVars['article']);
//create a new view and pass it our template name
$view = new View_Model($this->templateName);
//assign article data to view
$view->assign('title' , $article['title']);
$view->assign('content' , $article['content']);
$view->render();
}
The render function is basically just an include to bring the View into the Controller to be displayed down the chain. If that's what's going on, one could simply use $article directly in the View rather than go through the hassle of assigning variables to the View.
Keep in mind that PHP copies on write. So there is no major performance hit to a simple variable assignment.
As already mentioned, scope is a big issue here. The view is a separate entity from the controller and doesn't have access to its data. Of course, you could pass an instance of the controller to the view, but that's creating an unnecessarily too strict of coupling between the two. The view should be able to work independent of the controller.
So by explicitly assigning data to the view you decouple the two. You will tend to write better and cleaner code as a result.
Second, the process of assigning data to a view could do some data sanitizing or other extra work. For instance, in my framework, I consider all data passed to an HTML view as unsafe. When data is passed to the view (unless explicitly marked as safe) it is encoded via htmlspecialchars.
Finally, you can always assign objects or arrays to the view:
$view->assign('article', $article);
If you do this you generally don't need to assign very much stuff. (And if you do, perhaps your page is doing too many different things.)
MVC is a very loose categorization. You are describing one way it could work. It's also possible that the variables you use in your controller may not be intended to be used as-is within your view. You may have some sort of template processor that takes in data from the controller, alongside a specially marked-up view template, and spits out the result. Or you may be calling functions/methods from within your view that return ready-made markup.
your include inherits everthing from the render() method's variable scope, but the render() method does not inherit anything from the controller's variable scope.
class foo {
public function bar() {
echo $somevar;
}
}
$somevar = 'test';
$foo = new foo();
$foo->bar();
this code will echo nothing and give you a warning that $somevar has not been defined (if your error reporting is set to show warnings). the reason for this is because methods and functions do not inherit the scope of where they were called from.
php.net/manual/en/language.variables.scope.php
php.net/manual/en/language.oop5.visibility.php
Because of the scope the controllers variables are in. Unless you make everything global (really bad idea) your concept won't work.
I am confused about variables scope when calling a view from within a view.
I tested a bit and found:
If the variables are originally passed from a controller, there is no need to do something to pass the variables from a view to a view.
If the variables are declared in a view, I have to explicitly pass the variables from a view to a view. (e.g. : $this->load->view("hoge", $data);)
I find it bit odd about the second case because my understanding was $this->load->view() is codeigniter version of the php include() which doesn't require me to pass variables explicitly.
Can anyone guess/shed a little light on why they did this?
If you look at the Loader library's _ci_load method (which view() calls), around line 639 in the latest version, you'll see this bit of code:
/*
* Extract and cache variables
*
* You can either set variables using the dedicated $this->load_vars()
* function or via the second parameter of this function. We'll merge
* the two types and cache them so that views that are embedded within
* other views can have access to these variables.
*/
if (is_array($_ci_vars))
{
$this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
}
extract($this->_ci_cached_vars);
That's why your variables passed to the view are available automatically in nested views.
But your locally declared variable aren't.. because they aren't passed on to the next view() call.
Note that it merges the variables, so technically, you could just pass to your subview the variable that are changed in the top view, the rest will be inherited automatically.
IMHO though, I think that for the sake of clarity and other potential people reading your code it's best to always pass on explicitly all the variables that your subview will require.. code becomes easier to read/debug.
Note: a side effect of the caching is that if you have 2 subviews, variables passed to the first one will get cached and get automatically passed on to the second view as well.. that can lead to debugging trouble sometimes.