- Add this to the composer.json script section
"lint": "vendor/bin/phpcs --ignore=database/migrations/** && composer lint2",
"lint:fix": "vendor/bin/phpcbf && composer lint2:fix",
"lint2": "vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --using-cache=no",
"lint2:fix": "vendor/bin/php-cs-fixer fix --config=.php_cs.dist -v --using-cache=no",
"test": "vendor/bin/phpunit --configuration phpunit.xml",
"test:feature": "vendor/bin/phpunit --configuration phpunit.xml --testsuite Feature --no-coverage",
"test:unit": "vendor/bin/phpunit --configuration phpunit.xml --no-coverage --testsuite Unit",
- Install php linter & code sniffer
composer require friendsofphp/php-cs-fixer squizlabs/php_codesniffer
- Use uuid (optional. This is because I prefer working with UUID) Read the article
composer require dyrynda/laravel-model-uuid
- Install spatie query builder
composer require spatie/laravel-query-builder
// Usage
<?php
public function index (Request $request) {
}
$items = QueryBuilder::for(Model::class)
->allowedIncludes([
])
->allowedFilters([
])
->allowedSort([
])
->jsonPaginate();
return ModelResource::collection($items);
- Create Category model
php artisan make:model Category -mfc
Notice how we're not implementing yet until we describe the expected results with tests.
php artisan make:test -u CategoryTest
<?php
namespace Tests\Unit\Models;
use App\Models\Category;
use App\Models\Post;
use Tests\TestCase;
class CategoryTest extends TestCase {
public function testModel () {
/** @var Category $post */
$category = Category::factory()->create();
$this->assertDatabaseHas('categories', [
'id' => $category->id,
'name' => $category->name
]);
}
public function testPosts () {
$category = Category::factory()->create();
$post = Post::factory()->create([
'category_id' => $category->id
]);
$this->assertEquals($category->posts()->first()->uuid, $post->uuid);
}
}
- Edit the migration Sample migration
<?php
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
-
Edit Category model
- Annotate model with properties along with relationships
-
Create Post model
php artisan make:model Post -mfc
- Write test for the model
php artisan make:test -u PostTest
<?php
namespace Tests\Unit\Models;
use App\Models\Category;
use App\Models\Post;
use Tests\TestCase;
class PostTest extends TestCase {
public function testModel () {
/** @var Post $post */
$post = Post::factory()->create();
$this->assertDatabaseHas('posts', [
'id' => $item->id,
'title' => $item->title,
'category_id' => $item->category_id,
]);
}
public function testCategory () {
$category = Category::factory()->create();
/** @var Post $post */
$post = Post::factory()->create([
'category_id' => $category->id
]);
$this->assertEquals($post->category()->id, $category->id);
}
}
- Edit the migration
Sample migration
```php
<?php
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('content');
$table->integer('category_id')->index();
// no foreign keys because I'm lazy but index for performance
});
Sample relationship
<?php
namespace App\Models;
class Model {
public function foo ()
{
return $this->belongsTo(Foo::class);
}
public function bars()
{
return $this->hasMany(Bar::class);
}
}
- Create Category resource test
<?php
namespace Tests\Unit\Http\Resources;
use App\Http\Resources\CategoryResource;
use App\Models\Category;
use Illuminate\Http\Request;
use Illuminate\Testing\Assert;
use Tests\TestCase;
class CategoryResourceTest extends TestCase
{
public function testResource()
{
$item = Post::factory()->create();
$resource = new PostResource($item);
$expected = [
"id" => $item->id,
"name" => $item->name,
];
$request = app()->make(Request::class);
$result = $resource->toArray($request);
Assert::assertArraySubset($expected, $result);
// TODO test relationships
}
}
- Create Post resource
php artisan make:resource PostResource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource {
public function toArray($request)
{
/** @var Post */
$post = $this;
return [
'id' => $post->id,
'name' => $post->name,
'content' => $post->content,
'category' => new CategoryResource($this->whenLoaded('category')),
'bars' => Bar::collection($this->whenLoaded('bars')),
];
}
}
- Create Post resource test
<?php
namespace Tests\Unit\Http\Resources;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Testing\Assert;
use Tests\TestCase;
class PostTest extends TestCase
{
public function testResource()
{
$item = Post::factory()->create();
$resource = new PostResource($item);
$expected = [
"id" => $item->id,
"name" => $item->name,
];
$request = app()->make(Request::class);
$result = $resource->toArray($request);
Assert::assertArraySubset($expected, $result);
// TODO test relationships
}
}
- Create Post resource
php artisan make:resource PostResource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource {
public function toArray($request)
{
/** @var Post */
$post = $this;
return [
'id' => $post->id,
'name' => $post->name,
'content' => $post->content,
'category' => new CategoryResource($this->whenLoaded('category')),
'bars' => Bar::collection($this->whenLoaded('bars')),
];
}
}