Add documentation covering architecture, modules, getting started, and security considerations for the Core PHP Framework starter template. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.6 KiB
6.6 KiB
| title | description | updated |
|---|---|---|
| Getting Started | Quick start guide for creating a new Core PHP Framework application | 2026-01-29 |
Getting Started
This guide walks you through creating your first application with Core PHP Framework using the core-template.
Prerequisites
- PHP 8.2 or higher
- Composer 2.x
- Node.js 18+ and npm
- SQLite (default) or MySQL/PostgreSQL
Installation
1. Clone the Template
git clone https://github.com/host-uk/core-template.git my-project
cd my-project
Or use Composer create-project (once published):
composer create-project host-uk/core-template my-project
2. Install Dependencies
# PHP dependencies
composer install
# JavaScript dependencies
npm install
3. Configure Environment
# Copy environment file
cp .env.example .env
# Generate application key
php artisan key:generate
# Create SQLite database
touch database/database.sqlite
# Run migrations
php artisan migrate
4. Start Development Server
# In one terminal - PHP server
php artisan serve
# In another terminal - Vite dev server
npm run dev
Visit http://localhost:8000 to see your application.
Creating Your First Module
The Core PHP Framework uses a modular architecture. Features are organised as self-contained modules.
Using the Artisan Command
# Create a full-featured module
php artisan make:mod Blog --all
# Or select specific features
php artisan make:mod Blog --web --api
Manual Creation
- Create the module directory:
mkdir -p app/Mod/Blog/{Models,Routes,Views,Livewire,Migrations,Tests}
- Create
app/Mod/Blog/Boot.php:
<?php
declare(strict_types=1);
namespace App\Mod\Blog;
use Core\Events\WebRoutesRegistering;
class Boot
{
public static array $listens = [
WebRoutesRegistering::class => 'onWebRoutes',
];
public function onWebRoutes(WebRoutesRegistering $event): void
{
$event->routes(fn() => require __DIR__.'/Routes/web.php');
$event->views('blog', __DIR__.'/Views');
}
}
- Create
app/Mod/Blog/Routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/blog', function () {
return view('blog::index');
})->name('blog.index');
- Create
app/Mod/Blog/Views/index.blade.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blog</title>
</head>
<body>
<h1>Welcome to the Blog</h1>
</body>
</html>
Visit http://localhost:8000/blog to see your module in action.
Adding a Model
Create app/Mod/Blog/Models/Post.php:
<?php
declare(strict_types=1);
namespace App\Mod\Blog\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'content',
'published_at',
];
protected function casts(): array
{
return [
'published_at' => 'datetime',
];
}
}
Create a migration in app/Mod/Blog/Migrations/:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->text('content');
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Run the migration:
php artisan migrate
Adding a Livewire Component
Create app/Mod/Blog/Livewire/PostListPage.php:
<?php
declare(strict_types=1);
namespace App\Mod\Blog\Livewire;
use App\Mod\Blog\Models\Post;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Livewire\WithPagination;
class PostListPage extends Component
{
use WithPagination;
public function render(): View
{
return view('blog::posts.index', [
'posts' => Post::latest()->paginate(10),
]);
}
}
Update app/Mod/Blog/Routes/web.php:
<?php
use App\Mod\Blog\Livewire\PostListPage;
use Illuminate\Support\Facades\Route;
Route::get('/blog', PostListPage::class)->name('blog.index');
Create app/Mod/Blog/Views/posts/index.blade.php:
<div>
<h1 class="text-2xl font-bold mb-4">Blog Posts</h1>
@forelse ($posts as $post)
<article class="mb-4 p-4 border rounded">
<h2 class="text-xl font-semibold">{{ $post->title }}</h2>
<p class="text-gray-600">{{ Str::limit($post->content, 200) }}</p>
</article>
@empty
<p>No posts yet.</p>
@endforelse
{{ $posts->links() }}
</div>
Writing Tests
Create app/Mod/Blog/Tests/PostTest.php:
<?php
use App\Mod\Blog\Models\Post;
it('displays the blog index', function () {
$this->get('/blog')
->assertOk()
->assertSee('Blog Posts');
});
it('shows posts on the index page', function () {
$post = Post::create([
'title' => 'Test Post',
'slug' => 'test-post',
'content' => 'This is a test post.',
]);
$this->get('/blog')
->assertOk()
->assertSee('Test Post');
});
Run tests:
vendor/bin/pest
Code Formatting
Before committing, run Laravel Pint:
# Format changed files only
vendor/bin/pint --dirty
# Format all files
vendor/bin/pint
Next Steps
- Read the Architecture documentation to understand the module system
- Review Security considerations before deploying
- Explore the Core PHP Framework documentation
- Add the Admin Panel with
host-uk/core-admin - Build an API with
host-uk/core-api
Common Commands
# Development
php artisan serve # Start PHP server
npm run dev # Start Vite with HMR
npm run build # Build for production
# Modules
php artisan make:mod Name # Create a new module
php artisan make:mod Name --all # With all features
# Database
php artisan migrate # Run migrations
php artisan migrate:fresh # Reset and re-run migrations
php artisan db:seed # Run seeders
# Testing
vendor/bin/pest # Run all tests
vendor/bin/pest --filter=Name # Run specific test
# Code Quality
vendor/bin/pint # Format code
vendor/bin/pint --test # Check formatting without changes