Changing how variables are retrieved in a Zend Framework view script - php

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.

Related

How can i make all variables outiside accessible inside a method in PHP

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.

What is the best way to use many different instances of objects insider another PHP class?

I have a class called Page, which loads a PHP file for the current page, containing all the HTML (template file). In my template file, I want to use instances of other objects, that is initialized outside the Page class (ex. User, PDO or other classes). My problem is, how I do this the smartest way.
In my page class i have a method called get_page() which loads my template file (containing all the code for my GUI.
public function get_page() {
// Load theme template
...
$template_file = ABSPATH_THEME . 'tpl.' . $result['template_file'] . '.php';
if(file_exists($template_file)) {
$page = require_once($template_file);
return $page;
}
}
As you see the template file are loaded inside my Page class, and therefore will it not access instances of classes initialized outside my Page class.
I can come up with different solutions:
1) I pass all instances of the different classes to my class Page, when constructing my page. I think this is the right way, but can be very complex if I need 5, 10 or 20 different objects in my design.
2) Find a way to include the template file outside the Page class, but triggered from the get_page() function - have no clue how to do this, and if it is a good solution?
Can you please tell me what is best, and if there are some better ways to do it?
You can just include classes on the top of your php
eg. /CLASSPATH/ClassName.php
And then you can create an entity for that class once and use it everywhere
eg. $entity = new ClassName();
I think your best bet will be to pass them in as arguments, depending on what you need you may want to make them properties.
Edit: This is assuming that by "using instances of other objects" you mean that you need to use objects that have already been instantiated elsewhere.
If by "istances of other classes" you mean other generical objects (you mention PDO and user which are goos examples of this) I would store these in the $_SESSION array (or in $_GLOBAL array, $_SESSION being the best option in most cases).
Then you can access them just by using $_SESSION['PDO']->... and the like
One of the most popular method to handle php application rooting is to implement MVC design patern, or use an MVC Framework. Google 'MVC php' for details, good luck.
Take a look at the functions get_defined_vars and extract. Using these you can export variables from one scope to another.
A silly example could be: A function A transfer locally defined variable to a function B.
function A()
{
$var1 = "1";
$var2 = "2";
// etc
$data = get_defined_vars();
B($data);
}
function B($data)
{
extract($data);
// somescript.php can use $var1, $var2, etc if B is call from A.
require("somescript.php");
}
A();
The best practice is to use a ServiceLocator or an InversionOfControll-Container to retrieve class instances without violation of DI-Principle. For your template file you can create view helper objects to have direct access to other objects.

Laravel: Difference between View::share() and View::composer()

In relation to the question Passing default variables to view, to pass variables available among all views, is there a technical or functional difference between the use of View::composer():
View::composer('*', function($view) {
$thundercats = 'Woooooohh!!';
$view->with('thundercats', $thundercats);
})
in the filters.php file or the use of View::share() in the BaseController.php file:
public function __construct {
$thundercats = 'Woooooohh!!';
View::share('thundercats', $thundercats);
}
I've only recently learned about View::share() and find it exceptionally intruiging although I've already started using the former in another project.
Edit:
My first assumption is that the former is a file (filters.php) while the the latter is a class (BaseController.php). With this in mind, I'm guessing a class is much better? Although, I'm not quite sure why at this point. :)
Technically they are not at all alike. View::share simply sets a variable, while View::composer is a callback function.
Let me explain in greater detail:
View::share is really straight forward it sets a variable which can be used within any of the views, think of it like a global variable.
View::composer registers an event which is called when the view is rendered, don't confuse it with a View::creator which is fired when a view is instantiated.
View::composer / View::creator can both be used as a class which is well documented.
While these give you the ability to pass additional data to a view, they also give you to ability to do a lot of other things, for example they could:
Aid in debugging a view
Log information about views
Be used to create custom caching (probably not a great idea, but possible)
These are just some examples of what could be possible using View::composer and View::creator.
View::composer('*', callback());
Means that the callback will be called for all views (*).
View::share
Means that a variable will be shared with all outputed views.
Because the first is in filters.php, it'll apply for all routes.
The second is in a controller contructor, so it'll apply for all views triggered by this controller.
One last thing: when overriding a constructor, it's a good pratice to allways call the parent constructor with this code:
parent::_construct();

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