Custom PHP framework that ONLY includes the bare minimum functionality required to build RESTFUL PHP APIs.
- Request Router - league/router
- DI Container - league/container
- ORM - maghead/maghead
- Request validator - vlucas/valitron
- JWT - lcobucci/jwt
-
Route definitions go in
app/Routes/routes.php
, please do not define callback routes. Any route should ultimately terminate into a controller, example is available in the route file. For advanced routing shenanigans, see the request router documentation. -
Controller definitions go in
app/Controllers
, please place your controllers in theMoonwalker\Controllers
namespace. Your controller- MUST be registered in
app/Config/generic.php
'scontrollers
array. This is so we can autoinject dependencies via the IoC container. - MUST extend
Moonwalker\Core\Controller
- MUST be registered in
-
Controller methods MUST return an instance of
Moonwalker\Core\Response
on success. Our response class is context aware, that means it will respond via lookup of content-type headers (json / xml / msgpack).- On failure, the framework expects an exception to be thrown.
- Please use
Moonwalker\Core\Errors\UserFriendlyException ($message, $http_response_code)
to throw exceptions that are safe to disclose to the user. - Please use
Moonwalker\Core\Errors\ValidationFailedException (Array $validationFailures)
to throw exceptions that illustrate to the user why exactly their request was denied. You can get$validationFailures
from the validator library, seeHelloWorldController::postHello
for an example. Response code is fixed to400
for this. - You can throw any of
League\Route\Http\Exception\*
to define a generic HTTP error, full list is here. These will also be disclosed to the user. - ANY other
Exception
thrown or normal PHP error will result in a response code of500
and a generic response ofWe are sorry, something went wrong
to the user.
- Please use
- On failure, the framework expects an exception to be thrown.
-
ORM (and specifically the CLI
maghead
tool require DBAL init before they work). Please configure your local database instance inapp/Config/database.php
- Once you've updated your config, please run
vendor/bin/maghead use app/Config/database.php
- Make sure the defined
Schema
s show up invendor/bin/maghead schema list
- If they do, you can now build static bindings ("models") for them like
vendor/bin/maghead schema build
- If the build succeeds, you're now ready to build the schema in the database server with
vendor/bin/maghead sql
- Any time a change is made to the schema, the last two commands need to be rerun.
- Once you've updated your config, please run
-
ORM Relationships
- The general process to do this is defined here
- Please note that
one
(as defined in the doc) does not exist, and you'll be forced to replace it withhasOne
instead. - Please name the accessors sensibly:
- An user may have multiple
permissions
androles
, thus this (below) makes sense. Read it like this: An user may have many permissions and roles.$this->many('permissions', 'Moonwalker\Models\PermissionAssociationSchema', 'user_id', 'id'); $this->many('roles', 'Moonwalker\Models\RoleAssociationSchema', 'user_id', 'id');
- An association table however has a
definition
, i.e: a pointer to what that table creates an association for. ForPermissionAssociation
andRoleAssociation
, these thus make sense (below). A permission (or role) association ultimately belongs to a specific permission or role.$this->belongsTo('definition', 'Moonwalker\Models\PermissionSchema', 'id', 'permission_id'); $this->belongsTo('definition', 'Moonwalker\Models\RoleSchema', 'id', 'role_id');
- An user may have multiple
-
The framework's request pipeline functions like
request -> route dispatcher -> middlewares -> controllers -> response
, if you want to perform things like Unmarshalling content, or checking for JWT auth, or checking for recaptcha token existing, the suggested place to do this is via aMiddleware
. Seeapp/Middlewares/UnmarshalRequestBody.php
for a fully dressed example.- You must define the magic
__invoke
method with 3 parameters like(ServerRequestInterface $request, ResponseInterface $response, Callable $next)
- At the end of your processing, you MUST either throw an
Exception
(of any kind, this halts request processing and hands off to the error handler), or return$next ($request, $response)
. Please note that these $request and $response objects do not have to be the same ones passed into the method, you're free to make changes to them before injecting them back into the pipeline. - Middlewares are attached to specific routes or groups in
app/Routes/routes.php
- You must define the magic
-
Moonwalker\Core\Controller comes with built in Pagination support, see
core/Controller::paginate
for documentation on how to use it, andUserController::getUsers
for a real application.