gemvc / library
Server Agnostic (openSwoole/Nginx/Apache) Rest Api Microservice ready Framework/Library
Installs: 1 173
Dependents: 0
Suggesters: 0
Security: 0
Stars: 20
Watchers: 4
Forks: 17
Open Issues: 0
pkg:composer/gemvc/library
Requires
- firebase/php-jwt: ^6.8
- gemvc/connection-contracts: ^1.0
- gemvc/connection-openswoole: ^1.0
- gemvc/connection-pdo: ^1.0
- symfony/dotenv: ^6.4 || ^7.2
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.1
- dev-main
- 5.2.0-alpha3
- 5.2.0-alpha2
- 5.2.0-alpha1
- 5.2.0-alpha
- 5.1.4
- 5.1.3
- 5.1.2
- 5.1.1
- 5.1.0
- 5.0.12
- 5.0.11
- 5.0.10
- 5.0.9
- 5.0.8
- 5.0.7
- 5.0.6
- 5.0.5
- 5.0.4
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- 4.1.0
- 4.0.74
- 4.0.73
- 4.0.72
- 4.0.71
- 4.0.70
- 4.0.69
- 4.0.68
- 4.0.67
- 4.0.66
- 4.0.65
- 4.0.64
- 4.0.63
- 4.0.62
- 4.0.61
- 4.0.60
- 4.0.59
- 4.0.58
- 4.0.57
- 4.0.56
- 4.0.55
- 4.0.54
- 4.0.53
- 4.0.52
- 4.0.51
- 4.0.50
- 4.0.49
- 4.0.48
- 4.0.47
- 4.0.46
- 4.0.45
- 4.0.44
- 4.0.43
- 4.0.42
- 4.0.41
- 4.0.40
- 4.0.39
- 4.0.38
- 4.0.37
- 4.0.36
- 4.0.35
- 4.0.34
- 4.0.33
- 4.0.32
- 4.0.31
- 4.0.30
- 4.0.29
- 4.0.28
- 4.0.27
- 4.0.26
- 4.0.25
- 4.0.24
- 4.0.23
- 4.0.22
- 4.0.21
- 4.0.20
- 4.0.19
- 4.0.18
- 4.0.17
- 4.0.16
- 4.0.15
- 4.0.14
- 4.0.13
- 4.0.12
- 4.0.11
- 4.0.10
- 4.0.9
- 4.0.8
- 4.0.7
- 4.0.6
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- v3.28.2
- v3.28.1
- v3.28.0
- v3.27.8
- v3.27.7
- v3.27.6
- v3.27.5
- v3.27.4
- v3.27.3
- 3.27.2
- v3.27.1
- v3.27.0
- v3.26.8
- v3.26.7
- v3.26.5
- v3.26.4
- v3.26.3
- v3.26.2
- v3.26.1
- v3.26
- v3.25
- v3.24
- v3.23
- v3.22
- v3.21
- v3.20
- v3.19
- v3.18
- v3.17
- v3.16
- v3.15
- v3.14
- v3.13
- v3.12
- v3.11.3
- v3.11.2
- v3.11.1
- v3.11.0
- v3.10.2
- v3.10.1
- v3.10.0
- v3.9.0
- v3.8.0
- v3.7.0
- v3.6.6
- v3.6.5
- v3.6.4
- v3.6.3
- v3.6.2
- v3.6.1
- v3.6.0
- v3.5.0
- v3.4.5
- v3.3.4
- v3.3.3
- v3.3.2
- v3.3.1
- v3.3.0
- v3.2.0
- v3.1.12
- v3.1.11
- v3.1.10
- v3.1.9
- v3.1.8
- v3.1.7
- v3.1.6
- v3.1.5
- v3.1.4
- v3.1.3
- v3.1.2
- v3.1.1
- v3.1.0
- v3.0.0
- v2.8.6
- v2.8.5
- v2.8.4
- v2.8.3
- v2.8.2
- v2.8.1
- v2.8.0
- v2.7.1
- v2.7.0
- v2.6.4
- v2.6.3
- v2.6.2
- v2.6.1
- v2.5.2
- v2.5.1
- v2.5.0
- v2.4.3
- v2.4.2
- v2.4.1
- v2.4.0
- v2.3.13
- v2.3.12
- v2.3.11
- v2.3.10
- v2.3.9
- v2.3.8
- v2.3.7
- v2.3.6
- v2.3.5
- v2.3.4
- v2.3.3
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.4
- v2.2.3
- v2.2.0
- v2.1.1
- v2.0.6
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.5.9
- v1.5.8
- v1.5.7
- v1.5.6
- v1.5.5
- v1.5.4
- v1.5.3
- 1.5.2
- v1.5.1
- v1.5.0
- V1.4.0
- V1.3.1
- V1.3.0
- V1.2.0
- V1.1.0
- V1.0.0.5
- V1.0.0
- dev-dev
- dev-db
- dev-post
This package is auto-updated.
Last update: 2025-12-13 00:04:51 UTC
README
🚀 Start in 30 Seconds
composer require gemvc/library php vendor/bin/gemvc init
Stop using a Swiss Army Knife when you need a Scalpel. GEMVC is a PHP Multi-Platform(OpenSwoole, Apache and NginX) specialized, ultra-lightweight framework designed for high-performance REST APIs and Microservices.
Not to replace, but to complete
GEMVC is not a replacement for lovely Laravel or powerful Symfony; it is a complementary tool designed to solve special challenges. It is always good to have it in your arsenal!
You are the Master of your Code
In GEMVC, architecture is just a recommendation. GEMVC NEVER forces you to follow its rules. You can implement the recommended 4-layer architecture, or write your own familiar 3, 2, or even single-layer code!
AI-Ready - Born for AI Agents
Thanks to its transparent structure, strict naming conventions, and clean 4-layer separation of concerns (with no magic functions or hidden classes), GEMVC is natively AI-Friendly. AI Assistants can easily understand your code context and assist you efficiently. Writing code with GEMVC is a joy for both humans and AI. GEMVC is designed to work seamlessly with Cursor, Copilot, and ChatGPT. We include pre-configured context files (
AI_API_REFERENCE.md,.cursorrules) right in the root. Your AI assistant already knows how to write GEMVC code perfectly!
Easy to Learn
It takes only a couple of hours to master this tool. GEMVC respects your time and is not here to replace your existing knowledge, but to sharpen it.
No-Hassle Documentation
In GEMVC, Sanitization IS Documentation. When you sanitize API inputs (as you normally should), the framework automatically generates full documentation for your endpoints. You get beautiful, well-designed documentation simply by defining your validation rules. Plus, you get out-of-the-box support to export your latest API version to Postman with a single click. Your frontend developers will love GEMVC!
⚡ The "Async Magic"
Write standard, synchronous PHP code (like you always do) on Apache/Nginx. Switch to OpenSwoole, and your exact same code automatically runs as Asynchronous Non-blocking I/O. Zero code changes required.
Fully and Easily Customizable
You can easily define custom Class Templates for any layer, and then CLI Commands will generate your classes in seconds!
Library or Framework? The Choice is Yours.
You can use GEMVC as a library within a legacy project to migrate to a modern architecture step-by-step, without breaking existing functionality. Or, for new projects, simply install it via Composer and run the
gemvc initcommand to use it as a modern framework from day one.
Testing & Quality Assurance
When coding with GEMVC, you can enjoy PHPStan Level 9 compliance! The framework natively supports strong typing—while not forced, it is strongly recommended. It also comes with PHPUnit and Pest support right out of the box during the installation process. You can easily test your product using your beloved PHPUnit or the beautiful Pest framework. Plus, the 4-layer architecture makes creating comprehensive Unit and Integration tests a breeze.
Full Transparency Policy
It is Open Source, MIT Licensed, and small. There is no hidden code or "black box". You can download the source code, analyze it, test it, and use it with peace of mind. It is built with love to make your life as a developer more enjoyable.
🤖 FOR AI ASSISTANTS - READ THIS FIRST!
ATTENTION: If you are an AI assistant (Cursor AI, GitHub Copilot, Claude, etc.), you MUST read the following file first:
GEMVC is NOT Laravel or Symfony - It has its own unique architecture, naming conventions, and design philosophy. This guide will teach you how to write code the GEMVC way.
⚠️ QUICK_START_AI.md - MASTER INSTRUCTIONS FOR AI ASSISTANTS
This file will:
- ✅ Instruct you to read ALL GEMVC documentation files
- ✅ Teach you the complete 4-layer architecture (MANDATORY)
- ✅ Show you correct method signatures and return types
- ✅ Explain security features (90% automatic)
- ✅ Provide code generation patterns you MUST follow
- ✅ List common mistakes you MUST avoid
After reading QUICK_START_AI.md, you should read:
.cursorrules- Complete framework rulesAI_API_REFERENCE.md- All method signaturesAI_CONTEXT.md- Quick examplesGEMVC_GUIDE.md- Code generation patterns
Do NOT skip layers or use Laravel patterns. Follow GEMVC conventions only!
🎯 What is GEMVC?
GEMVC is a multi-platform PHP REST API framework that works identically on:
- ✅ OpenSwoole (async, WebSocket, hot reload)
- ✅ Apache (traditional PHP-FPM)
- ✅ Nginx (high performance, reverse proxy)
Key Features:
- 🔒 90% Security Automatic - Input sanitization, SQL injection prevention, path protection
- 🌐 Webserver-Agnostic - Same code works on all platforms
- 🛠️ CLI Code Generation - Generate Services, Controllers, Models, Tables
- 📝 Simple API - Clean, straightforward code structure
- ⚡ High Performance - Connection pooling, async capabilities
- ✅ PHPStan Level 9 - Write type-safe, bug-free code with the highest static analysis level
🏗️ Architecture Overview
GEMVC uses a 4-layer architecture pattern:
API Layer (app/api/) → URL endpoints, schema validation
↓
Controller Layer (app/controller/) → Business logic orchestration
↓
Model Layer (app/model/) → Data logic, validations
↓
Table Layer (app/table/) → Database access, queries
Example Flow:
POST /api/User/create
↓
app/api/User.php::create() → Validates schema
↓
app/controller/UserController.php → Handles business logic
↓
app/model/UserModel.php → Data validations, transformations
↓
app/table/UserTable.php → Database operations
📐 4-Layer Architecture
1. API Layer (app/api/)
Purpose: URL endpoints, request validation, authentication
Naming: PascalCase (e.g., User.php, Product.php)
Responsibilities:
- Define request schemas (
definePostSchema(),defineGetSchema()) - Handle authentication (
$request->auth()) - Delegate to Controller layer
Example (app/api/User.php):
<?php namespace App\Api; use App\Controller\UserController; use Gemvc\Core\ApiService; use Gemvc\Http\Request; use Gemvc\Http\JsonResponse; class User extends ApiService { public function __construct(Request $request) { parent::__construct($request); } public function create(): JsonResponse { // Validate request schema if(!$this->request->definePostSchema([ 'name' => 'string', 'email' => 'email', 'password' => 'string' ])) { return $this->request->returnResponse(); } // Delegate to controller return (new UserController($this->request))->create(); } }
Key Points:
- ✅ Extends
ApiService(orSwooleApiServicefor OpenSwoole) - ✅ Uses
definePostSchema()for validation - ✅ Uses
?prefix for optional fields:'?name' => 'string' - ✅ Delegates to Controller, doesn't handle business logic
2. Controller Layer (app/controller/)
Purpose: Business logic orchestration
Naming: PascalCase + "Controller" suffix (e.g., UserController.php)
Responsibilities:
- Orchestrate business logic
- Map request data to models
- Handle request/response flow
Example (app/controller/UserController.php):
<?php namespace App\Controller; use App\Model\UserModel; use Gemvc\Core\Controller; use Gemvc\Http\Request; use Gemvc\Http\JsonResponse; class UserController extends Controller { public function __construct(Request $request) { parent::__construct($request); } public function create(): JsonResponse { // Map POST data to Model with custom handlers $model = $this->request->mapPostToObject( new UserModel(), [ 'email' => 'email', 'name' => 'name', 'description' => 'description', 'password' => 'setPassword()' // Calls setPassword() method ] ); if(!$model instanceof UserModel) { return $this->request->returnResponse(); } return $model->createModel(); } }
Key Points:
- ✅ Extends
Controller - ✅ Uses
mapPostToObject()to convert request to model - ✅ Can specify method calls:
'password' => 'setPassword()' - ✅ Delegates to Model layer
3. Model Layer (app/model/)
Purpose: Data logic, validations, transformations
Naming: PascalCase + "Model" suffix (e.g., UserModel.php)
Responsibilities:
- Business validations (e.g., duplicate email check)
- Data transformations (e.g., password hashing)
- Error handling
Example (app/model/UserModel.php):
<?php namespace App\Model; use App\Table\UserTable; use Gemvc\Helper\CryptHelper; use Gemvc\Http\JsonResponse; use Gemvc\Http\Response; class UserModel extends UserTable { public function createModel(): JsonResponse { // Business validation: Check duplicate email $this->email = strtolower($this->email); $found = $this->selectByEmail($this->email); if ($found) { return Response::unprocessableEntity("User already exists"); } // Data transformation: Hash password $this->setPassword($this->password); // Perform database operation $success = $this->insertSingleQuery(); if ($this->getError()) { return Response::internalError($this->getError()); } return Response::created($this, 1, "User created successfully"); } public function setPassword(string $plainPassword): void { $this->password = CryptHelper::hashPassword($plainPassword); } }
Key Points:
- ✅ Extends corresponding
Tableclass (e.g.,UserModel extends UserTable) - ✅ Contains business logic and validations
- ✅ Uses
insertSingleQuery(),updateSingleQuery(),deleteByIdQuery() - ✅ Returns
JsonResponseobjects
4. Table Layer (app/table/)
Purpose: Database access, queries, schema definition
Naming: PascalCase + "Table" suffix (e.g., UserTable.php)
Responsibilities:
- Define database table structure
- Define properties matching database columns
- Provide query methods
Example (app/table/UserTable.php):
<?php namespace App\Table; use Gemvc\Database\Table; use Gemvc\Database\Schema; class UserTable extends Table { // Properties match database columns public int $id; public string $name; public string $email; public ?string $description; protected string $password; // Protected = not exposed in selects protected array $_type_map = [ 'id' => 'int', 'name' => 'string', 'email' => 'string', 'description' => 'string', 'password' => 'string', ]; public function __construct() { parent::__construct(); } public function getTable(): string { return 'users'; // Database table name } public function defineSchema(): array { return [ Schema::index('email'), Schema::unique('email'), Schema::index('description') ]; } // Custom query methods public function selectById(int $id): null|static { $result = $this->select()->where('id', $id)->limit(1)->run(); return $result[0] ?? null; } public function selectByEmail(string $email): null|static { $arr = $this->select()->where('email', $email)->limit(1)->run(); return $arr[0] ?? null; } }
Key Points:
- ✅ Extends
Tableclass - ✅ Properties match database columns (with types)
- ✅
protectedproperties are not exposed in SELECT queries - ✅ Properties starting with
_are ignored in CRUD operations (see below) - ✅ Uses fluent query builder:
$this->select()->where()->limit()->run() - ✅ Returns
null|staticornull|static[]for query methods
🔗 Model Aggregation & Composition (Properties with _ prefix)
Important Feature: Properties starting with _ are completely ignored in all CRUD table operations!
This allows you to:
- ✅ Aggregate other models (composition)
- ✅ Store arrays of related models
- ✅ Create relationships without affecting database operations
- ✅ Use PHPStan Level 9 type checking for aggregated models
How It Works
Properties starting with _ are skipped:
- ❌ Not included in
INSERToperations - ❌ Not included in
UPDATEoperations - ❌ Not included in table schema generation
- ✅ Can be used for aggregation/composition
- ✅ Can be public, private, or protected
Example 1: Aggregating a Profile Model
User Model with Profile Aggregation:
<?php namespace App\Model; use App\Table\UserTable; use App\Model\Profile; // Aggregated model class UserModel extends UserTable { // This property is IGNORED in database operations public ?Profile $_profile = null; /** * Get user with profile loaded */ public function withProfile(): self { if ($this->_profile === null && $this->id) { $profileTable = new ProfileTable(); $this->_profile = $profileTable->selectByUserId($this->id); } return $this; } /** * Set profile */ public function setProfile(Profile $profile): void { $this->_profile = $profile; } }
Usage:
$user = new UserModel(); $user->id = 1; $user->name = "John"; $user->email = "john@example.com"; // Add profile without affecting database operations $profile = new Profile(); $profile->bio = "Software Developer"; $user->_profile = $profile; // Save user (profile is NOT inserted, only user data) $user->insertSingleQuery(); // Only inserts: id, name, email
Example 2: Aggregating an Array of Orders
User Model with Orders Array (PHPStan Level 9):
<?php namespace App\Model; use App\Table\UserTable; use App\Model\Order; class UserModel extends UserTable { /** * Array of Order models - ignored in CRUD operations * @var array<Order> */ public array $_orders = []; /** * Get user's orders * @return array<Order> */ public function orders(): array { if (empty($this->_orders) && $this->id) { $orderTable = new OrderTable(); $this->_orders = $orderTable->selectByUserId($this->id); } return $this->_orders; } /** * Add order to user */ public function addOrder(Order $order): void { $this->_orders[] = $order; } /** * Create order for user */ public function createOrder(array $orderData): Order { $order = new Order(); $order->user_id = $this->id; $order->amount = $orderData['amount']; $order->insertSingleQuery(); $this->_orders[] = $order; return $order; } }
Usage:
$user = new UserModel(); $user->id = 1; $user->name = "John"; // Add orders (ignored in database operations) $order1 = new Order(); $order1->amount = 100; $user->addOrder($order1); $order2 = new Order(); $order2->amount = 200; $user->addOrder($order2); // Save user (orders array is NOT inserted!) $user->insertSingleQuery(); // Only inserts: id, name // Later, create actual orders in database foreach ($user->_orders as $order) { $order->user_id = $user->id; $order->insertSingleQuery(); // Save each order separately }
Example 3: Complex Relationships
Product Model with Categories and Reviews:
<?php namespace App\Model; use App\Table\ProductTable; use App\Model\Category; use App\Model\Review; class ProductModel extends ProductTable { /** * Single related model * @var Category|null */ public ?Category $_category = null; /** * Array of related models * @var array<Review> */ public array $_reviews = []; /** * Load product with category and reviews */ public function loadRelations(): self { if ($this->id) { // Load category $categoryTable = new CategoryTable(); $this->_category = $categoryTable->selectById($this->category_id); // Load reviews $reviewTable = new ReviewTable(); $this->_reviews = $reviewTable->selectByProductId($this->id); } return $this; } /** * Get average rating */ public function getAverageRating(): float { if (empty($this->_reviews)) { return 0.0; } $total = 0; foreach ($this->_reviews as $review) { $total += $review->rating; } return round($total / count($this->_reviews), 2); } }
Usage:
$product = new ProductModel(); $product->id = 1; $product->name = "Laptop"; $product->price = 999.99; // Load relations $product->loadRelations(); // Use aggregated data echo $product->_category->name; // "Electronics" echo $product->getAverageRating(); // 4.5 // Save product (category and reviews are NOT affected!) $product->updateSingleQuery(); // Only updates: id, name, price
Best Practices
- Use Descriptive Names:
$_profile,$_orders,$_reviews - Add Type Hints: Use PHPStan Level 9 compatible types
public ?Profile $_profile = null; // Single model public array $_orders = []; // Array of models public array<int, Order> $_orders = []; // Typed array (PHPStan)
- Create Helper Methods:
orders(),withProfile(),loadRelations() - Lazy Loading: Load aggregated data only when needed
- Keep Separate: Don't mix database columns with aggregated properties
Common Patterns
// Pattern 1: Single aggregation public ?Profile $_profile = null; // Pattern 2: Array aggregation public array $_orders = []; // Pattern 3: Private aggregation with getter private array $_reviews = []; public function getReviews(): array { return $this->_reviews; } // Pattern 4: Protected aggregation protected ?Category $_category = null;
PHPStan Level 9 Examples
// ✅ Full type safety with PHPStan Level 9 /** @var array<Order> */ public array $_orders = []; // ✅ Nullable single model public ?Profile $_profile = null; // ✅ Typed array with PHPDoc /** * @var array<int, Review> */ public array $_reviews = [];
Result: Clean, type-safe code with powerful aggregation capabilities! 🎯
🔄 URL Mapping
GEMVC maps URLs to code automatically:
URL: /api/User/create
↓
Extracts: Service = "User", Method = "create"
↓
Loads: app/api/User.php
↓
Calls: User::create()
URL Structure:
/api/{ServiceName}/{MethodName}
Examples:
POST /api/User/create→User::create()GET /api/User/read/?id=1→User::read()POST /api/User/update→User::update()POST /api/User/delete→User::delete()GET /api/User/list→User::list()
Configuration (.env):
SERVICE_IN_URL_SECTION=1 # Service name position in URL METHOD_IN_URL_SECTION=2 # Method name position in URL
🔑 Key Differences from Laravel/Symfony
1. Architecture Pattern
Laravel/Symfony: MVC (Model-View-Controller)
GEMVC: 4-Layer (API → Controller → Model → Table)
2. Routing
Laravel: Routes defined in routes/web.php or routes/api.php
GEMVC: Automatic URL-to-class mapping (/api/User/create → User::create())
3. Request Validation
Laravel: Form Requests, Validation Rules
GEMVC: definePostSchema() method with inline validation
4. Database Queries
Laravel: Eloquent ORM (User::create(), User::find())
GEMVC: Fluent Query Builder ($this->select()->where()->run())
5. Naming Conventions
Laravel: Singular models (User), plural tables (users)
GEMVC: Consistent naming (User API, UserController, UserModel, UserTable)
6. Response Format
Laravel: Various response types
GEMVC: Consistent JsonResponse with Response::success(), Response::created(), etc.
7. Security
Laravel: Manual middleware, CSRF tokens
GEMVC: 90% automatic - Input sanitization, SQL injection prevention built-in
🚀 Quick Start
📦 For complete installation guide, see INSTALLATION.md
Quick Overview:
1. Install GEMVC:
composer require gemvc/swoole
2. Initialize Project:
php vendor/bin/gemvc init # Select: 1) OpenSwoole, 2) Apache, or 3) Nginx # Install PHPStan: Yes (recommended) # Setup Docker: Yes (recommended)
3. Start Server:
# With Docker docker-compose up -d # Without Docker (OpenSwoole) php index.php
4. Test Server:
# Visit: http://localhost:9501/api # Should return: "GEMVC server is running"
5. Setup Database (optional):
php vendor/bin/gemvc db:init php vendor/bin/gemvc db:migrate UserTable
6. Generate Your Service:
php vendor/bin/gemvc create:crud Product
7. Run PHPStan:
vendor/bin/phpstan analyse
✅ For detailed step-by-step instructions, see INSTALLATION.md
📚 Examples
Example 1: Creating a User
Request:
POST /api/User/create Content-Type: application/json { "name": "John Doe", "email": "john@example.com", "password": "secret123" }
Flow:
User::create()validates schemaUserController::create()maps data toUserModelUserModel::createModel()validates business rules, hashes passwordUserTable::insertSingleQuery()inserts into database
Response:
{
"response_code": 201,
"message": "created",
"count": 1,
"service_message": "User created successfully",
"data": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"description": null
}
}
Example 2: Reading a User
Request:
GET /api/User/read/?id=1
Flow:
User::read()validates GET parameterUserController::read()delegates to modelUserModel::readModel()callsselectById()- Password is hidden (
password = "-")
Response:
{
"response_code": 200,
"message": "OK",
"count": 1,
"service_message": "User retrieved successfully",
"data": {
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"password": "-"
}
}
Example 3: Listing Users with Filtering
Request:
GET /api/User/list/?sort_by=name&find_like=name=John
Flow:
User::list()definesfindable()andsortable()fieldsUserController::list()usescreateList()helper- Automatic filtering and sorting applied
Response:
{
"response_code": 200,
"message": "OK",
"count": 1,
"service_message": "Users retrieved successfully",
"data": [
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
]
}
🎓 Learning Path
-
Study the User Example (
src/startup/user/)- See how all 4 layers work together
- Understand request flow
- Learn validation patterns
-
Generate Your First CRUD
gemvc create:crud Product
-
Run PHPStan Level 9
vendor/bin/phpstan analyse
- Fix any type errors
- Write type-safe code
- Catch bugs early!
-
Customize Templates (
templates/cli/)- Edit templates to match your coding style
- Add custom methods and patterns
-
Read Documentation
ARCHITECTURE.md- Full architecture detailsSECURITY.md- Security featuresTEMPLATE_SYSTEM.md- Template customization
📖 Important Notes
⚠️ Remember:
- GEMVC is NOT Laravel - Don't expect Laravel conventions
- GEMVC is NOT Symfony - Different architecture and patterns
- Follow GEMVC patterns - Use the User example as a reference
- 4-Layer Architecture - API → Controller → Model → Table
- Automatic Security - Input sanitization, SQL injection prevention built-in
✅ Do's:
- ✅ Extend
ApiServicefor API classes - ✅ Extend
Controllerfor controllers - ✅ Extend
Tablefor models and tables - ✅ Use
definePostSchema()for validation - ✅ Use fluent query builder for database operations
- ✅ Return
JsonResponseobjects - ✅ Use PHPStan Level 9 - Write type-safe code!
- ✅ Add type hints to all methods and properties
- ✅ Use strict types:
declare(strict_types=1); - ✅ Use
_prefix for aggregation - Properties starting with_are ignored in CRUD operations
❌ Don'ts:
- ❌ Don't use Laravel conventions
- ❌ Don't create routes files
- ❌ Don't use Eloquent-style syntax
- ❌ Don't skip the 4-layer architecture
- ❌ Don't manually sanitize inputs (it's automatic!)
- ❌ Don't skip PHPStan - Run it regularly!
- ❌ Don't ignore type errors - Fix them!
- ❌ Don't use
mixedtypes without reason
📚 Comprehensive Documentation
GEMVC has extensive documentation to help you understand every aspect of the framework. All documentation files (.md) are important and provide different perspectives on GEMVC:
📖 Core Documentation Files
🏗️ ARCHITECTURE.md - Complete Architecture Overview
Learn: Overall framework structure, component breakdown, design patterns, request flow
- Directory structure and component organization
- Webserver-agnostic architecture
- Automatic security features
- Request flow for Apache and OpenSwoole
- Performance optimizations
- Design patterns used
🛠️ CLI.md - CLI Commands Reference
Learn: All command-line tools, code generation, project management
- Complete CLI command reference
- Command architecture and class hierarchy
- How commands extend
Commandbase class - How
AbstractInituses Template Method pattern - How
DockerComposeInitmanages Docker services - How
ProjectHelperresolves paths - Step-by-step examples and troubleshooting
🗄️ DATABASE_LAYER.md - Database Layer Guide
Learn: Table layer, schema definition, type mapping, migrations
- How all table classes must extend
Table - Understanding
$_type_mapproperty - Using
defineSchema()for constraints - Property mapping and visibility rules
- Schema constraints (primary, unique, foreign keys, indexes)
- Complete examples and best practices
🌐 HTTP_REQUEST_LIFE_CYCLE.md - Request Handling
Learn: Server-agnostic HTTP request handling, adapters, unified Request object
- How server adapters (
ApacheRequest,SwooleRequest) work - Unified
Requestobject design - Request life cycle for Apache and OpenSwoole
- Automatic input sanitization
- Response handling abstraction
- Security features in request processing
🎨 TEMPLATE_SYSTEM.md - Customizable Templates
Learn: Code generation templates, customization, template variables
- How templates are copied during
gemvc init - Template lookup priority (project vs vendor)
- Available templates (service, controller, model, table)
- Template variables and replacement
- Customization examples
- Best practices for template management
🔒 SECURITY.md - Security Features
Learn: Security architecture, attack prevention, automatic security
- Multi-layer security architecture
- 90% automatic security coverage
- Input sanitization (XSS prevention)
- SQL injection prevention
- Header sanitization
- File security (MIME, signature, encryption)
- JWT authentication/authorization
- Schema validation for mass assignment prevention
📑 Additional Documentation
- CHANGELOG.md - Version history and notable changes
- SECURITY.md - Detailed security features and best practices
- LICENSE - License information
💡 Learning Resources
- Example Code:
src/startup/user/- Complete User implementation (API, Controller, Model, Table) - Template Examples:
templates/cli/- Default code generation templates - Stubs:
src/stubs/- IDE type stubs for OpenSwoole and Redis
🎯 Quick Navigation for AI Assistants
To understand GEMVC architecture:
- Start with README.MD (this file) for overview
- Read ARCHITECTURE.md for deep dive
- Study
src/startup/user/for code examples
To understand CLI commands:
- Read CLI.md for complete command reference
- Check how commands extend
Commandbase class - Understand Template Method pattern in
AbstractInit
To understand database layer:
- Read DATABASE_LAYER.md for Table layer guide
- Learn about
$_type_mapanddefineSchema() - Understand how all table classes extend
Table
To understand HTTP request handling:
- Read HTTP_REQUEST_LIFE_CYCLE.md
- Learn about server adapters (
ApacheRequest,SwooleRequest) - Understand unified
Requestobject
To understand template system:
- Read TEMPLATE_SYSTEM.md
- Learn template customization
- Understand template variable replacement
To understand security:
- Read SECURITY.md
- Learn about automatic security features
- Understand attack prevention mechanisms
🆘 Need Help?
- 📖 Read ARCHITECTURE.md for detailed architecture
- 🔒 Read SECURITY.md for security features
- 🎨 Read TEMPLATE_SYSTEM.md for template customization
- 💡 Study
src/startup/user/for code examples
🎯 Code Quality with PHPStan Level 9
GEMVC is built with PHPStan Level 9 (the highest level!) and you should use it too!
Why PHPStan Level 9?
PHPStan Level 9 catches:
- ✅ Type errors before runtime
- ✅ Null pointer exceptions
- ✅ Undefined method calls
- ✅ Incorrect array access
- ✅ Type mismatches
- ✅ Missing return types
- ✅ And much more!
Setup PHPStan in Your Project
During gemvc init, you'll be asked if you want to install PHPStan. Say YES!
Or install manually:
composer require --dev phpstan/phpstan
Run PHPStan Analysis
# Run analysis vendor/bin/phpstan analyse # Or use composer script composer phpstan
Example: PHPStan Catches Bugs
Without PHPStan (bugs in production):
public function getUser($id) { return $this->selectById($id)->name; // ❌ Might be null! }
With PHPStan Level 9 (caught at development):
public function getUser(int $id): ?UserModel { $user = $this->selectById($id); if (!$user) { return null; } return $user; // ✅ Type-safe! }
Benefits for Your Code
- Type Safety: Catch errors before they happen
- Better IDE Support: Auto-completion, refactoring
- Cleaner Code: Forces you to write explicit types
- Fewer Bugs: Static analysis catches issues early
- Team Consistency: Everyone writes code the same way
GEMVC's PHPStan Configuration
GEMVC includes:
- ✅ Level 9 configuration (highest level)
- ✅ OpenSwoole stubs for proper type checking
- ✅ Redis stubs for connection type safety
- ✅ Pre-configured
phpstan.neonfile
Use PHPStan Level 9 - Write clean, type-safe, bug-free code! 🎯
Links
- 🤖 FOR AI ASSISTANTS - READ THIS FIRST!
- 📦 Installation Guide ⭐ Start Here!
- What is GEMVC?
- Architecture
📄 License
MIT License bei Ali Khorsandfard gemvc.de(https://www.gemvc.de)
Built with ❤️ for developers who want simplicity, security, and performance.