Skip to content

Using DOM in PHP

Greg Bowler edited this page Jun 20, 2017 · 17 revisions

The easiest way to use DOM in your PHP application is to install it as a dependency via Composer.

From your project's root directory, assuming you have Composer installed:

composer require phpgt/dom

Composer will download and install DOM and its dependencies into your project within the vendor/ directory. Inside that directory is the Composer autoloader script, which can be used to magically load any class you have installed.

Once DOM is installed using Composer:

<?php
require "vendor/autoloader.php";
$document = new Gt\Dom\HTMLDocument("<!doctype html><h1>Hello, World!</h1>");
$h2 = $document->createElement("h2");
$h2->textContent = "Goodbye, World!";
$document->body->appendChild($h2);

echo $document->saveHTML();

Without Composer

All releases are available on Github in zip and tar format for downloading. Of course you can clone the git repository too. This library follows the PSR-4 standard for autoloading, so once you have this library's PHP scripts in your project you can use a simple autoloader function to load the classes as they are referenced in your code.

Loading and rendering a page

A webpage's lifespan begins with an HTTP request from a browser to a server. After the server processes the page in some way, a corresponding HTTP response is sent back to the browser. For example, a request might be to get /quote-of-the-day and a corresponding response might be <!doctype html><h1>Quote of the day</h1><p id="output">Don't waste your time, or time will waste you.</p>. Building the response using code is where DOM comes in to make things easier.

The DOM is an indispensable tool when working with webpages, but to get the most out of it will require some code to route the incoming request to your code in a structured way. This library can be used in any PHP 7 application, but see the following sections for trivial examples of how to use DOM as the backbone of your next project.

More from PHP.Gt: The PHP.Gt WebEngine is a rapid development engine for PHP 7 applications that ties up all of the concepts described within these sections, including utilising DOM throughout and handling all of the routing, loading, rendering, etc.

Loading HTML into a new DOM

To create a DOM representation of an HTML page, all that is required is to construct a new HTMLDocument and pass the HTML as a string to the constructor's first parameter.

page.html:

<!doctype html>
<h1>List of useful programming books</h1>
<ul>
	<li>Code Complete 2, Steve McConnell</li>
	<li>Clean Code, Robert Martin</li>
	<li>Git for teams, Emma Jane Hogbin Westby</li>
	<li>Regular Expressions Cookbook, Jan Goyvaerts, Steven Levithan</li>
</ul>

index.php:

$html = file_get_contents("page.html");
$document = new HTMLDocument($html);

// Create a new entry and add it to the end of the list:
$ul = $document->querySelector("ul");
$li = $document->createElement("li");
$li->textContent = "Boolean Logic for Babies, Eric Redmond";
$ul->appendChild($li);

In the above example we can see a contrived example of how to take a static string of HTML and begin adding dynamic content to it. We are loading the HTML from a file called page.html as to not mix the page view with the page logic, and we will cover more methods of separating logic later in this section.

Rendering DOM contents to the browser

Any Document such as an HTMLDocument can be cast to a string in order to output the HTML representation. In order for a web browser to be able to display the page, at some point the HTML must be sent as a string to the web browser.

The simplest way to do this is:

echo $document;

Routing requests

In the previous examples we've seen how to load HTML into an HTMLDocument, how to save HTML and send it to the browser, and we know that the contents of the page can be traversed/manipulated using the many standard DOM methods and properties.

Now we can begin to route all requests to our PHP script in order to build a multi-page site. We can configure our web server or use PHP's inbuilt server to direct all requests at our router.php script. To do this with PHP's inbuilt server, run php -S 0.0.0.0:8080 router.php from the project's directory.

Once all incoming requests are being handled by our router script, it's the router's responsibility for rendering a response according to the requested URI. We can put all of our HTML files within a page/ directory and load them according to the requested URI by following this simple example:

router.php:

<?php
// 1. Obtain a URI without any query string.
$uri = strtok($_SERVER["REQUEST_URI"], "?");

// 2. Find a matching page, or throw a 404 error.
$viewPath = "page$uri.html";
if(!is_file($viewPath)) {
	http_response_code(404);
	die("File not found.");
}

// 3. Load HTML from the source file.
$html = file_get_contents($viewPath);
$document = new HTMLDocument($html);

// 4. Perform logic on our document.
// TODO.

// 5. Render the document to the page.
echo $document;

Running the above code allows us to load the relevant HTML document and render it back to the browser. Of course, for just displaying a static HTML file to the browser there is no need for a DOM -- or PHP for that matter -- but the magic lies in step 4 of the example code above.

Within step 4 we can load and execute PHP scripts that match the request in order to provide dynamic content to each page. We can also introduce templating mechanisms to share HTML across multiple pages (header, footer, navigation, etc.) and interact with database storage, for example.

Separating logic

Now that we have a page view system that loads HTML pages according to the requested URI, we can introduce a page logic system that executes PHP according to the requested URI. The logic that is executed in context of a page is sometimes referred to as the controller code -- the view and controller make up the "V" and "C" of "MVC".

More from PHP.Gt: The PHP.Gt WebEngine is a rapid development engine for PHP 7 applications that ties up all of the concepts described within these sections, including handling the distinction between Page View and Page Logic.

Continuing on from the previous example, we can begin to introduce page logic in step 4. A simple way to organise our view and logic files is to provide a matching .php file for any .html file that requires dynamic content.

For example, a simple page that calculates the percentage of a number can have its view stored in page/calculator.html and its logic in page/calculator.php.

In a real-world project, an object oriented solution would be recommended, but for simplicity's sake, let's assume the calculator.php file expects to interact with the global $document variable directly.

Update router.php:

// 4. Perform logic on our document.
$logicPath = "page/$uri.php";
if(is_file($logicPath)) {
	require($logicPath);
}

page/calculator.html:

<!doctype html>
<h1>Percentage calculator</h1>

<div id="output">
	Result: <span id="result"></span>
</div>

<form>
	<label>
		Percentage:
		<input name="percentage" placeholder="e.g. 25%" required />
	</label>
	<label>
		Of:
		<input name="number" placeholder="e.g. 105" required />
	</label>

	<button>Calculate</button>
</form>

page/calculator.php:

<?php
$percentage = $_GET["percentage"] ?? null;
$number = $_GET["percentage"] ?? null;

if($percentage && $number) {
	$result = ($percentage * $number) / 100;
	$document->getElementById("result")->textContent = $result;
}
else {
	$document->getElementById("output")->remove();
}