📜 ⬆️ ⬇️

Refactoring a simple PHP application for MODx

Posted on Sep 02, 2011 by James Rotering
PHP Skill Level: medium
MODx Skill Level: Beginner

Description: This tutorial shows how to remake a file with mixed PHP / HTML code for the MODx Revolution. It is for people who are comfortable working with PHP, but they still learn the basics of MODx.

If you fit most of the following descriptions, this guide should be helpful to you:
- You wrote scripts that combine PHP code and HTML
- you understand PHP loops and arrays
- You wrote a PHP code that connects to the database and retrieves records
- Do you have a general idea of ​​how MODx snippets and other elements work?

For example, I will consider a simplified version of a real project that I recently completed.
The application was developed in PHP / HTML and does the following:
- get list of records from database table
- displays entries in an HTML table
- Displays two drop-down selection fields to filter results by specific column values.

If you are interested, you can see the work of the application here .

Starting with a mixed PHP / HTML file


')
The source code for this application looked like this (simplified for clarity):

File: acctCodes.php (original version)
<html> <head> <title>    SFS</title> </head> <body> <h1>    SFS</title> <form> <!--  SELECT box --> <div> <label for="byCategory">  :</label> <select name="byCategory" id="byCategory"> <option> </option> 
  <?php //   -     $values = //   -         foreach ($values as $value) { echo '<option value="' . $value . '">' . $value . '</option>'; } ?> 
  </select> </div> <!--  SELECT box --> <div> <label for="byType">  :</label> <select name="byType" id="byType"> <option> </option> 
  <?php $values = //   -         foreach ($values as $value) { echo '<option value="' . $value . '">' . $value . '</option>'; } ?> 
  </select> </div> </form> <!--    --> <table id="acctCodes"> <thead> <!--  ,    <th>.    --> </thead> <tbody> 
  <?php $records = //   -        foreach ($records as $record) { ?> 
  <tr> <td><?php echo $record['category']; ?></td> <td><?php echo $record['status']; ?></td> <td><?php echo $record['account']; ?></td> <td><?php echo $record['acctType']; ?></td> <td><?php echo $record['title']; ?></td> <td><?php echo $record['definition']; ?></td> </tr> 
  <?php } ?> 
  </tbody> </table> </body> </html> 

PHP is pretty simple here. There are three separate blocks of code where the query is executed, then the results are framed into suitable HTML tags and displayed on the page. The third block is somewhat bizarre - the PHP code is interrupted in order to use normal HTML code inside the loop, and not bulky, unpleasant “echo” statements.
But nothing terribly difficult here happens.

However, we will need to do some cleaning in order to prepare for the transition to MODx.

Part One: Cleaning (First we get the values ​​and then the output)



The first step to cleaning this PHP code for MODx (and indeed in general) is to avoid mixing the application logic with the page markup. Instead of executing each query before using it, we will run all the queries, and then, if necessary, simply display the results using echo.

The result is something like this (again, very simplified for clarity):

File: acctCodes.php (cleared version)
 <?php //   -     $values = //   -         $options1 = ''; foreach ($values as $value) { $options1 .= '<option value="' . $value . '">' . $value . '</option>'; } $values = //   -         $options2 = ''; foreach ($values as $value) { $options2 .= '<option value="' . $value . '">' . $value . '</option>'; } $records = //   -        $trrows = ''; foreach ($records as $record) { $trrows .= '<tr><td>' . $record['category'] . '</td><td>' . $record['status'] . '</td><td>' . $record['account'] . '</td><td>' . $record['acctType'] . '</td><td>' . $record['title'] . '</td><td>' . $record['definition'] . '</td></tr>'; } ?> 
 <html> <head> <title>    SFS</title> </head> <body> <h1>    SFS</h1> <form> <!--  SELECT box --> <div> <label for="byCategory">  :</label> <select name="byCategory" id="byCategory"> <option> </option> <?php echo $options1; ?> </select> </div> <!--  SELECT box --> <div> <label for="byType">  :</label> <<font color="#006699">select name="byType" id="byType"> <option> </option> <?php echo $options2; ?> </select> </div> </form> <!--    --> <table id="acctCodes"> <thead> <!--  ,    <th>.    --> </thead> <tbody> <?php echo $trrows; ?> </tbody> </table> </body> </html> 


This makes markup much easier to view and edit. All PHP code is contained in four blocks: the first query sets the values, and the next three simple echo commands display these values ​​on the screen.
This is more acceptable for transferring this small web application to MODx.

Part Two: Snippets and Placeholders



To transfer our cleaned code to MODx, we need to make a few additional changes.
Our HTML code can be immediately copied to the MODx resource. (The resource will no longer change! - approx. Lane.)
But we need to replace the PHP code with snippets and some placeholders.

The content of our MODx resource will look like this:
Resource MODx: 'acctCodes'
 [[accountCodes]] <html> <head> <title>    SFS</title> </head> <body> <h1>    SFS</h1> <form> <!--  SELECT box --> <div> <label for="byCategory">  :</label> <select name="byCategory" id="byCategory"> <option> </option> [[+options1]] </select> </div> <!--  SELECT box --> <div> <label for="byType">  :</label> <select name="byType" id="byType"> <option> </option> [[+options2]] </select> </div> </form> <!--    --> <table id="acctCodes"> <thead> <!--  ,    <th>.    --> </thead> <tbody> [[+trrows]] </tbody> </table> </body> </html> 

In our resource, four blocks of PHP code have been replaced by MODx tags. The first, [[accountCodes]] , will call the accountCodes snippet (which we haven't written yet). The next three tags are placeholders, which will be replaced by the values ​​given by our snippet.
Now we need to write this snippet.

Part Three: Snippet



Our “accountCodes” snippet will contain the code from this first PHP block — all requests and loops. The only thing we are going to add is a few lines of MODx API code for creating placeholders.

Snippet: "accountCodes"
 <?php //   -     $values = //   -         $options1 = ''; foreach ($values as $value) { $options1 .='<option value="' . $value . '">' . $value . '</option>'; } $values = //   -         $options2 = ''; foreach ($values as $value) { $options2 .= '<option value="' . $value . '">' . $value . '</option>'; } $records = //   -        $trrows = ''; foreach ($records as $record) { $trrows .= '<tr><td>' . $record['category'] . &nbsp; '</td><td>' . $record['status'] . '</td><td>' . $record['account'] . '</td><td>' . $record['acctType'] . '</td><td>' . $record['title'] . '</td><td>' . $record['definition'] . '</td></tr>'; } $modx->setPlaceholder('options1', $options1); $modx->setPlaceholder('options2', $options2); $modx->setPlaceholder('trrows', $trrows); 


This is our snippet. Compared to our original PHP code, it is supplemented with three lines of “setPlaceholder” at the bottom. They simply say MODx that if and when he meets the placeholder [[options + options1]] on the page below, he should replace it with the value $ options1 . Placeholders are a simple and elegant way to process output values ​​from snippets.

Now we have done everything we need for the web application to work inside the MODx. However, we can take a few additional steps that will make our application much sexier using more API functions in MODx. I would rate our current implementation as “satisfactory” (in the original, “C.” ) Let's continue the work.

Part Four: Using Chunks as Output Templates



One of the criticisms that can be made to our current PHP code is that it still mixes markup with logic. Our foreach loop still contains chunks of HTML markup:
 foreach ($values as $value) { $options1 .= '<option value="' . $value . '">' . $value . '/option>'; } 

This strategy is far from ideal: suppose the boss asks for the HTML encoder Skippy (in the original “Skippy the HTML code monkey”) , change the HTML code of this application, adding a few additional attributes for each <option> tag. But we do not want Skippy ("Skippy the HTML code monkey") to be somewhere near our PHP script, is it?

There are several ways to remedy this situation in PHP - pulling HTML code from external files and replacing strings comes to mind. However, we do not need to worry and figure out a suitable solution. For this task, MODx offers another simple and elegant solution: chunks with placeholders .

The “option” code from the snippet above can be rewritten as a chunk called “option”:

Chunk: "option"
 <option value="[[+value]]">[[+value]]</option> 

This chunk is nothing special - some HTML with a couple of placeholders. “Option” is a simple, useful chunk that can be used anywhere - in several snippets in different resources.

Now we can change our snippet by adding a bit more MODx API code to use the value of this chunk in our loop:
 <?php //   -     $values = //   -         $options1 = ''; foreach ($values as $value) { $modx->setPlaceholder('value', $value); $options1 .= $modx->getChunk('option'); } 

Now our loop creates a placeholder for $ value and adds the value of the 'option' chunk to the output string.
This allows you to completely separate all HTML code from PHP. If Skippy (“Skippy the HTML code monkey”) needs to add an attribute to the <option> elements, he can do this by editing the “option” chunk. (Just tell him not to touch these placeholders!)

Table rows can be made in the same way:
Chunk: "trrows"
 <tr> <td>[[+category]]</td> <td>[[+status]]</td> <td>[[+account]]</td> <td>[[+acctType]]</td> <td>[[+title]]</td> <td>[[+definition]]</td> </tr> 

and php code to call it
 each ($records as $record) { $trrows .= $modx->getChunk('trrows', $record); } 

Note that in this example we don’t even have to install any placeholders!
We can pass the associative $ record array into GetChunk () as an argument, and placeholders will automatically ** be set for each key / value pair in the array!
(** MODX Awesomeness! You're soaking in it! **) (Analogy with the slogan of some laundry detergent? - Lane comment.)

So now we can save all our pieces of HTML in chunks and rewrite our snippet like this:
 <?php //   -     $values = //   -         $options1 = ''; foreach ($values as $value) { $modx->setPlaceholder('value', $value); $options1 .= $modx->getChunk('option'); } $values = //   -         $options2 = ''; foreach ($values as $value) { $modx->setPlaceholder('value', $value); $options2 .= $modx->getChunk('option'); } $records = //   -        $trrows = ''; foreach ($records as $record) { $trrows .= $modx->getChunk('trrows', $record); } $modx->setPlaceholder('options1', $options1); $modx->setPlaceholder('options2', $options2); $modx->setPlaceholder('trrows', $trrows); 

It is already starting to look very good. We used the MODx API for the output template and our snippet looks really clean. Nevertheless, there is one thing that bothers me, and can be potentially problematic - now we have MODx API calls attached to the logic of our application. If we are 100% sure that we will only ever need the data printed on this web page and in this format, then this is really not a problem. But if there is a possibility that this data may need to be used differently - somewhere outside the MODx - it would be better to keep the main application logic separate from the MODx entities.

Currently, the application receives a rating of "good" (in the original - "B") . Let's take the last step and increase our rating to “Excellent” (in the original - “A”) .

Part Five: Separate Your Application Logic



All we need to do for the last step is to divide our snippet into two parts. The first part will contain our application logic and return all arrays as members of one large array.
This will be done in pure PHP and ideally should be saved as a file on our server.

The second part is the snippet itself. He will first get the array returned by the logic file, then use chunks to standardize the result lines, and finally set up placeholders to display the results in resources.

This is how it all ends:

File: acctCodes.php
 <?php //   -     $values = //   -         $values2 = //   -         $records = //   -        return array('values'=>$values, 'values2'=>$values2, 'records'=>$records); ?> 


Snippet: 'acctCodes'
 <?php $data = include_once(MY_INCLUDE_PATH . 'acctCodes.php'); $options1 = ''; foreach ($data['values'] as $value) { $modx->setPlaceholder('value', $value); $options1 .= $modx->getChunk('option'); } $options2 = ''; foreach ($data['values2'] as $value) { $modx->setPlaceholder('value', $value); $options2 .= $modx->getChunk('option'); } $trrows = ''; foreach ($data['records'] as $record) { $trrows .= $modx->getChunk('trrows', $record); } $modx->setPlaceholder('options1', $options1); $modx->setPlaceholder('options2', $options2); $modx->setPlaceholder('trrows', $trrows); 

Now our ducks are abreast (now we have our ducks in a row) . Let's take a look at what we did:
- We have the application logic in the file on the server (completely outside of MODx).
- We transfer data directly (without any HTML markup) to our MODx snippet.
- We allow MODx to manage the templating of our output records.
- We set all the placeholder values ​​in one snippet at the top of the resource.
- Where it is necessary, we display our data on the page using placeholders.

We have come a long way from our original mixed PHP / HTML file, right? I would rate this final implementation as “excellent” (in the original - “A”) . However, someone probably has better ideas on how to separate the various problem areas. But for PHP connoisseurs, like me, this is a good place to start.

I hope you learned some of the key problems when writing simple PHP applications for use in MODx. Feel free to leave any thoughts, questions or suggestions about this guide in the comments here .

Note per. - as a result were created:
- resource acctCodes (part 2)
- accountCodes snippet (p.5)
- acctCodes.php file ( p.5 )
- chunk option (part 4)
- chunk trrows (part 4)

Source: https://habr.com/ru/post/128088/


All Articles