Assigning defaults for Smarty using Object Oriented style

大兔子大兔子 提交于 2019-12-08 08:37:13

问题


I'm just very slowly starting to sink into object-oriented programming, so please be gentle on me.

I have a custom class for Smarty that was partially borrowed. This is how the only example reflects the basic idea of using it across my current project:

class Template {

    function Template() {
        global $Smarty;
        if (!isset($Smarty)) {
            $Smarty = new Smarty;
        }
    }

    public static function display($filename) {
        global $Smarty;
        if (!isset($Smarty)) {
            Template::create();
        }
        $Smarty->display($filename);
    }

Then in the PHP, I use the following to display templates based on the above example:

Template::display('head.tpl');
Template::display('category.tpl');
Template::display('footer.tpl');

I made the following example of code (see below) work across universally, so I wouldn't repeat the above lines (see 3 previous lines) all the time in each PHP file.

I would just like to set, e.g.:

Template::defauls();

that would load:

Template::display('head.tpl');
Template::display('template_name_that_would_correspond_with_php_file_name.tpl');
Template::display('footer.tpl');

As you can see Template::display('category.tpl'); will always be changing based on the PHP file, which name is corresponded with the template name, meaning, if for example, PHP file is named stackoverflow.php then the template for it would be stackoverflow.tpl.


I've tried my solution that have worked fine but I don't like it the way it looks (the way it's structured).

What I did was:

  1. Assigned in config a var and called it $current_page_name (that derives the current PHP page name, like this: basename($_SERVER['PHP_SELF'], ".php"); ), which returned, for e.g.: category.
  2. In PHP file I used Template::defaults($current_page_name);
  3. In my custom Smarty class I added the following:


public static function defaults($template) {

   global $Smarty;

   global $msg;
   global $note;
   global $attention;
   global $err;

   if (!isset($Smarty)) {
      Templates::create();
   }
      Templates::assign('msg', $msg);
      Templates::assign('note', $note);
      Templates::assign('attention', $attention);
      Templates::assign('err', $err);

      Templates::display('head.tpl');
      Templates::display($template . '.tpl');
      Templates::display('footer.tpl');
}

Is there a way to make it more concise and well structured? I know about Code Review but I would like you, guys, to take a good look at it.


回答1:


This looks like you haven't loaded Smarty, that's why the error happens. You need to start by including Smarty before the class starts. If you follow my other config suggestion you should start by including that one as well.

In you Template class, just add the following function:

function defaults() {
    // Don't know if you need the assignes, havn't used Smarty, but if so, insert them here...

    Template::display( Config::get('header_template') ); //header_template set in the Config file
    Template::display( basename($_SERVER['PHP_SELF'], ".php") . '.tpl' );
    Template::display( Config::get('footer_template') ); //footer_template set in the Config file
}

Now you should be able to use it in any file:

$template = new Template();
$template->defaults();

EDIT:

A singleton is in every sense the same as a global, that will keep your same problem. But your problem is that if you try to use one of the Template's static functions you are in the "static" mode, which means the constructor have not been run. And Smarty has not been assigned. If you want to go this road, you can do one of two thinks:

  1. Make the Template a real singleton, meaning set the constructor to private add a function getInstance, that returns a instance of the class, and then use that object to call the functions in it (which should not be static), or

  2. Make all those static functions check if smarty is set, and if it's not, create a new instance of smarty, otherwise use the one that already is instantiated to run its function.

EDIT 2:

Here's the proper way to make a singleton:

class Singleton {
    private static $instance = null;
    // private static $smarty = null;

    private function __construct() {
        //self::$smarty = new Smarty();
    }

    public static function getInstance() {
        if( self::$instance === null ) {
            self::$instance = self();
        }
        return self::$instance;
    }

    public function doSomething() {
        //self::$smarty->doSomething();
    }
}

It's used like this:

$singleton = Singletong::getInstance();
$singleton->doSomething();

I commented out the things you probably want do to to make this a singleton wrapper around a singleton Smarty object. Hope this helps.

EDIT 3:

Here's a working copy of your code:

class Template {
    private static $smarty_instance;
    private static $template_instance;

    private function Template() {
        self::$smarty_instance = new Smarty();
        $this->create();
    }

    public static function getInstance() {
        if( ! isset( self::$template_instance ) ) {
            self::$template_instance = new self();
        }
        return self::$template_instance;
    }

    private function create() {
        self::$smarty_instance->compile_check = true;
        self::$smarty_instance->debugging = false;
        self::$smarty_instance->compile_dir   = "/home/docs/public_html/domain.org/tmp/tpls";
        self::$smarty_instance->template_dir  = "/home/docs/public_html/domain.org";
        return true;
    }

    public function setType($type) {
        self::$smarty_instance->type = $type;
    }

    public function assign($var, $value) {
        self::$smarty_instance->assign($var, $value);
    }

    public function display($filename) {
        self::$smarty_instance->display($filename);
    }

    public function fetch($filename) {
        return self::$smarty_instance->fetch($filename);
    }

    public function defaults($filename) {
        global $user_message;
        global $user_notification;
        global $user_attention;
        global $user_error;

        self::$smarty_instance->assign('user_message', $user_message);
        self::$smarty_instance->assign('user_notification', $user_notification);
        self::$smarty_instance->assign('user_attention', $user_attention);
        self::$smarty_instance->assign('user_error', $user_error);

        self::$smarty_instance->assign('current_page', $filename);

        self::$smarty_instance->display('head.tpl');
        self::$smarty_instance->display($filename . '.tpl');
        self::$smarty_instance->display('footer.tpl');
    }
}

When using this function, you should use it like this:

$template = Template::getInstance();
$template->defaults($filename);

Try it now.




回答2:


You can get current file name in your defaults() function. Use this piece of code:

$currentFile = $_SERVER['REQUEST_URI'];
$parts = explode('/', $currentFile);
$fileName = array_pop($parts);
$viewName = str_replace('.php', '.tpl', $fileName);

$viewName is the name that you need.




回答3:


This is a quick wrapper I made for Smarty, hope it gives you some ideas

class Template extends Smarty
{
     public $template = null;
     public $cache    = null;
     public $compile  = null;

     public function var($name, $value, $cache)
     {
         $this->assign($name, $value, $cache);
     }

     public function render($file, $extends = false)
     {
         $this->prep();

         $pre  = null;
         $post = null;

         if ($extends)
         {
             $pre = 'extends:';
             $post = '|header.tpl|footer.tpl';
         }

         if ($this->prep())
         {
             return $this->display($pre . $file . $post);
         }
      }

      public function prep()
      {
          if (!is_null($this->template))
          {
              $this->setTemplateDir($this->template);

              return true;
          }

          if (!is_null($this->cache))
          {
              $this->setCacheDir($this->cache);
          }

          if (!is_null($this->compile))
          {
              $this->setCompileDir($this->compile);

              return true;
          }

              return false;
      }
}

Then you can use it like this

$view = new Template();

$view->template = 'path/to/template/';
$view->compile  = 'path/to/compile/'
$view->cache    = 'path/to/cache';

$view->assign('hello', 'world');

// or

$view->var('hello', 'world');

$view->render('index.tpl');

//or

$view->render('index.tpl', true); // for extends functionality

I did this kinda fast, but just to show you the basic ways you can use smarty. In a more complete version you could probably want to check to see if compile dir is writable, or if file templates exist etc.




回答4:


After trying for few days to solve this simple problem, I have finally came up with working and fully satisfying solution. Remember, I'm just a newby in object-oriented programming and that's the main reason why it took so long.

My main idea was not to use global $Smarty in my initial code that worked already fine. I like to use my Smarty as just simple as entering, e.g.: Template::assign('array', $array). To display defaults, I came up with the trivial solution (read my initial post), where now it can be just used Template::defaults(p()); to display or assign anything that is repeated on each page of your project.

For doing that, I personally stopped on the following fully working solution:

function p() {
    return basename($_SERVER['PHP_SELF'], ".php");
}

require('/smarty/Smarty.class.php');

class Template
{
    private static $smarty;
    static function Smarty()
    {
        if (!isset(self::$smarty)) {
            self::$smarty                 = new Smarty();
            self::Smarty()->compile_check = true;
            self::Smarty()->debugging     = false;
            self::Smarty()->plugins_dir   = array(
                '/home/docs/public_html/domain.com/smarty/plugins',
                '/home/docs/public_html/domain.com/extensions/smarty');
            self::Smarty()->compile_dir   = "/home/docs/public_html/domain.com/cache";
            self::Smarty()->template_dir  = "/home/docs/public_html/domain.org";
        }
        return self::$smarty;
    }
    public static function setType($type)
    {
        self::Smarty()->type = $type;
    }
    public static function assign($var, $value)
    {
        self::Smarty()->assign($var, $value);
    }
    public static function display($filename)
    {
        self::Smarty()->display($filename);
    }
    public static function fetch($filename)
    {
        self::Smarty()->fetch($filename);
    }
    public static function defaults($filename)
    {
        Template::assign('current_page_name', $filename);
        Template::display('head.tpl');
        Template::display($filename . '.tpl');
        Template::display('footer.tpl');
    }
}

Please use it if you like it in your projects but leave comments under this post if you think I could improve it or you have any suggestions.

Initial idea of doing all of that was learning and exercising in writing a PHP code in object-oriented style.



来源:https://stackoverflow.com/questions/12436203/assigning-defaults-for-smarty-using-object-oriented-style

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!