I have a view class with a function to build the view
class view {
//...
public function build() {
$view = $this;
$data = $this->resources->data;
function s($value) {
return \classes\tools\html\html::specialChars($value);
}
require $this->viewFile;
}
//...
}
And a view some view files
<?php var_dump($view);
// works fine, variables passed ok ?>
<?= s($data->someUnsafeString) ?>
<?php //Fatal error: Call to undefined function s() ?>
I could define the function s In each view file but I really dont want to have to do that.
I could pass the function as a variable $s=function(){..} but I'd prefer not too
I could call the static function in the view directly but even that is more long winded than I'd like:
<?= html::s($data->someUnsafeString) ?>
Is this possible? or any other suggestions?
If your project has a Front Controller (one file - entry point),
then you can to declare your function in common namespace in this or required(#require) by this file.
Common namespace is code without namespace or
namespace {
function s() {
}
}
You may be misunderstanding what you're doing there. Functions aren't scoped in PHP. Your function s(..) inside view::build is merely declaring a regular global function. Doing that inside functions isn't anything special. You can simply declare functions conditionally in PHP, e.g.:
if (!function_exists('s')) {
function s(..) ..
}
So just put that function declaration into a separate file and include it as needed; no need to define it again and again separately in each file.
Related
Is it possible to use a classes methods without actually calling the class into a variable. I am sure i have seen this somewhere but i'm not sure if i was dreaming.
Take this example:
<?php
namespace proj;
class beer{
public function whichIsBest(){
return 'Not cheap stuff';
}
}
Include the file start the class but then how can i get to the whishIsBest method without calling the class into a variable first.
<?php
include 'beerClass.php';
new \proj\beer();
echo \proj\beer()->whichIsBest
Or is this just not possible and I was actually dreaming?
http://www.php.net/manual/en/language.oop5.static.php
class beer {
public static function whichIsBest() {
do //
}
}
..
echo beer::whichIsBest();
I have two functions loadView() and render() in my view class.
public function loadView($view){
if(file_exists(APP.'view/'.$view)){
require(APP.'view/'.$view);
}
else{
die(APP.'view/'.$view.' not found.');
}
}
public function render($view,$data = array()){
if(!empty($data)){
extract($data);
ob_start();
//$this->loadView($view); -------------- not woriking
require(APP.'view/'.$view); ------ working
$this->output = ob_get_clean();
echo $this->output;
}
}
Whenever I call the loadview function from the render its not working. But if I include the view file directly after extracting data, it works. Anybody can tell me Why is this happening here or any solution ?
This will not work, because require() includes the required code in the place of the require() statement and in the scope of that location. In this case, the scope is the loadView() method. Within that method scope the extracted variables from the render() method are not available.
Instead of finding a solution for that, I would encourage you to use a template engine for your views like Twig. This is standard practice in MVC frameworks. Then, you could do something like this:
public function render($view,$data = array()){
$template = $twig->loadTemplate($view);
echo $template->render($data);
}
I have a unique situation that is hard to debug.
I need to set a global string inside a php class that is not strictly defined as a global, the class must be in another file.
The file.php with the string has simply this:
//this cannot be changed
$foo_version = '1.1.1';
The example.php file trying to access this string must use a class:
class Bar extends Task {
public function main() {
require_once('../file.php');
//global $foo_version; this doesn't work
// update the database with this string, does not work
update_option( 'db_field', $foo_version );
}
}
How can I get the $foo_version to return something inside the class?
Also nothing can be defined/done outside the class.
If you include the file, and the variable is in the include file, you can just use it.
class Bar extends Task
{
public function main() {
require_once('../file.php');
update_option( 'db_field', $foo_version );
}
}
What you have is a variable $foo_version and it can easily be changed. You can use define to make it a constant instead see PHP DOC
define("FOO_VERSION", "1.1.1");
class Bar extends Task {
public function main() {
require_once ('../file.php');
update_option('db_field', FOO_VERSION);
}
}
If you insist Replace require_once with require your code would work because PHP will check if the file has already been included, and if so, not include (require) it again.
If you have used this in another class definitely it would not work. Change your code to the following
class Bar extends Task {
public function main() {
require ('../file.php');
update_option('db_field', $foo_version);
}
}
From the function abc();1. How do I call ‘function a within class A’? ($this->a(); returns error)?
2. How do I access to public variable $bbb?
(- I know the structure is bad but ‘require_once’ part is dynamic etc…)
class AAA extends CI_Controller
{
public $bbb;
function ccc ()
{
}
function index ()
{
require_once '1.php';
}
}
// in 1.php
function abc ()
{
// how do i call method a of Class A?
$this->ccc(); // returns error - Using $this when not in object context in ...
$this->bbb; //
}
abc(); // etc etc
You're trying to do something with require() which it is not designed to do, and doesn't work for.
However, all functions and classes defined in the included file have the global scope.
http://us.php.net/manual/en/function.include.php which also also applies to require().
abc() gets defined in the global scope and thus doesn't have the object context necessary to use $this.
As amber mentioned require wont help here. Couldnt you just pass reference to the function?
function abc (&$ref)
{
$ref->ccc();
$ref->bbb;
}
require it outside of class normally ant then just call
function index ()
{
abc($this);
}
not sure it will work, but worth a try i believe
I am working on creating my own very simple MVC and I am brainstorming ways to go from the controller to the view. Which involves sending variables from a class to just a plain old PHP page.
I am sure that this has been covered before, but I wanted to see what kind of ideas people could come up with.
//this file would be /controller/my_controller.php
class My_Controller{
function someFunction(){
$var = 'Hello World';
//how do we get var to our view file in the document root?
//cool_view.php
}
}
Some kind of hashtable is a good way to do that. Return your variables as association array which will fill all the gaps in your view.
Store your variables as a property in your controller object, then extract them when rendering
class My_Controller {
protected $locals = array();
function index() {
$this->locals['var'] = 'Hello World';
}
protected function render() {
ob_start();
extract($this->locals);
include 'YOUR_VIEW_FILE.php';
return ob_get_clean();
}
}
You can define those magic __get and __set methods to make it prettier
$this->var = 'test';
I'm also developing my own simple MVC and the most simple way to do it is ...
class My_Controller
{
function someFunction() {
$view_vars['name'] = 'John';
$view = new View('template_filename.php', $view_vars);
}
}
View class
class View
{
public function __construct($template, $vars) {
include($template);
}
}
template_filename.php
Hello, <?php echo $vars['name'];?>
I highly recommend you to take a look at PHP Savant http://phpsavant.com/docs/
I'd checkout Zend_View and how it accomplished view rendering.
You can get the source of View and AbstractView on github - unfortunaly I don't find the current repository (in svn) that easy to browse.
Essentially the view variables are contained in a View object (which your controller would have access to), then the template (plain old php document) is rendered inside that object. That method allows the template access to $this.
It would be something like:
<?php
class View
{
public function render()
{
ob_start();
include($this->_viewTemplate); //the included file can now access $this
return ob_get_clean();
}
}
?>
So in your controller:
<?php
class Controller
{
public function someAction()
{
$this->view->something = 'somevalue';
}
}
?>
And your template:
<p><?php echo $this->something;?></p>
In my opinion this pattern allows you much flexibility with the view.
I created my own MVC for the free PHP course I'm conducting for a handful of people wanting to get better at PHP.
By far the best way to do this is to use the Command + Factory pattern.
E.g.
interface ControllerCommand
{
public function execute($action);
}
In each controller:
class UserController implements ControllerCommand
{
public function execute($action)
{
if ($action == 'login')
{
$data['view_file'] = 'views/home.tpl.php';
}
else if ($action == 'edit_profile')
{
$data['view_file'] = 'views/profile.tpl.php';
$data['registration_status'] = $this->editProfile();
}
return $data;
}
}
From your main front controller:
$data = ControllerCommandFactory::execute($action);
if (!is_null($data)) { extract($data); }
/* We know the view_file is safe, since we explicitly set it above. */
require $view_file;
The point is that every Controllercommand class has an execute function and that returns its view and any data for that view.
For the complete MVC, you can access the open source app by emailing me at theodore[at]phpexperts.pro.