Blog Post Title
This is the post content.
# **SartajPHP: The Event-Oriented PHP Framework** **A Comprehensive Developer Guide** --- ## **Table of Contents** ### **Part I: Foundations** 1. **Introduction to SartajPHP Philosophy** 2. **Architecture and Core Concepts** 3. **Installation and Project Setup** 4. **Understanding the Event-Oriented Paradigm** ### **Part II: Development Fundamentals** 5. **Project Structure and Configuration** 6. **Application Lifecycle and PageEvents** 7. **FrontFile System: HTML with Superpowers** 8. **Components: Server-Side UI Building Blocks** ### **Part III: Advanced Patterns** 9. **Fusion Attributes and Execution Flow** 10. **Expression Tags and Dynamic Evaluation** 11. **Multi-Application Architecture** 12. **NativeGate and Real-Time Systems** ### **Part IV: Practical Development** 13. **Building Web Applications** 14. **Forms, Validation, and Database Operations** 15. **AJAX and Client-Server Communication** 16. **Security and Performance Optimization** ### **Part V: Reference** 17. **Component Reference Guide** 18. **Best Practices and Patterns** 19. **Troubleshooting and Debugging** 20. **Migration and Integration Strategies** --- # **Chapter 1: Introduction to SartajPHP Philosophy** SartajPHP is not MVC Framework, It is Event oriented PHP Framework. A typical SartajPHP Project constructed with BasicGate (Web App's Gate), Front File, Master File, Componets and Front Place. SartajPHP don't use Controller and MVC pattern. # **SartajPHP Gate Architecture** ### *Gate‑Driven Event Architecture (GDEA)* SartajPHP uses a **Gate‑Driven Event Architecture (GDEA)** instead of traditional MVC. In this architecture, every application is represented by a **Gate**, and every request is processed as a sequence of **events**. A Gate acts as the **entry point**, **lifecycle controller**, and **event processor** for the application. All browser, terminal, or socket requests must pass through a Gate before any output is generated. This design provides: - A unified request entry point - A clean event‑oriented workflow - A predictable lifecycle - A flexible structure for different application types --- ## **What Is a Gate?** A **Gate** is a class that: - Receives the incoming request - Interprets URL → Event + Parameters - Executes lifecycle events - Executes page events - Processes data - Renders output (HTML, JSON, text, etc.) - Returns the final response A Gate replaces the traditional “Controller” or “App” class found in MVC frameworks. --- ## **Gate Types** SartajPHP provides multiple Gate types for development of different type of application: | Gate Type | Purpose | |----------|----------| | **BasicGate** | Standard web applications (HTML output) | | **NativeGate** | WebSocket or long‑running applications | | **ConsoleGate** | Terminal‑based applications | All custom Gates must extend one of these base classes. Example: ```php class Index extends \Sphp\tools\BasicGate {} ``` --- ## **Gate Naming Convention** To avoid confusion with the similar file extension “php” all Gate files must use the **.gate.php** suffix in file name. So we can easily identified Gate class files. ### **Class Name** ``` Index Admin Api ``` ### **File Name** ``` Index.gate.php Admin.gate.php Api.gate.php ``` This ensures: - Clear categorization - Clean autocomplete grouping - Predictable file structure - Zero naming collisions with “App” --- ## **Request Flow** The request lifecycle in SartajPHP follows this sequence: ``` Browser / Terminal Request ↓ SartajPHP Framework Core ↓ URL Translator (index-myevent-eventpara.html → GateName + EventName + EventParams) ↓ Gate Loader ↓ Gate Object Created ↓ Lifecycle Events Executed ↓ Page Events Executed ↓ Data Processing (optional) ↓ Front File + Master File Rendering (optional) ↓ Output Returned to Browser / Terminal ``` --- ## **URL → Gate Translation** SartajPHP uses a structured URL format: ``` index-myevent-eventpara.html ``` This is translated into: - **Gate Name:** `Index` - **Event Name:** `myevent` - **Event Parameter:** `eventpara` This translation is handled internally by the framework. --- ## **Gate Lifecycle** Lifecycle events trigger for all requests. So you can code here which is required for every request like check authentication on onstart event. So all Lifecycle events are used for configuration in sequence. Most of Gate only need to implement onstart event handler. Every Gate follows a predictable lifecycle: 1. **onstart()** Trigger On Start after construct, Initialize environment, Create Front File Objects, Check Authentication, Check Permission. 2. **onready()** TriggerAfter onstart. Update or change Components settings. 3. **onrun()** Trigger After onready and before process any PageEevnt 4. **onrender()** Trigger After onrun, PageEvents and before output send to browser. Add extra on demand CSS,JS File Links or codes Developers may override any lifecycle method. --- ## **Page Events** A Gate can handle multiple **page events**, each handle to a specific browser URL in BasicGate and NativeGate and command line arguments in ConsoleGate. Example: ```php /** url=gate-login-evtp.html */ public function page_event_login($evtp) { // Handle login } ``` Events are triggered automatically based on the URL translation. --- ## **Rendering System** Gates may optionally use: - **Front File** *.front files (page template) - **Master File** *.mast.php files inside masters folder (layout template) Rendering is handled by the Gate’s internal rendering engine. --- ## **Why Gate Architecture?** The Gate‑Driven Event Architecture provides several advantages: ### ✔ No MVC complexity No controllers, models, or views to manage. ### ✔ Event‑oriented Everything is an event — simple and predictable. ### ✔ Unified entry point Each application task has a single Gate controlling its lifecycle. ### ✔ Flexible output HTML, JSON, text, or WebSocket responses. ### ✔ Clean naming No confusion between “php” files and “php” Gate (class). ### ✔ Perfect for multi‑application frameworks Web, console, and socket apps share the same architecture. --- ## **Example Gate** ```php frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/index_main.front"); } /** Browser send Get Request to landing URL of Gate, Trigger New Event*/ public function page_new() { $this->frtMain->addMetaData('title', 'Welcome'); $this->setFrontFile($this->frtMain); } } ``` --- ## **Conclusion** SartajPHP’s **Gate‑Driven Event Architecture** provides a clean, modern, event‑oriented alternative to MVC. By using Gates as the core entry point for all applications, the framework achieves: - Simplicity - Predictability - Flexibility - High readability - Strong architectural identity This pattern is unique to SartajPHP and forms the foundation of its design philosophy. 1. BasicGate :- A Gate (*.gate.php file) where you can write your Business Logic as OOP Programming and Handle Browser Requests landed as Events. 2. Front File :- A HTML File (*.front file) with some special Tags and Attributes which is processed on Server. You can easily convert any HTML file into Front File. 3. Components :- A (*.php file) PHP Classes extends with \Sphp\tools\Component parent. Front File convert HTML Tags with runat="server" into Component Objects. Component can create a complex HTML,CSS,JS output without writing a single line of code. You can use them in Front File as HTML Tag. 4. Master File :- A (*.mast.php) PHP File which call SartajPHP API to get Generated Dynamic output from App,Front File,PHP and Front Places. Master File include head and body tag of HTML page to send to browser. First MasterFile gather all dynamic output and then place into HTML Tags accoridng to layout. Master File is actually a combination of header and footer in other frameworks + Front Places. 5. Front Places :- Front Place (*.place.front or *.place.php file) is a place in Master File which generate dynamic output and print in Master File. Front File and PHP Class extends with Sphp\tools\FrontPlace class can be used as Front Place. For Example A Slider in website can be created with use of Front Place and Show and Hide with Gate and easily control HTML output send to browser without creating a separate files. ## **1.1 The Evolution Beyond MVC** In the landscape of PHP frameworks, developers have long been confined to the Model-View-Controller (MVC) pattern. While MVC provides structure, it often imposes rigid constraints that don't align with modern web development needs. Enter SartajPHP—a revolutionary approach that reimagines how PHP applications are structured and executed. SartajPHP isn't just another framework; it's a paradigm shift. It replaces controller-based routing with an **event-oriented architecture** where every user interaction becomes a discrete event handled by specialized application units. This fundamental change unlocks unprecedented flexibility, performance, and developer productivity. ## **1.2 Core Philosophy: Event-Oriented Design** At the heart of SartajPHP lies a simple but powerful principle: **Every request is an event, not a route.** Traditional frameworks map URLs to controller methods: ``` GET /users/profile → UserController::profile() POST /users/update → UserController::update() ``` SartajPHP translates URLs into PageEvents: ``` GET index.html → Index.gate.php::page_new() POST index.html → Index.gate.php::page_submit() GET index-profile-123.html → Index.gate.php::page_event_profile("123") ``` This event-oriented approach offers several advantages: ### **1.2.1 Natural Request Handling** Human interactions with websites are inherently event-driven: "click submit," "view details," "delete item." SartajPHP mirrors this natural model in code, making application logic more intuitive and maintainable. ### **1.2.2 Decoupled Architecture** Gate in SartajPHP are self-contained unit that declare what events they handle. There's no central routing table to maintain, no fragile route definitions that break when refactoring. ### **1.2.3 Multiple Application Types** Because each Gate Object is independent, a single SartajPHP project can host: - Traditional web application - API-only services - Real-time WebSocket services - Legacy systems (WordPress, Laravel modules) - Background workers - All running simultaneously, isolated yet interoperable ## **1.3 The Three Pillars of SartajPHP** ### **Pillar 1: Pure HTML Templates** SartajPHP's FrontFile system uses **100% valid HTML** as templates. No custom templating language to learn, no special syntax that breaks HTML validation. Designers can work with standard HTML files, while developers enhance them with special attributes that add server-side behavior only when needed. **Example: Progressive Enhancement** ```html ``` The same HTML file serves both as a static prototype and a fully dynamic application view. ### **Pillar 2: Component-Based UI** UI elements in SartajPHP are **Components**—server-side objects that bind to HTML elements. A Component isn't just a widget; it's a complete unit with: - Server-side validation - Database binding - Lifecycle events - Client-server synchronization - Permission and authentication control Components automatically handle their own concerns, reducing boilerplate and eliminating common security oversights. ### **Pillar 3: Multi-Application Environment** Unlike single-application frameworks, SartajPHP treats each functional Gate unit as an independent application. This enables: **Microservices Architecture in a Single Codebase:** ``` /project/ ├── apps/ │ ├── Blog.gate.php # Blog system │ ├── Shop.gate.php # E-commerce │ └── Api.gate.php # JSON API ├── appsn/ │ └── Notifications.gate.php # WebSocket service └── reg.php # Registry connects them all ``` Each Gate has its own lifecycle, configuration, and resources, yet they share the same runtime and can communicate seamlessly. ## **1.4 Performance by Design** SartajPHP achieves exceptional performance through architectural decisions: ### **1.4.1 Minimal Runtime Overhead** The framework loads only what's needed for the current request. A typical SartajPHP request completes in **20-50ms**, compared to 150-1200ms for heavier frameworks. ### **1.4.2 Intelligent Caching** The caching system operates at multiple levels: - **FrontFile compilation cache** (parsed templates) - **Component initialization cache** - **PageEvent output cache** - **Database query cache** Caching rules are declarative and fine-grained: ```php // Cache all index Gate responses for 1 hour addCacheList("index", 3600); // Cache specific event with parameter addCacheList("index", "view", 1800, "cep"); ``` ### **1.4.3 Built-in Optimization** - Automatic CSS/JS minification and bundling - Intelligent asset loading (CSS in head, JS at bottom) - Duplicate prevention for included resources - Gzip compression and HTTP/2 push support ## **1.5 Security Architecture** Security isn't bolted on—it's built into SartajPHP's foundation: ### **1.5.1 No URL-to-File Mapping** Traditional frameworks expose their structure through URLs: ``` /user/profile → /app/controllers/UserController.php ``` SartajPHP uses Gate Name that hide the actual file path structure: ``` user-profile.html → Gate Loader "user" → /apps/User.gate.php user-profile.html → Gate Loader "user" → /apps/users/UserMember.gate.php ``` Attackers cannot infer paths or probe for files. ### **1.5.2 Component-Level Security** Each Component can declare permission requirements: ```html
``` If permission checks fail, the Component (and its contents) are completely removed from output—not just hidden with CSS. ### **1.5.3 Automatic Input Handling** Components automatically sanitize and validate their values. There's no need for manual `htmlspecialchars()` or SQL escaping when using built-in data binding. ## **1.6 When to Choose SartajPHP** SartajPHP excels in several scenarios: ### **Ideal Use Cases:** 1. **Modern Web Applications** requiring real-time features 2. **Legacy System Integration** where multiple technologies must coexist 3. **Rapid Prototyping** with immediate client review capability 4. **Microservices Architecture** in a monolithic deployment 5. **Progressive Web Apps** with offline capabilities 6. **Real-Time Dashboards** and monitoring systems ### **Comparison with Other Frameworks:** | Aspect | Laravel | Symfony | SartajPHP | |--------|---------|---------|-----------| | **Learning Curve** | Moderate | Steep | Shallow (HTML-first) | | **Performance** | Good | Good | Excellent | | **Real-time Support** | Requires packages | Requires packages | Built-in | | **Multiple Apps** | Not designed for | Possible but complex | Fundamental feature | | **Template System** | Blade (custom) | Twig (custom) | Pure HTML | | **Architecture** | MVC | MVC | Event-Oriented | ## **1.7 The Developer Experience** ### **1.7.1 Back-to-Front Development** Developers can work in their preferred direction: - **Back-to-Front**: Start with PHP logic, add UI later - **Front-to-Back**: Design HTML first, connect logic later - **Middle-Out**: Build Components, integrate both sides ### **1.7.2 Tools and Ecosystem** - **SphpDesk**: Integrated development environment - **VS Code Extension**: Intelligent code completion - **Browser DevTools Integration**: Debug Components in console - **CLI Tools**: Project scaffolding and management ### **1.7.3 Progressive Complexity** Start simple and add sophistication as needed: ```php // Phase 1: Simple page class Hello extends BasicGate { public function page_new() { echo "Hello World"; } } // Phase 2: Add FrontFile class Hello extends BasicGate { private $frtMain; public function onstart() { $this->frtMain = new FrontFile($this->mypath . "/hello_main.front"); } public function page_new() { $this->setFrontFile($this->frtMain); } } // Phase 3: Add Components and events class Hello extends BasicGate { // ... plus Components and page_event handlers private $frtMain; public function onstart() { $this->frtMain = new FrontFile($this->mypath . "/hello_main.front"); } public function page_new() { $this->setFrontFile($this->frtMain); } /** * Handle start render event of div1 Component. */ public function comp_div1_on_startrender($args){ $str1 = ""; // Loop All Children of Form Components foreach($this->frtMain->frmcheck->getAllChildren() as $i=> $child){ $str1 .= " Child $i : " . get_class($child) . " id = " . $child->id . "Updated
"); ``` **Redirects:** ```php $this->page->forward(getGateURL("dashboard")); ``` ## **2.8 Cache Architecture** SartajPHP's caching operates at multiple levels for maximum performance. ### **2.8.1 Cache Levels** 1. **FrontFile Cache**: Parsed .front files stored as PHP objects 2. **Component Cache**: Initialized Components with default values 3. **Output Cache**: Complete HTML responses 4. **Database Cache**: Query results (optional) ### **2.8.2 Cache Configuration** **Project-level (`cachelist.php`):** ```php // Cache all index app responses for 1 hour addCacheList("index", 3600); // Cache specific Gate + event addCacheList("blog-view", 1800, "ce"); // Cache with Gate + event + event parameter addCacheList("shop-product-shirt", 3600, "cep"); // Cache only match event from any Gate and with any event parameter addCacheList("info", 3600, "e"); ``` **Programmatic caching:** ```php // Check cache if (!isRegisterCacheItem("index")) { addCacheList("index", 3600); } ``` ### **2.8.3 Cache Invalidation** Automatic invalidation occurs when: - FrontFile changes (file modification time) - Component configuration changes - Database tables are modified (with proper tagging) Manual invalidation: ```php clearCacheItem("blog-view"); ``` ## **2.9 Security Architecture Deep Dive** ### **2.9.1 Input Validation Layers** 1. **Component-Level Validation**: ```html ``` Validation occurs automatically before `page_submit()` proceeds. 2. **Type Conversion**: ```php $intValue = (int)$this->Client->post('number'); $safeHtml = $this->Client->request('htmlcontent'); // Auto-sanitized ``` 3. **Database Protection**: ```php // Component binding automatically escapes $this->page->insertData($form2); // Manual queries use parameterized statements $insertid = $this->dbEngine->runSQL("users", ["name"=>$name]); // or $sql = $this->dbEngine->insertSQL(["name"=>$name],"users"); $insertid = $this->dbEngine->executeQueryQuick($sql); ``` ### **2.9.2 Output Protection** **Automatic Context-Aware Escaping:** ```html##{$userInput}#
##{raw:$trustedHtml}#
``` **Content Security Policy:** ```php // In prerun.php $policy = SphpBase::sphp_response()->getSecurityPolicy( "https://*.trusted.com 'self'" ); SphpBase::sphp_response()->addSecurityHeaders($policy); ``` ## **2.10 Performance Optimization Patterns** ### **2.10.1 Lazy Loading** Components and resources load only when needed. Resources renderonce="true" ignore on AJAX request and load in only full normal load request: ```html ``` ### **2.10.2 AJAX Response Merging** Multiple AJAX response can be batched: ```php // Server-side $this->JSServer->addJSONHTMLBlock("alert1", "Response1"); SphpBase::JSServer->addJSONJSBlock("$('#alert1').css('background-color','#FF0000');"); // Framework may batch these automatically ``` ### **2.10.3 Progressive Enhancement** Start with basic HTML, enhance with Components: ```html ``` ## **2.11 Chapter Summary** SartajPHP's architecture represents a thoughtful balance between power and simplicity. By understanding these core concepts: 1. **Layered Architecture** ensures separation of concerns while maintaining integration 2. **Event-Oriented Design** makes applications more intuitive and maintainable 3. **Component System** reduces boilerplate and improves security 4. **Multiple Application Types** provide flexibility for any project need 5. **Built-in Performance Optimizations** deliver fast applications by default This architectural foundation enables the development patterns we'll explore in the coming chapters. With this understanding, you're ready to start building with SartajPHP. --- *Next: Chapter 3 covers Installation and Project Setup, where we'll put these concepts into practice.* # **Chapter 3: Installation and Project Setup** ## **3.1 System Requirements and Prerequisites** Before installing SartajPHP, ensure your development environment meets these requirements: ### **3.1.1 Server Requirements** - **PHP 7.0 or higher** (7.0+ recommended) - **Composer** (for dependency management) - **Web Server** (SphpServer, Apache 2.4+, Nginx 1.18+, or built-in PHP server) - **Extensions Required**: - PDO (with MySQL, PostgreSQL, or SQLite drivers) - JSON - MBString - OpenSSL - Zip (for Composer operations) ### **3.1.2 Optional Components** - **Node.js 14+** (for SphpDesk and npm tools) - **Redis** (for advanced caching) - **SphpServer** (for NativeGate features) - **MySQL 5.7+ / MariaDB 10.3+ / PostgreSQL 12+** (for production databases) ### **3.1.3 Development Tools** - **Git** (version control) - **VS Code** (recommended IDE with SartajPHP extension) - **Composer** (PHP package manager) - **SphpDesk** (optional desktop environment) ## **3.2 Installation Methods** SartajPHP supports multiple installation methods to suit different workflows. ### **3.2.1 Composer Installation (Recommended)** For new projects, use Composer to create a SartajPHP project: ```bash # Create a new directory for your project mkdir my-sartaj-project cd my-sartaj-project # Initialize Composer and install SartajPHP composer init --name="mycompany/myproject" --type="project" --no-interaction composer require sartajphp/sartajphp # Install sample project structure composer run-script post-install-cmd ``` This creates the following structure: ``` my-sartaj-project/ ├── vendor/sartajphp/sartajphp/ # Framework core ├── apps/ # Your applications ├── masters/ # Master templates ├── cache/ # Cache directory ├── composer.json # Dependencies ├── start.php # Entry point └── .htaccess # URL rewriting ``` ### **3.2.2 Manual Installation** For environments without Composer or custom deployments: ```bash # Download the framework wget https://github.com/sartajphp/sartajphp/releases/latest/sartajphp.zip unzip sartajphp.zip -d /var/www/myproject # Set up project structure cd /var/www/myproject cp -r res/proj1/* . ``` ### **3.2.3 Docker Installation** For containerized development: ```dockerfile # Dockerfile FROM php:8.2-apache RUN apt-get update && apt-get install -y \ git unzip libzip-dev \ && docker-php-ext-install zip pdo_mysql RUN curl -sS https://getcomposer.org/installer | php -- \ --install-dir=/usr/local/bin --filename=composer WORKDIR /var/www/html COPY . . RUN composer install EXPOSE 80 ``` Create a `docker-compose.yml`: ```yaml version: '3.8' services: app: build: . ports: - "8080:80" volumes: - .:/var/www/html - ./cache:/var/www/html/cache environment: - APP_ENV=development db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: sartajdb ``` ## **3.3 Project Structure Explained** Understanding the project structure is crucial for effective development. ### **3.3.1 Core Project Structure** ``` myproject/ ├── .htaccess # Apache/Nginx rewrite rules ├── start.php # Application entry point ├── composer.json # Dependencies and scripts ├── comp.php # Project configuration ├── reg.php # Application registry ├── cachelist.php # Cache configuration ├── prerun.php # Pre-execution hooks ├── app.sphp # Desktop app configuration │ ├── apps/ # Web applications (.gate.php files) │ ├── Index.gate.php # Main application │ ├── uuadmin.gate.php # Admin application │ ├── uuapi.gate.php # API application │ └── fronts/ # FrontFiles for apps │ ├── index_main.front │ ├── admin_main.front │ └── api_main.front │ ├── appsn/ # NativeGate and ConsoleGate │ ├── uuchat.gate.php # WebSocket chat server │ ├── uuworker.gate.php # Background worker │ └── console/ # CLI applications │ └── uubackup.gate.php │ ├── masters/ # Master templates and assets │ ├── default/ # Default master set │ │ ├── master.php # Main layout │ │ ├── menu_guest.php # Guest menu │ │ └── menu_admin.php # Admin menu │ ├── db.php # Database schema │ └── sphpcodeblock.php # Custom code blocks │ ├── plugin/ # Project-specific plugins │ ├── myplugin/ │ │ ├── uuplugin.gate.php │ │ └── regapp.php │ └── config.json │ └── cache/ # Runtime cache ├── front/ # Compiled FrontFiles ├── component/ # Component cache ├── output/ # Page output cache └── logs/ # Error and access logs ``` ### **3.3.2 The `res/` Folder - Framework Resources** The `res/` folder contains shared framework resources. Its location depends on installation method: **Composer installation:** ``` vendor/sartajphp/sartajphp/res/ ``` **Manual installation:** ``` /path/to/framework/res/ ``` **Key subdirectories:** - `res/Score/` - Core framework engine - `res/Slib/` - Shared libraries and Components - `res/jslib/` - JavaScript libraries (jQuery, Bootstrap, etc.) - `res/components/` - Additional Components - `res/plugin/` - Framework plugins ## **3.4 Configuration Files** ### **3.4.1 `start.php` - The Entry Point** The `start.php` file is the single entry point for all requests. Never rename or remove this file. **Minimal `start.php`:** ```php execute(true); } ``` **Customizing paths for different environments:** ```php // Development environment if ($_SERVER['HTTP_HOST'] === 'localhost') { $sharedpath = "./vendor/sartajphp/sartajphp"; $respath = "./vendor/sartajphp/sartajphp/res"; } // Production environment elseif ($_SERVER['HTTP_HOST'] === 'example.com') { $sharedpath = "/usr/share/sartajphp"; $respath = "https://cdn.example.com/sartajphp/res"; } // Staging environment else { $sharedpath = "/opt/sartajphp"; $respath = "/shared/res"; } ``` ### **3.4.2 `.htaccess` - URL Rewriting** Apache configuration for clean URLs: ```apache # .htaccess - Apache Configuration Options +FollowSymLinks -Indexes DirectoryIndex start.php RewriteEngine On # Base directory adjustment (if project is in subfolder) RewriteBase /myproject/ # Route all .html/.htm requests to start.php RewriteCond %{REQUEST_URI} \.(html|htm)$ [NC] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ start.php [NC,L] # Prevent direct access to framework files RewriteCond %{REQUEST_URI} \.(front|app|sphp)$ [NC] RewriteRule ^(.*)$ start.php [NC,L] # Force HTTPS in production RewriteCond %{HTTPS} off RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC] RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L] # Cache static assets'. $row["user_name"] .'
'; } $divuser = $this->frtMain->getComponent("divuser"); $divuser->setInnerHTML($str1); $divuser->setAttribute("class","card-body"); $divuser->setPreTag('
This is the post content.
Welcome, ##{$userName}#!
#{ $pageTitle = "Home Page"; }###{$parentgate->siteName}#
##{$frontobj->getFilePath()}#
##{$sphp_settings->getBase_url()}#
##{$metadata->get('description')}#
``` ### **5.5.3 Safe Expression Patterns** **Good patterns:** ```html##{$output}#
``` ## **5.6 Special Tags and Their Behavior** ### **5.6.1 `##{$productCount}# amazing products
##{$productGrid->getRow('description')}#
##{$stats['userCount']}#
##{$stats['orderCount']}#
$##{$stats['revenue']}#
##{$stats['productCount']}#
| Time | User | Action | Details |
|---|---|---|---|
| ##{$div1->getItem('time')}# | ##{$div1->getItem('user')}# | ##{$div1->getItem('action')}# | ##{$div1->getItem('details')}# |
```
**Container Components** (Layout):
```html
Access Parent Front File Component: ##{$'. $this->name .'->getAttribute("class")}#
'; // private Front File, Components can't access in Parent FrontFile //$this->front1 = $this->createFrontObjectPrivate($str1,true); // share Front File, Components can access in Parent FrontFile // and also parent components can access in child FrontFile // database binding also works in shared FrontFile // shared FrontFile use prefix as "name + _" of parent to avoid id/name conflicts $this->front1 = $this->createFrontObjectShare($str1,true); $this->streetComponent = $this->front1->getComponent($this->name. '_street'); $this->cityComponent = $this->front1->getComponent($this->name. '_city'); $this->stateComponent = $this->front1->getComponent($this->name. '_state'); // parent FrontFile can access child Front File Components with proper prefix $this->frontobj->getComponent($this->name.'_street')->fi_setDefaultValue('84 Bell'); $this->stateComponent->fi_setDefaultValue('Ohio'); // ... more child Components } public function onrender() { // Render child Components $str1 =$this->front1->ProcessMe(); $this->setInnerHTML($str1); } public function getValue() { // Return composite value return [ 'street' => $this->streetComponent->getValue(), 'city' => $this->cityComponent->getValue(), 'state' => $this->stateComponent->getValue() ]; } public function setValue($data) { // Distribute composite value if (is_array($data)) { $this->streetComponent->setValue($data['street'] ?? ''); $this->cityComponent->setValue($data['city'] ?? ''); $this->stateComponent->setValue($data['state'] ?? ''); } } } ``` ### **6.8.2 Data-Aware Components** Components that fetch their own data: ```php class CategorySelect extends \Sphp\Comp\Form\Select { // query execute on render time save useless processing when no rendering required public function onprerender() { // Fetch categories from database $db = SphpBase::dbEngine(); $categories = $db->executeQuery( "SELECT id, name FROM categories WHERE active = 1 ORDER BY name" ); // Build options array $options = []; foreach ($categories as $cat) { $options[] = [$cat['id'],$cat['name']]; } // Set options $this->setOptionsKeyArray(); $this->setOptionsArray($options); parent::onprerender(); } } ``` ### **6.8.3 Stateful Components** Components that maintain state across requests: ```php class ShoppingCart extends \Sphp\tools\Component { private $sessionKey; public function oninit() { $this->sessionKey = 'cart_' . $this->id; // Initialize from session if (!(SphpBase::sphp_request()->isSession($this->sessionKey))) { SphpBase::sphp_request()->session($this->sessionKey, []); } } public function addItem($productId, $quantity = 1) { $cart = SphpBase::sphp_request()->session($this->sessionKey); if (isset($cart[$productId])) { $cart[$productId] += $quantity; } else { $cart[$productId] = $quantity; } SphpBase::sphp_request()->session($this->sessionKey, $cart); } public function getValue() { return SphpBase::sphp_request()->isSession($this->sessionKey) ?? []; } public function setValue($cartData) { SphpBase::sphp_request()->session($this->sessionKey, $cartData); } public function onrender() { $cart = $this->getValue(); $itemCount = array_sum($cart); $total = $this->calculateTotal($cart); $html = " "; $this->element->setInnerHTML($html); } } ``` ## **6.9 Component Validation System** ### **6.9.1 Built-in Validation Rules** ```html ``` ### **6.9.2 Custom Validation Methods** ```php include_once(SphpBase::sphp_settings()->comp_uikit_path . "/form/TextField.php"); class CustomTextField extends \Sphp\Comp\Form\TextField { private $usernameFormat = false; private $uniqueUsername = false; // User Name Format validation method public function fi_setUsernameFormat() { // true = User Name Format validation enabled $this->usernameFormat = true; // check server side validation when Component is submitted if ($this->issubmit) { // Must start with letter // check server side validation if (!preg_match('/^[a-zA-Z]/', $this->value)) { // inform user and Framework about the Validation error $this->setErrMsg( $this->getAttribute("msgname") . " Username must start with a letter"); } // Only letters, numbers, underscore // check server side validation if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->value)) { // inform user and Framework about the Validation error $this->setErrMsg( $this->getAttribute("msgname") . " Username can only contain letters, numbers, and underscore"); } } } /** User Name Existence validation (check against database) * we will check database on client side validation with * use AJAX call to server event and handle in this file */ public function fi_setUniqueUsername() { // true = Unique User Name validation enabled $this->uniqueUsername = true; // check server side validation when Component is submitted if ($this->issubmit) { if ($this->findUniqueUsername()) { // inform user and Framework about the Validation error $this->setErrMsg($this->getAttribute("msgname") . " Username already taken"); } } } private function findUniqueUsername() { $db = SphpBase::dbEngine(); return $db->isRecordExist( "SELECT COUNT(*) FROM ". $this->dtable ." WHERE ". $this->dfield ." = '". $this->value ."'", ); } protected function onprerender() { // Add client side validation with javascript if ($this->usernameFormat) { // insert javascript code into form component submit event addHeaderJSFunctionCode("{$this->formName}_submit", "{$this->name}usernameformat", ' var usernameformat = /^[a-zA-Z][a-zA-Z0-9_]*$/; var blnusernameformat = usernameformat.test(document.getElementById("'. $this->name .'").value); if(!blnusernameformat){ // show validation error message displayValidationError(document.getElementById("'. $this->name .'"),"Value isn\'t match with User Name Format "); // prevent form submit blnSubmit = false ; }'); } // For AJAX based Unique User Name validation // we call AJAX function on keyup event to server event to check username existence if ($this->uniqueUsername) { // insert javascript into jQuery ready event handler addHeaderJSFunctionCode("ready", "{$this->name}uniqueusername", ' $("#'. $this->name .'").keyup(function(){ // check username existence with call getAJAX function to server event var data = {}; data["'. $this->name .'"] = $("#'. $this->name .'").val(); getAJAX("'. getEventURL("checkusername") .'",data,true,function(response){ // process server response if(response.exists){ // show validation error message displayValidationError(document.getElementById("'. $this->name .'"),"Username already taken"); // disable form submit blnSubmit = false ; } else { // clear validation error message clearValidationError(document.getElementById("'. $this->name .'")); } }); });'); } parent::onprerender(); } /** now we handle server event and reply AJAX validation request. * So we override onappevent event handler to handle server event. */ protected function onappevent() { // check if it is validation request with use of Page Class: SphpBase::page() if(SphpBase::page()->getEvent() == "checkusername") { // check username existence with call findUniqueUsername function $this->findUniqueUsername() ? SphpBase::JSServer()->addJSONReturnBlock(['exists' => true]) : SphpBase::JSServer()->addJSONReturnBlock(['exists' => false]); } } } ``` **Usage:** ```html ``` ### **6.9.3 Validation Groups** ```html ``` ```php // In App public function page_event_validate_group($evtp) { $group = $evtp; // "personal" or "contact" $personal = $this->frtMain->getComponent($group); // Validate only Components in this group $isValid = false; // we validate name should not contain @ foreach($personal->getChildren() as $compname=>$compobj){ $isValid = $isValid || (strpos($compobj->value,'@') > 0) ? false : true ; } $strError = ""; if(! $isValid) $strError = "Error in Validation"; // send error to display in tag with id='err' $this->JSServer->addJSONHTMLBlock('err',$strError); } ``` ## **6.10 Performance Optimization** ### **6.10.1 Component Caching** ```php class CachedComponent extends \Sphp\tools\Component { private $cacheKey; private $cacheTtl = 300; // 5 minutes public function oninit() { $this->cacheKey = 'component_' . $this->name; } public function getCachedData() { $sphp_api = SphpBase::sphp_api(); if ($data = $sphp_api->readFromCache($this->cacheKey,$this->cacheTtl)) { return $data; } // Expensive operation $data = $this->fetchDataFromExternalAPI(); // $data save to Cache $sphp_api->saveToCache($this->cacheKey, $data); return $data; } public function clearCache() { SphpBase::sphp_api()->clearCache($this->cacheKey); } } ``` ### **6.10.2 Lazy Loading Components** ```html