project
PHP microframework, (*1)
This is a small framework designed for REST APIs and simple websites. It is very lightweight, and has a shallow stack-trace, meaning that applications run fast and application errors are easy to track down., (*2)
how to add to a project via composer
to add this microframework to your project, you should add it to the 'require' section of composer.json, as follows:, (*3)
"require": {
"willv/project": "^1.0.0"
}
how to use
example app
The example app can be used to get up and running quickly; just copy it and adapt it to your needs, (*4)
directory structure
The web root should be 'www' and all PHP requests should be routed to www/index.php (other content in the www directory should be static resources only; this microframework does not concern itself with handling them).
All 'project' files and directories should be at the same level as the 'www' directory (i.e. one above the web root), (*5)
bootstrapper
The microframework contains a bootstrapper object called App that can be used to easily set-up your projects. You should instantiate it in a file called, e.g. "global.php" which you then require in every script that needs to use the framework; typically, the main front-controller for HTTP requests, and any shell scripts that need the environment as well., (*6)
namespace
You will need to invent a namespace for your app, for the autoloader to work; see the example app for more details., (*7)
constructors
The 'new' keyword is disabled for all classes in this framework; instead, there is a factory method called 'create' which should be called statically (e.g. User::create()). This is because the static-method syntax allows, more versions of PHP, for calling methods on objects in the same line as instantiating them., (*8)
abstract classes
Many of the classes in 'project' are abstract classes, meaning that you can't instantiate them directly. Instead you should extend the class with a version relevant for your app, and use that instead. For example, if you are writing a blog app you might have Domain Objects (see below) called User, Post, and Comment. These classes should all extend the base DomainObject class., (*9)
setUp methods
Many of the abstract classes in 'project' have setUp methods, which is where you should do your configuring (e.g. defining fields in a dataset). See the example app for more details., (*10)
core concepts
domain objects
Domain objects represent entities used by your app (for example, blog posts, or users). Each domain object is associated with a type of Dataset, meaning that that data submitted for its various properties has a set of validation rules; if you break them, an exception will be thrown., (*11)
For example, if you have a domain object called User, you might associate it with a dataset called UserDataset, which contained the fields "name" and "age", (*12)
$alice = User::create(array("name" => "Alice", "age" => "54"))
$alice->set("age", "55")
On both the above lines, the whole dataset will be validated., (*13)
datasets
Datasets are used in two ways:, (*14)
* To validate data submitted by a user
* To validate data associated with a domain object
To make a new type of dataset, extend the class \WillV\Project\Dataset; you can then, (*15)
* Instantiate this dataset and call its isValid method to check if a set of data is valid
* Associate the class with a domain object, and it will be used to validate data submitted when creating or changing the domain object
To associate a dataset with a domain object, configure it in the relevant domain object's setUp method, like this:, (*16)
class Task extends DomainObject {
protected function setUp() {
$this->dataSetName = "\ProjectExampleApp\Datasets\TaskDataset";
}
}
data mappers
Datamappers are used to save domain objects., (*17)
At present, there is only one type of datamapper; MySQLMapper, which saves objects to MySQL databases; although more may be added (next on the list is a MongoMapper, which should be a drop-in replacement that saves them to MongoDB instead)., (*18)
The DataMappers assume that the database schema has fields for "id", "created_utc" (date created), and "updated_utc" (date updated) so you should make sure that your database schema contains those fields, or there will be an error., (*19)
controllers
Controllers are simple PHP scripts, which should be placed in a directory called 'controllers'. While being simple scripts, they are included from a context in which they have access to various pieces of information, for example URL parameters, which are available from the array '$this->urlParams'.
They should directly 'echo' their output, and are then free to 'exit'., (*20)
routing
Routing should be done by extending the Router class. In the Router's setUp method, you can define routes for most common HTTP methods; parameters should be included in {braces}, and will be available in controllers in the numerically-indexed array $this->urlParams. When you add a route, there are three parameters; the pattern, the controller-name, and the response type; the latter defaults to text/html. See the example app for more information., (*21)
404 and 500 errors
If you create controllers called 404.php and 500.php these will be used automatically to handle the cases, respectively, of no-such-route and uncaught exceptions., (*22)
environments
Environment objects in 'project' store key-value pairs, and a function for determining whether or not the environment is active., (*23)
Your app should extend the \WillV\Project\Environment class, configuring your environment with a list of required fields that each environment must provide. You can then instantiate your environments and add them to your environment list (see below)., (*24)
When instantiating environments, you should provide a list of key/value pairs, and a function to determine if the new environment is active or not. Some of the key/value pairs can be stored in JSON config files, which have the advantage that you can list them in .gitignore so that they will not end up in version control; these are good for storing, for example, access credentials for databases and third-party APIs., (*25)
environment lists
You should use an EnvironmentList to store a list of available environments. The getActiveEnvironment method will find the activeEnvironment by calling the appropriate method of each environment in turn, until the active environment is found., (*26)