A simple framework to extend Laravel/Lumen
The quickest way to get setup is to fist ensure you have docker installed. Then proceed with running the following:
docker-compose build
This will create a php-7.4 docker image and container with everything we need to run and verify our code. Once complete we can run the composer through our newly minted container.
docker-compose run php-7.4 composer install
There are two simple steps for verifying your changes.
We utilizes PHPUnit for all testing.
docker-compose run php-7.4 composer test
We utilizes PHPCodesniffer for all liniting needs.
docker-compose run php-7.4 composer lint
We utilizes PHPStan for all static analysis needs.
docker-compose run php-7.4 composer stan
Currently our configuration is set to level 5 with one ignored error in our baseline. Our goal will be to maintain a strict baseline with as few ignored errors as possible. As our source catches up with PHP 7.4+ features we will tighted our level to address our increasing complexity.
We utilizes PHPFixer for all formatting needs. This cmd will write changes to disk.
docker-compose run php-7.4 composer format
If you simply want to check for issues without writing to disk run the following cmd.
docker-compose run php-7.4 composer format:dry-run
All cmd alias can be found in the composer.json file under scripts. Most of what you see above is run within our build pipeline to ensure quality.
The Http model is meant to help abstract the request into an input model. The example below shows how it might be used in production.
First we have our Address model which defines how our API accepts address.
<?php
declare(strict_types=1);
namespace App\Http\Models;
use PixelOven\Http\Model;
/**
* @SWG\Definition(
* type="object",
* required={"street", "postal", "region", "country"},
* @SWG\Xml(
* name="AddressBody"
* )
* )
*
* Class AddressBody
* @package App\Http\Models
*/
class AddressBody extends Model
{
/**
* @SWG\Property(
* description="Street address",
* )
* @var string
*/
public $street;
/**
* @SWG\Property(
* description="Postal code",
* )
* @var string
*/
public $postal;
/**
* @SWG\Property(
* description="Region, Province or State",
* )
* @var string
*/
public $region;
/**
* @SWG\Property(
* description="Country",
* )
* @var string
*/
public $country;
}
Then building off of this we define our User model which has a relationship with Address.
<?php
declare(strict_types=1);
namespace App\Http\Models;
use PixelOven\Http\Model;
/**
* @SWG\Definition(
* type="object",
* required={"email", "name"},
* @SWG\Xml(
* name="UserBody"
* )
* )
*
* Class UserBody
* @package App\Http\Models
*/
class UserBody extends Model
{
protected $relations = [
'address' => AddressBody::class
];
/**
* @SWG\Property(
* description="User's email",
* )
* @var string
*/
public $email;
/**
* @SWG\Property(
* description="User's full name",
* )
* @var string
*/
public $name;
/**
* @SWG\Property(
* description="Address body",
* )
* @var AddressBody
*/
public $address;
}
As we can see from the above User now is related to address where address is a nested property. There is nothing stoping us from also extending a model if we wish for a flatter structure.
Lastly we can use these models to replace the raw Request object.
<?php
declare(strict_types=1);
/**
* @SWG\Post(
* path="/pixeloven/v1/user",
* summary="Create user",
* tags={"V1 User"},
* description="Create a new user",
* operationId="createUser",
* consumes={"application/json"},
* produces={"application/json"},
* @SWG\Parameter(
* name="UserBody",
* in="body",
* description="User object",
* required=true,
* @SWG\Schema(ref="#/definitions/UserBody")
* ),
* @SWG\Response(ref="#/responses/201", response=201),
* @SWG\Response(ref="#/responses/404", response=404),
* @SWG\Response(ref="#/responses/422", response=422),
* @SWG\Response(ref="#/responses/500", response=500)
* )
*
* @param UserBody $model
*/
public function createUser(
UserBody $model,
) {
$model->validate([
'email' => ['required', 'string', 'email'],
'name' => ['required', 'string'],
]);
$userEmail = $model->email;
$userName = $model->name;
$userAddress = $model->address;
// ...
In this particular example we are also leveraging:
darkaonline/swagger-lume
This package allows us to use swagger annotations along side our request model.