Initial Core PHP Framework template

This commit is contained in:
Snider 2026-01-26 17:19:26 +00:00
commit 06ab3456e9
45 changed files with 671 additions and 0 deletions

76
.env.example Normal file
View file

@ -0,0 +1,76 @@
APP_NAME="Core PHP App"
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
APP_LOCALE=en_GB
APP_FALLBACK_LOCALE=en_GB
APP_FAKER_LOCALE=en_GB
APP_MAINTENANCE_DRIVER=file
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=core
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
# Core PHP Framework
CORE_CACHE_DISCOVERY=true
# CDN Configuration (optional)
CDN_ENABLED=false
CDN_DRIVER=bunny
BUNNYCDN_API_KEY=
BUNNYCDN_STORAGE_ZONE=
BUNNYCDN_PULL_ZONE=
# Flux Pro (optional)
FLUX_LICENSE_KEY=

11
.gitattributes vendored Normal file
View file

@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

23
.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.nova
/.vscode
/.zed

16
LICENSE Normal file
View file

@ -0,0 +1,16 @@
European Union Public Licence
EUPL © European Union 2007, 2016
This European Union Public Licence (the 'EUPL') applies to the Work (as defined below)
which is provided under the terms of this Licence. Any use of the Work, other than as
authorised under this Licence is prohibited (to the extent such use is covered by a right
of the copyright holder of the Work).
The Work is provided under the terms of this Licence when the Licensor (as defined below)
has placed the following notice immediately following the copyright notice for the Work:
Licensed under the EUPL
or has expressed by any other means his willingness to license under the EUPL.
For the full EUPL text, see: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12

117
README.md Normal file
View file

@ -0,0 +1,117 @@
# Core PHP Framework Project
A modular monolith Laravel application built with Core PHP Framework.
## Features
- **Core Framework** - Event-driven module system with lazy loading
- **Admin Panel** - Livewire-powered admin interface with Flux UI
- **REST API** - Scoped API keys, rate limiting, webhooks, OpenAPI docs
- **MCP Tools** - Model Context Protocol for AI agent integration
## Requirements
- PHP 8.2+
- Composer 2.x
- SQLite (default) or MySQL/PostgreSQL
- Node.js 18+ (for frontend assets)
## Installation
```bash
# Clone or create from template
git clone https://github.com/host-uk/core-template.git my-project
cd my-project
# Install dependencies
composer install
npm install
# Configure environment
cp .env.example .env
php artisan key:generate
# Set up database
touch database/database.sqlite
php artisan migrate
# Start development server
php artisan serve
```
Visit: http://localhost:8000
## Project Structure
```
app/
├── Console/ # Artisan commands
├── Http/ # Controllers & Middleware
├── Models/ # Eloquent models
├── Mod/ # Your custom modules
└── Providers/ # Service providers
config/
└── core.php # Core framework configuration
routes/
├── web.php # Public web routes
├── api.php # REST API routes
└── console.php # Artisan commands
```
## Creating Modules
```bash
# Create a new module with all features
php artisan make:mod Blog --all
# Create module with specific features
php artisan make:mod Shop --web --api --admin
```
Modules follow the event-driven pattern:
```php
<?php
namespace App\Mod\Blog;
use Core\Events\WebRoutesRegistering;
use Core\Events\ApiRoutesRegistering;
use Core\Events\AdminPanelBooting;
class Boot
{
public static array $listens = [
WebRoutesRegistering::class => 'onWebRoutes',
ApiRoutesRegistering::class => 'onApiRoutes',
AdminPanelBooting::class => 'onAdminPanel',
];
public function onWebRoutes(WebRoutesRegistering $event): void
{
$event->routes(fn() => require __DIR__.'/Routes/web.php');
$event->views('blog', __DIR__.'/Views');
}
}
```
## Core Packages
| Package | Description |
|---------|-------------|
| `host-uk/core` | Core framework components |
| `host-uk/core-admin` | Admin panel & Livewire modals |
| `host-uk/core-api` | REST API with scopes & webhooks |
| `host-uk/core-mcp` | Model Context Protocol tools |
## Documentation
- [Core PHP Framework](https://github.com/host-uk/core-php)
- [Getting Started Guide](https://host-uk.github.io/core-php/guide/)
- [Architecture](https://host-uk.github.io/core-php/architecture/)
## License
EUPL-1.2 (European Union Public Licence)

View file

0
app/Mod/.gitkeep Normal file
View file

0
app/Models/.gitkeep Normal file
View file

View file

@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}

15
artisan Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env php
<?php
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
// Bootstrap Laravel and handle the command...
$status = (require_once __DIR__.'/bootstrap/app.php')
->handleCommand(new ArgvInput);
exit($status);

23
bootstrap/app.php Normal file
View file

@ -0,0 +1,23 @@
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withProviders([
// Core PHP Framework Packages
\Core\CoreServiceProvider::class,
])
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

2
bootstrap/cache/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

5
bootstrap/providers.php Normal file
View file

@ -0,0 +1,5 @@
<?php
return [
App\Providers\AppServiceProvider::class,
];

78
composer.json Normal file
View file

@ -0,0 +1,78 @@
{
"name": "host-uk/core-template",
"type": "project",
"description": "Core PHP Framework - Project Template",
"keywords": ["laravel", "core-php", "modular", "framework", "template"],
"license": "EUPL-1.2",
"require": {
"php": "^8.2",
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10",
"livewire/flux": "^2.0",
"livewire/flux-pro": "^2.0",
"livewire/livewire": "^3.0",
"host-uk/core": "^1.0",
"host-uk/core-admin": "^1.0",
"host-uk/core-api": "^1.0",
"host-uk/core-mcp": "^1.0"
},
"require-dev": {
"fakerphp/faker": "^1.23",
"laravel/pail": "^1.2",
"laravel/pint": "^1.18",
"laravel/sail": "^1.41",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.6",
"phpunit/phpunit": "^11.5"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"repositories": [
{
"type": "composer",
"url": "https://composer.fluxui.dev"
}
],
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
"@php artisan migrate --graceful --ansi"
]
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"php-http/discovery": true
}
},
"minimum-stability": "stable",
"prefer-stable": true
}

24
config/core.php Normal file
View file

@ -0,0 +1,24 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Core PHP Framework Configuration
|--------------------------------------------------------------------------
*/
'module_paths' => [
app_path('Core'),
app_path('Mod'),
app_path('Website'),
],
'services' => [
'cache_discovery' => env('CORE_CACHE_DISCOVERY', true),
],
'cdn' => [
'enabled' => env('CDN_ENABLED', false),
'driver' => env('CDN_DRIVER', 'bunny'),
],
];

View file

View file

View file

@ -0,0 +1,16 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// Core modules handle their own seeding
}
}

16
package.json Normal file
View file

@ -0,0 +1,16 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"axios": "^1.7.4",
"laravel-vite-plugin": "^1.2.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13",
"vite": "^6.0.0"
}
}

33
phpunit.xml Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>

6
postcss.config.js Normal file
View file

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

21
public/.htaccess Normal file
View file

@ -0,0 +1,21 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

17
public/index.php Normal file
View file

@ -0,0 +1,17 @@
<?php
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
// Bootstrap Laravel and handle the request...
(require_once __DIR__.'/../bootstrap/app.php')
->handleRequest(Request::capture());

2
public/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow:

3
resources/css/app.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

1
resources/js/app.js Normal file
View file

@ -0,0 +1 @@
import './bootstrap';

3
resources/js/bootstrap.js vendored Normal file
View file

@ -0,0 +1,3 @@
import axios from 'axios';
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

View file

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Core PHP Framework</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.container {
text-align: center;
padding: 2rem;
}
h1 {
font-size: 3rem;
margin-bottom: 0.5rem;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.version {
color: #888;
font-size: 0.9rem;
margin-bottom: 2rem;
}
.links {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
a {
color: #667eea;
text-decoration: none;
padding: 0.75rem 1.5rem;
border: 1px solid #667eea;
border-radius: 0.5rem;
transition: all 0.2s;
}
a:hover {
background: #667eea;
color: #fff;
}
</style>
</head>
<body>
<div class="container">
<h1>Core PHP Framework</h1>
<p class="version">Laravel {{ Illuminate\Foundation\Application::VERSION }} | PHP {{ PHP_VERSION }}</p>
<div class="links">
<a href="https://github.com/host-uk/core-php">Documentation</a>
<a href="/admin">Admin Panel</a>
<a href="/api/docs">API Docs</a>
</div>
</div>
</body>
</html>

5
routes/api.php Normal file
View file

@ -0,0 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
// API routes are registered via Core modules

3
routes/console.php Normal file
View file

@ -0,0 +1,3 @@
<?php
// Console commands are registered via Core modules

7
routes/web.php Normal file
View file

@ -0,0 +1,7 @@
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});

3
storage/app/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*
!public/
!.gitignore

2
storage/app/public/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

9
storage/framework/.gitignore vendored Normal file
View file

@ -0,0 +1,9 @@
compiled.php
config.php
down
events.scanned.php
maintenance.php
routes.php
routes.scanned.php
schedule-*
services.json

3
storage/framework/cache/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*
!data/
!.gitignore

View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/sessions/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/testing/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/framework/views/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

2
storage/logs/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

11
tailwind.config.js Normal file
View file

@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./resources/**/*.blade.php",
"./resources/**/*.js",
],
theme: {
extend: {},
},
plugins: [],
};

0
tests/Feature/.gitkeep Normal file
View file

10
tests/TestCase.php Normal file
View file

@ -0,0 +1,10 @@
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
//
}

0
tests/Unit/.gitkeep Normal file
View file

11
vite.config.js Normal file
View file

@ -0,0 +1,11 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
});