Codeigniter : variables scope when calling a view from within a view. Odd - php

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.

Related

How come it is possible to access variables without $this in the view?

I started working with Zend Framework 2 a short while ago.
In the controller, I am sending variables to view using
return $viewmodel->setVariables(array(
'exampleVariable' => 'exampleValue',
'exampleVariable2' => array(
'variableInArray' => $this->getMacAddress(),
),
));
In the view I was doing:
$exampleVariable = $this->exampleVariable
// and
$exampleVariable2 = $this->exampleVariable2
and then using those variable directly so I don't have to go through $this each time I use them.
I was working on it, and was modified a few stuff, and while I wanted to debug, I removed those two previous lines hoping it would break.
To my surprise, the $exampleVariable and $exampleVariable2 were still available. At first, I thought it was a caching problem, but it turns out all the array keys that are sent to the view with SetVariables() can be accessed as variables.
My question is, how come it is possible to access them without $this?
I am probably gonna be warned about this, but this question if just for curiosity. I won't use the variables directly, as I prefer to create them in the view so I can comment them and add their respective variable types and stuff.
Take a look here
Variables assigned to the view – either via a View Model, Variables container, or simply by passing an array of variables to render()– may be retrieved in three ways:
Explicitly, by retrieving them from the Variables container composed in the PhpRenderer: $this->vars()->varname.
As instance properties of the PhpRenderer instance: $this->varname. (In this situation, instance property access is simply proxying to the composed Variables instance.)
As local PHP variables: $varname. The PhpRenderer extracts the members of the Variables container locally.
The explanation:
The PhpRenderer uses extract function to extract the variables into the function (render) scope. This allows to use $exampleVariable in the template. Further the PhpRenderer uses the magic __get function. So if you call $this->exampleVariable it looks in the data array directly.
If you take a look at the PHPRenderer class, specifically PHPRendered::render()
Zend\View\Renderer\PHPRenderer
You will see how the Views are generated, using extract (http://php.net/extract)
This allows any of the views variables to be accessed locally inside the view / template.

Make a variable accessible in all test methods. PHPUnit

In my test class I want a variable to be accessible from any test method. I know this is possible by initializing it in setUp method or declaring in bootstrap file.
But the issue is that the value of variable is unknown until test starts. It gets generated during a test and then used by subsequent test methods.
Currently I use this value by declaring subsequent methods to depend on the method, which generates the value, and then passing the value using return statement from method generating the value. But I don't think this is proper way as I have to add return statement just to make variable accessible elsewhere.
Is there any standard way to make variable accessible to every method which gets generated dynamically during test method execution?
Follow these steps:
1. Create a public class.
2. Declare the variable as global.
You can reuse the variable in any part of your application.

Changing how variables are retrieved in a Zend Framework view script

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.

MVC: Why bother "sending" data to the View

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.

PHP MVC Questions

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.

Categories