Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: Separating Markup from Logic  (Read 260 times)

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Separating Markup from Logic
« on: November 18, 2012, 04:20:48 PM »

If you are a web designer, you know about evolving technologies - aka HTML5, CSS3, & heavier reliance on Javascript.  You also may have heard about Progressive Enhancement, where each layer of Content (HTML), Presentation (CSS), & Behaviour (JS), are seperated. There is also the markup that helps define your content further such as ARIA, RDFa, Schema.org, & microformats. And as a front end developer, you know that you have all these choices and then some to present your content for your site.

Where does that leave CMSs?
CMS's that bundle markup, styles, and behaviour should push to have these things removed from thier core system.  This move would ulitmatly lead to leaner and more maintainable code for the CMS developers and gives the template authors more choice in thier markup.

Let's take a look at a quick example using the search field:

For the server side, if we think about it, we really don't need much.
Code: [Select]
<?php

if( isset( 
$_POST['submit_search'] ) ) {
search($_POST['search_query']);
}

?>

<form method="post" action="test.php">
<p>
<input type="text" name="search_query">
<input type="submit" name="submit_search" value="Search">
</p>
</form>

The POST values come from the name attribute in the HTML form. Even if we use GET or an AJAX request, it comes from the same place - the name attribute.

Let's take a look at the base markup for a search form using HTML4, XHTML1.1 & HTML5:

HTML4
Code: [Select]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title></title>
</head>
<body>
<div id="header">
<form action="">
<p>
<input type="text">
<input type="submit" value="Search">
</p>
</form>
</div>
</body>
</html>

XHTML1.1
Code: [Select]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<div id="header">
<form action="">
<p>
<input type="text" />
<input type="submit" value="Search" />
</p>
</form>
</div>
</body>
</html>

HTML5
Code: [Select]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<header>
<form>
<p>
<input type="search">
<input type="submit" value="Search">
</p>
</form>
</header>
</body>
</html>

In each example, I have left out the name attributes intentionally to show a point - the template author can use whatever markup they choose, as long as they include what the script needs to parse and give the content they need to be marked up.

If we take another look at the HTML5 markup - adding some more attributes, it is the same scenario:
Code: [Select]
<form action="test.php">
<p>
<input type="search" placeholder="Search Keywords" required aria-required="true" role="search">
<input type="submit" value="Search">
</p>
</form>
The name attribute is still left out to illustrate what the server needs in respect to markup.

Let's see how we can start adding the required attributes by PHP:
Code: [Select]
<?php

error_reporting(-1);

function searchForm_reqAttr() {
$array = array(
"search" => array("name"   => "search_field"),
"submit" => array("name"   => "submit_search_form")
);
return $array;
}

?>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<header>
<?php $searchAttr searchForm_reqAttr(); ?>
<form method="" action="test.php">
<p>
<input  type="search"
name="<?php echo $searchAttr['search']['name'] ; ?>">
<input  type="submit"
name="<?php echo $searchAttr['submit']['name'] ; ?>"
value="Search">
</p>
</form>
</header>
</body>
</html>
Overall, it's pretty simple.  We are just making the array and outputting in the template. In this instance, I am leaving out the form method to show different options - GET, POST, & POST via AJAX, later on.

Now for some processing:
Quote
Part of the code is from the in progress core framework I have up - the validator portion is again based on the Zend Framework Validator class. The plugin is a simplified version of that code.

Here is where the plugin/add-on author would start thier code
Code: [Select]
<?php

define('SEARCH_FORM_METHOD''post'); // GET or POST

function searchForm_reqAttr() {
$array = array(
"form" => array("method" => SEARCH_FORM_METHOD),
"search" => array("name"   => "search_field"),
"submit" => array("name"   => "submit_search_form")
);
return $array;
}

function validateSearchRequest() {
$reqAttr  searchForm_reqAttr();
$validation = new Validate;
$method  $GLOBALS['_'.strtoupper(SEARCH_FORM_METHOD)];

$validation->addValidator($reqAttr['search']['name'], new IsBlank);
// execPlugin('getSearchResults', $validation); - If we want to add fields to validate in our search

if( !$validation->isValid($method) ) {
return $validation->getErrors();
} else {
return true;
}
}

function getSearchResults($request) {
// code to query db based on search request
// return array of data
}

?>

Nothing too radical or over the top.  All of the processing & validating of the search function is noted here.  Again note, there is no HTML present in our processing code at all.

I have added the form method as something that can be user defined (GET | POST). It would be added the same way as noted before in the search form.  You may note the $GLOBALS['_'.strtoupper(SEARCH_FORM_METHOD)] line - the $GLOBALS superglobal array houses the $_GET, $_POST, $_SERVER, etc global arrays

Now, let's have the site maintainer do the final processing using either GET, POST, or a POST request with AJAX. Each way is almost identical, with minor differences - check if a key is set, check if the fields are valid, and if so, get out results.
Code: [Select]
<?php

// POST
$reqAttr  searchForm_reqAttr();
$request $reqAttr['search']['name'];
$method  $GLOBALS['_'.strtoupper(SEARCH_FORM_METHOD)];
if( isset($method[$reqAttr['submit']['name']]) ) {  # - From Submit
if( validateSearchRequest() !== true) {
print_r(validateSearchRequest()); // do something with the errors
} else {
$results getSearchResults($request);
}
}
unset($reqAttrm$request$method);

foreach( $results as $result ) {
// output html & php
}
?>


Code: [Select]
<?php

// GET - remove name field from submit - don't need it in the url
$reqAttr  searchForm_reqAttr();
$request $reqAttr['search']['name'];
$method  $GLOBALS['_'.strtoupper(SEARCH_FORM_METHOD)];
if( isset($method[$reqAttr['search']['name']]) ) {   # - From URL
if( validateSearchRequest() !== true) {
print_r(validateSearchRequest()); // do something with the errors
} else {
$results getSearchResults($request);
}
}
unset($reqAttrm$request$method);

foreach( $results as $result ) {
// output html & php
}

?>


Code: [Select]
<?php

// POST AJAX Request
if( // an Ajax request
    isset($_SERVER['HTTP_X_REQUESTED_WITH']) 
&&  strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'
) {
$reqAttr  searchForm_reqAttr();
$request $reqAttr['search']['name'];
if( validateSearchRequest() !== true) {
echo json_encode(validateSearchRequest());
// Use JS to output the errors
} else {
echo json_encode(getSearchResults($request));
// Use JS to output the results
}
die();
}

?>


A very simple example to ilustrate the different ways to process the search results - all without including markup, styling or javascript in the core code.  And with seeing the examples, you can see how the core script & plugin/add-on didn't change for each method or for the change in markup - those decisions were left with the site maintainer/template author, who now has more control on their site.

Quote
This post is in addition to this thread as ideas for future version or ideas for forks.
« Last Edit: November 19, 2012, 02:01:46 AM by nukpana »
Logged

Fred K

  • Still trying to learn stuff
  • ULTIMATE member
  • ******
  • Karma: 130
  • Posts: 2728
    • Personal
Re: Separating Markup from Logic
« Reply #1 on: November 20, 2012, 07:01:50 PM »

Great example Jason! +1 karma.
Logged

Rui Mendes

  • Development,Testing, Support
  • Hero Member
  • *****
  • Karma: 195
  • Posts: 1009
  • sNews1.7
    • Comunidade Portuguesa
Re: Separating Markup from Logic
« Reply #2 on: November 20, 2012, 09:10:04 PM »

Jason I read your post, thanks for share with us.

One question, if you have a form with multiple inputs with same type (i.e. text), how can do it

Code: [Select]
<?php
function searchForm_reqAttr() {
 $array = array(
 "form"  => array("method" => SEARCH_FORM_METHOD),
 "search"  => array("name"   => "name_field",  "email"   => "email_field""website"   => "website_field"),
 "submit"  => array("name"   => "submit_search_form")
 );
 return $array;
 }
?>


<body>
<header>
<?php $searchAttr searchForm_reqAttr(); ?
<form method="<?php echo $searchAttr['search']['form'] ; ?>
" action="test.php">
<p>
<input  type="text"
name="<?php echo $searchAttr['search']['name'] ; ?>">
<input  type="text"
name="<?php echo $searchAttr['search']['email'] ; ?>">
<input  type="text"
name="<?php echo $searchAttr['search']['website'] ; ?>">
<input  type="submit"
name="<?php echo $searchAttr['submit']['submit'] ; ?>"
value="Search">
</p>
</form>
</header>
</body>

Is this correct?
« Last Edit: November 20, 2012, 09:11:58 PM by Rui Mendes »
Logged
Need a Job on Europe. Linkdin - Facebook / Group

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Separating Markup from Logic
« Reply #3 on: November 21, 2012, 12:21:43 AM »

@Rui, define it semantically like so:
Code: [Select]
<?php

define('SEARCH_FORM_METHOD''post'); // GET or POST

function searchForm_reqAttr() {
$array = array(
"form"   => array(
"method" => SEARCH_FORM_METHOD,
"action" => basename($_SERVER['SCRIPT_NAME'])
),
"search"  => array(
"name"  => "search_field",  
"id"  => "seach_field"
),
"email"  => array(
"name"  => "email_field"
),
"website"  => array(
"name" => "website_field"
),
"hidden" => array(
"ip" => array(
"name" => "ip",
"value" => $_SERVER['REMOTE_ADDR']
),
"time" => array(
"name"  => "time",
"value" => date('Y-m-d H:i:s')
)
),
"submit"  => array(
"name"  => "submit_search_form"
)
);
return $array;
}

?>

<body>
<header>
<?php $searchAttr searchForm_reqAttr(); ?>
<form
method="<?php echo $searchAttr['form']['method']; ?>"
action="<?php echo $searchAttr['form']['action'] ; ?>">
<p>Search for:
<input
type="text"
name="<?php echo $searchAttr['search']['name'] ; ?>"
id="<?php echo $searchAttr['search']['id']; ?>">
</p>
<p>Email:
<input 
type="text"
name="<?php echo $searchAttr['email']['name']; ?>">
</p>
<p>Website:
<input 
type="text"
name="<?php echo $searchAttr['website']['name']; ?>">
</p>
<input
type="hidden"
name="<?php echo $searchAttr['hidden']['ip']['name']; ?>"
value="<?php echo $searchAttr['hidden']['ip']['value']; ?>">
<input
type="hidden"
name="<?php echo $searchAttr['hidden']['time']['name']; ?>"
value="<?php echo $searchAttr['hidden']['time']['value']; ?>">
<input 
type="submit"
name="<?php echo $searchAttr['submit']['name']; ?>"
value="Search">
</form>
</header>
</body>
I even added hidden inputs examples as well.

You see the array mimics a form without the actual markup. The idea is what-the-item-is => array(attribute => value).  Hope this helps!
« Last Edit: November 21, 2012, 12:56:58 AM by nukpana »
Logged