{"id":34877507,"url":"https://github.com/gemvc/gemvc","last_synced_at":"2026-02-18T17:01:18.511Z","repository":{"id":186299245,"uuid":"674961595","full_name":"gemvc/gemvc","owner":"gemvc","description":"A lightweight, server-agnostic PHP framework (Swoole/Nginx/Apache) designed for building high-performance Microservices \u0026 REST APIs","archived":false,"fork":false,"pushed_at":"2026-02-09T12:36:14.000Z","size":3837,"stargazers_count":22,"open_issues_count":0,"forks_count":17,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-02-09T16:12:36.272Z","etag":null,"topics":["ai-ready","apache","framework","microservice","nginx","openswoole","php","rest-api"],"latest_commit_sha":null,"homepage":"https://www.gemvc.de","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gemvc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-08-05T10:05:39.000Z","updated_at":"2026-02-09T12:14:21.000Z","dependencies_parsed_at":"2026-01-17T08:00:48.336Z","dependency_job_id":null,"html_url":"https://github.com/gemvc/gemvc","commit_stats":null,"previous_names":["secure73/gemvc","gemvc/gemvc"],"tags_count":274,"template":false,"template_full_name":null,"purl":"pkg:github/gemvc/gemvc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gemvc%2Fgemvc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gemvc%2Fgemvc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gemvc%2Fgemvc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gemvc%2Fgemvc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gemvc","download_url":"https://codeload.github.com/gemvc/gemvc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gemvc%2Fgemvc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29587066,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T16:55:40.614Z","status":"ssl_error","status_checked_at":"2026-02-18T16:55:37.558Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-ready","apache","framework","microservice","nginx","openswoole","php","rest-api"],"created_at":"2025-12-26T01:02:10.852Z","updated_at":"2026-02-18T17:01:17.985Z","avatar_url":"https://github.com/gemvc.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"![gemvc-tracekit](https://github.com/user-attachments/assets/c730d3b8-877f-4793-9261-34ca392cf692)\n\n\n# [GEMVC](https://www.gemvc.de) - The PHP Multi-Platform Microservices REST API Framework\n\n[![PHP Version](https://img.shields.io/badge/php-%3E%3D8.2-777bb4.svg?style=flat-square\u0026logo=php\u0026logoColor=white)](https://www.php.net/releases/)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)\n[![Swoole](https://img.shields.io/badge/Swoole-Supported-green.svg?style=flat-square\u0026logo=swoole\u0026logoColor=white)](https://openswoole.com/)\n[![Apache](https://img.shields.io/badge/Apache-Supported-D22128.svg?style=flat-square\u0026logo=apache\u0026logoColor=white)](https://httpd.apache.org/)\n[![Nginx](https://img.shields.io/badge/Nginx-Supported-009639.svg?style=flat-square\u0026logo=nginx\u0026logoColor=white)](https://nginx.org/)\n[![PHPStan](https://img.shields.io/badge/PHPStan-Level%209-brightgreen.svg?style=flat-square)](https://phpstan.org/)\n[![PHPUnit](https://img.shields.io/badge/PHPUnit-Supported-3b8c3b.svg?style=flat-square\u0026logo=phpunit\u0026logoColor=white)](https://phpunit.de/)\n[![Pest](https://img.shields.io/badge/Pest-Supported-purple.svg?style=flat-square\u0026logo=pest\u0026logoColor=white)](https://pestphp.com/)\n## 🚀 Start in 30 Seconds\n```bash\ncomposer require gemvc/library\nphp vendor/bin/gemvc init\n```\n\n### 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.\n\n### Not to replace, but to complete\n\u003e 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!\n\n### You are the Master of your Code\n\u003e 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!\n\n### AI-Ready - Born for AI Agents\n\u003eThanks 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.\n\u003eGEMVC is designed to work seamlessly with **Cursor, Copilot, and ChatGPT**.\nWe include pre-configured context files (`AI_API_REFERENCE.md`, `.cursorrules`) right in the root. \nYour AI assistant already knows how to write GEMVC code perfectly!\n\n### Easy to Learn\n\u003e 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.\n\n### No-Hassle Documentation\n\u003e 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!\n\n### ⚡ The \"Async Magic\"\n\u003e Write standard, synchronous PHP code (like you always do) on Apache/Nginx. \nSwitch to **OpenSwoole**, and your exact same code automatically runs as **Asynchronous Non-blocking I/O**.\n**Zero code changes required.**\n\n### Fully and Easily Customizable\n\u003e You can easily define custom Class Templates for any layer, and then CLI Commands will generate your classes in seconds!\n\n### Library or Framework? The Choice is Yours.\n\u003e 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 init` command to use it as a modern framework from day one.\n\n### Testing \u0026 Quality Assurance\n\u003e 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.\n\n### Full Transparency Policy\n\u003e 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.\n\n\n---\n\n## 🤖 FOR AI ASSISTANTS - READ THIS FIRST!\n\n**ATTENTION: If you are an AI assistant (Cursor AI, GitHub Copilot, Claude, etc.), you MUST read the following file first:**\n\u003e **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.\n### ⚠️ **[QUICK_START_AI.md](QUICK_START_AI.md)** - MASTER INSTRUCTIONS FOR AI ASSISTANTS\n\n**This file will:**\n1. ✅ Instruct you to read ALL GEMVC documentation files\n2. ✅ Teach you the complete 4-layer architecture (MANDATORY)\n3. ✅ Show you correct method signatures and return types\n4. ✅ Explain security features (90% automatic)\n5. ✅ Provide code generation patterns you MUST follow\n6. ✅ List common mistakes you MUST avoid\n\n**After reading QUICK_START_AI.md, you should read:**\n- `.cursorrules` - Complete framework rules\n- `AI_API_REFERENCE.md` - All method signatures\n- `AI_CONTEXT.md` - Quick examples\n- `GEMVC_GUIDE.md` - Code generation patterns\n\n**Do NOT skip layers or use Laravel patterns. Follow GEMVC conventions only!**\n---\n\n## 🎯 What is GEMVC?\n\nGEMVC is a **multi-platform PHP REST API framework** that works identically on:\n- ✅ **OpenSwoole** (async, WebSocket, hot reload)\n- ✅ **Apache** (traditional PHP-FPM)\n- ✅ **Nginx** (high performance, reverse proxy)\n\n**Key Features**:\n- 🔒 **90% Security Automatic** - Input sanitization, SQL injection prevention, path protection\n- 🌐 **Webserver-Agnostic** - Same code works on all platforms\n- 🛠️ **CLI Code Generation** - Generate Services, Controllers, Models, Tables\n- 📝 **Simple API** - Clean, straightforward code structure\n- ⚡ **High Performance** - Connection pooling, async capabilities\n- ✅ **PHPStan Level 9** - Write type-safe, bug-free code with the highest static analysis level\n- 📊 **Native APM Integration** - Automatic Application Performance Monitoring with zero configuration\n  - Automatic request tracing (root spans)\n  - Controller operation tracing (optional)\n  - Database query tracing (optional)\n  - Environment-controlled via `.env` flags\n  - Works with any APM provider (TraceKit, Datadog, New Relic, etc.)\n  - Fire-and-forget pattern (zero performance impact)\n- 📈 **Server Monitoring** - Built-in RAM, CPU, network, and database metrics\n\n---\n\n## 🏗️ Architecture Overview\n\nGEMVC uses a **4-layer architecture** pattern:\n\n```\nAPI Layer (app/api/)          → URL endpoints, schema validation\n    ↓\nController Layer (app/controller/) → Business logic orchestration\n    ↓\nModel Layer (app/model/)      → Data logic, validations\n    ↓\nTable Layer (app/table/)      → Database access, queries\n```\n\n**Example Flow**:\n```\nPOST /api/User/create\n    ↓\napp/api/User.php::create()        → Validates schema\n    ↓\napp/controller/UserController.php  → Handles business logic\n    ↓\napp/model/UserModel.php           → Data validations, transformations\n    ↓\napp/table/UserTable.php           → Database operations\n```\n\n---\n\n## 📊 Native APM Integration\n\nGEMVC includes **native Application Performance Monitoring (APM)** integration that works automatically with zero code changes. The APM system captures the full request lifecycle and provides deep insights into your application's performance.\n\n### Key Features\n\n✅ **Automatic Root Trace** - Captures full request lifecycle from Bootstrap  \n✅ **Controller Tracing** - Automatic spans for controller operations (optional)  \n✅ **Database Query Tracing** - Automatic spans for all SQL queries (optional)  \n✅ **Exception Tracking** - Automatic exception recording in traces  \n✅ **Environment-Controlled** - Enable/disable via `.env` variables  \n✅ **Zero Performance Impact** - Fire-and-forget pattern, traces sent after HTTP response  \n✅ **Provider-Agnostic** - Works with any APM provider (TraceKit, Datadog, New Relic, etc.)\n\n### Quick Setup\n\n**1. Install APM Provider:**\n```bash\ncomposer require gemvc/apm-tracekit\n```\n\n**2. Configure Environment:**\n```env\nAPM_NAME=TraceKit\nTRACEKIT_API_KEY=your-api-key\nTRACEKIT_API_URL=https://app.tracekit.dev/v1/traces\n\n# Optional: Enable controller and database tracing\nAPM_TRACE_CONTROLLER=1\nAPM_TRACE_DB_QUERY=1\n```\n\n**3. Use `callController()` in API Services:**\n```php\n// app/api/User.php\npublic function create(): JsonResponse\n{\n    // Automatic controller tracing (if APM_TRACE_CONTROLLER=1)\n    return $this-\u003eUserController-\u003ecreate();\n}\n```\n\n*Note: You can still use `$this-\u003ecallController(new UserController($this-\u003erequest))` if you prefer, but the magic property syntax is recommended.*\n\n**4. Use `createModel()` in Controllers:**\n```php\n// app/controller/UserController.php\npublic function create(): JsonResponse\n{\n    // Automatic Request propagation for database tracing\n    $model = $this-\u003ecreateModel(new UserModel());\n    // ... rest of code\n}\n```\n\n**That's it!** APM tracing works automatically. No code changes needed beyond using `callController()` and `createModel()`.\n\n### What Gets Traced\n\n- **Root Request** - Full request lifecycle (automatic)\n- **Controller Operations** - Method calls with response codes (if `APM_TRACE_CONTROLLER=1`)\n- **Database Queries** - All SQL queries with execution time (if `APM_TRACE_DB_QUERY=1`)\n- **Exceptions** - All exceptions automatically recorded\n\n### Trace Structure\n\n```\nRoot Trace (Bootstrap)\n  └─ controller-operation (UserController::create)\n      └─ database-query (INSERT INTO users ...)\n```\n\nAll spans share the same `traceId` for complete request visibility.\n\n### Performance\n\n- **Zero Overhead When Disabled** - Environment flags control tracing\n- **Minimal Overhead When Enabled** - ~0.25ms per request\n- **Non-Blocking** - Traces sent after HTTP response (fire-and-forget)\n\n### Documentation\n\nFor complete APM integration guide, see **[GEMVC_APM_INTEGRATION.md](GEMVC_APM_INTEGRATION.md)**\n\n---\n\n## 📐 4-Layer Architecture\n\n### 1. **API Layer** (`app/api/`)\n**Purpose**: URL endpoints, request validation, authentication\n\n**Naming**: PascalCase (e.g., `User.php`, `Product.php`)\n\n**Responsibilities**:\n- Define request schemas (`definePostSchema()`, `defineGetSchema()`)\n- Handle authentication (`$request-\u003eauth()`)\n- Delegate to Controller layer\n\n**Example** (`app/api/User.php`):\n```php\n\u003c?php\nnamespace App\\Api;\n\nuse App\\Controller\\UserController;\nuse Gemvc\\Core\\ApiService;\nuse Gemvc\\Http\\Request;\nuse Gemvc\\Http\\JsonResponse;\n\nclass User extends ApiService\n{\n    public function __construct(Request $request)\n    {\n        parent::__construct($request);\n    }\n\n    public function create(): JsonResponse\n    {\n        // Validate request schema\n        if(!$this-\u003erequest-\u003edefinePostSchema([\n            'name' =\u003e 'string',\n            'email' =\u003e 'email',\n            'password' =\u003e 'string'\n        ])) {\n            return $this-\u003erequest-\u003ereturnResponse();\n        }\n        \n        // Delegate to controller\n        return (new UserController($this-\u003erequest))-\u003ecreate();\n    }\n}\n```\n\n**Key Points**:\n- ✅ Extends `ApiService` (or `SwooleApiService` for OpenSwoole)\n- ✅ Uses `definePostSchema()` for validation\n- ✅ Uses `?` prefix for optional fields: `'?name' =\u003e 'string'`\n- ✅ Delegates to Controller, doesn't handle business logic\n\n---\n\n### 2. **Controller Layer** (`app/controller/`)\n**Purpose**: Business logic orchestration\n\n**Naming**: PascalCase + \"Controller\" suffix (e.g., `UserController.php`)\n\n**Responsibilities**:\n- Orchestrate business logic\n- Map request data to models\n- Handle request/response flow\n\n**Example** (`app/controller/UserController.php`):\n```php\n\u003c?php\nnamespace App\\Controller;\n\nuse App\\Model\\UserModel;\nuse Gemvc\\Core\\Controller;\nuse Gemvc\\Http\\Request;\nuse Gemvc\\Http\\JsonResponse;\n\nclass UserController extends Controller\n{\n    public function __construct(Request $request)\n    {\n        parent::__construct($request);\n    }\n\n    public function create(): JsonResponse\n    {\n        // Map POST data to Model with custom handlers\n        $model = $this-\u003erequest-\u003emapPostToObject(\n            new UserModel(),\n            [\n                'email' =\u003e 'email',\n                'name' =\u003e 'name',\n                'description' =\u003e 'description',\n                'password' =\u003e 'setPassword()'  // Calls setPassword() method\n            ]\n        );\n        \n        if(!$model instanceof UserModel) {\n            return $this-\u003erequest-\u003ereturnResponse();\n        }\n        \n        return $model-\u003ecreateModel();\n    }\n}\n```\n\n**Key Points**:\n- ✅ Extends `Controller`\n- ✅ Uses `mapPostToObject()` to convert request to model\n- ✅ Can specify method calls: `'password' =\u003e 'setPassword()'`\n- ✅ Delegates to Model layer\n\n---\n\n### 3. **Model Layer** (`app/model/`)\n**Purpose**: Data logic, validations, transformations\n\n**Naming**: PascalCase + \"Model\" suffix (e.g., `UserModel.php`)\n\n**Responsibilities**:\n- Business validations (e.g., duplicate email check)\n- Data transformations (e.g., password hashing)\n- Error handling\n\n**Example** (`app/model/UserModel.php`):\n```php\n\u003c?php\nnamespace App\\Model;\n\nuse App\\Table\\UserTable;\nuse Gemvc\\Helper\\CryptHelper;\nuse Gemvc\\Http\\JsonResponse;\nuse Gemvc\\Http\\Response;\n\nclass UserModel extends UserTable\n{\n    public function createModel(): JsonResponse\n    {\n        // Business validation: Check duplicate email\n        $this-\u003eemail = strtolower($this-\u003eemail);\n        $found = $this-\u003eselectByEmail($this-\u003eemail);\n        if ($found) {\n            return Response::unprocessableEntity(\"User already exists\");\n        }\n        \n        // Data transformation: Hash password\n        $this-\u003esetPassword($this-\u003epassword);\n        \n        // Perform database operation\n        $success = $this-\u003einsertSingleQuery();\n        if ($this-\u003egetError()) {\n            return Response::internalError($this-\u003egetError());\n        }\n        \n        return Response::created($this, 1, \"User created successfully\");\n    }\n    \n    public function setPassword(string $plainPassword): void\n    {\n        $this-\u003epassword = CryptHelper::hashPassword($plainPassword);\n    }\n}\n```\n\n**Key Points**:\n- ✅ Extends corresponding `Table` class (e.g., `UserModel extends UserTable`)\n- ✅ Contains business logic and validations\n- ✅ Uses `insertSingleQuery()`, `updateSingleQuery()`, `deleteByIdQuery()`\n- ✅ Returns `JsonResponse` objects\n\n---\n\n### 4. **Table Layer** (`app/table/`)\n**Purpose**: Database access, queries, schema definition\n\n**Naming**: PascalCase + \"Table\" suffix (e.g., `UserTable.php`)\n\n**Responsibilities**:\n- Define database table structure\n- Define properties matching database columns\n- Provide query methods\n\n**Example** (`app/table/UserTable.php`):\n```php\n\u003c?php\nnamespace App\\Table;\n\nuse Gemvc\\Database\\Table;\nuse Gemvc\\Database\\Schema;\n\nclass UserTable extends Table\n{\n    // Properties match database columns\n    public int $id;\n    public string $name;\n    public string $email;\n    public ?string $description;\n    protected string $password;  // Protected = not exposed in selects\n    \n    protected array $_type_map = [\n        'id' =\u003e 'int',\n        'name' =\u003e 'string',\n        'email' =\u003e 'string',\n        'description' =\u003e 'string',\n        'password' =\u003e 'string',\n    ];\n    \n    public function __construct()\n    {\n        parent::__construct();\n    }\n    \n    public function getTable(): string\n    {\n        return 'users';  // Database table name\n    }\n    \n    public function defineSchema(): array\n    {\n        return [\n            Schema::index('email'),\n            Schema::unique('email'),\n            Schema::index('description')\n        ];\n    }\n    \n    // Custom query methods\n    public function selectById(int $id): null|static\n    {\n        $result = $this-\u003eselect()-\u003ewhere('id', $id)-\u003elimit(1)-\u003erun();\n        return $result[0] ?? null;\n    }\n    \n    public function selectByEmail(string $email): null|static\n    {\n        $arr = $this-\u003eselect()-\u003ewhere('email', $email)-\u003elimit(1)-\u003erun();\n        return $arr[0] ?? null;\n    }\n}\n```\n\n**Key Points**:\n- ✅ Extends `Table` class\n- ✅ Properties match database columns (with types)\n- ✅ `protected` properties are not exposed in SELECT queries\n- ✅ Properties starting with `_` are **ignored in CRUD operations** (see below)\n- ✅ Uses fluent query builder: `$this-\u003eselect()-\u003ewhere()-\u003elimit()-\u003erun()`\n- ✅ Returns `null|static` or `null|static[]` for query methods\n\n---\n\n## 🔗 Model Aggregation \u0026 Composition (Properties with `_` prefix)\n\n**Important Feature**: Properties starting with `_` are **completely ignored** in all CRUD table operations!\n\nThis allows you to:\n- ✅ Aggregate other models (composition)\n- ✅ Store arrays of related models\n- ✅ Create relationships without affecting database operations\n- ✅ Use PHPStan Level 9 type checking for aggregated models\n\n### How It Works\n\n**Properties starting with `_` are skipped**:\n- ❌ Not included in `INSERT` operations\n- ❌ Not included in `UPDATE` operations\n- ❌ Not included in table schema generation\n- ✅ Can be used for aggregation/composition\n- ✅ Can be public, private, or protected\n\n### Example 1: Aggregating a Profile Model\n\n**User Model with Profile Aggregation**:\n```php\n\u003c?php\nnamespace App\\Model;\n\nuse App\\Table\\UserTable;\nuse App\\Model\\Profile;  // Aggregated model\n\nclass UserModel extends UserTable\n{\n    // This property is IGNORED in database operations\n    public ?Profile $_profile = null;\n    \n    /**\n     * Get user with profile loaded\n     */\n    public function withProfile(): self\n    {\n        if ($this-\u003e_profile === null \u0026\u0026 $this-\u003eid) {\n            $profileTable = new ProfileTable();\n            $this-\u003e_profile = $profileTable-\u003eselectByUserId($this-\u003eid);\n        }\n        return $this;\n    }\n    \n    /**\n     * Set profile\n     */\n    public function setProfile(Profile $profile): void\n    {\n        $this-\u003e_profile = $profile;\n    }\n}\n```\n\n**Usage**:\n```php\n$user = new UserModel();\n$user-\u003eid = 1;\n$user-\u003ename = \"John\";\n$user-\u003eemail = \"john@example.com\";\n\n// Add profile without affecting database operations\n$profile = new Profile();\n$profile-\u003ebio = \"Software Developer\";\n$user-\u003e_profile = $profile;\n\n// Save user (profile is NOT inserted, only user data)\n$user-\u003einsertSingleQuery();  // Only inserts: id, name, email\n```\n\n---\n\n### Example 2: Aggregating an Array of Orders\n\n**User Model with Orders Array** (PHPStan Level 9):\n\n```php\n\u003c?php\nnamespace App\\Model;\n\nuse App\\Table\\UserTable;\nuse App\\Model\\Order;\n\nclass UserModel extends UserTable\n{\n    /**\n     * Array of Order models - ignored in CRUD operations\n     * @var array\u003cOrder\u003e\n     */\n    public array $_orders = [];\n    \n    /**\n     * Get user's orders\n     * @return array\u003cOrder\u003e\n     */\n    public function orders(): array\n    {\n        if (empty($this-\u003e_orders) \u0026\u0026 $this-\u003eid) {\n            $orderTable = new OrderTable();\n            $this-\u003e_orders = $orderTable-\u003eselectByUserId($this-\u003eid);\n        }\n        return $this-\u003e_orders;\n    }\n    \n    /**\n     * Add order to user\n     */\n    public function addOrder(Order $order): void\n    {\n        $this-\u003e_orders[] = $order;\n    }\n    \n    /**\n     * Create order for user\n     */\n    public function createOrder(array $orderData): Order\n    {\n        $order = new Order();\n        $order-\u003euser_id = $this-\u003eid;\n        $order-\u003eamount = $orderData['amount'];\n        $order-\u003einsertSingleQuery();\n        \n        $this-\u003e_orders[] = $order;\n        return $order;\n    }\n}\n```\n\n**Usage**:\n```php\n$user = new UserModel();\n$user-\u003eid = 1;\n$user-\u003ename = \"John\";\n\n// Add orders (ignored in database operations)\n$order1 = new Order();\n$order1-\u003eamount = 100;\n$user-\u003eaddOrder($order1);\n\n$order2 = new Order();\n$order2-\u003eamount = 200;\n$user-\u003eaddOrder($order2);\n\n// Save user (orders array is NOT inserted!)\n$user-\u003einsertSingleQuery();  // Only inserts: id, name\n\n// Later, create actual orders in database\nforeach ($user-\u003e_orders as $order) {\n    $order-\u003euser_id = $user-\u003eid;\n    $order-\u003einsertSingleQuery();  // Save each order separately\n}\n```\n\n---\n\n### Example 3: Complex Relationships\n\n**Product Model with Categories and Reviews**:\n\n```php\n\u003c?php\nnamespace App\\Model;\n\nuse App\\Table\\ProductTable;\nuse App\\Model\\Category;\nuse App\\Model\\Review;\n\nclass ProductModel extends ProductTable\n{\n    /**\n     * Single related model\n     * @var Category|null\n     */\n    public ?Category $_category = null;\n    \n    /**\n     * Array of related models\n     * @var array\u003cReview\u003e\n     */\n    public array $_reviews = [];\n    \n    /**\n     * Load product with category and reviews\n     */\n    public function loadRelations(): self\n    {\n        if ($this-\u003eid) {\n            // Load category\n            $categoryTable = new CategoryTable();\n            $this-\u003e_category = $categoryTable-\u003eselectById($this-\u003ecategory_id);\n            \n            // Load reviews\n            $reviewTable = new ReviewTable();\n            $this-\u003e_reviews = $reviewTable-\u003eselectByProductId($this-\u003eid);\n        }\n        return $this;\n    }\n    \n    /**\n     * Get average rating\n     */\n    public function getAverageRating(): float\n    {\n        if (empty($this-\u003e_reviews)) {\n            return 0.0;\n        }\n        \n        $total = 0;\n        foreach ($this-\u003e_reviews as $review) {\n            $total += $review-\u003erating;\n        }\n        \n        return round($total / count($this-\u003e_reviews), 2);\n    }\n}\n```\n\n**Usage**:\n```php\n$product = new ProductModel();\n$product-\u003eid = 1;\n$product-\u003ename = \"Laptop\";\n$product-\u003eprice = 999.99;\n\n// Load relations\n$product-\u003eloadRelations();\n\n// Use aggregated data\necho $product-\u003e_category-\u003ename;  // \"Electronics\"\necho $product-\u003egetAverageRating();  // 4.5\n\n// Save product (category and reviews are NOT affected!)\n$product-\u003eupdateSingleQuery();  // Only updates: id, name, price\n```\n\n---\n\n### Best Practices\n\n1. **Use Descriptive Names**: `$_profile`, `$_orders`, `$_reviews`\n2. **Add Type Hints**: Use PHPStan Level 9 compatible types\n   ```php\n   public ?Profile $_profile = null;        // Single model\n   public array $_orders = [];              // Array of models\n   public array\u003cint, Order\u003e $_orders = [];  // Typed array (PHPStan)\n   ```\n3. **Create Helper Methods**: `orders()`, `withProfile()`, `loadRelations()`\n4. **Lazy Loading**: Load aggregated data only when needed\n5. **Keep Separate**: Don't mix database columns with aggregated properties\n\n### Common Patterns\n\n```php\n// Pattern 1: Single aggregation\npublic ?Profile $_profile = null;\n\n// Pattern 2: Array aggregation\npublic array $_orders = [];\n\n// Pattern 3: Private aggregation with getter\nprivate array $_reviews = [];\npublic function getReviews(): array {\n    return $this-\u003e_reviews;\n}\n\n// Pattern 4: Protected aggregation\nprotected ?Category $_category = null;\n```\n\n### PHPStan Level 9 Examples\n\n```php\n// ✅ Full type safety with PHPStan Level 9\n/** @var array\u003cOrder\u003e */\npublic array $_orders = [];\n\n// ✅ Nullable single model\npublic ?Profile $_profile = null;\n\n// ✅ Typed array with PHPDoc\n/**\n * @var array\u003cint, Review\u003e\n */\npublic array $_reviews = [];\n```\n\n**Result**: Clean, type-safe code with powerful aggregation capabilities! 🎯\n\n---\n\n## 🔄 URL Mapping\n\nGEMVC maps URLs to code automatically:\n\n```\nURL: /api/User/create\n    ↓\nExtracts: Service = \"User\", Method = \"create\"\n    ↓\nLoads: app/api/User.php\n    ↓\nCalls: User::create()\n```\n\n**URL Structure**:\n```\n/api/{ServiceName}/{MethodName}\n```\n\n**Examples**:\n- `POST /api/User/create` → `User::create()`\n- `GET /api/User/read/?id=1` → `User::read()`\n- `POST /api/User/update` → `User::update()`\n- `POST /api/User/delete` → `User::delete()`\n- `GET /api/User/list` → `User::list()`\n\n**Configuration** (`.env`):\n```env\nSERVICE_IN_URL_SECTION=1  # Service name position in URL\nMETHOD_IN_URL_SECTION=2   # Method name position in URL\n```\n\n---\n\n## 🔑 Key Differences from Laravel/Symfony\n\n### 1. **Architecture Pattern**\n**Laravel/Symfony**: MVC (Model-View-Controller)  \n**GEMVC**: 4-Layer (API → Controller → Model → Table)\n\n### 2. **Routing**\n**Laravel**: Routes defined in `routes/web.php` or `routes/api.php`  \n**GEMVC**: Automatic URL-to-class mapping (`/api/User/create` → `User::create()`)\n\n### 3. **Request Validation**\n**Laravel**: Form Requests, Validation Rules  \n**GEMVC**: `definePostSchema()` method with inline validation\n\n### 4. **Database Queries**\n**Laravel**: Eloquent ORM (`User::create()`, `User::find()`)  \n**GEMVC**: Fluent Query Builder (`$this-\u003eselect()-\u003ewhere()-\u003erun()`)\n\n### 5. **Naming Conventions**\n**Laravel**: Singular models (`User`), plural tables (`users`)  \n**GEMVC**: Consistent naming (`User` API, `UserController`, `UserModel`, `UserTable`)\n\n### 6. **Response Format**\n**Laravel**: Various response types  \n**GEMVC**: Consistent `JsonResponse` with `Response::success()`, `Response::created()`, etc.\n\n### 7. **Security**\n**Laravel**: Manual middleware, CSRF tokens  \n**GEMVC**: **90% automatic** - Input sanitization, SQL injection prevention built-in\n\n---\n\n## 🚀 Quick Start\n\n\u003e **📦 For complete installation guide, see [INSTALLATION.md](INSTALLATION.md)**\n\n### Quick Overview:\n\n**1. Install GEMVC:**\n```bash\ncomposer require gemvc/swoole\n```\n\n**2. Initialize Project:**\n```bash\nphp vendor/bin/gemvc init\n# Select: 1) OpenSwoole, 2) Apache, or 3) Nginx\n# Install PHPStan: Yes (recommended)\n# Setup Docker: Yes (recommended)\n```\n\n**3. Start Server:**\n```bash\n# With Docker\ndocker-compose up -d\n\n# Without Docker (OpenSwoole)\nphp index.php\n```\n\n**4. Test Server:**\n```bash\n# Visit: http://localhost:9501/api\n# Should return: \"GEMVC server is running\"\n```\n\n**5. Setup Database (optional):**\n```bash\nphp vendor/bin/gemvc db:init\nphp vendor/bin/gemvc db:migrate UserTable\n```\n\n**6. Generate Your Service:**\n```bash\nphp vendor/bin/gemvc create:crud Product\n```\n\n**7. Run PHPStan:**\n```bash\nvendor/bin/phpstan analyse\n```\n\n**✅ For detailed step-by-step instructions, see [INSTALLATION.md](INSTALLATION.md)**\n\n---\n\n## 📚 Examples\n\n### Example 1: Creating a User\n\n**Request**:\n```http\nPOST /api/User/create\nContent-Type: application/json\n\n{\n    \"name\": \"John Doe\",\n    \"email\": \"john@example.com\",\n    \"password\": \"secret123\"\n}\n```\n\n**Flow**:\n1. `User::create()` validates schema\n2. `UserController::create()` maps data to `UserModel`\n3. `UserModel::createModel()` validates business rules, hashes password\n4. `UserTable::insertSingleQuery()` inserts into database\n\n**Response**:\n```json\n{\n    \"response_code\": 201,\n    \"message\": \"created\",\n    \"count\": 1,\n    \"service_message\": \"User created successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"John Doe\",\n        \"email\": \"john@example.com\",\n        \"description\": null\n    }\n}\n```\n\n---\n\n### Example 2: Reading a User\n\n**Request**:\n```http\nGET /api/User/read/?id=1\n```\n\n**Flow**:\n1. `User::read()` validates GET parameter\n2. `UserController::read()` delegates to model\n3. `UserModel::readModel()` calls `selectById()`\n4. Password is hidden (`password = \"-\"`)\n\n**Response**:\n```json\n{\n    \"response_code\": 200,\n    \"message\": \"OK\",\n    \"count\": 1,\n    \"service_message\": \"User retrieved successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"John Doe\",\n        \"email\": \"john@example.com\",\n        \"password\": \"-\"\n    }\n}\n```\n\n---\n\n### Example 3: Listing Users with Filtering\n\n**Request**:\n```http\nGET /api/User/list/?sort_by=name\u0026find_like=name=John\n```\n\n**Flow**:\n1. `User::list()` defines `findable()` and `sortable()` fields\n2. `UserController::list()` uses `createList()` helper\n3. Automatic filtering and sorting applied\n\n**Response**:\n```json\n{\n    \"response_code\": 200,\n    \"message\": \"OK\",\n    \"count\": 1,\n    \"service_message\": \"Users retrieved successfully\",\n    \"data\": [\n        {\n            \"id\": 1,\n            \"name\": \"John Doe\",\n            \"email\": \"john@example.com\"\n        }\n    ]\n}\n```\n\n---\n\n## 🎓 Learning Path\n\n1. **Study the User Example** (`src/startup/common/init_example/`)\n   - See how all 4 layers work together\n   - Understand request flow\n   - Learn validation patterns\n\n2. **Explore Built-in Services**\n   - `Apm.php` - APM provider management and testing\n   - `GemvcAssistant.php` - Developer/admin tools\n   - `GemvcMonitoring.php` - Server monitoring metrics\n\n3. **Generate Your First CRUD**\n   ```bash\n   gemvc create:crud Product\n   ```\n\n4. **Run PHPStan Level 9**\n   ```bash\n   vendor/bin/phpstan analyse\n   ```\n   - Fix any type errors\n   - Write type-safe code\n   - Catch bugs early!\n\n5. **Customize Templates** (`templates/cli/`)\n   - Edit templates to match your coding style\n   - Add custom methods and patterns\n\n6. **Read Documentation**\n   - `ARCHITECTURE.md` - Full architecture details\n   - `SECURITY.md` - Security features\n   - `TEMPLATE_SYSTEM.md` - Template customization\n\n---\n\n## 📖 Important Notes\n\n### ⚠️ Remember:\n- **GEMVC is NOT Laravel** - Don't expect Laravel conventions\n- **GEMVC is NOT Symfony** - Different architecture and patterns\n- **Follow GEMVC patterns** - Use the User example as a reference\n- **4-Layer Architecture** - API → Controller → Model → Table\n- **Automatic Security** - Input sanitization, SQL injection prevention built-in\n- **Native APM Integration** - Automatic Application Performance Monitoring\n  - Zero configuration required (just install APM provider)\n  - Environment-controlled tracing (`APM_TRACE_CONTROLLER`, `APM_TRACE_DB_QUERY`)\n  - Use `callController()` for controller tracing\n  - Use `createModel()` for database query tracing\n  - See [GEMVC_APM_INTEGRATION.md](GEMVC_APM_INTEGRATION.md) for complete guide\n- **Built-in Services** - Example services for APM, monitoring, and developer tools are included\n\n### ✅ Do's:\n- ✅ Extend `ApiService` for API classes\n- ✅ Extend `Controller` for controllers\n- ✅ Extend `Table` for models and tables\n- ✅ Use `definePostSchema()` for validation\n- ✅ Use fluent query builder for database operations\n- ✅ Return `JsonResponse` objects\n- ✅ **Use PHPStan Level 9** - Write type-safe code!\n- ✅ Add type hints to all methods and properties\n- ✅ Use strict types: `declare(strict_types=1);`\n- ✅ **Use `_` prefix for aggregation** - Properties starting with `_` are ignored in CRUD operations\n- ✅ **Use `callController()` in API services** - Enables automatic controller tracing\n- ✅ **Use `createModel()` in controllers** - Enables automatic database query tracing\n\n### ❌ Don'ts:\n- ❌ Don't use Laravel conventions\n- ❌ Don't create routes files\n- ❌ Don't use Eloquent-style syntax\n- ❌ Don't skip the 4-layer architecture\n- ❌ Don't manually sanitize inputs (it's automatic!)\n- ❌ Don't skip PHPStan - Run it regularly!\n- ❌ Don't ignore type errors - Fix them!\n- ❌ Don't use `mixed` types without reason\n\n---\n\n## 📚 Comprehensive Documentation\n\nGEMVC has extensive documentation to help you understand every aspect of the framework. **All documentation files (.md) are important** and provide different perspectives on GEMVC:\n\n### 📖 Core Documentation Files\n\n#### 🏗️ [ARCHITECTURE.md](ARCHITECTURE.md) - Complete Architecture Overview\n**Learn**: Overall framework structure, component breakdown, design patterns, request flow\n- Directory structure and component organization\n- Webserver-agnostic architecture\n- Automatic security features\n- Request flow for Apache and OpenSwoole\n- Performance optimizations\n- Design patterns used\n\n#### 🛠️ [CLI.md](CLI.md) - CLI Commands Reference\n**Learn**: All command-line tools, code generation, project management\n- Complete CLI command reference\n- Command architecture and class hierarchy\n- How commands extend `Command` base class\n- How `AbstractInit` uses Template Method pattern\n- How `DockerComposeInit` manages Docker services\n- How `ProjectHelper` resolves paths\n- Step-by-step examples and troubleshooting\n\n#### 🗄️ [DATABASE_LAYER.md](DATABASE_LAYER.md) - Database Layer Guide\n**Learn**: Table layer, schema definition, type mapping, migrations\n- How all table classes must extend `Table`\n- Understanding `$_type_map` property\n- Using `defineSchema()` for constraints\n- Property mapping and visibility rules\n- Schema constraints (primary, unique, foreign keys, indexes)\n- Complete examples and best practices\n\n#### 🌐 [HTTP_REQUEST_LIFE_CYCLE.md](HTTP_REQUEST_LIFE_CYCLE.md) - Request Handling\n**Learn**: Server-agnostic HTTP request handling, adapters, unified Request object\n- How server adapters (`ApacheRequest`, `SwooleRequest`) work\n- Unified `Request` object design\n- Request life cycle for Apache and OpenSwoole\n- Automatic input sanitization\n- Response handling abstraction\n- Security features in request processing\n\n#### 🎨 [TEMPLATE_SYSTEM.md](TEMPLATE_SYSTEM.md) - Customizable Templates\n**Learn**: Code generation templates, customization, template variables\n- How templates are copied during `gemvc init`\n- Template lookup priority (project vs vendor)\n- Available templates (service, controller, model, table)\n- Template variables and replacement\n- Customization examples\n- Best practices for template management\n\n#### 🔒 [SECURITY.md](SECURITY.md) - Security Features\n**Learn**: Security architecture, attack prevention, automatic security\n- Multi-layer security architecture\n- 90% automatic security coverage\n- Input sanitization (XSS prevention)\n- SQL injection prevention\n- Header sanitization\n- File security (MIME, signature, encryption)\n- JWT authentication/authorization\n- Schema validation for mass assignment prevention\n\n#### 📊 [GEMVC_APM_INTEGRATION.md](GEMVC_APM_INTEGRATION.md) - APM Integration Guide\n**Learn**: Application Performance Monitoring, tracing, performance insights\n- Automatic request tracing setup\n- Controller and database query tracing\n- Environment variable configuration\n- Custom tracing with ApmTracingTrait\n- Performance optimization and sample rates\n- Troubleshooting and best practices\n\n### 📑 Additional Documentation\n\n- **[CHANGELOG.md](CHANGELOG.md)** - Version history and notable changes\n- **[SECURITY.md](SECURITY.md)** - Detailed security features and best practices\n- **[LICENSE](LICENSE)** - License information\n\n### 💡 Learning Resources\n\n- **Example Code**: `src/startup/common/init_example/` - Complete examples including User, Apm, GemvcAssistant, GemvcMonitoring\n- **Template Examples**: `templates/cli/` - Default code generation templates\n- **Stubs**: `src/stubs/` - IDE type stubs for OpenSwoole and Redis\n- **Helper Classes**: `src/helper/` - ServerMonitorHelper, NetworkHelper, and other utilities\n\n### 🎯 Quick Navigation for AI Assistants\n\n**To understand GEMVC architecture:**\n1. Start with [README.MD](README.MD) (this file) for overview\n2. Read [ARCHITECTURE.md](ARCHITECTURE.md) for deep dive\n3. Study `src/startup/common/init_example/` for code examples\n\n**To understand CLI commands:**\n1. Read [CLI.md](CLI.md) for complete command reference\n2. Check how commands extend `Command` base class\n3. Understand Template Method pattern in `AbstractInit`\n\n**To understand database layer:**\n1. Read [DATABASE_LAYER.md](DATABASE_LAYER.md) for Table layer guide\n2. Learn about `$_type_map` and `defineSchema()`\n3. Understand how all table classes extend `Table`\n\n**To understand HTTP request handling:**\n1. Read [HTTP_REQUEST_LIFE_CYCLE.md](HTTP_REQUEST_LIFE_CYCLE.md)\n2. Learn about server adapters (`ApacheRequest`, `SwooleRequest`)\n3. Understand unified `Request` object\n\n**To understand template system:**\n1. Read [TEMPLATE_SYSTEM.md](TEMPLATE_SYSTEM.md)\n2. Learn template customization\n3. Understand template variable replacement\n\n**To understand security:**\n1. Read [SECURITY.md](SECURITY.md)\n2. Learn about automatic security features\n3. Understand attack prevention mechanisms\n\n**To understand APM integration:**\n1. Read [GEMVC_APM_INTEGRATION.md](GEMVC_APM_INTEGRATION.md) for complete guide\n2. Learn about automatic tracing and environment controls\n3. Understand trace context propagation\n4. Study `src/startup/common/init_example/api/Apm.php` for examples\n\n---\n\n## 🆘 Need Help?\n\n- 📖 Read [ARCHITECTURE.md](ARCHITECTURE.md) for detailed architecture\n- 🔒 Read [SECURITY.md](SECURITY.md) for security features\n- 🎨 Read [TEMPLATE_SYSTEM.md](TEMPLATE_SYSTEM.md) for template customization\n- 💡 Study `src/startup/common/init_example/` for code examples\n\n---\n\n## 🎯 Code Quality with PHPStan Level 9\n\nGEMVC is built with **PHPStan Level 9** (the highest level!) and **you should use it too!**\n\n### Why PHPStan Level 9?\n\n**PHPStan Level 9** catches:\n- ✅ Type errors before runtime\n- ✅ Null pointer exceptions\n- ✅ Undefined method calls\n- ✅ Incorrect array access\n- ✅ Type mismatches\n- ✅ Missing return types\n- ✅ And much more!\n\n### Setup PHPStan in Your Project\n\n**During `gemvc init`**, you'll be asked if you want to install PHPStan. Say **YES!**\n\nOr install manually:\n```bash\ncomposer require --dev phpstan/phpstan\n```\n\n### Run PHPStan Analysis\n\n```bash\n# Run analysis\nvendor/bin/phpstan analyse\n\n# Or use composer script\ncomposer phpstan\n```\n\n### Example: PHPStan Catches Bugs\n\n**Without PHPStan** (bugs in production):\n```php\npublic function getUser($id)\n{\n    return $this-\u003eselectById($id)-\u003ename;  // ❌ Might be null!\n}\n```\n\n**With PHPStan Level 9** (caught at development):\n```php\npublic function getUser(int $id): ?UserModel\n{\n    $user = $this-\u003eselectById($id);\n    if (!$user) {\n        return null;\n    }\n    return $user;  // ✅ Type-safe!\n}\n```\n\n### Benefits for Your Code\n\n1. **Type Safety**: Catch errors before they happen\n2. **Better IDE Support**: Auto-completion, refactoring\n3. **Cleaner Code**: Forces you to write explicit types\n4. **Fewer Bugs**: Static analysis catches issues early\n5. **Team Consistency**: Everyone writes code the same way\n\n### GEMVC's PHPStan Configuration\n\nGEMVC includes:\n- ✅ Level 9 configuration (highest level)\n- ✅ OpenSwoole stubs for proper type checking\n- ✅ Redis stubs for connection type safety\n- ✅ Pre-configured `phpstan.neon` file\n\n**Use PHPStan Level 9** - Write clean, type-safe, bug-free code! 🎯\n\n---\n## Links\n\n- [🤖 FOR AI ASSISTANTS - READ THIS FIRST!](GEMVC_GUID.md)\n- [📦 Installation Guide](INSTALLATION.md) ⭐ **Start Here!**\n- [What is GEMVC?](GEMVC.md)\n- [Architecture](ARCHITECTURE.md)\n---\n## 📄 License\n\nMIT License bei Ali Khorsandfard gemvc.de(https://www.gemvc.de)\n\n\n---\n\n**Built with ❤️ for developers who want simplicity, security, and performance.**\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgemvc%2Fgemvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgemvc%2Fgemvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgemvc%2Fgemvc/lists"}