Skip to content
Ali Khorsandfard edited this page Nov 26, 2025 · 12 revisions

GEMVC - The PHP Multi-Platform Microservices REST API Framework

PHP Version License Swoole Apache Nginx PHPStan PHPUnit Pest

🎯 What is GEMVC?

GEMVC is a multi-platform PHP framework to create REST API that works 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

GEMVC uses a 4-layer architecture pattern but as recommendation , it never force you :

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

📐 4-Layer Responsibilities

1. API Layer (app/api/)

Purpose: URL endpoints, request validation, authentication

Naming: PascalCase (e.g., User.php, Product.php)

Responsibilities:

  • Handel Authentication and Sanitization for incoming request
  • Request schemas what input accepted by this endpoint (definePostSchema(), defineGetSchema())
  • Handle authentication ($request->auth())
  • Delegate to Controller layer

Example openSwoole (app/api/User.php) is endpoint domain.com/user/:

Example apache/nginx (app/api/User.php) is endpoint domain.com/api/user/:

Example openSwoole (app/api/User.php method create()) is endpoint domain.com/user/create:

Example apache/nginx (app/api/User.php method create()) is endpoint domain.com/api/user/create:

Note in .env file you can by setting SERVICE_IN_URL_SECTION=0 and METHOD_IN_URL_SECTION=1 have same result as openSwoole:

Why? because of support traditional shared cpanel hosting based on NginX and Apache:

Key Points:

  • ✅ Extends ApiService (or SwooleApiService for 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):

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):

Key Points:

  • ✅ Extends corresponding Table class (e.g., UserModel extends UserTable)
  • ✅ Contains business logic and validations
  • ✅ Uses insertSingleQuery(), updateSingleQuery(), deleteByIdQuery()
  • ✅ Returns JsonResponse objects

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):

Key Points:

  • ✅ Extends Table class
  • ✅ Properties match database columns (with types)
  • protected properties 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|static or null|static[] for query methods

🔄 URL Mapping No Router Complexity!

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/createUser::create()
  • GET /api/User/read/?id=1User::read()
  • POST /api/User/updateUser::update()
  • POST /api/User/deleteUser::delete()
  • GET /api/User/listUser::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/createUser::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


📖 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 ApiService for API classes
  • ✅ Extend Controller for controllers
  • ✅ Extend Table for models and tables
  • ✅ Use definePostSchema() for validation
  • ✅ Use fluent query builder for database operations
  • ✅ Return JsonResponse objects
  • 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 mixed types without reason

🎯 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

  1. Type Safety: Catch errors before they happen
  2. Better IDE Support: Auto-completion, refactoring
  3. Cleaner Code: Forces you to write explicit types
  4. Fewer Bugs: Static analysis catches issues early
  5. 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.neon file

Use PHPStan Level 9 - Write clean, type-safe, bug-free code! 🎯