# **Chapter 1: Gate-Driven Event Architecture - The Core Foundation** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **1.1 What is Gate-Driven Event Architecture?** SartajPhp uses a **Gate-Driven Event Architecture (GDEA)** where an Application can have multiple **Gates**, and each browser request is handled by a specific Gate through a **Page Event**. ### **Understanding Gate vs Application** Think of it this way: - **Application** = Your complete software system (the whole website/app) - **Gate** = An entry point within the Application (like a door/gate) that handles requests for a specific area - **Page Event** = An Event Trigger by Browser URL and handle by a method in your Gate Class - **URL** = Maps to Gate + Event + Parameters ``` Application (Your Website) │ ├── Gate: index → handles index.html, index-view-5.html ├── Gate: blog → handles blog.html, blog-search-php.html ├── Gate: admin → handles admin.html, admin-users.html └── Gate: shop → handles shop.html, shop-products.html ``` **A Gate is the Application's Gate** - it allows user requests to enter into specific parts of your application, processes those requests, and sends responses back to the user. One Application can have multiple Gates, each reserved by a unique "request-word" (the gate name in the URL). ### **How a Gate Works** ``` Browser Request: blog-view-5.html ↓ Gate: blog (reserved word "blog") ↓ Event: view (maps to page_view()) Parameter: 5 (available via $this->page->evtp) ↓ Output: HTML rendered from Front File + Master File ``` The URL segment before the first hyphen (or before .html) is the "request-word" that maps to a specific Gate class. ## **1.2 Why Not MVC?** Traditional MVC has issues as applications grow: - Routes become complex and hard to maintain - Controllers get bloated with too many responsibilities - URL changes break existing code SartajPhp solves this with events: - **No routing configuration needed** - URL directly maps to method - **Natural organization** - Related functionality groups in events - **Easy to extend** - Add new events without changing existing code ## **1.3 The Three Types of Gates** SartajPhp provides different Gate types for different purposes: | Gate Type | Use Case | Extension | |-----------|----------|-----------| | **BasicGate** | Standard web applications | `*.gate.php` | | **NativeGate** | WebSocket/real-time apps | `*.gate.php` | | **ConsoleGate** | CLI applications | `*.gate.php` | For web development, we use `BasicGate`. ## **1.4 BasicGate Structure** Here's what a basic Gate class looks like: ```php page->evtp` or `$this->getEventParameter()`: ```php // URL: blog-view-5.html → calls page_view() (NO parameter passed) // Access parameter via $this->page->evtp public function page_view() { $recordId = $this->page->evtp; // Returns "5" // Or use: $this->getEventParameter() } ``` | Page Event | URL Pattern | Parameter Access | Triggered When | |------------|-------------|-------------------|----------------| | `page_new()` | `gate.html` | `$this->page->evtp` | Browser loads page (GET) | | `page_submit()` | `gate.html` | `$this->page->evtp` | Form is submitted (POST) | | `page_insert()` | `gate.html` | `$this->page->evtp` | Auto-triggered after `page_submit()` for new records | | `page_update()` | `gate.html` | `$this->page->evtp` | Auto-triggered after `page_submit()` for existing records | | `page_view()` | `gate-view-123.html` | `$this->page->evtp` returns "123" | Browser requests specific record | | `page_delete()` | `gate-delete-123.html` | `$this->page->evtp` returns "123" | Browser requests deletion | ### **Custom Page Events** You can create custom events by naming method `page_event_*` - these DO take `$evtp` directly as a parameter: ```php // URL: gate-login.html → calls page_event_login("") (empty evtp) public function page_event_login($evtp) { } // URL: gate-search-laptop.html → calls page_event_search("laptop") public function page_event_search($evtp) { } // URL: gate-export-pdf.html → calls page_event_export("pdf") public function page_event_export($evtp) { } ``` | Custom Event | URL Pattern | Parameter | |--------------|-------------|-----------| | `page_event_login()` | `gate-login.html` | `$evtp = ""` | | `page_event_search($evtp)` | `gate-search-keyword.html` | `$evtp = "keyword"` | | `page_event_export($evtp)` | `gate-export-format.html` | `$evtp = "format"` | The `$evtp` parameter contains everything after the event name in the URL. ### **Generic Event Handler (Advanced)** For complete control over events, you can override the `page_event($event, $evtp)` method which catches all unmatched events: ```php // Catches any event that doesn't match built-in or custom page_event_* public function page_event($event, $evtp) { // $event = "custom", $evtp = "value" if ($event == "custom") { // handle custom event } } ``` ### **Getting Event Parameter in Your Gate** There are multiple ways to access the event parameter: ```php public function page_view() { // Method 1: Direct access to page property $id = $this->page->evtp; // Method 2: Using Gate helper method $id = $this->getEventParameter(); // Method 3: Using Page helper method $id = $this->page->getEventParameter(); } ``` ## **1.6 URL Translation in Action** Let's see how URLs translate to events: ``` URL: index.html ↓ Gate: index (maps to Index.gate.php) Event: new (maps to page_new()) ↓ Executes: Index::page_new() URL: blog-view-5.html ↓ Gate: blog (maps to Blog.gate.php) Event: view (maps to page_view()) Parameter: 5 (available via $this->page->evtp) ↓ Executes: Blog::page_view() → $this->page->evtp returns "5" URL: shop-search-laptop.html ↓ Gate: shop (maps to Shop.gate.php) Event: search (maps to page_event_search()) Parameter: laptop (passed as $evtp) ↓ Executes: Shop::page_event_search("laptop") ``` **Important:** Built-in page events (`page_new`, `page_view`, `page_delete`, etc.) do NOT receive parameters directly in the method signature. Custom events (`page_event_*`) DO receive `$evtp` as a parameter. ## **1.7 The Request Flow Diagram** Here's the complete flow when a browser makes a request: ``` ┌─────────────────────────────────────────────────────────┐ │ Browser Request │ │ (index.html) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ URL Translation Layer │ │ (gate = "index", event = "new") │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ Gate Loader │ │ (Loads Index.gate.php from reg.php) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ Gate Instantiation │ │ (Creates new Index object) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ Gate Lifecycle Events │ │ onstart() → onready() → onrun() │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ Page Event Execution │ │ (page_new()) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ FrontFile Processing │ │ (If setFrontFile is called) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ MasterFile Merge │ │ (Layout template applied) │ └───────────────────────────┬───────────────────────────────┘ ↓ ┌───────────────────────────▼───────────────────────────────┐ │ HTML Response │ └───────────────────────────────────────────────────────────┘ ``` ## **1.8 Key Concepts Summary** 1. **Gate** - Your application's Gate class that extends BasicGate 2. **Page Event** - Methods in Gate that handle browser requests 3. **URL Pattern** - `--.html` 4. **No Routing** - URL directly maps to Gate + Event method ## **1.9 What's Next?** Now you understand the core architecture. In the next chapter, you'll learn: - How to register your Gate in `reg.php` - How to create your first Gate class - How the URL maps to your Gate's events --- *Next: Chapter 2 - Registering Your First Gate*# **Chapter 2: Registering Your First Gate - From URL to Page Event** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **2.1 The Registration Process** Before your Gate can handle requests, you must register it in the `reg.php` file. This tells SartajPhp which Gate class to load for which URL. ### **The registerGate Function** ```php registerGate("gate_name", "path_to_gate_file.php"); ``` Parameters: - **gate_name** - The word used in URL (e.g., "index" from "index.html") - **path_to_gate_file.php** - Full path to your Gate file ### **Example: Registering the Index Gate** ```php showNotFrontFile(); echo "Home Page"; } /** * Custom Page Event - triggered by index-about.html */ public function page_event_about($evtp) { echo "About Page - Parameter: " . $evtp; } /** * Custom Page Event - triggered by index-contact.html */ public function page_event_contact($evtp) { echo "Contact Page"; } /** * Form Submit - triggered by index.html (POST) */ public function page_submit() { echo "Form Submitted!"; } } ``` URL mapping: ``` index.html → Index::page_new() index-about.html → Index::page_event_about("") index-contact.html → Index::page_event_contact("") index.html (POST) → Index::page_submit() ``` ## **2.6 Event Parameter Handling** When your URL includes a parameter, it gets passed to your event method: ```php // URL: blog-view-5.html public function page_view() { // $evtp = "5" echo "Viewing record ID: " . $this->page->evtp; } // URL: user-profile-john.html public function page_event_profile($evtp) { // $evtp = "john" echo "User Profile: " . $evtp; } // URL: shop-search-laptop-price-100.html public function page_event_search($evtp) { // $evtp = "laptop-price-100" // You parse it yourself $parts = explode('-', $evtp); // $parts = ["laptop", "price", "100"] } ``` ## **2.7 Automatic Events** SartajPhp automatically triggers certain events based on form submissions: ```php // Form submission handling public function page_submit() { // This is called first on any form POST if ($this->frtMain->form->getRecID() == "") { // No record ID = Insert new record // page_insert() is automatically called after } else { // Has record ID = Update existing // page_update() is automatically called after } } // Called when inserting new record public function page_insert() { echo "Inserting new record..."; } // Called when updating existing record public function page_update() { echo "Updating record..."; } ``` ## **2.8 Chapter Summary** Key points from this chapter: 1. **Register Gate** in `reg.php` using `registerGate("name", "path")` 2. **Create Gate class** extending `BasicGate` 3. **Page Events** are methods like `page_new()`, `page_submit()`, `page_event_name()` 4. **URL maps** directly: `gate-event-parameter.html` → `Gate::page_event_name(parameter)` 5. **Default event** is `page_new()` when no event specified ## **2.9 What's Next?** In the next chapter, you'll learn about Gate lifecycle events (`onstart`, `onready`, `onrun`, `onrender`) and when to use each one for initialization and processing. --- *Next: Chapter 3 - The Gate Lifecycle Events*# **Chapter 3: The Gate Lifecycle Events - Understanding Event Flow** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **3.1 What are Lifecycle Events?** Lifecycle events are special methods in your Gate class that get called at specific times during request processing. They're different from Page Events (like `page_new()`) because they're triggered automatically by the framework, not by URL requests. Think of lifecycle events as the "behind-the-scenes" setup and teardown of each request. ## **3.2 The Complete Lifecycle Order** Here's when each lifecycle event fires: ``` Request Received ↓ onstart() ← First - Initialize your Gate ↓ FrontFile Loaded (if used) ↓ onfrontinit() ← FrontFile is ready ↓ onfrontprocess() ← FrontFile processed ↓ onready() ← Gate is ready to process ↓ onrun() ← Before Page Event executes ↓ Page Event ← e.g., page_new() or page_event_* ↓ onrender() ← After Page Event, before output ↓ Response Sent ← Final HTML to browser ``` ## **3.3 onstart() - The Initialization Event** `onstart()` fires FIRST when your Gate is created. Use it for: - Creating FrontFile objects - Initializing resources - Setting up authentication - Loading configuration ### **Example: Initializing FrontFile in onstart** ```php frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/index_main.front"); } /** * Default Page Event */ public function page_new() { // Use the FrontFile we created in onstart $this->setFrontFile($this->frtMain); } } ``` ### **Example: Authentication in onstart** ```php public function onstart() { // Require ADMIN or MEMBER role $this->getAuthenticate("MEMBER,ADMIN"); // Initialize FrontFile $this->frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/admin_main.front"); } ``` ## **3.4 onready() - The Preparation Event** `onready()` fires AFTER FrontFile is parsed and Components are created. Use it for: - Modifying Component properties - Setting default values - Accessing Components by ID - Pre-processing form data ### **Example: Modifying Components in onready** ```php public function onstart() { $this->frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/form.front"); } public function onready() { // All Components are now created and accessible // Get a text field component $txtName = $this->frtMain->getComponent("txtName"); // Set default value $txtName->fu_setDefaultValue("John Doe"); // Get a dropdown component $sltCountry = $this->frtMain->getComponent("sltCountry"); // Populate options $sltCountry->setOptions("USA,Canada,Mexico,UK"); } ``` ## **3.5 onrun() - The Pre-Processing Event** `onrun()` fires BEFORE the Page Event executes. Use it for: - Final permission checks - Logging - Data pre-processing - Redirects before Page Event runs ### **Example: Pre-Event Processing in onrun** ```php public function onstart() { $this->frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/dashboard.front"); } public function onrun() { // Log this access $this->logAccess(); // Check specific permission $this->page->getAuthenticatePerm("view_dashboard"); // Pre-process request data $this->currentPage = $this->Client->request("page", 1); } public function page_new() { // By the time we reach here, onrun has already executed $this->setFrontFile($this->frtMain); } ``` ## **3.6 onrender() - The Post-Processing Event** `onrender()` fires AFTER the Page Event completes but BEFORE the final HTML is sent. Use it for: - Adding JavaScript/CSS - Modifying Master File - Adding Front Places - Final output adjustments ### **Example: Post-Processing in onrender** ```php public function onstart() { $this->frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/page.front"); } public function page_new() { $this->setFrontFile($this->frtMain); } public function onrender() { // Page Event has executed, FrontFile is rendered // Add custom CSS addFileLink("custom_style.css"); // Add custom JavaScript addHeaderJSCode("console.log('Page rendered!');"); // Add a Front Place to Master File addFrontPlace("sidebar", __DIR__ . "/places/sidebar.place.front"); } ``` ## **3.7 FrontFile Events - Template Interaction** Beyond lifecycle events, you can also handle events from your FrontFile templates: ### **onfrontinit() - FrontFile Just Loaded** ```php public function onfrontinit($frontobj) { // FrontFile object is now available // $frontobj is the FrontFile instance // Do something with the FrontFile $frontobj->addMetaData("title", "My Page"); } ``` ### **onfrontprocess() - FrontFile Processed** ```php public function onfrontprocess($frontobj) { // FrontFile has been fully processed // All Components created, Fusion attributes executed // Can modify components here too $component = $frontobj->getComponent("txtTitle"); $component->fu_setReadonly(true); } ``` ## **3.8 When to Use Each Event** | Event | When | Best Use For | |-------|------|--------------| | `onstart()` | First | Create FrontFiles, auth check, init | | `onfrontinit()` | After FrontFile loaded | Set metadata, prepare data | | `onfrontprocess()` | After FrontFile processed | Modify Components | | `onready()` | Before Page Event | Modify Components, defaults | | `onrun()` | Just before Page Event | Final checks, logging | | `onrender()` | After Page Event | Add CSS/JS, Front Places | ## **3.9 Complete Example** Here's a Gate showing all lifecycle events in action: ```php getAuthenticate("MEMBER,ADMIN"); // Create FrontFile objects $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_list.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_edit.front"); } /** * FrontFile Event: onfrontinit * Called when FrontFile is loaded */ public function onfrontinit($frontobj) { // Add page metadata $frontobj->addMetaData("author", "My App"); } /** * Lifecycle Event: onready * Modify Components before Page Event */ public function onready() { // Set default values for form $this->frtEdit->getComponent("txtDate")->fi_setDefaultValue(date("Y-m-d")); } /** * Lifecycle Event: onrun * Pre-processing before Page Event */ public function onrun() { // Check permission for this specific action if ($this->page->getEvent() === "delete") { $this->page->getAuthenticatePerm("delete_product"); } } /** * Page Event: page_new * Display product list - URL: product.html */ public function page_new() { // Get products from database $products = $this->getProducts(); // Pass to FrontFile $this->frtList->getComponent("divProducts")->setInnerHTML($products); $this->setFrontFile($this->frtList); } /** * Page Event: page_view * View single product - URL: product-view-5.html */ public function page_view() { $productId = $this->page->evtp; $product = $this->getProduct($productId); // Populate edit form $this->frtEdit->getComponent("txtName")->fu_setValue($product["name"]); $this->frtEdit->getComponent("txtPrice")->fu_setValue($product["price"]); $this->setFrontFile($this->frtEdit); } /** * Lifecycle Event: onrender * Add final touches after Page Event */ public function onrender() { // Add analytics addHeaderJSCode("ga('send', 'pageview');"); } // Helper methods private function getProducts() { /* ... */ } private function getProduct($id) { /* ... */ } } ``` ## **3.10 Chapter Summary** 1. **Lifecycle events** fire automatically at specific times during request processing 2. **onstart()** - First, for initialization and FrontFile creation 3. **onfrontinit()** - After FrontFile loaded, for metadata 4. **onfrontprocess()** - After FrontFile processed, for Component modification 5. **onready()** - Before Page Event, for final Component setup 6. **onrun()** - Just before Page Event, for pre-processing 7. **onrender()** - After Page Event, for adding CSS/JS and Front Places 8. **FrontFile events** (`onfrontinit`, `onfrontprocess`) - For template interaction ## **3.11 What's Next?** Now you understand lifecycle events. In the next chapter, you'll learn about Page Events in detail - how to handle different browser requests and form submissions. --- *Next: Chapter 4 - Page Events: Handling Browser Requests*# **Chapter 4: Page Events - Handling Browser Requests** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **4.1 Understanding Page Events** Page Events are the methods in your Gate class that handle actual browser requests. Unlike lifecycle events which fire automatically, Page Events are triggered by URLs. The URL pattern is: ``` gate-event-parameter.html ``` Examples: - `index.html` → Gate: index, Event: new - `product.html` → Gate: product, Event: new - `product-view-5.html` → Gate: product, Event: view, Parameter: 5 - `user-edit-10.html` → Gate: user, Event: edit, Parameter: 10 ## **4.2 Built-in Page Events** SartajPhp provides several built-in Page Events for common scenarios: ### **page_new() - Default Page Load** Triggered when browser simply loads a page (GET request). ```php // URL: index.html public function page_new() { // Display the main page $this->setFrontFile($this->frtMain); } ``` ### **page_submit() - Form Submission** Triggered when form is submitted (POST request). This is the main handler for form processing. ```php // URL: index.html (when form with action POST is submitted) public function page_submit() { // Get submitted values $name = $this->Client->post("txtName"); $email = $this->Client->post("txtEmail"); // Get submitted Component values $password = $this->frtMain->getComponent("txtpassword")->getValue(); // Process the data // check any validation,sql or any other error set with setErr if (!getCheckErr()) { echo "Form submitted successfully!"; } } ``` ### **page_insert() - Insert New Record** Auto-triggered AFTER `page_submit()` when no record ID exists (new record). ```php public function page_submit() { // Check if validation passed if (!getCheckErr()) { // If no record ID = new record // page_insert() will be called automatically } } public function page_insert() { // Insert new record into database $data = [ "name" => $this->Client->post("txtName"), "email" => $this->Client->post("txtEmail") ]; $this->dbEngine->runSQL("users", $data); echo "Record inserted!"; } ``` ### **page_update() - Update Existing Record** Auto-triggered AFTER `page_submit()` when record ID exists (update record). ```php public function page_submit() { // Check if validation passed if (!getCheckErr()) { // If has record ID = update // page_update() will be called automatically } } public function page_update() { $recordId = $this->frtMain->form->getRecID(); // Update existing record $data = [ "name" => $this->Client->post("txtName"), "email" => $this->Client->post("txtEmail") ]; $sql = $this->dbEngine->updateSQL("users", $data, "WHERE id='$recordId'"); $this->dbEngine->executeQueryQuick($sql); echo "Record updated!"; } ``` ### **page_view() - View Single Record** Triggered when viewing a specific record. ```php // URL: user-view-5.html public function page_view() { // $this->page->evtp contains "5" $userId = (int)$this->page->evtp; // Fetch user from database $user = $this->getUser($userId); // Display in FrontFile $this->frtMain->getComponent("txtName")->fu_setValue($user["name"]); $this->frtMain->getComponent("txtEmail")->fu_setValue($user["email"]); $this->setFrontFile($this->frtMain); } ``` ### **page_delete() - Delete Record** Triggered when deleting a record. ```php // URL: user-delete-5.html public function page_delete() { $userId = (int)$this->page->evtp; // Delete from database $this->dbEngine->executeQuery("DELETE FROM users WHERE id = $userId"); // Redirect to list $this->page->forward(getGateURL("user")); } ``` ## **4.3 Custom Page Events** Create your own events using the `page_event_*` naming pattern: ### **Basic Custom Event** ```php // URL: product-search-laptop.html public function page_event_search($evtp) { // $evtp = "laptop" $results = $this->searchProducts($evtp); $this->frtMain->getComponent("divResults")->setInnerHTML($results); $this->setFrontFile($this->frtMain); } ``` ### **Multiple Parameter Custom Event** ```php // URL: shop-filter-category-electronics-price-100-500.html public function page_event_filter($evtp) { // $evtp = "category-electronics-price-100-500" // Parse the parameter $parts = explode('-', $evtp); // $parts = ["category", "electronics", "price", "100", "500"] $category = $parts[1]; // "electronics" $minPrice = $parts[3]; // "100" $maxPrice = $parts[4]; // "500" $products = $this->filterProducts($category, $minPrice, $maxPrice); $this->frtMain->getComponent("divProducts")->setInnerHTML($products); $this->setFrontFile($this->frtMain); } ``` ### **AJAX Custom Event** ```php // Called via AJAX: getAJAX('product', 'checkstock', '123') public function page_event_checkstock($evtp) { // $evtp = "123" - product ID $stock = $this->getProductStock($evtp); // Return JSON response $this->JSServer->addJSONReturnBlock([ "product_id" => $evtp, "in_stock" => $stock > 0, "quantity" => $stock ]); } ``` ## **4.4 Getting Request Data** In your Page Events, access request data using `$this->Client`: ### **GET Parameters** ```php public function page_new() { // From URL: product.html?sort=price&order=asc $sort = $this->Client->request("sort"); // "price" $order = $this->Client->request("order"); // "asc" $products = $this->getProducts($sort, $order); } ``` ### **POST Parameters (Form Data)** ```php public function page_submit() { // From form submission $name = $this->Client->post("txtName"); // text field $email = $this->Client->post("txtEmail"); // text field $country = $this->Client->post("sltCountry"); // dropdown $agree = $this->Client->post("chkAgree"); // checkbox } ``` ### **All Request Types** ```php public function page_new() { // Get any parameter (GET or POST) $value = $this->Client->request("param"); // Get Raw POST data without security, same as $_POST["json1"] $rawData = $this->Client->post("json1", true); // Check if parameter exists if ($this->Client->isRequest("search")) { // do search } } ``` ## **4.5 Sending Responses** ### **HTML Response (Most Common)** ```php public function page_new() { // Set FrontFile to render $this->setFrontFile($this->frtMain); } ``` ### **JSON/AJAX Response** ```php public function page_event_checkstock($evtp) { // Send JSON data $this->JSServer->addJSONReturnBlock([ "success" => true, "stock" => 50 ]); // Or update HTML element $this->JSServer->addJSONHTMLBlock("divStatus", "In Stock!"); // Or execute JavaScript $this->JSServer->addJSONJSBlock("$('#btnBuy').prop('disabled', false);"); } ``` ### **Redirect Response** ```php public function page_submit() { // After processing, redirect to another page $this->page->forward(getGateURL("product")); // Or redirect with event $this->page->forward(getEventURL("view", $newId)); } ``` ## **4.6 Complete Example - Blog Application** Here's a complete Blog Gate showing various Page Events: ```php getAuthenticate("GUEST,MEMBER,ADMIN"); // Create FrontFiles $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/blog_list.front"); $this->frtPost = new \Sphp\tools\FrontFile($this->mypath . "/fronts/blog_post.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/blog_edit.front"); } /** * URL: blog.html * Display list of blog posts */ public function page_new() { $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery( "SELECT * FROM posts ORDER BY created_at DESC LIMIT 10" ); $html = ""; while ($post = $this->dbEngine->row_fetch_assoc($result)) { $html .= "

{$post['title']}

{$post['excerpt']}

"; } $this->dbEngine->disconnect(); $this->frtList->getComponent("divPosts")->setInnerHTML($html); $this->setFrontFile($this->frtList); } /** * URL: blog-view-5.html * View single post */ public function page_view() { $postId = (int)$this->page->evtp; $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery( "SELECT * FROM posts WHERE id = $postId" ); $post = $this->dbEngine->row_fetch_assoc($result); $this->dbEngine->disconnect(); if (!$post) { $this->page->forward(getGateURL("blog")); return; } $this->frtPost->getComponent("txtTitle")->fu_setValue($post['title']); $this->frtPost->getComponent("txtContent")->fu_setValue($post['content']); $this->setFrontFile($this->frtPost); } /** * URL: blog-create.html * Show create form (requires MEMBER or ADMIN) */ public function page_event_create($evtp) { if (!$this->page->isAuthenticate("MEMBER,ADMIN")) { $this->page->forward(getGateURL("login")); return; } $this->setFrontFile($this->frtEdit); } /** * URL: blog.html (POST) * Handle form submission - insert or update */ public function page_submit() { // Validation already done by Components if (getCheckErr()) { // Show form again with errors $this->setFrontFile($this->frtEdit); return; } // Check if insert or update if ($this->frtEdit->form->getRecID() == "") { // Will trigger page_insert() automatically // But we can also handle here $this->insertPost(); } else { $this->updatePost(); } // Redirect to list $this->page->forward(getGateURL("blog")); } /** * URL: blog-delete-5.html * Delete a post */ public function page_event_delete($evtp) { // Require ADMIN $this->getAuthenticate("ADMIN"); $postId = (int)$evtp; $this->dbEngine->executeQuery("DELETE FROM posts WHERE id = $postId"); // Redirect back to list $this->page->forward(getGateURL("blog")); } /** * URL: blog-search-keyword.html * Search posts */ public function page_event_search($evtp) { $keyword = $evtp; // "keyword" $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery( "SELECT * FROM posts WHERE title LIKE '%$keyword%' OR content LIKE '%$keyword%'" ); $html = ""; while ($post = $this->dbEngine->row_fetch_assoc($result)) { $html .= "

{$post['title']}

Found in: {$post['excerpt']}

"; } $this->dbEngine->disconnect(); $this->frtList->getComponent("divPosts")->setInnerHTML($html); $this->setFrontFile($this->frtList); } // Helper methods private function insertPost() { /* ... */ } private function updatePost() { /* ... */ } } ``` ## **4.7 URL Mapping Reference** | URL | Gate | Event | Parameter | Page Event Called | Parameter Access | |-----|------|-------|-----------|-------------------|------------------| | `index.html` | index | new | - | `page_new()` | `$this->page->evtp` | | `blog.html` | blog | new | - | `page_new()` | `$this->page->evtp` | | `blog.html` (POST) | blog | submit | - | `page_submit()` → `page_insert()`/`page_update()` | `$this->page->evtp` | | `blog-view-5.html` | blog | view | 5 | `page_view()` | `$this->page->evtp` returns "5" | | `blog-delete-5.html` | blog | delete | 5 | `page_event_delete($evtp)` | `$evtp = "5"` | | `blog-search-php.html` | blog | search | php | `page_event_search($evtp)` | `$evtp = "php"` | | `blog-create.html` | blog | create | - | `page_event_create($evtp)` | `$evtp = ""` | **Note:** Built-in page events (`page_new`, `page_view`, `page_delete`, etc.) do NOT receive parameters directly in the method signature. Access parameters via `$this->page->evtp`. Custom events (`page_event_*`) DO receive `$evtp` as a parameter. ## **4.8 Chapter Summary** 1. **Page Events** handle browser requests mapped from URLs 2. **Built-in events**: `page_new()`, `page_submit()`, `page_insert()`, `page_update()`, `page_view()`, `page_delete()` - access parameter via `$this->page->evtp` 3. **Custom events**: Use `page_event_name($evtp)` pattern - parameter passed directly to method 4. **Get data**: `$this->Client->request()`, `$this->Client->post()` 5. **Send responses**: `setFrontFile()`, `JSServer` for AJAX, `page->forward()` for redirect ## **4.9 What's Next?** In the next chapter, you'll learn about FrontFile Events - how to interact with your templates from within your Gate class. --- *Next: Chapter 5 - FrontFile Events: Interacting with Templates*# **Chapter 5: FrontFile Events - Interacting with Templates** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **5.1 What are FrontFile Events?** FrontFile Events allow your Gate class to interact with the FrontFile template. While Page Events handle browser requests, FrontFile Events handle template interactions. These events are called at specific times during FrontFile processing, allowing you to: - Modify Components before/after they're created - Set metadata dynamically - Handle Component-specific events - Inject dynamic content ## **5.2 The FrontFile Event Methods** ### **onfrontinit($frontobj) - FrontFile Just Loaded** Called immediately after the FrontFile is loaded but before Components are created. ```php public function onfrontinit($frontobj) { // $frontobj is the FrontFile instance // Set page metadata $frontobj->addMetaData("title", "My Product Page"); $frontobj->addMetaData("description", "Products available for purchase"); $frontobj->addMetaData("keywords", "products,shop,online"); } ``` ### **onfrontprocess($frontobj) - FrontFile Processed** Called after the FrontFile has been fully processed - all Components created, all Fusion attributes executed. ```php public function onfrontprocess($frontobj) { // At this point, all Components exist // We can modify Components before rendering $txtTitle = $frontobj->getComponent("txtTitle"); $txtTitle->fu_setReadonly(true); // Make it read-only // Or hide/show components based on logic $divAdmin = $frontobj->getComponent("divAdmin"); if (!$this->page->isAuthenticate("ADMIN")) { $divAdmin->unsetVisible(); } } ``` ## **5.3 Interacting with Components** ### **Getting Components** ```php // Get a specific component by ID $textField = $this->frtMain->getComponent("txtName"); $dropdown = $this->frtMain->getComponent("sltCategory"); $div = $this->frtMain->getComponent("divContent"); ``` ### **Modifying Components** ```php public function page_new() { // Get component $txtName = $this->frtMain->getComponent("txtName"); // Set value (Render Phase) $txtName->fu_setValue("John Doe"); // Set default value (Parse Phase) $txtName->fi_setDefaultValue("Enter your name"); // Make read-only $txtName->fu_setReadonly(true); // Hide component $txtName->unsetVisible(); // Show component $txtName->setVisible(); // Set inner HTML $divContent = $this->frtMain->getComponent("divContent"); $divContent->setInnerHTML("

Dynamic content here

"); } ``` ### **Working with Forms** For database operations with forms, use `$this->page` helper methods (see Section 5.8 for details): ```php public function page_submit() { // Get form component $form = $this->frtMain->getComponent("userForm"); // Get record ID $currentId = $form->getRecID(); // Check if form is in insert or update mode if ($currentId == "") { // New record mode - use $this->page->insertData() $insertedID = $this->page->insertData($form); } else { // Edit mode - use $this->page->updateData() $this->page->updateData($form, array(), $currentId); } } // View record for editing public function page_event_edit($evtp) { $form = $this->frtMain->getComponent("userForm"); $this->page->viewData($form, $evtp); } // Delete record public function page_delete() { $this->page->deleteRec(); } ``` ## **5.4 Component Events from FrontFile** You can also handle events that originate from Components in your FrontFile using the naming pattern: ### **Component Event Naming** In your FrontFile, add attributes like `on-init="true"` or `on-create="true"`: ```html ``` Then in your Gate, create methods following this pattern: ```php public function comp_txtName_on_init($evtp) { // Called when txtName Component initializes // $evtp contains: ['obj' => component, 'element' => NodeTag, 'value' => value] $component = $evtp['obj']; $component->fi_setDefaultValue("Guest User"); } public function comp_txtName_on_create($evtp) { // Called after txtName Component is fully created $component = $evtp['obj']; // Additional setup } ``` ### **Handling Multiple Component Events** ```php // In FrontFile: // public function comp_txtEmail_on_init($evtp) { $component = $evtp['obj']; // Add validation $component->fi_setEmail(); $component->fi_setRequired(); } ``` ## **5.5 Using Holder in FrontFile** The `runas="holder"` attribute creates placeholders for dynamic content: ### **Holder Patterns in FrontFile** ```html
``` ### **Setting Holder Content in Gate** ```php public function page_new() { // Set property for holder $this->frtMain->addProp("pageTitle", "Welcome to My Site"); // Or set directly on FrontFile $this->frtMain->addProp("userList", $this->getUserListHTML()); $this->setFrontFile($this->frtMain); } // Method that returns HTML for holder public function getUserListHTML() { $users = $this->dbEngine->executeQueryQuick("SELECT * FROM users"); $html = "
    "; foreach ($users as $user) { $html .= "
  • {$user['name']}
  • "; } $html .= "
"; return $html; } ``` ## **5.6 The onholder Event** There's also a special `onholder` method that gets called for any holder tag: ```php public function onholder($element) { // $element is the NodeTag with runas="holder" // Check what kind of holder it is $type = $element->getAttribute("data-type"); switch ($type) { case "user-list": $html = $this->getUserListHTML(); $element->setInnerHTML($html); break; case "product-grid": $html = $this->getProductGridHTML(); $element->setInnerHTML($html); break; case "recent-posts": $html = $this->getRecentPostsHTML(); $element->setInnerHTML($html); break; } } ``` FrontFile: ```html
``` ## **5.7 Complete Example - Product Catalog** Here's a Gate demonstrating FrontFile Events: ```php getAuthenticate("GUEST,MEMBER,ADMIN"); // Set default table name for $this->page database methods $this->page->tblName = "products"; $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_list.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_edit.front"); } /** * FrontFile Event: onfrontinit * Set metadata for list page */ public function onfrontinit($frontobj) { // Determine which FrontFile if ($frontobj === $this->frtList) { $frontobj->addMetaData("title", "Product Catalog"); $frontobj->addMetaData("description", "Browse our products"); } else { $frontobj->addMetaData("title", "Product Form"); } } /** * FrontFile Event: onfrontprocess * Modify components after processing */ public function onfrontprocess($frontobj) { // Hide admin-only elements from non-admins if (!$this->page->isAuthenticate("ADMIN")) { $deleteBtn = $frontobj->getComponent("btnDelete"); if ($deleteBtn) { $deleteBtn->unsetVisible(); } } } /** * Lifecycle Event: onready * Prepare components */ public function onready() { // Pre-populate category dropdown $sltCategory = $this->frtEdit->getComponent("sltCategory"); $categories = $this->getCategories(); $sltCategory->setOptions($categories); // Set default values $txtDate = $this->frtEdit->getComponent("txtDate"); $txtDate->fi_setDefaultValue(date("Y-m-d")); } /** * Page Event: page_new - Show product list * Method 1: Using $this->dbEngine directly (verbose but flexible) */ public function page_new() { $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery("SELECT * FROM products ORDER BY name"); // Build HTML for list $html = ""; while ($product = $this->dbEngine->row_fetch_assoc($result)) { $html .= "
"; $html .= "

{$product['name']}

"; $html .= "

Price: \${$product['price']}

"; $html .= "View"; $html .= "
"; } $this->dbEngine->disconnect(); // Inject into FrontFile $this->frtList->getComponent("divProducts")->setInnerHTML($html); $this->setFrontFile($this->frtList); } /** * Alternative: Using $this->page helper methods for database operations * These methods reduce code when Components use Database Binding (dfield and dtable attributes) */ /** * View data - Fill form components from database record * Usage: Components need dfield and dtable attributes */ public function page_event_view($evtp) { // $evtp contains the record ID $form = $this->frtEdit->getComponent("productForm"); // Fill form with data from database $this->page->viewData($form, $evtp); $this->setFrontFile($this->frtEdit); } /** * Insert data - Save form components to database * Components need dfield and dtable attributes */ public function page_insert() { $form = $this->frtEdit->getComponent("productForm"); // Extra fields to insert $extra = array(); $extra[]['created_at'] = date('Y-m-d H:i:s'); // Insert data - returns new record ID $insertedID = $this->page->insertData($form, $extra); echo "New product inserted with ID: " . $insertedID; } /** * Update data - Update existing database record * Components need dfield and dtable attributes */ public function page_update() { $form = $this->frtEdit->getComponent("productForm"); $recID = $form->getRecID(); // Get record ID from form // Extra fields to update $extra = array(); $extra[]['updated_at'] = date('Y-m-d H:i:s'); // Update data $this->page->updateData($form, $extra, $recID); echo "Product updated!"; } /** * Delete data - Delete database record */ public function page_delete() { // Delete record using event parameter as record ID $this->page->deleteRec(); echo "Product deleted!"; } /** * Component Event Handler * When txtName gets initialized */ public function comp_txtName_on_init($evtp) { $component = $evtp['obj']; $component->fi_setRequired(); $component->fi_setMinLen(3); } /** * Custom method for holder */ public function getFeaturedProducts() { // auto connect to db if not connected $result = $this->dbEngine->executeQueryQuick( "SELECT * FROM products WHERE featured = 1 LIMIT 5" ); $html = ""; return $html; } private function getCategories() { return "Electronics,Clothing,Books,Home,Garden"; } } ``` ## **5.8 $this->page Helper Methods for Database Operations** SartajPHP provides helper methods through `$this->page` object that reduce code when working with database operations. These methods work with Components that have database binding attributes (`dfield` and `dtable`). ### **Setting Table Name** Before using database methods, set the default table name: ```php public function onstart() { $this->page->tblName = "products"; } ``` ### **$this->page->viewData($form, $recID, $fldList, $where)** Fill form components with data from database: ```php public function page_event_edit($evtp) { $form = $this->frtEdit->getComponent("productForm"); // Fill form with record data // $evtp is the record ID $this->page->viewData($form, $evtp); // Or specify custom fields and where clause // $this->page->viewData($form, '', "name,price,description", "WHERE id=5"); $this->setFrontFile($this->frtEdit); } ``` ### **$this->page->insertData($form, $extra)** Insert form component values to database: ```php public function page_insert() { $form = $this->frtEdit->getComponent("productForm"); // Extra fields to insert $extra = array(); $extra[]['created_at'] = date('Y-m-d H:i:s'); $extra[]['created_by'] = $this->page->getUserID(); $insertedID = $this->page->insertData($form, $extra); // Returns new record ID echo "Inserted record ID: " . $insertedID; } ``` ### **$this->page->updateData($form, $extra, $recID, $where)** Update existing database record: ```php public function page_update() { $form = $this->frtEdit->getComponent("productForm"); $recID = $form->getRecID(); // Get from form component // Extra fields to update $extra = array(); $extra[]['updated_at'] = date('Y-m-d H:i:s'); // Update record $this->page->updateData($form, $extra, $recID); // Or use custom where clause // $this->page->updateData($form, $extra, '', "WHERE code='ABC'"); } ``` ### **$this->page->deleteRec($recID)** Delete a database record: ```php public function page_delete() { // Delete using event parameter as record ID $this->page->deleteRec(); // Or specify record ID explicitly // $this->page->deleteRec(5); } ``` ### **Database Binding in FrontFile Components** For `$this->page` helper methods to work, Components need database binding attributes: ```html
``` - `dfield`: Database table field name - `dtable`: Database table name (optional if $this->page->tblName is set in onstart) ## **5.9 Chapter Summary** 1. **FrontFile Events** allow Gate-template interaction 2. **onfrontinit($frontobj)** - Called after FrontFile loaded 3. **onfrontprocess($frontobj)** - Called after FrontFile processed 4. **onready()** - Components are accessible, modify them here 5. **Component Events** - Handle via `comp_componentId_on_event()` 6. **Holders** - Use `runas="holder"` with `sphp-app-prop`, `sphp-comp`, or `sphp-app-fun` 7. **$this->page helper methods** - Use `viewData`, `insertData`, `updateData`, `deleteRec` for database operations ## **5.10 What's Next?** Now you understand how Gate interacts with FrontFile. Next, let's build actual webpages using Front Files and Master Files. --- *Next: Chapter 6 - Building Your First Webpage*# **Chapter 6: Building Your First Webpage - Single Front File + Master File** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **6.1 The Page Building Blocks** Before building pages, let's understand the structure: 1. **Gate Class** - Handles logic, events, and data 2. **Front File** (`.front`) - Contains page content (HTML with SartajPhp attributes) 3. **Master File** (`.mast.php`) - Contains page layout (header, footer, menus) The flow: ``` Gate → FrontFile → MasterFile → Browser ``` ## **6.2 Step 1: Register Your Gate** First, register your Gate in `reg.php`: ```php mypath gives the directory of this Gate file $this->frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/index_main.front"); } public function page_new() { // Set the FrontFile to render $this->setFrontFile($this->frtMain); } } ``` ## **6.4 Step 3: Create the Front File** Create `apps/fronts/index_main.front`: ```html Welcome

Welcome to My Website

This is the main content of the page.

Loading content...

About Us | Contact

``` This is valid HTML that can be opened in any browser! ## **6.5 Step 4: Create the Master File** Create `masters/default/master.mast.php`: ```php getHeaderHTML(); ?>

© My Website

getFooterHTML(); ?> ``` ## **6.6 Step 5: Create the Menu (Front Place)** Create `masters/default/menu.place.front`: ```html ``` ## **6.7 Complete Flow** Here's what happens when browser requests `index.html`: ``` 1. Browser requests: index.html ↓ 2. Framework finds registered Gate: "index" ↓ 3. Loads: apps/Index.gate.php ↓ 4. Creates: new Index() object ↓ 5. Fires: onstart() - Creates FrontFile object ↓ 6. Fires: page_new() - Calls $this->setFrontFile($this->frtMain) ↓ 7. Framework processes: index_main.front - Parses HTML - Creates Components (runat="server" tags) - Evaluates expressions ↓ 8. Framework merges with: master.mast.php - Adds header/footer - Injects menu from menu.place.front - Puts FrontFile content in
↓ 9. Browser receives complete HTML page ``` ## **6.8 Adding Dynamic Content** Let's enhance our example to show dynamic content: ```php frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/index_main.front"); } public function onready() { // Get dynamic content in onready (after Components created) $content = $this->getLatestNews(); // Inject into FrontFile Component $this->frtMain->getComponent("divContent")->setInnerHTML($content); // Set page title $this->frtMain->getComponent("pageTitle")->fu_setValue("Home - My Website"); } public function page_new() { $this->setFrontFile($this->frtMain); } private function getLatestNews() { // Simulated database content $news = [ ["title" => "New Product Launch", "date" => "2024-01-15"], ["title" => "Special Offer", "date" => "2024-01-10"], ["title" => "Website Updated", "date" => "2024-01-05"] ]; $html = "

Latest News

    "; foreach ($news as $item) { $html .= "
  • {$item['title']} - {$item['date']}
  • "; } $html .= "
"; return $html; } } ``` ## **6.9 Using Expression Tags in FrontFile** Add dynamic content directly in FrontFile using expression tags: ```html ##{$parentgate->getPageTitle()}#

##{$siteName}#

Today's date: ##{date('F j, Y')}#

#{if $parentgate->isLoggedIn()}#

Welcome, ##{$parentgate->getUserName()}#!

#{else}#

Login to access member area.

#{endif}#
##{$message}#
``` ## **6.10 Adding Components for Interactivity** Add form Components to your FrontFile: ```html

Contact Us

``` ## **6.11 Complete File Structure** Your project should look like this: ``` myproject/ ├── reg.php # Gate registration ├── start.php # Entry point ├── comp.php # Configuration │ ├── apps/ │ ├── Index.gate.php # Main Gate │ │ │ └── fronts/ │ ├── index_main.front # Home page │ └── contact.front # Contact page │ └── masters/ └── default/ ├── master.mast.php # Main layout └── menu.place.front # Navigation menu ``` ## **6.12 Chapter Summary** 1. **Register Gate** in `reg.php` with `registerGate()` 2. **Create Gate class** extending `BasicGate` 3. **Create Front File** (`.front`) with page content 4. **Create Master File** (`.mast.php`) with layout 5. **Create Front Place** (`.place.front`) for reusable sections like menus 6. Use `$this->setFrontFile()` to render FrontFile 7. Use Components (`runat="server"`) for interactivity 8. Use Expression tags (`##{}#`) for dynamic content ## **6.13 What's Next?** In the next chapter, you'll learn how to use TWO Front Files in one Gate - one for displaying data (Pagination) and one for editing (Form). --- *Next: Chapter 7 - Two Front Files Pattern*# **Chapter 7: Two Front Files Pattern - Pagination and Edit Form** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **7.1 The Two Front Files Pattern** A common pattern in SartajPhp is using **two Front Files** in one Gate: 1. **List Front File** - Displays data with Pagination Component 2. **Edit Front File** - Form for inserting/updating records This pattern provides: - Clean separation between viewing and editing - Reusable pagination for any table - Automatic database operations - Built-in form validation ## **7.2 When to Use This Pattern** Use when your application needs: - List view with pagination - Add new record functionality - Edit existing record functionality - Delete functionality ## **7.3 Step 1: Register the Gate** ```php getAuthenticate("GUEST,MEMBER,ADMIN"); // Create two FrontFile objects $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_list.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_edit.front"); } // Page Events will go here } ``` ## **7.5 Step 3: Create List Front File with Pagination** Create `apps/fronts/product_list.front`: ```html Product List
##{$productGrid->getRow('name')}#
$##{$productGrid->getRow('price')}#
##{$productGrid->getRow('category')}#
``` ### **Key Pagination Component Attributes:** | Attribute | Purpose | |-----------|---------| | `dtable` | Database table name | | `fun-setFieldNames` | Fields to display (comma-separated) | | `fun-setPerPageRows` | Rows per page | | `fun-setAJAX` | Enable AJAX pagination | | `path` | Component path (built-in) | ## **7.6 Step 4: Create Edit Front File with Form** Create `apps/fronts/product_edit.front`: ```html Product Form

##{$formTitle}#

Cancel #{if $isEditMode}# Delete #{endif}#
``` ### **Key Form Component Attributes:** | Attribute | Purpose | |-----------|---------| | `dtable` | Database table to bind to | | `dfield` | Database field name | | `fui-setRequired` | Field is required | | `fui-setForm` | Bind to form for validation | ## **7.7 Step 5: Add Page Events to Handle Everything** Now add the Page Events in your Gate: ```php getAuthenticate("GUEST,MEMBER,ADMIN"); $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_list.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_edit.front"); } /** * URL: product.html * Display list with pagination */ public function page_new() { $this->setFrontFile($this->frtList); } /** * URL: product-create.html * Show empty form for new record */ public function page_event_create($evtp) { // Set mode properties for FrontFile $this->frtEdit->addProp("formTitle", "Add New Product"); $this->frtEdit->addProp("isEditMode", false); $this->frtEdit->addProp("recordId", ""); $this->setFrontFile($this->frtEdit); } /** * URL: product-view-5.html * View existing record (same as edit but read-only) */ public function page_view() { $recordId = (int)$this->page->evtp; // Load data into form $this->loadRecordToForm($recordId, false); $this->setFrontFile($this->frtEdit); } /** * URL: product-edit-5.html * Show form populated with existing data */ public function page_event_edit($evtp) { $recordId = (int)$evtp; // Load data into form $this->loadRecordToForm($recordId, true); $this->setFrontFile($this->frtEdit); } /** * URL: product.html (POST) * Handle form submission - insert or update */ public function page_submit() { // Check validation errors if (getCheckErr()) { // Show form again with errors $this->frtEdit->addProp("formTitle", "Please Fix Errors"); /** * you can also use setErr to inform other about error in working. This is not * PHP error so it will not stop PHP execution. */ $this->setFrontFile($this->frtEdit); return; } // Determine insert or update based on record ID if ($this->frtEdit->getComponent("txtId")->getValue() == "") { // No ID = Insert $this->page->insertData($this->frtEdit->getComponent("productForm")); } else { // Has ID = Update $this->page->updateData($this->frtEdit->getComponent("productForm")); } // Redirect back to list $this->page->forward(getGateURL("product")); } /** * URL: product-delete-5.html * Delete a record */ public function page_event_delete($evtp) { // Require higher permission $this->getAuthenticate("MEMBER,ADMIN"); $recordId = (int)$evtp; // Delete from database $this->dbEngine->executeQuery("DELETE FROM products WHERE id = $recordId"); // Redirect to list $this->page->forward(getGateURL("product")); } /** * Helper: Load record into form */ private function loadRecordToForm($recordId, $isEditMode) { $this->dbEngine->connect(); // Fetch from database $result = $this->dbEngine->executeQuery( "SELECT * FROM products WHERE id = $recordId" ); $row = $this->dbEngine->row_fetch_assoc($result); $this->dbEngine->disconnect(); if (!$row) { $this->page->forward(getGateURL("product")); return; } // Set form values $this->frtEdit->getComponent("txtId")->fi_setDefaultValue($row['id']); $this->frtEdit->getComponent("txtName")->fi_setDefaultValue($row['name']); $this->frtEdit->getComponent("txtPrice")->fi_setDefaultValue($row['price']); $this->frtEdit->getComponent("sltCategory")->fi_setDefaultValue($row['category']); $this->frtEdit->getComponent("txaDescription")->fi_setDefaultValue($row['description']); // Set properties for display $this->frtEdit->addProp("formTitle", $isEditMode ? "Edit Product" : "View Product"); $this->frtEdit->addProp("isEditMode", $isEditMode); $this->frtEdit->addProp("recordId", $recordId); } } ``` ## **7.8 URL Mapping Summary** | URL | Event | Action | |-----|-------|--------| | `product.html` | page_new | Show list with pagination | | `product.html` (POST) | page_submit | Save form data | | `product-create.html` | page_event_create | Show empty form | | `product-view-5.html` | page_view | Show record (read-only) | | `product-edit-5.html` | page_event_edit | Show populated form | | `product-delete-5.html` | page_event_delete | Delete record | ## **7.9 How Database Operations Work** ### **Automatic Insert** ```php // Gets form Components with dtable/dfield and inserts $this->page->insertData($this->frtEdit->getComponent("productForm")); ``` This looks at Components in the form: - `txtName` with `dtable="products" dfield="name"` - `txtPrice` with `dtable="products" dfield="price"` - etc. And generates: `INSERT INTO products (name, price, ...) VALUES (?, ?, ...)` ### **Automatic Update** ```php // Gets form Components and updates by record ID $this->page->updateData($this->frtEdit->getComponent("productForm")); ``` Generates: `UPDATE products SET name=?, price=? WHERE id=?` ### **Loading Data for Edit** SartajPHP provides two approaches for loading data into form components: #### **Approach 1: Using $this->page->viewData() (Recommended)** ```php // Auto-populate form from record using database binding // Components need dfield and dtable attributes $this->page->viewData($this->frtEdit->getComponent("productForm"), $recordId); ``` **How viewData works internally:** ```php // viewData iterates over all form children components $compList = $form->getAllChildren(); foreach ($compList as $compid => $comp) { // Only process components with dfield attribute and not marked blnDontFill if ($comp->dfield != '' && !$comp->blnDontFill) { // Get table from dtable attribute or use default tblName $table = ($comp->dtable != '') ? $comp->dtable : $this->page->tblName; // Build SELECT query and fetch data // Set component value from database row } } ``` **Component flags for database binding:** - `dfield`: Database field name to bind with - `dtable`: Database table name (optional, uses `$this->page->tblName` by default) - `blnDontFill`: When set, component won't be filled from database (use `fur-unsetDataFill="true"` in FrontFile) #### **Approach 2: Manual fetch** ```php // Manual approach - fetch then set each component $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery("SELECT * FROM products WHERE id = $id"); $row = $this->dbEngine->row_fetch_assoc($result); $this->dbEngine->disconnect(); // Set each component manually $this->frtEdit->getComponent("txtName")->fi_setDefaultValue($row['name']); $this->frtEdit->getComponent("txtPrice")->fi_setDefaultValue($row['price']); ``` #### **FrontFile Component Database Binding** ```html
``` ### **Using Dynamic URLs** Always use `getThisGateURL()`,`getEventURL()`, `getGateURL()` for dynamic URLs instead of hardcoded paths: In FrontFile: ```html Add New Product ``` **Why use getThisGateURL()?** - Generates domain-binded absolute URLs - Works even if you change the Gate registration name in `registerGate()` - Handles URL extensions dynamically (configured in comp.php) ## **7.10 Complete File Structure** ``` myproject/ ├── reg.php │ ├── apps/ │ ├── Product.gate.php │ │ │ └── fronts/ │ ├── product_list.front # Pagination view │ └── product_edit.front # Add/Edit form │ └── masters/ └── default/ ├── master.mast.php └── menu.place.front ``` ## **7.11 Chapter Summary** 1. **Two Front Files Pattern** - List for viewing, Form for editing 2. **Pagination Component** - Use built-in `Pagination.php` with `dtable` and `dtable` attributes 3. **Form Components** - Use `dtable` and `dfield` for database binding 4. **Page Events**: - `page_new()` - Show list - `page_event_create()` - Empty form - `page_event_edit(id)` - Populated form - `page_view(id)` - Read-only view - `page_submit()` - Save (auto insert/update) - `page_event_delete(id)` - Delete 5. **Database Operations** - `page->insertData()`, `page->updateData()`, `page->viewData()` ## **7.12 What's Next?** Next, learn about Master Files - how to create page layouts with headers, footers, and menus. --- *Next: Chapter 8 - Master Files: Creating Page Layouts*# **Chapter 8: Master Files - Creating Page Layouts** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **8.1 What are Master Files?** Master Files (`.mast.php`) define the overall page layout - the skeleton that wraps your FrontFile content. They contain: - HTML `` section with meta tags and CSS - Page header (logo, navigation) - Main content container - Page footer - JavaScript includes The Master File receives your FrontFile's output and wraps it with the common layout. ## **8.2 Master File Location** Master files are stored in the `masters/` directory: ``` masters/ ├── default/ │ └── master.mast.php # Default layout ├── admin/ │ └── admin.mast.php # Admin area layout └── minimal/ └── simple.mast.php # Minimal layout ``` ## **8.3 Basic Master File Structure** ```php My Website getHeaderHTML(); ?>
getFooterHTML(); ?> ``` ## **8.4 Key Master File Functions** ### **addFrontPlace() - Register a Place** ```php addFrontPlace("name", "path/to/file.place.front", "position"); ``` Parameters: - **name** - Identifier for the place - **path** - Full path to the Front Place file - **position** - Optional position within the place ### **runFrontPlace() - Execute Logic** ```php runFrontPlace("name", "position"); ``` Must be called AFTER `addFrontPlace()` but BEFORE `` ### **renderFrontPlace() - Output Content** ```php ``` Called where you want the content to appear in the HTML. ### **getAppOutput() - FrontFile Content** ```php ``` This is where your FrontFile's rendered HTML appears! ## **8.5 Creating a Menu Front Place** Create `masters/default/menu.main.place.front`: ```html ``` ## **8.6 Creating a Footer Front Place** Create `masters/default/footer.place.front`: ```html
About Us

We provide quality products and excellent service.

Quick Links
Contact

Email: info@example.com
Phone: (123) 456-7890


© ##{date('Y')}# MyApp. All rights reserved.
``` ## **8.7 Adding Custom CSS/JS to Master File** ### **Adding Custom CSS** ```php ``` ### **Adding Custom JavaScript** ```php ``` ## **8.8 Multiple Master Files** You can have different layouts for different sections: ```php page->getGate() === "admin") { $this->masterf = __DIR__ . "/../masters/admin/master.mast.php"; } // ... } ``` ## **8.9 Complete Master File Example** Here's a production-ready Master File: ```php getProp("showSidebar") ?? false; ?> getHeaderHTML(); ?> ##{$pageTitle}# - My Website getCustomCSS(); ?> hasProp("showBreadcrumb")): ?>
getFooterHTML(); echo SphpBase::sphp_api()->traceError(true); // Show errors in debug mode ?> ``` ## **8.10 How Master File Gets Selected** The Master File to use is configured in `comp.php`: ```php masterf = __DIR__ . "/masters/custom/master.mast.php"; } ``` ## **8.11 Chapter Summary** 1. **Master Files** (`.mast.php`) provide page layout 2. **Front Places** (`.place.front`) provide reusable sections (menu, footer) 3. **addFrontPlace()** - Register a place 4. **runFrontPlace()** - Execute place logic 5. **renderFrontPlace()** - Output place content 6. **getAppOutput()** - Where FrontFile content goes 7. Configure master in `comp.php` or in Gate's `onstart()` ## **8.12 What's Next?** Next, learn about the `runas="holder"` attribute for dynamic content injection in FrontFiles. --- *Next: Chapter 9 - The runas="holder" Attribute*# **Chapter 9: The runas="holder" Attribute - Dynamic Content Injection** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **9.1 What is runas="holder"?** The `runas="holder"` attribute creates a **placeholder** in your FrontFile that gets filled with dynamic content from your Gate class. It's like a slot that gets populated at render time. Unlike `runat="server"` which creates a Component, `runas="holder"` just marks a spot for dynamic content without creating a Component. ## **9.2 Basic Holder Syntax** ```html
``` - `runas="holder"` - Marks this as a placeholder - `sphp-app-prop` - Property name to get from FrontFile ## **9.3 Setting Holder Content from Gate** ### **Method 1: Using addProp()** ```php public function page_new() { // Add property to FrontFile $this->frtMain->addProp("welcomeMessage", "Hello, World!"); // Set the holder content $this->setFrontFile($this->frtMain); } ``` In FrontFile: ```html
``` Output: `
Hello, World!
` ### **Method 2: Direct Property on Gate** ```php // In Gate public function page_new() { $this->siteName = "My Website"; $this->userCount = 150; $this->setFrontFile($this->frtMain); } ``` In FrontFile: ```html

##{$parentgate->siteName}#

Users: ##{$parentgate->userCount}#

``` ## **9.4 Holder from Component** Get content from a Component property: ```html
``` In Gate, the Component would have: ```php // Component returns HTML public function getOutput() { return "

Component content

"; } ``` ## **9.5 Holder from Component Method (Function)** Call a Component method directly: ```html
``` ## **9.6 Holder from Gate Method (Function)** Call a Gate method directly: ```html
``` In Gate: ```php public function getUserList() { $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery("SELECT * FROM users LIMIT 10"); $html = "
    "; while ($user = $this->dbEngine->row_fetch_assoc($result)) { $html .= "
  • {$user['name']}
  • "; } $html .= "
"; $this->dbEngine->disconnect(); return $html; } ``` ## **9.7 Practical Example - Dynamic Sidebar** ### Gate Code: ```php frtMain = new \Sphp\tools\FrontFile($this->mypath . "/fronts/product_page.front"); } public function onready() { // Set properties for holders $this->frtMain->addProp("categoryList", $this->getCategoryList()); $this->frtMain->addProp("featuredProducts", $this->getFeaturedProducts()); $this->frtMain->addProp("recentPosts", $this->getRecentPosts()); } public function page_new() { $this->setFrontFile($this->frtMain); } private function getCategoryList() { $cats = ["Electronics", "Clothing", "Books", "Home", "Sports"]; $html = "
    "; foreach ($cats as $cat) { $html .= "
  • $cat
  • "; } $html .= "
"; return $html; } private function getFeaturedProducts() { // In real app, fetch from database $html = "
"; $html .= "
Featured Product
"; $html .= "

Special discount!

"; $html .= "
"; return $html; } private function getRecentPosts() { return "

Recent blog posts will appear here.

"; } } ``` ### FrontFile: ```html

Products

Welcome to our product catalog!

Categories
Featured
Latest Posts
``` ## **9.8 Using Holder with onholder Event** For more complex dynamic content, use the `onholder()` event in your Gate: ```php // In Gate - catches any holder without specific sphp-app-prop public function onholder($element) { $type = $element->getAttribute("data-widget-type"); switch ($type) { case "user-stats": $html = $this->getUserStats(); $element->setInnerHTML($html); break; case "product-grid": $html = $this->getProductGrid(); $element->setInnerHTML($html); break; case "news-feed": $html = $this->getNewsFeed(); $element->setInnerHTML($html); break; } } ``` FrontFile: ```html
``` ## **9.9 Holder vs Component** | Aspect | runat="server" (Component) | runas="holder" | |--------|---------------------------|----------------| | Creates | Component object | No Component | | Use Case | Interactive elements | Static content | | Lifecycle | Has events (oninit, onrender, etc.) | No events | | Database | Can use dtable/dfield | Just displays content | | Best For | Forms, inputs, interactive | Sidebars, lists, static sections | ## **9.10 Holder with Conditional Logic** Use expression tags for conditional holder content: ```html #{if $parentgate->isLoggedIn()}#
#{else}#
#{endif}# ``` Or conditional class based on holder content: ```html
``` ## **9.11 Chapter Summary** 1. **runas="holder"** creates placeholder for dynamic content 2. **sphp-app-prop** - Get content from FrontFile property 3. **sphp-comp** - Get content from Component 4. **sphp-comp-fun** - Call Component method 5. **sphp-app-fun** - Call Gate method directly 6. **onholder()** event - Handle holders dynamically 7. Use holders for sidebars, lists, static content 8. Use Components (`runat="server"`) for interactive elements ## **9.12 What's Next?** Next, learn about Code Blocks - how to enhance FrontFile design with reusable styling and layout transformations. --- *Next: Chapter 10 - Code Blocks: Enhancing FrontFile Design*# **Chapter 10: Code Blocks - Enhancing FrontFile Design** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **10.1 What are Code Blocks?** Code Blocks (`runcb="true"`) allow you to apply pre-defined styling and layout transformations to any HTML element in your FrontFile without writing custom PHP code. They work similar to CSS utility classes but with server-side processing. Think of code blocks as **reusable design patterns** that transform simple HTML into styled, structured output. ## **10.2 Basic Syntax** ```html
Content
``` - `runcb="true"` - Enable code block processing - `sphp-cb-[blockname]` - Apply the named block - Parameters can be passed after the block name ## **10.3 Defining Code Blocks** Code blocks are defined in `masters/sphpcodeblock.php`: ```php wrapTag('
'); $element->wrapInnerTags('
'); // Add header if first argument provided if (!empty($args[0])) { $element->setPreTag('
' . $args[0] . '
'); } // Add footer if second argument provided if (!empty($args[1])) { $element->setPostTag(''); } }); ``` ## **10.4 Using Code Blocks in FrontFile** ### **Basic Card** ```html
This is card content
This is card content
``` ### **Card with Header and Footer** ```html
This is the card body content
Product Details
This is the card body content
``` ## **10.5 Common Code Block Examples** ### **Alert Block** ```php // Define SphpCodeBlock::addCodeBlock('alert', function($element, $args) { $type = $args[0] ?? 'info'; // info, success, warning, danger $element->wrapTag('
'); if (!empty($args[1])) { $element->setPreTag('' . $args[1] . ': '); } }); ``` ```html
Operation completed!
Something went wrong!
``` ### **Button Block** ```php SphpCodeBlock::addCodeBlock('btn', function($element, $args) { $style = $args[0] ?? 'primary'; // primary, secondary, success, etc. $size = $args[1] ?? ''; // sm, lg $classes = "btn btn-$style"; if ($size) $classes .= " btn-$size"; $element->appendAttribute('class', $classes); $element->setAttribute('type', 'button'); }); ``` ```html ``` ### **Shadow Block** ```php SphpCodeBlock::addCodeBlock('shadow', function($element, $args) { $size = $args[0] ?? 'md'; // sm, md, lg, xl $element->appendAttribute('class', "shadow-$size"); }); ``` ```html
Content with large shadow
``` ### **Spacing Block** ```php SphpCodeBlock::addCodeBlock('padding', function($element, $args) { $size = $args[0] ?? '3'; // 0-5 $element->appendAttribute('class', "p-$size"); }); SphpCodeBlock::addCodeBlock('margin', function($element, $args) { $size = $args[0] ?? '3'; $dir = $args[1] ?? ''; // t, b, l, r $dirMap = ['' => '', 't' => '-t', 'b' => '-b', 'l' => '-l', 'r' => '-r']; $dirSuffix = $dirMap[$dir] ?? ''; $element->appendAttribute('class', "m$dirSuffix-$size"); }); ``` ```html
Padded content
Margin top
``` ## **10.6 Combining Multiple Code Blocks** You can apply multiple code blocks to the same element: ```html
Content with card, shadow, and padding
``` The blocks are processed in order, so later blocks can build on earlier transformations. ## **10.7 Using Code Blocks for Layout** ### **Grid Layout** ```php SphpCodeBlock::addCodeBlock('row', function($element, $args) { $element->wrapTag('
'); $element->appendAttribute('class', 'row'); }); SphpCodeBlock::addCodeBlock('col', function($element, $args) { $size = $args[0] ?? '12'; // 1-12 $element->appendAttribute('class', "col-md-$size"); }); ``` ```html
Column 1
Column 2
``` ### **Flex Box** ```php SphpCodeBlock::addCodeBlock('flex', function($element, $args) { $dir = $args[0] ?? 'row'; // row, column $justify = $args[1] ?? ''; // start, center, end, between, around $element->wrapTag('
'); if ($justify) { $justifyMap = [ 'start' => 'justify-content-start', 'center' => 'justify-content-center', 'end' => 'justify-content-end', 'between' => 'justify-content-between', 'around' => 'justify-content-around' ]; $element->appendAttribute('class', $justifyMap[$justify] ?? ''); } }); ``` ```html
Left Right
``` ## **10.8 Practical Example - Product Card** ### Define the code blocks: ```php // masters/sphpcodeblock.php // Product Card SphpCodeBlock::addCodeBlock('productCard', function($element, $args) { // Wrap in card $element->wrapTag('
'); // Add image container if image provided if (!empty($args[0])) { $element->setPreTag( 'Product' . $element->getPreTag() ); } // Wrap body $element->wrapInnerTags('
'); // Add footer if price provided if (!empty($args[1])) { $element->setPostTag(''); } }); // Badge SphpCodeBlock::addCodeBlock('badge', function($element, $args) { $color = $args[0] ?? 'primary'; $element->wrapTag(''); }); ``` ### Use in FrontFile: ```html
Product Name

Description goes here.

Another Product

Another description.

In Stock Low Stock ``` ## **10.9 Code Blocks vs Components** | Feature | Code Blocks | Components | |---------|-------------|-------------| | Syntax | `runcb="true"` | `runat="server"` | | Creates Object | No | Yes | | Interactive | No | Yes | | Database Binding | No | Yes (dtable/dfield) | | Best For | Styling, layout | Forms, data display | | Complexity | Low | Higher | ## **10.10 Chapter Summary** 1. **Code Blocks** (`runcb="true"`) apply pre-defined transformations 2. **sphp-cb-[name]** applies the named block 3. **Arguments** can be passed: `sphp-cb-card="Header,Footer"` 4. **Multiple blocks** can be combined on one element 5. **Define** in `masters/sphpcodeblock.php` 6. Use code blocks for **styling, cards, badges, spacing** 7. Use components (`runat="server"`) for **interactive elements** ## **10.11 What's Next?** Now let's put everything together in a complete example application! --- *Next: Chapter 11 - Putting It All Together*# **Chapter 11: Putting It All Together - Complete Example** > **File Extension Reference:** > - Gate Files: `*.gate.php` (e.g., `Index.gate.php`) > - Front Files: `*.front` (e.g., `index_main.front`) > - Master Files: `*.mast.php` (e.g., `default/master.mast.php`) > - Front Places: `*.place.front` or `*.place.php` --- ## **11.1 The Complete Project** In this chapter, we'll build a complete **Task Manager** application that demonstrates: - Gate registration and URL mapping - Lifecycle events (onstart, onready, onrender) - Page Events (list, create, edit, view, delete) - FrontFile Events (onfrontinit) - Two Front Files pattern (list + edit) - Master File with navigation - Holders and Code Blocks ## **11.2 Project Structure** ``` myproject/ ├── reg.php # Gate registration ├── comp.php # Configuration ├── start.php # Entry point │ ├── apps/ │ ├── Task.gate.php # Main Gate │ │ │ └── fronts/ │ ├── task_list.front # List view with pagination │ └── task_edit.front # Add/Edit form │ └── masters/ └── default/ ├── master.mast.php # Layout ├── menu.place.front # Navigation └── sphpcodeblock.php # Code blocks ``` ## **11.3 Step 1: Register the Gate** ```php getAuthenticate("GUEST,MEMBER,ADMIN"); // Create FrontFile objects $this->frtList = new \Sphp\tools\FrontFile($this->mypath . "/fronts/task_list.front"); $this->frtEdit = new \Sphp\tools\FrontFile($this->mypath . "/fronts/task_edit.front"); } /** * FrontFile Event: Set metadata when loaded */ public function onfrontinit($frontobj) { $frontobj->addMetaData("title", "Task Manager"); } /** * Lifecycle Event: Prepare components */ public function onready() { // Pre-populate category options $sltCategory = $this->frtEdit->getComponent("sltPriority"); $sltCategory->setOptions("Low,Medium,High,Urgent"); } /** * Page Event: task.html - Show task list */ public function page_new() { // Pagination Component handles the list // Just set the FrontFile $this->setFrontFile($this->frtList); } /** * Page Event: task-create.html - Show empty form */ public function page_event_create($evtp) { // Clear form for new record $this->clearForm(); $this->frtEdit->addProp("formTitle", "Create New Task"); $this->frtEdit->addProp("isEditMode", false); $this->setFrontFile($this->frtEdit); } /** * Page Event: task-view-5.html - View task (read-only) */ public function page_view() { $taskId = (int)$this->page->evtp; $this->loadTaskToForm($taskId, false); $this->setFrontFile($this->frtEdit); } /** * Page Event: task-edit-5.html - Edit task */ public function page_event_edit($evtp) { $taskId = (int)$evtp; $this->loadTaskToForm($taskId, true); $this->setFrontFile($this->frtEdit); } /** * Page Event: task.html (POST) - Handle form submission */ public function page_submit() { // Check validation if (getCheckErr()) { $this->frtEdit->addProp("formTitle", "Please Fix Errors"); $this->setFrontFile($this->frtEdit); return; } // Get form component $form = $this->frtEdit->getComponent("taskForm"); // Check if insert or update if ($form->getRecID() == "") { // Insert new $this->page->insertData($form); } else { // Update existing $this->page->updateData($form); } // Redirect to list $this->page->forward(getGateURL("task")); } /** * Page Event: task-delete-5.html - Delete task */ public function page_event_delete($evtp) { $taskId = (int)$evtp; // Delete from database $this->dbEngine->executeQuery("DELETE FROM tasks WHERE id = $taskId"); // Redirect to list $this->page->forward(getGateURL("task")); } /** * Page Event: task-search-keyword.html - Search tasks */ public function page_event_search($evtp) { // Pass search to FrontFile holder $this->frtList->addProp("searchTerm", $evtp); // Could modify the Pagination Component's query here // For now, just show list $this->setFrontFile($this->frtList); } /** * Lifecycle Event: Add final touches */ public function onrender() { // Add page-specific CSS/JS if needed // addFileLink("task-styles.css"); } // ===== Helper Methods ===== private function clearForm() { $this->frtEdit->getComponent("txtId")->fi_setDefaultValue(""); $this->frtEdit->getComponent("txtTitle")->fi_setDefaultValue(""); $this->frtEdit->getComponent("txaDescription")->fi_setDefaultValue(""); $this->frtEdit->getComponent("sltPriority")->fi_setDefaultValue(""); } private function loadTaskToForm($taskId, $isEditMode) { $this->dbEngine->connect(); $result = $this->dbEngine->executeQuery( "SELECT * FROM tasks WHERE id = $taskId" ); $row = $this->dbEngine->row_fetch_assoc($result); $this->dbEngine->disconnect(); if (!$row) { $this->page->forward(getGateURL("task")); return; } // Populate form $this->frtEdit->getComponent("txtId")->fi_setDefaultValue($row['id']); $this->frtEdit->getComponent("txtTitle")->fi_setDefaultValue($row['title']); $this->frtEdit->getComponent("txaDescription")->fi_setDefaultValue($row['description']); $this->frtEdit->getComponent("sltPriority")->fi_setDefaultValue($row['priority']); // Set mode $this->frtEdit->addProp("formTitle", $isEditMode ? "Edit Task" : "View Task"); $this->frtEdit->addProp("isEditMode", $isEditMode); } } ``` ## **11.5 Step 3: Create List Front File** ```html My Tasks

Task Manager

##{$taskGrid->getRow('title')}#
##{$taskGrid->getRow('priority')}#
##{$taskGrid->getRow('status')}#
##{$taskGrid->getRow('due_date')}#
``` ## **11.6 Step 4: Create Edit Front File** ```html Task Form

##{$formTitle}#

Cancel #{if $isEditMode}#
Delete
#{else}# #{endif}#
``` ## **11.7 Step 5: Create Master File** ```php getHeaderHTML(); ?> Task Manager
© 2024 Task Manager
getFooterHTML(); ?> ``` ## **11.8 Step 6: Create Menu Front Place** ```html ``` ## **11.9 Step 7: Create Code Blocks (Optional Enhancement)** ```php wrapTag('
'); $element->wrapInnerTags('
'); if (!empty($args[0])) { $element->setPreTag('
' . $args[0] . '
'); } }); ``` ## **11.10 URL Mapping Summary** | URL | Gate | Event | Parameter | Result | |-----|------|-------|------------|--------| | `task.html` | task | new | - | Show list with pagination | | `task.html` (POST) | task | submit | - | Save form (insert/update) | | `task-create.html` | task | create | - | Show empty form | | `task-view-5.html` | task | view | 5 | Show task (read-only) | | `task-edit-5.html` | task | edit | 5 | Show populated form | | `task-delete-5.html` | task | delete | 5 | Delete task | | `task-search-work.html` | task | search | work | Search results | ## **11.11 Complete Flow Summary** 1. **Browser requests** `task.html` 2. **Framework** finds "task" in reg.php, loads Task.gate.php 3. **onstart()** creates FrontFile objects, checks authentication 4. **onfrontinit()** sets metadata 5. **onready()** prepares components (sets dropdown options) 6. **page_new()** sets FrontFile, renders with Master File 7. **Pagination Component** displays tasks from database 8. **onrender()** adds final touches 9. **Browser receives** complete HTML page ## **11.12 Chapter Summary** This chapter demonstrated the complete development flow: 1. **Registration** - `registerGate()` in reg.php 2. **Gate Class** - Extends BasicGate, handles events 3. **Lifecycle Events** - onstart, onready, onrender 4. **Page Events** - page_new, page_submit, page_event_* 5. **Two Front Files** - List view + Edit form 6. **Master File** - Layout with menu 7. **Front Place** - Reusable navigation ## **What You've Learned** - How URL maps to Gate + Event - Gate lifecycle events and when to use each - Page events for different request types - FrontFile events for template interaction - Building pages with FrontFiles and Master Files - Two Front Files pattern for list/edit - Holders and Code Blocks for design enhancement **You are now ready to build web applications with SartajPhp!** --- **End of Book**