phossa2 / framework
A modern PHP framework built-upon configuration, dependency injection and middlewares.
Installs: 17
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 0
Type:project
Requires
- php: >=5.4.0
- fxp/composer-asset-plugin: 1.*
- phossa2/app-skeleton: dev-master
This package is not auto-updated.
Last update: 2024-10-26 19:59:11 UTC
README
phossa2/framework is a modern PHP framework built-upon configuration, dependency injection and middlewares.
It requires PHP 5.4, supports PHP 7.0+ and HHVM. It is compliant with PSR-1, PSR-2, PSR-3, PSR-4, and other proposed PSR standards.
Create the project
Install via the composer
utility.
# cd installation_dir/ # composer create-project phossa2/framework PROJECT
Directory structure
phossa2/framework is delivered with the single server installation
directory structure. It also can be restructured to fit different requirements
by modifying directory settings in the .env
file.
-
Default framework distribution is for a single server installation.
|--- .env the environment file +--- PROJECT/ the project directory |--- phossa2 the utility script |--- app/ app installation dir |--- config/ where all the config files located |--- plugin/ where all the plugins installed |--- public/ where public stuff located | |--- asset/ | +--- index.php single public entry |--- runtime/ runtime related stuff | |--- local/ host-specific storage | | |--- cache | | +--- session | +--- log/ log file directory |--- system/ system files | +--- bootstrap.php bootstrap file +--- vendor/ third-party libs
-
Multiple servers installation
The framework can also be installed across multiple servers to provide capabilities such as load balancing, central app managment (NFS mounted) etc.
|--- .env host-specific environments |--- local host-specific local storage | |--- cache/ | +--- session/ | |--- PROJECT/ shared among servers (NFS mounted) | |--- phossa2 | |--- app/ | |--- config/ | |--- plugin/ | |--- public/ | |--- system/ | +--- vendor/ | +--- runtime/ shared runtime stuff (NFS mounted) |--- log/host1 host-specific log dir |--- upload/ upload dir +--- static/ generated static html files
Execution path
-
Application execution path
Single app entry point. Load
system/bootstrap.php
file and then process the app middleware queue defined inconfig/middleware.php
<?php // public/index.php // Load bootstrap file require dirname(__DIR__) . '/system/bootstrap.php'; // execute the main middleware queue $response = Service::middleware()->process( ServerRequestFactory::fromGlobals(), new Response() );
Required by
public/index.php
or phossa2 utility script. Bootstrap all required stuff, including-
set basic environments.
-
start autloading.
-
load other environments from
.env
file. -
start $config and $container which read configs from the
config/
directory.
Environment file installled at one level upper of
PROJECT
directory. This file is host specific and may differ on different servers.See phossa2/env and phossa2/config for detail.
-
To change app environment
Change the value of
PHOSSA2_ENV
to implement different servers, such as production server, dev server or staging servers. -
To restructure the framework
By changing directory settings in this file, user may be able to restructure the framework.
- start
$config
and$container
-
Configurations are grouped into files and located in the directory
config/
.See phossa2/config for detail.
-
phossa2/di provides a PSR-11 compliant container implementation built upon phossa2/config.
Container objects are configured in
config/di.php
or scattered in the 'di' section of different files such asconfig/db.php
.A service locator
Phossa2\Di\Service
is also provided.The container object is available as
Service::container()
. The configuration object is available asService::config()
.use Phossa2\Di\Service; $config = Service::config(); $container = Service::container(); // get the db configuration array $db_conf = $config->get('db'); // get the db object $db = $container->get('db'); // or get from locator $db = Service::db();
- Process the app middleware queue
Middlewares are defined in
config/middleware.php
. -
-
Console script execution path
Single utility entry point. Load
system/bootstrap.php
file and then process command line arguments- Common line arguments
Common line arguments processed. And then look for controller/action pairs in the 'system/Console/' and 'app/Console/' directories for specific actions.
Configuration driven framework
phossa2/framework is a configruation driven framework. Most of the objects,
utilities are defined in config files under the config/
directory. Objects are
generated automatically by the DI container and avaiable via
Service::objectId()
.
For example, the database connection is defined in config/db.php
as follows,
use Phossa2\Db\Driver\Pdo\Driver as Pdo_Driver; // config/db.php return [ // PDO driver classname 'driver.pdo.class' => Pdo_Driver::getClassName(), // connect conf 'driver.pdo.conf' => [ 'dsn' => 'mysql:dbname=test;host=127.0.0.1;charset=utf8', ], // container section 'di' => [ // ${#db} 'db' => [ 'class' => '${db.driver.pdo.class}', 'args' => ['${db.driver.pdo.conf}'], ], ], ];
The last section di
equals to defining a $db
in the container
$db = new Pdo_Driver(['dsn' => '...']); $container->set('db', $db);
To utilize the database connection in your code, you may either inject it in another container object configuration file.
// config/article.php return [ 'class' => MyArticle::getClassName(); // ${#article} in container 'di' => [ 'article' => [ 'class' => '${article.class}', 'args' => ['${#db}'] // inject $db ] ] ];
Or use it explicitly with the service locator,
use Phossa2\Di\Service; // get db $db = Service::db(); $article = new MyArticle($db);
Complicated db configurations can be found in config/production/db.php
which
uses a db connection manager with a pool of a read-write connection and couple
of read-only connections.
use Phossa2\Db\Manager as Db_Manager; use Phossa2\Db\Driver\Pdo\Driver as Pdo_Driver; // config/production/db.php return [ // driver manager 'manager.class' => Db_Manager::getClassName(), // more connect confs 'driver.pdo.conf2' => [ 'dsn' => 'mysql:dbname=test;host=127.0.0.2;charset=utf8', ], 'driver.pdo.conf3' => [ 'dsn' => 'mysql:dbname=test;host=127.0.0.3;charset=utf8', ], // callback to get a db from db manager with tagname 'callable.getdriver' => function($dbm, $tag) { return $dbm->getDriver($tag); }, // container section 'di' => [ // ${#dbm} 'dbm' => [ 'class' => '${db.manager.class}', 'methods' => [ ['addDriver', ['${#db1}', 1]], ['addDriver', ['${#db2}', 5]], ['addDriver', ['${#db3}', 5]], ], ], // ${#db1} 'db1' => [ 'class' => '${db.driver.pdo.class}', 'args' => ['${db.driver.pdo.conf}'], 'methods' => [ ['addTag', ['RW']] ] ], // ${#db2} 'db2' => [ 'class' => '${db.driver.pdo.class}', 'args' => ['${db.driver.pdo.conf2}'], 'methods' => [ ['addTag', ['RO']] ] ], // ${#db3} 'db3' => [ 'class' => '${db.driver.pdo.class}', 'args' => ['${db.driver.pdo.conf3}'], 'methods' => [ ['addTag', ['RO']] ] ], // ${#dbro} read only driver (round-robin) 'dbro' => [ 'class' => '${db.callable.getdriver}', 'args' => ['${#dbm}', 'RO'], 'scope' => Container::SCOPE_SINGLE, ], // ${#dbrw} readwrite driver (round-robin if any) 'dbrw' => [ 'class' => '${db.callable.getdriver}', 'args' => ['${#dbm}', 'RW'], 'scope' => Container::SCOPE_SINGLE, ], // ${#db} either RW or RO 'db' => [ 'class' => '${db.callable.getdriver}', 'args' => ['${#dbm}', ''], 'scope' => Container::SCOPE_SINGLE, ], ], ];
The previous configruations equal to the following code,
// different db connectors $db1 = (new Pdo_Driver($conf ))->addTag('RW'); $db2 = (new Pdo_Driver($conf2))->addTag('RO'); $db3 = (new Pdo_Driver($conf3))->addTag('RO'); // db manager $dbm = (new Db\Manager\Manager()) ->addDriver($db1, 1) // readwrite, factor 1 ->addDriver($db2, 5) // read_only, factor 5 ->addDriver($db3, 5) // read_only, factor 5 // get a readonly connection (round robin) $dbro = $dbm->getDriver('RO'); // get a readwrite connection $dbrw = $dbm->getDriver('RW'); // get a db connection (either RW or RO) $db = $dbm->getDriver('');
Middleware driven framework
phossa2/framework is not a pure MVC structure but a middleware-centric framework. For middleware runner implementation, please see phossa2/middleware.
Different middleware queues are defined in config/middleware.php
.
Routing
Routes are handled by Phossa2\Middleware\Middleware\Phossa2RouteMiddleware
.
See phossa2/middleware, phossa2/route for
detail.
Route dispatcher $dispatcher
is defined in config/route.php
. It will be
injected into the main middleware queue when processing reaches the
Phossa2RouteMiddleware
.
Different routes should be defined in config/route/*.php
files. For example,
// route/50_admin.php $ns = "App\\Controller\\"; // controller namespace return [ 'prefix' => '/admin/', 'routes' => [ // resolve to ['App\Controller\AdminController', 'defaultAction'] '/admin/{action:xd}/{id:d}' => [ 'GET,POST', // http methods, [$ns . 'Admin', 'default'], // handler, ['id' => 1] // default values ], ] ];
Note: 50_
in the route filename is for sorting purpose.
Application programming
-
Do it a simple way
You may just start programming in the
app/
directory where phossa2/app-skeleton is already installed during the project creation. -
Do it a nice way
-
Git clone app-skeleton to your local directory.
-
Add your own stuff to the cloned application skeleton.
-
Remove the initially installed
app-skeleton
from the project
# cd PROJECT/ # composer remove phossa2/app-skeleton
- Install your app into the
PROJECT
-
If your app is on the git
Add the following lines to your
PROJECT/composer.json
"repositories": [ { "type":"package", "package": { "name": "my/app", "version": "master", "source": { "url": "https://github.com/my/app.git", "type": "git", "reference":"master" } } } ]
-
If your app is just a zip.
Add the following lines to your
PROJECT/composer.json
"repositories": [ { "type": "package", "package": { "name": "my/app", "version": "master", "dist": { "type": "zip", "url": "http://mydomain.com/downloads/app-1.4.zip", "reference": "master" } } } ]
-
then install the app via
composer require
orcomposer update
# cd PROJECT/ # composer require my/app
-