Sandlight CMS I: Device Closures

devicesIn previous posts on this blog, I’ve included PHP patterns that deal with the issue of creating sites for multiple devices. In developing a Content Management System (CMS) for my Sandlight site, I wanted to start from scratch and use both elements of OOP and design patterns as well as functional programming. (Functional programmers may furrow their collective brows and mutter You’re ruining FP, but there’re enough arguments among FP advocates, that I’m not overly concerned.)

The Problem with User Agents

The problem with user agents (UAs) such as $_SERVER['HTTP_USER_AGENT'] in PHP, is that the information they provide is insufficient. For example, if you get “trident” from a user agent, it could be anything from a Microsoft-based computer to a MS phone. Devices identified as “iPad” can be the iPad Minis or the full-size iPads. And of course, if you get “Android” or “iPhone,” it can be any size screen from the early smart phones to what some call “Phablets”— the big phones like iPhone 6+ and Galaxy Note 3. To get started, take a look at this table. Not only will that table give you a range of mobile devices, it provides the way in which browsers communicate the type of device currently reading a page. (The CSS column is the most relevant for setting up a CMS that will adjust to different devices.)

How Can You Get the Screen Size for PHP?

If you’ve used CSS3, you are familiar with CSS media queries where you can direct the CSS to different classes and IDs depending on the screen size. It’s just as easy using JavaScript. The built-in document properties, screen.width and screen.height can be passed to variables and in turn to PHP. The procedure is a simple one-line program:

<script>
  window.location.href = "WiHi.php?hor=" + screen.width + "&vert=" + screen.height;
</script>

The JavaScript variables are hor and vert and can retrieved in PHP using $_GET[‘hor’] and $_GET[‘hi’]. So while that code can be saved as an html file and pass the data to a PHP class, it also offers up an opportunity to demonstrate how to add functional programming (FP) to JavaScript and to use FP with OOP. Use the buttons to test the program on as many devices as you have to see the range of screen sizes. Download the complete file set as well:
PlayDownload

Instead of stopping here and announce Mission Accomplished, I’d like to consider functional programming in JavaScript and closures in particular. In order to understand why I think it’s important to do this, consider the general purpose of both OOP design patterns and functional programming. Both were developed to better organize programming so that larger programs (consider what goes into your favorite game program) can be developed, maintained and changed.

Hackers vs Programmers

Hackers and hacks have a history of unthoughtful and malicious programming. It takes talent to build a house, but none to burn one down. The term “hack” originated as a program created by programmers who just threw code at a problem until something worked. The problem with hacks and hackers is that while the short-term goals may be accomplished, especially with short programs, hacks are like a guy with a machete chopping his way through the jungle to make a trail. The next time he comes down the trail, it’ll be grown over, and he’ll have to hack a new path. Figure 1 illustrates creating a hack vs. creating a program:

Figure 1: Hacking vs. Programming

Figure 1: Hacking vs. Programming


Compared to a modern highway, where planning, use of structure and interactive cooperation can create something of lasting value, hacks are a one-time accomplishment. It’s a kid playing in the mud. Fun until he’s got to start cleaning his own clothes.

Functional Programming in JavaScript

As you probably know, JavaScript does not have classes per se, and so we’re not going to try to create an OOP class in JS. However, the JavaScript folks are fortunate in having the book, Functional JavaScript (O’Reilly, 2013) by Michael Fogus. Functional programming is an important framework to understand in both PHP and JavaScript, and you can find a number of articles and other works covering FP in JS in addition to the Fogus book.

The “objects” in FP are called closures. In variations on JS and in special FP libraries (e.g., Underscore.js) you can find more FP functionality just as in the Hack dialect of PHP has functional operations for PHP not found in standard PHP. However, for here, I’d like to stick to plain vanilla JS and create what Fogus referred to as a “closure simulators” (faux closures), but they serve the same purposes. (PHP also has closures and a built-in Closure class.) I tend to think of closures as FP “objects,” but that characterization has a number of fuzzy edges; however, it’s a convenient way to think about them. Fogus summarizes a closure

as a function that captures the external bindings (i.e., not its own arguments) contained in the scope in which it was defined for later use (even after that scope has completed.)

—Michael Fogus p. 60, Functional JavaScript (O’Reilly, 2013)

A bit more dramatic description by Fogus is,

Closures are the programming language equivalent of vampires—they capture minions and give them everlasting life until they themselves are destroyed. The only difference is that closures don’t sparkle when exposed to sunlight.
—Michael Fogus p. 61, Functional JavaScript( O’Reilly, 2013)

Unfortunately, the PHP manual describes closures as equivalent to anonymous functions or lambdas. Simon Holywell in Functional Programming in PHP (p. 33) clarifies the manual’s misconception by noting that PHP closures are functional structures that include the use clause. In any event, both Holywell and Fogus describe a type of “object” where data can be packaged and used elsewhere in a program. So let’s take a look at a closure in JavaScript:

<html>
	<head>
		<title>Passing Width & Height with Closure</title>
		<script type="text/javascript">
			//Use closure "objects" to store screen size
			function getWide()
			{
				var wide = screen.width;
				return function()
				{
					return wide;
				}
			}
			function getHi()
			{
				var hi = screen.height;
				return function()
				{
					return hi;
				}
			}
 
			//Pass closures to variables
			var w = getWide();
			var h = getHi();
 
		        //Send data to PHP class, WiHi.php	
			var lambdaPass= function() {window.location.href = "WiHi.php?hor=" + w() + "&vert=" + h();};
		</script>
	</head>
	<body onload=lambdaPass()>
	</body>
</html>

The two functions, getWide() and getHi() are simulated closures, but functionally, they work just like closures. In fact, they work pretty much like objects. These two closures are passed to variables, w and h, which themselves are then closures and can be used to return the width and height of the device screen.

The important feature of the JS code is how it is able to package everything into a function that is called when the HTML loads. Figure 2 is a breakdown of what goes into the code passing between JavaScript and PHP:

Figure 2: Structures in passing data to PHP

Figure 2: Structures in passing data to PHP

The variable list begins with ?varName= and continues with any number of variables in the format, &varNext=. Values are assigned using concatenation (+), including closure functions such as w() and h(). The lambdaPass variable is assigned a lambda (anonymous) function that includes values returned from the two closures, w() and h().

PHP Captures the Width and Size

Using a class with a static function to display the data, PHP’s super-global $_GET[] finds the passed data using the JavaScript variable names, hor and vert. So, objects in the form of JavaScript closures are passed to a PHP object in the form of a class and used to display the data.

<?php
class WiHi
{
	private static $wide, $hi;
 
	public static function showSize()
	{
		self::$wide=$_GET['hor'];
		self::$hi=$_GET['vert'];
		echo "Width = " . self::$wide . "<br />Height = " . self::$hi;
	}
}
WiHi::showSize();
?>

When you test this first step in the CMS building process, be sure to test it with different devices. Figure 3 shows the results from an iMac with a 27 inch screen and an iPhone 6+.

Figure 3: Device width and height displayed.

Figure 3: Device width and height displayed.

In developing the CMS, the PHP object uses the device dimensions, but their display is only reflected in the nature of the page display. While this task has been simple because JavaScript can pass the screen width and height of the current device, the important feature to keep in mind as a programmer is how to use JavaScript closures to capture and retain data until it is needed. In the next part, we’ll look at choosing a page to reflect the device.

Share

Copyright © 2015 William Sanders. All Rights Reserved.

0 Responses to “Sandlight CMS I: Device Closures”


  • No Comments

Leave a Reply