Passing Variables to Include Files

learning_brain

New Member
Messages
206
Reaction score
1
Points
0
This is a little more complex than the title suggests.

I have a menu system in a header - which is, as you might expect, an include file.

http://www.donbur.co.uk/eng/css/csstest.php

Within the menu, I have options for making the <dd> elements with a "current" class or not...

So... my first step was to get the current url.

PHP:
            //obtain full current url
            $protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
            $host = $_SERVER['HTTP_HOST'];
            $url = $_SERVER['REQUEST_URI'];
            $currentFullURL = $protocol.'://'.$host.$url;

All pretty basic stuff - provided it resides in the original file - not the include file (which would have been more convenient). Testing fro the main file, this works a treat.

Then a simple line in the include...

PHP:
<dd <?php if($currentFullURL == "http://www.donbur.co.uk/eng/about/history.php"){?>class="current"<?php } ?>>

Theoretically, this would then pick up that its the same page and change the class to "current". The css takes care of the rest.

NOPE...

For some unknown and frustrating reason, the $currentFullURL variable in the main file is not passing to the include. If I try to echo this variable from the include (anywhere in the include), it's an empty variable..... why??????

I have looked at putting it into a Session variable and also a $GLOBALS variable - all without success.

Am I missing something???

Rich
 

descalzo

Grim Squeaker
Community Support
Messages
9,373
Reaction score
326
Points
83
Don't read the book before it is printed.
 

learning_brain

New Member
Messages
206
Reaction score
1
Points
0
Don't read the book before it is printed.

Nice cryptic response to get me started in the morning!!

I've had a good think about this and managed to come up with a working solution.

As the url has to be "GOT" in the main file, I have passed this variable in the include address and then used the GET method in the include itself - which works.

ie.

Main Page
PHP:
get the full url and assign to variable $currentURL

include('./menu.php?currentURL='.$currerntURL.'');

Include
PHP:
if($_GET['currentURL']=="whatever the link is"){
class="current"
}

Phew!
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
For essentially the same reasons that globals are bad, code should be isolated into local scopes (basically, functions); this is part of separating concerns. Instead of having code output the menu at a global level, create a view: a function or class that outputs it. You can either call the function/instantiate the class in the main controller script, or in some other menu controller script included in the main script. That way, you can pass any custom classes to the appropriate function/set the appropriate property instead of mucking about with global variables or superglobals. Also, you won't need a test for every element when outputting the element's classes.

You'll need to decide on a standard way of creating identifiers for each type of object you need to deal with (e.g. pages, links and menu items), and a way of mapping the identifier to each object given the type. URLs are identifiers, so you could use the path (e.g. "/eng/about/history") or part of the path (e.g. "about/history") as an identifier. The downside to this is that URL paths include characters that aren't legal in HTML identifiers. You could use a unique page name (e.g. "history") that would be a valid HTML ID and include a mapping from the ID to URLs.

For example, an outline off using a function; views/sitemenu.php:
PHP:
<?php
function displaySiteMenu($current) {
    static $items = array(
        ...
        );
    
    $items[$current]['class'] .= ' current';

    foreach ($items as $id => $item) {
        ...
    }
}

fragments/sitemenu.php:
PHP:
<?php
include_once('views/sitemenu.php');
displaySiteMenu(url2id($_SERVER['REQUEST_URI']));

If you don't want to construct the menu programmatically, you can instead define the menu in an HTML fragment file (or a document in some other data structuring language), load it with an HTML (or whatever) parser, modify it as necessary & output. This approach is particularly useful if there are designers who know HTML but not PHP working on a project (which I'm guessing isn't currently true of your project). There isn't much of a performance impact over the original approach. Of course, at this point you may as well pick an existing MVC framework to use rather than implementing one yourself (unless the point is self-education).
PHP:
abstract class View {
    abstract function __toString();
    /* output this view */
    function display() {
        echo (string)$this;
    }
    /* prepare for output */
    abstract function generate();
}

/* produces HTML. If you have views that create HTML programmatically, 
 * refactor some of HTMLView into  an HTMLTemplate class that loads the 
 * HTML fragment.
 * You could also add methods to HTMLView that allows hierarchical views, 
 * where one view can be a child of another.
 * Example implementation based on DOMDocument.
 */
abstract class HTMLView extends View {
    protected $_doc, # HTML parser, e.g. DOMDocument
        $_path, # document traverser, e.g. DOMXPath
        $_file; # HTML fragment

    function __construct($file) {
        parent::__construct();
        $this->_file = $file;
        $this->generate();
    }
    function __toString() {
        /* Pass root node to prevent DOCTYPE declaration, <html> and 
         * <body> from being included in result. Requires PHP >= 5.3.6
         */
        return $this->_doc->saveHTML($this->_doc->documentElement);
    }
    function generate() {
        if (! $this->_doc) {
            $this->_doc = new DOMDocument;
            $this->doc->validateOnParse = TRUE; # so getElementById will work
            $this->_load();
            $this->_revise();
        }
    }
    /* load HTML fragment */
    protected function _load() {
        $this->_doc->loadHTMLFile($this->_file);
        $this->_path = new DOMXPath($this->_doc);
	# so you can use php functions in XPath expressions
	$this->path->registerNamespace("php", "http://php.net/xpath");
	$this->path->registerPhpFunctions();
    }
    /* modify loaded HTML */
    abstract protected function _revise();
}

class HTMLMenuView extends HTMLView {
    public $current;

    protected function _revise() {
        $this->_markCurrentItem();
        ...
    }

    protected function _markCurrentItem() {
        # "/path/to/" could simply be "//" to search all <dd>
        $dds = $this->_path->query("/path/to/dd[@id='{$this->current}_menu_item']");
        if ($dds->length) {
            # assume node is an element
            $classes = $dds->item(0)->getAttribute('class');
            $dds->item(0)->setAttribute('class', $classes . ' current');
        }
    }
}
 
Top