Coding a PHP 7 Framework #4 - Code Workshop

In part 4 of Coding a PHP Framework, we delve into the creation of the 'do' classes: doAction, doResponse and controllAction.



Coding a PHP 7 Framework #4 - Code Workshop

15th September 2018 in   PHP Tutorials by Elliott Barratt

You can view the finished framework at any time by visiting the GitHub repo at https://github.com/erbarratt/lectric.

If you need more space to see the code, click "Hide Sidebar >" above the Article Categories box to the right ->

In the last article we tackled the main /library/Lectric/controller.class.php file, that made decisions based on the URL_NODES constant array as to which of three classes should be called:

  • /library/Lectric/view.class.php
  • /library/Lectric/doAction.class.php
  • /library/Lectric/doResponse.class.php

Ignoring the /library/Lectric/view.class.php file for now, in this part of the series we'll look at the creation of three small, but important files:

  • /library/Lectric/doAction.class.php
  • /library/Lectric/doResponse.class.php
  • /library/Lectric/controlAction.class.php

You'll notice a class we haven't seen yet: /library/Lectric/controlAction.class.php. All will become clear.

Do-Response

The first of the 'do' class files we'll consider is the /library/Lectric/doResponse.class.php file. The job of this class is to look in the /do/ directory in our directory tree for a particular file, requested by the URL:

<?php
namespace Lectric;

/**
* do response class
*
* @package    Lectric Framework
* @author     Elliott Barratt
* @copyright  Elliott Barratt, all rights reserved.
*
*/ 
class doResponse extends lecPDO
{
	/**
     * The do response construct for calling do response files
     *
	 * @param object $DBH db handler 
	 *
     */
		function __construct(&$DBH)
		{
			
			parent::__construct($DBH);
			
			if (count(URL_NODES) !== 4){
				throw new \Exception('Wrong Node Count for Do-Response.');
			}
			
			if (file_exists(DOC_ROOT.'/do/'.URL_NODES[2].'/'.URL_NODES[3].'.php')) {
				require(DOC_ROOT.'/do/'.URL_NODES[2].'/'.URL_NODES[3].'.php');
			} else {
				throw new \Exception('File not in /do/ directory: '.htmlentities(URL_NODES[2]));
			}
			
		}
	
}

As usual, we'll accept the &$BH variable by reference. This is here in case the file we later require needs access to the database. To that end this class extends lecPDO (we'll get round to that file later in the series, it's a biggy). The lecPDO class needs the database handle in it's construct, so we call parent::__construct() here to do that, but continue with our own __construct().

After a quick test to make sure we have the correct number of elements in our URL_NODES array, we attempt to grab the file detailed by the URL. Note here that our URL's cannot have '.php' on the end of them (which for public websites will help with SEO). Folders in the /do/ directory should have file permissionsof 710 or similar to prevent public execution (remember we put the file rule in the /.htaccess file). This ensures that files within /do/ are only executed as part of a proper request. Just in case, it's always worth having additional checks within the files, like the existence of a $_POST index etc...

API's and Services

It's worth a bit of an aside to talk about how this response thing can make the framework deal with none-view type applications such as API's. By using a URL format of /do/response/folder/file/ you can easily split the API functionality into folders and files, and have quick access to the database to boot. Those files can then do pretty much anything, authenticate the connection, parse and process $_GET paramters, echo out some JSON with JSON headers etc...

Do-Action

The doAction class is a little more involved than the doResponse class, but not by much:

<?php
namespace Lectric;

/**
* do-action class
*
* @package    Lectric Framework
* @author     Elliott Barratt
* @copyright  Elliott Barratt, all rights reserved.
*
*/ 
class doAction
{
	
    /**
     * The do action construct for calling do functions
     *
	 * @param object $DBH db handler 
	 *
     */
		function __construct(&$DBH)
		{
			
			if (count(URL_NODES) !== 5){
				throw new \Exception('Wrong Node Count for Do-Action.');
			}
			
			if (class_exists('\\'.URL_NODES[2].'\\'.URL_NODES[3])){
				
				$doClass = '\\'.URL_NODES[2].'\\'.URL_NODES[3];
				$doer = new $doClass($DBH);
				
				if (method_exists($doer, 'do_'.URL_NODES[4])){
					
					$action = $doer->{'do_'.URL_NODES[4]}();
					
					if ($action instanceof controlAction) {
					
						$action->performAction();
						
					} else {
						throw new \Exception('Class '.htmlentities('\\'.URL_NODES[2].'\\'.URL_NODES[3].' doesn\'t return a controllAction class in Do-Action.'));
					}
				
				} else {
					throw new \Exception('Class '.htmlentities('\\'.URL_NODES[2].'\\'.URL_NODES[3].' doesn\'t contain method '.'do_'.URL_NODES[4].' in Do-Action.'));
				}
				
			} else {
				throw new \Exception('Class '.htmlentities('\\'.URL_NODES[2].'\\'.URL_NODES[3]).' doesn\'t exist for Do-Action.');
			}
			
		}
	
}

Just like the doResponse class, we get the database handler by reference. The difference here however is that the doAction class does not extend the lecPDO class, the reason for which is eveident further down.

The job of the doAction class is to check for the existence, instantiate and then run a function of the requested class, passed through by the URL. The $doer->{'do_'.URL_NODES[4]}() call is a dynamic method invocation, making the object $doer try to execute a function called 'do_'.URL_NODES[4].

There are exceptions thrown for failing a few tests, all of which allow us to gracefully fall back to a view with status code of 400 if necessary (as in part 3 of this article series).

So having put that in place, this means there are a few restrictions:

  • do_ functions can never have arguments. They are intended for use with $_GET and $_POST paramter processing.
  • do_ functions must always return a \Lectric\controllAction() object.

ControlAction

It this basic form, the /library/Lectric/controlAction.class.php file either redirects to a view URL, or simply does nothing...

<?php
namespace Lectric;

/**
* Deals with actions from do functions
*
* The control action holds the action, if any, of the do function
*
* @package    Lectric Framework
* @author     Elliott Barratt
* @copyright  Elliott Barratt, all rights reserved.
*
*/ 
class controlAction 
{
	
	private $_type = '';
	private $_location = '';
	private $_message = '';
	
    /**
     *
     * Set member variables for use in performAction()
     */
		function __construct(string $type = 'none', string $location = '', string $msg = '')
		{
			
			switch ($type){
				
				case 'view':
					$this->_type = $type;
					$this->_location = $location;
					$this->_message = $msg;
				break;
				case 'none':
					$this->_message = $msg;
				break;
				default:
					//do nothing
				break;
				
				}
				
			return;
			
		}
	
    /**
     * perform the action set up by construct.
     * 
     * @return void
     */
		public function performAction(): void
		{
			
			switch ($this->_type){
				
				case 'view':
					if (trim($this->_message) !== ''){
						controller::setSessionMessage($this->_message);
					}
					header('Location: '.$this->_location);
					exit;
				break;
				case 'none':
					if (trim($this->_message) !== ''){
						echo $this->_message;
					}
					exit;
				break;
				default:
					exit;
				break;
				
			}
			
		}
	
}

For example, you could use it to process a login form for a user area:

  • Set the action of the form to something like /do/action/YourNameSpace/user/login/.
  • Then, in /library/YourNameSpace/user.class.php, you'd need a do_login() function.
  • That function would return a controlAction with arguments $type = 'view', $location = '/user-area/', $msg = 'You are now logged in.'
  • The user would be redirected to www.example.com/user-area/ and be shown a message of 'You are now logged in' (assuming the template looked for / output the session messages). 

Or, you could use it to perform a cron job function, setting the $type argument to 'none'.

Conclusion

Now we have the routing classes in place, we have one more class to contend with before we can make an example application, the /library/Lectric/lecPDO.class.php file.

Continue to Part 5 by clicking here.




Hide Sidebar >



Archive



Search


Hide Sidebar >


This website uses cookies. Privacy Policy