Below is a directory structure for a PHP application I have pieced together from examples that provides accessibility via a central (api.php) entry point, no namespaces yet, and class names are identical to file names.
I have separated directories into
- authentication (has login scripts to process log in, logout, create user
- config (site wide settings, database settings)
- controllers (holds class files, with member functions that call specific data method)
- models (makes
simple
CRUD operation calls) - data (
composite
operation methods, which call multiplesimple
method calls)
utilities (or 'libraries', that are external to application)
vendor (I don't know what to call this, but it autoloads a class)
Like so
├── api.class.php <------------- Routes all requests to controller method using HTTP method name (GET, PUT, POST, DELETE)
├── api.php <------------- Calls processRequest from api.class.php
├── authentication
│ └── authenticate.php <------------- Specifies log in, logout, register logic
├── config
│ └── database.php
├── controllers
│ ├── <nameof>Controller.php <------------- Calls a data method from data class (actionitems.php for example)
│ ├── LoginController.php <------------- Call specific authenticate.php methods
├── data
│ ├── actionitems.php <------------- Calls several model operations
│ └── users.php
├── models
│ └── actionitem.php <------------- Contains matching attributes with table in database, and simple CRUD methods
├── utilities
│ └── <nameoflibrary>.php
└── vendor
└── autoloader.php <------------- Loads the class needed without namespace
A few clarifying questions arise...
1) Should I keep the models
separate from data
to separate simple, composite operations?
2) Is it acceptable to remove the Controller suffix on each file in the Controllers directory?
3) What exactly is the model responsible if not all database CRUD operations?
4) Finally, where should login go if a separate API endpoint?
I've seen this many places where we append "Controller" to the file/class.
The autoloader class below does not recognize the suffix, and the url route doesn't use the entire controller name, in fact, it has the data class name (pluralized model file name).
api.php (main entry point)
<?php
require_once 'vendor/autoloader.php';
require_once 'api.class.php';
class MyAPI extends api
{
public function __construct($request){
parent::__construct($request);
}
}
$api = new MyAPI($_REQUEST);
echo $api->processRequest();
api.class.php
<?php
abstract class api
{
protected $endpoint = array();
protected $verb = '';
protected $args = array();
protected $file = null;
protected $id = null;
public function __construct(){
//gets the specific HTTP method type and assigns the url pieces to properties of api class
}
public function processRequest() {
if(count($this->endpoint) > 0){
$class = $this->endpoint[0];
if (class_exists($this->endpoint[0], true)) {
$method = strtolower($this->method);
if (method_exists($class, $method))
return $this->_response((new $class())->{$method}($this->id));
}
return $this->_response("No Endpoint: {$this->endpoint[0]}", 404);
}
}
}
}
autoloader.php
<?php
class autoloader
{
private $directoryName;
public function __construct($directoryName)
{
$this->directoryName = $directoryName;
}
public function autoload($className)
{
$fileName = strtolower($className).'.php';
$file = $this->directoryName.'/'.$fileName;
if (file_exists($file) == false)
{
return false;
}
include ($file);
}
}
# nullify any existing autoloads
spl_autoload_register(null, false);
# instantiate the autoloader object
$classes = [
new autoloader('config'),
new autoloader('data'),
new autoloader('models'),
new autoloader('controllers')
];
# register the loader functions
foreach ($classes as $class)
spl_autoload_register(array($class, 'autoload'));
EDIT:
After some more research on the topic of Enterprise Patterns I have settled on breaking my database directories down into separate layers. I will need to decide on how to organize directories in my application possible move them to a parent directory under api called data, database or something similar.
● Data Models - Represents individual entities, containing properties unique to model, in the application database
● Domain Logic Models - Represents the logical steps and decisions that pertain to app, including data validation and complex business rules
● Mappers - provides access to a data source like a database,
● Services - responsible for providing the Data Model or collection to the consumer, acting as public interface to the external framework or end customer
Sample structure for data portion of app
Sample screenshot was from this presentation by Aaron Saray.
https://www.slideshare.net/aaronsaray/midwest-php-2013
This question also covers the topic
Organizing the directory structure of my DDD-based web application?