News:

Want to get involved in developing SMF, then why not lend a hand on our github!

Main Menu

Code vs. Templates

Started by ptmuldoon, March 13, 2010, 03:38:09 PM

Previous topic - Next topic

ptmuldoon

Here's the MainFunction and MainTemplate being used.  The Main template is than populated by all of the subtemplates (or will be anyway).  These are separate files.  I just put them both in one big code block here.

// Determine the Sub Action and Templates Required.
function RiskMain() {
global $boardurl, $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile, $settings;
global $modSettings, $memberContext, $profile_vars, $smcFunc, $post_errors, $options, $user_settings;

$context['html_headers'] .= ' <link rel="stylesheet" type="text/css" href="' . $settings["default_theme_url"] .  '/css/riskbrowser.css" />';

loadTemplate('RiskBrowser');

// List of allowed sub actions, and their related template file called.
$subactions = array(
    'browser' => 'MainBrowser',
    'create'  => 'CreateGame',
    'glog'  => 'CreateGame',
    'mlog' => 'CreateGame',
    'profile'  => 'CreateGame',
    );

    //If no subaction is set or attempt to non subaction request.
    if (!isset($_REQUEST['sa']) || !array_key_exists($_REQUEST['sa'], $subactions))
{
    $context['sub_template'] = 'MainBrowser';
}
    // Find a Match and Return Necessary Template
    else if (isset($_REQUEST['sa']) && array_key_exists($_REQUEST['sa'], $subactions))
    {
    $context['sub_template'] = $subactions[$_REQUEST['sa']];
}
   
}

//Main Template
function template_MainBrowser() {
global $context, $settings, $options, $scripturl, $modSettings, $txt;

echo '
<div id="container">
<!-- Begin Menu Area -->
<div id="r_menu">', r_menu() . template_RMenu() ,'</div>
<!-- End Menu Area -->

<div>
<!-- Open Left Column -->
<div id="r_leftcol">
<div id="r_gamelist">', template_ActiveGames() ,'</div>
<div><br/> </div>
<div id="r_chatarea">', r_AjaxChat() ,'</div>
</div>
<!-- Close Left Column -->

<!-- Open Right Column -->
<div id="r_rightcol">
<div id="r_topten">', r_TopTen() ,'</div>
<div id="r_mygames">', r_UserActiveGames() ,'</div>
<div id="r_usersonline">', template_UsersOnline() ,'</div>
</div>
<!-- Close Right Column -->
</div>


<!-- Footer  -->
<div id="footer">', r_footer() ,'</div>

<!-- Close Container  -->
</div>

';
}

Arantor

Nothing's jumping at me there, other than a whole bunch of global variables you don't need (not that this is an issue)

ptmuldoon

Right.  I have all those globals there as I just copied them from somewhere else learning.  Its very strange.  All I can think of is something in either in php, a cache issue, etc. causing an issue.  But I've flush the cache, emptied temp files, and nothing looks out of place in the php.ini file

Arantor

Um... where's the content for those things being loaded?

I see the main function loading the template and figuring out the subtemplate, but I don't see it calling any other function to populate any variables...

ptmuldoon

Your right.  Thats the likely issue.

So I guess perhaps I'm back to understanding better on how you call 'sub' functions and sub_templates into your main function and template.

Do you know of a better method to pull it together?

Arantor

There isn't one, really, you have a master function that pushes execution to sub functions (i.e. action=something is simply a routing agent for action=something;sa=somethingelse and action=something;sa=somethingelseagain), and have those sub functions determine what they need to do.

ptmuldoon

#26
Ok, so I currently have a master function and master template.  I was than having multiple sub-fuctions, each to one to be used for a sub_template.  I had thought the master's would read all of the sub information and create the page.

Thus do this, do I need to include/reference all of the sub functions inside the main function in MyMod.php file?

So when you have action=mypage;sa=page1, that will only get the page1 function info, and not any of the additional (sub)functions used in creating that page? 

So with my main function still as below, I'll need to add in the additional functions used to create each page?


function RiskMain() {
global $boardurl, $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile, $settings;
global $modSettings, $memberContext, $profile_vars, $smcFunc, $post_errors, $options, $user_settings;

$context['html_headers'] .= ' <link rel="stylesheet" type="text/css" href="' . $settings["default_theme_url"] .  '/css/riskbrowser.css" />';

loadTemplate('RiskBrowser');

// List of allowed sub actions, and their related template file called.
$subactions = array(
    'browser' => 'MainBrowser',
    'create'  => 'CreateGame',
    'glog'  => 'CreateGame',
    'mlog' => 'CreateGame',
    'profile'  => 'CreateGame',
    );

    //If no subaction is set or attempt to non subaction request.
    if (!isset($_REQUEST['sa']) || !array_key_exists($_REQUEST['sa'], $subactions))
{
    $context['sub_template'] = 'MainBrowser';
}
    // Find a Match and Return Necessary Template
    else if (isset($_REQUEST['sa']) && array_key_exists($_REQUEST['sa'], $subactions))
    {
    $context['sub_template'] = $subactions[$_REQUEST['sa']];
}
   
}


Or perhaps easiest to include the required 'sub' function in each sub_template like this?

function template_ActiveGames(){
global $context;

//Get the required 'sub' functions needed.
r_ActiveGames();

echo $context['mytext'] . 'something else';  //Yet this is not getting info from the Mod file?

}

Arantor

You *could* do it that way but that is considered very very bad style with SMF.

The correct process is to have the Sources/ files gather all the necessary data and then have the template display it. So where you figure out the template you need, instead call the relevant function.

Then have the relevant data gathering function specify what template it uses.

SimpleDesk does this. For example, let's say we want action=helpdesk;sa=ticket. sa=ticket is handled by SimpleDesk-Display.php and SimpleDesk-Display.template.php, so the function called by action=helpdesk identifies the sa, and hands control over to SimpleDesk-Display.php, and its principle function shd_view_ticket. It is that function that gets a load of data before specifying that it needs subtemplate view_ticket.

ptmuldoon

Ok, I obviously went about initially setting things up originally incorrectly.  So to confirm as try to rework things.

1.  Is it should be possibly to have just 1 MyMod.php file.  And this file would include all necessary functions that you want to use.  Ie, function mainheader()  function mainfooter(), function mainbody() 

2. For templating, can you than also have 1 MyMod.template.php file.  And than this file would have a function template_mainlayout, and this main layout would than be including the other templates, such template_header, template_footer, etc?

3.  I guess I'm still unsure how I have (if possible) to simply have 1 file of each, and make it work correctly.  Ie, how to an action=mymod  and have it load both header, body, and footer functions, as well as the header, body, and footer templates.

I'm heading back to the 'drawing board to re-simplify the initial code to try and get it correct before beginning to run queries, etc.

Arantor

1. Sure it is. Provided that it has all the functions in it that aren't directly outputting HTML.

2. Yes. As long as it has all the different functions and subtemplates.

3.

Set up index.php to call MyMod.php, mymod_main or similar in $actionArray.

mymod_main does the following:
1. loadTemplate('MyMod'); to load MyMod.template.php

2. Identifies the relevant subaction from $_REQUEST['sa'].

3. Get any content that would apply to every single page within your mod and store it in $context

4. Calls the appropriate function in MyMod.php based on $_REQUEST['sa']

5. This function should be getting all the data it needs that's specific to this subaction, and storing it in $context.

6. The function should be dictating the specific subtemplate it needs.

SMF's theme system will handle calling the subtemplate.

Let's say you have sa=main as the front page, ultimately this goes to some function to get the front page code, followed up by calling template_mainpage. There's nothing stopping you directly calling other template functions from that. (We do it a lot in SimpleDesk, there is one master subtemplate for posting a ticket which calls about 10 other subtemplate components)

ptmuldoon

Right.  But where i get confused is how/where does the subtemplates get its info from?  Since I load action=mymod, which loads MyMod.php and the initial function called (identified in the index.php) 

Can you not have more than 1 function in your MyMod.php file?

Can I not have a separate function header() and footer()? and to have that $context info provide the info for those subtemplates?  I've ripped everything back to basics, trying to understand better.

So, I'm calling action=riskbrowser  (no subactions at the moment).  And now I'm pretty sure this will not work.  The RiskMain function is being called via the index.php  But the header, main and footer functions are not being called.

So I 'think' I need to include all the header and footer $context info inside the RiskMain function?  But what when setting up other 'pages', or subactions?   How do you include the code necessary to render those pages without including it your RiskMain function to send to a subtemplate?

For my mod file i have this;

function RiskMain() {
global $context;

$context['html_headers'] .= ' <link rel="stylesheet" type="text/css" href="' . $settings["default_theme_url"] .  '/css/riskbrowser.css" />';

loadTemplate('RiskBrowser');
    $context['sub_template'] = 'MainBrowser';
}

function r_Header(){
global $context;

$context['rheader'] = 'This will be the header';

// Template
$context['sub_template'] = 'rHeader';
}

function r_MainBody(){
global $context;

$context['rmain'] = 'Main Body Area';

// Template
$context['sub_template'] = 'rMainBody';
}

function r_Footer(){
global $context;

$context['rfooter'] = 'Footer Area';

// Template
$context['sub_template'] = 'rFooter';
}


and the template of

function template_MainBrowser() {
global $context, $settings, $options, $scripturl, $modSettings, $txt;

echo '
<div id="container">
<div >', template_RHeader() ,'</div>
<div >', template_RMainBody() ,'</div>
<div >', template_RFooter() ,'</div>

Just Testing Here

</div>
';
}

function template_rHeader(){
global $scripturl, $context;

echo $context['rheader'];
}

function template_rMainBody(){
global $scripturl, $context;

echo $context['rmain'];
}

function template_rFooter(){
global $scripturl, $context;

echo $context['rfooter'];
}

Arantor

You can have loads of functions in MyMod.php. See point 3, you can call other functions there to get general stuff before handing over to a specific subaction.

http://www.simpledesk.net/development/api/source/SimpleDesk/ documents what we have in SimpleDesk, which covers exactly what you're talking about.

shd_main is what's called from index.php, and figures out subactions. If the subaction is main, closedtickets or recyclebin, the function in question is in the same file, which does some setup before handing it over to shd_helpdesk_listing which is in the same file.

ptmuldoon

ok, I think I'm close to understanding things better, but...  My subaction request is returning me back to the forums, and I'm sure why.

Arantor

So what URL are you calling?

ptmuldoon

I start out by going to this link here: index.php?action=riskbrowser and the mod shows its main template

But than when I visit this subaction index.php?action=riskbrowkser;sa=create, it returns to the forums for some weird reason.

And the Mod file looks like this

function RiskMain() {
global $boardurl, $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile, $settings;
global $modSettings, $memberContext, $profile_vars, $smcFunc, $post_errors, $options, $user_settings;

//Add any addtional css we need
$context['html_headers'] = ' <link rel="stylesheet" type="text/css" href="' . $settings["default_theme_url"] .  '/css/riskbrowser.css" />';

//Create the Menu Items
$context['rmenu'] = array(
'create' => 'Create Game',
'browser' => 'Browser',
'glog' => 'Game Log',
'mlog' => 'Mission Log',
'profile' => 'Profile'
);

//Create the footer
$context['rfooter'] = 'This will be the footer';

// List of allowed sub actions, and their related template file called.
$subactions = array(
    'browser' => 'browser',
    'create'  => 'CreateGame',
    'glog'  => 'CreateGame',
    'mlog' => 'CreateGame',
    'profile'  => 'CreateGame',
    );

    // Load the general template for this action.
    loadTemplate('RiskBrowser');
   
    // Set the default subaction if undefined or not allowed
    if (!isset($_REQUEST['sa']) || !array_key_exists($_REQUEST['sa'], $subactions))
{
    $_REQUEST['sa'] = 'browser';
}
    // Set the subaction for the allowed subactions
    else if (isset($_REQUEST['sa']) && array_key_exists($_REQUEST['sa'], $subactions))
    {
    $_REQUEST['sa'] = $subactions[$_REQUEST['sa']];
}

}

function browser(){
global $context, $settings, $options, $scripturl, $modSettings, $txt;

$context['rbrowser'] = 'This Will be the Game Browser Code';
}

function create(){
global $context, $settings, $options, $scripturl, $modSettings, $txt;

$context['rcreate'] = 'This Will be the Game Creation Code';
}

Arantor

riskbrowkser is an unknown action - try ?action=riskbrowser;sa=create

Also, you're calling template_main in every single case?

Oh, and that big if statement can be condensed into a single statement:
$_REQUEST['sa'] = (!empty($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']])) ? $_REQUEST['sa'] : 'browser';

i.e. if $_REQUEST['sa'] isn't empty and it's a known subaction, use it, otherwise reset to browser.

ptmuldoon

#36
Thanks for finding that typo. It was staring me in the face for hours with out seeing it.

I'm calling the template_main, as thats the only way I get the Mod to show the information.  I am wrong in thinking that template_main is required?  Perhaps because I'm not initially calling a subaction when getting the mod page?  Or can I call any template to start?

Also, when i'm calling subaction sa=create.  Shouldn't that than be making the variables in that function available to the template(s)?  I was also wondering if that the variables can be used in multiple templates.  Ie, cna $context['myvar'] be used in template_1, template_2, etc as long you define global $context in the function and templates?

Arantor

You can call any template to start provided that you specify it in $context['sub_template']. That will be the only one that will be called by SMF itself, however you can call whatever you want from that.

Sure, that's the point of globals. $context is populated in your source and is available to any function you pull it into scope from. Again this is something I do extensively in SimpleDesk. Our posting template - best example - has two base functions, one for posting/editing a ticket, one for replying/editing replies, which at the top are template_ticket_post() and template_reply_post(), and that's what's set from the Sources file in $context['sub_template'].


That first function, template_ticket_post():
function template_ticket_post()
{
global $context;

// Back to the helpdesk.
echo'<div class="floatleft">', template_button_strip(array($context['navigation']['back']), 'bottom'), '</div><br /><br />';

template_preview();
template_ticket_info();
template_ticket_subjectbox();
template_ticket_meta();
template_ticket_postbox();
template_ticket_footer();
if (!empty($context['ticket_form']['do_replies']))
{
template_ticket_begin_replies();
template_ticket_do_replies();
template_ticket_end_replies();
}
template_ticket_pageend();
}


template_reply_post is similar in a lot of ways to this, it assembles the page out of parts that are common to both, and specific to each.

ptmuldoon

I'm starting to feel pretty stupid for still not getting this, but.....

If my index.php file is calling MyMod page, and the starting function of  RiskMain().  And that function includes the following to set the default subaction and subtempate

// Set the Default Subaction
    $_REQUEST['sa'] = (!empty($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']])) ? $_REQUEST['sa'] : 'browser';
   
    // Set the Default Template
    $context['sub_template'] = (!empty($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']])) ? $_REQUEST['sa'] : 'browser';


So, I think the above should 1) be than be loading any variables I have in the browser function, and 2 also passing any variables previously defined the browser template. 

And than any variables in the browser function included in Mymod should than also be available to use any templates?

function browser(){
global $context, $settings, $options, $scripturl, $modSettings, $txt;

$context['activegames'] = 'This Will be the Game Browser Code';

}


Currently I can't get the browser template to load, and error log keeps telling me " Unable to load the 'main' template."

Arantor

Because it's looking for template_browser, not just browser. Rename the function.

Advertisement: