# **Chapter 2: Architecture and Core Concepts**
## **2.1 The Layered Architecture**
SartajPHP employs a sophisticated layered architecture that separates concerns while maintaining tight integration. Understanding these layers is crucial to mastering the framework.
### **2.1.1 Runtime Layer (`Score/`)**
The innermost layer contains the framework engine:
- **Event Dispatcher**: Translates requests into PageEvents
- **Gate Loader**: Resolves and loads application's Gates
- **Component Factory**: Creates and manages Components
- **Cache Manager**: Handles multi-level caching
This layer is framework-managed and rarely accessed directly.
### **2.1.2 Shared Resource Layer (`res/`)**
The shared layer provides reusable assets across projects:
```
/res
├── Slib/ # Shared libraries, Components
├── jslib/ # JavaScript libraries (jQuery, Bootstrap, etc.)
├── components/ # Components,uikitdef, MasterFiles
├── plugin/ # Shared plugins
└── sample/ # Example projects
```
Projects reference these resources but don't modify them, ensuring upgradability.
### **2.1.3 Project Layer**
Your application code lives here:
```
/project/
├── apps/ # Web applications (*Gate.php files)
├── appsn/ # NativeGate and ConsoleGate
├── masters/ # Project-specific masters
├── plugin/ # Project plugins
└── cache/ # Runtime cache
```
Each layer has clear responsibilities and interaction rules.
## **2.2 The Request-Response Cycle**
Understanding how SartajPHP processes requests is fundamental to effective development.
### **2.2.1 Complete Request Flow**
```
Browser Request
↓
Web Server (Apache/Nginx)
↓
.htaccess → Rewrite to start.php
↓
SartajPHP Engine Initialization
├── Load core runtime
├── Parse CLI arguments (if console)
├── Set up error handling
↓
Router Analysis
├── Extract Gate from URL
├── Identify event type
├── Parse event parameters
↓
GateLoader Resolution
├── Check reg.php for Gate File registration
├── Load corresponding *Gate.php file
↓
prerun.php Execution
├── Security headers
├── CORS policies
├── Global initialization
↓
Gate Instantiation
├── Create Gate object
├── Trigger onstart() event
↓
FrontFile Processing (if applicable)
├── Parse .front file
├── Create Components
├── Execute Parse Phase Fusion
↓
PageEvent Execution
├── Trigger page_new() or page_event_*()
├── Handle form submissions
├── Process business logic
↓
Render Phase
├── Execute Render Phase Fusion
├── Process runtime attributes
├── Generate HTML output
↓
MasterFile Integration
├── Apply master template
├── Inject menus, headers, footers
↓
Cache Check/Store
├── Check if response is cacheable
├── Store in cache if needed
↓
Browser Response
```
### **2.2.2 URL Translation Rules**
SartajPHP uses a consistent URL pattern:
```
<Gate>-<event>-<parameter>.html
```
**Examples:**
```
index.html → Gate: index, Event: new
index-view-5.html → Gate: index, Event: view, Parameter: 5
shop-product-category-12.html → Gate: shop, Event: product, Parameter: category-12
```
The hyphen is always the separator. There are no query strings (?param=value) in the SartajPHP URL model—all parameters are part of the URL path. If you use query strings then it will be deal as same as in other php
applications and no effect to trigger or chnage event on Server.
## **2.3 Application Types**
SartajPHP supports multiple application types, each optimized for different use cases. You can also develop
your own Gate Type to extend with Parent Gate Type or from scratch.
### **2.3.1 BasicGate (Web Applications)**
The most common type, extending `Sphp\tools\BasicGate`:
```php
class MyGate extends \Sphp\tools\BasicGate {
private $frtMain;
public function onstart() {
$this->frtMain = new FrontFile($this->mypath . "/fronts/my_main.front");
}
public function page_new() {
$this->setFrontFile($this->frtMain);
}
}
```
**Characteristics:**
- Runs under Apache/Nginx
- Handles HTTP/HTTPS requests
- Supports AJAX communication
- Uses FrontFiles for UI
### **2.3.2 NativeGate (Real-Time Services)**
Extends `Sphp\tools\NativeGate` for long-running processes:
```php
class ChatServerGate extends \Sphp\tools\NativeGate {
public function onwscon($wsconobj) {
// Handle new WebSocket connection
$this->JSServer->addJSONReturnBlock("New User Entered " . $wsconobj->getConnectionId());
// Send Data to All connections but leave new Connection
$this->sendOthers();
}
public function page_event_mesaage($evtp) {
// extra data submit by browser via Web Socket
$bdata = $this->Client->request("bdata");
$msg = $bdata["msg"];
$user_name = $bdata["user_name"];
$this->JSServer->addJSONHTMLBlock("msgbox","@{$user_name} :- $msg");
// Send Data to All connections but leave sender Connection
$this->sendOthers();
}
public function onwsdiscon($wsconobj) {
$this->JSServer->addJSONReturnBlock("User Leave " . $wsconobj->getConnectionId());
// Send Data to All connections
$this->sendAll();
}
}
```
Little Long Sample
```php
class ChatServerGate extends \Sphp\tools\NativeGate {
public function onstart() {
// Create Python Gate as Child Process on start App
$pythonpath = __DIR__ . "/env/python.exe";
$pythonapp = __DIR__ . "/main.py";
$this->createProcess($pythonpath . " -u " . $pythonapp);
/** Make Global Gate mean handle All requests by only one process. The Manager of process
* of Gate is the mainConnection which send first request or setup by
* gate. For change or set new Manager use setGlobalAppManager. By Default
* Gate create one process per connection
*/
$this->setGlobalApp();
}
public function page_event_s_oncreateprocess($evtp,$bdata){
// child process is ready
// send to data to Socket Component message handler
$this->JSServer->addJSONReturnBlock("Child Process is Ready and Create By:- " . $this->mainConnection->getConnectionId());
// send to only current connection of WS and It is always Main Connection
$this->sendTo();
}
public function onwscon($wsconobj) {
// Handle new WebSocket connection
$this->JSServer->addJSONReturnBlock("New User Entered " . $wsconobj->getConnectionId());
// Send Data to All connections except New Connection
$this->sendOthers();
}
public function onwsdiscon($wsconobj) {
$this->JSServer->addJSONReturnBlock("User Leave " . $wsconobj->getConnectionId());
// Send Data to All connections
$this->sendAll();
}
public function onconsole($data,$type) {
// debug invalid data
if($type == ""){
$this->JSServer->addJSONReturnBlock("Unknown Data: " . $data);
// response to current request only
$this->sendTo();
}
}
public function onquit(){
$this->JSServer->addJSONReturnBlock("Gate Quit, Bye Bye");
// send to All WS connections bind with this App
$this->sendAll();
}
// call on quit of child process
// only child process is use with life of gate. so quit with child process
public function oncquit(){
// enable start button
$this->JSServer->addJSONJSBlock("$('#btnstart').prop('disabled',false)");
// Return Message to Socket Component
$this->JSServer->addJSONReturnBlock("Child Quit");
$this->sendTo();
// Exist The Gate also with quit of child process
$this->exitMe();
}
}
```
**Characteristics:**
- Requires SphpServer runtime
- Maintains persistent connections
- Can spawn child processes
- No HTTP request/response cycle
- Supports only WebSocket communication
### **2.3.3 ConsoleGate (CLI Applications)**
ConsoleGate can run with SphpDesk as Stand Alone Script file. You can use this as
alternative of bash file. To run this file you need SartajPHP framework for desktop
install with npm or download setup from sartajphp.com
npm install -g sphpdesk
then run this file:-
```
sphpdesk script ./compile.php
```
or as part of project
and run with start.php with php. gate = Gate, evt = Event and evtp = Event Parameter
You can also pass your own custom command lines start with "--"
```
php ./start.php --gate index --evt page --evtp contact --myparam "Hello World"
```
Extends `Sphp\tools\ConsoleGate` for command-line tools:
```php
class BackupToolGate extends \Sphp\tools\ConsoleGate {
public function page_new() {
$this->sendMsg("Starting backup...");
// Backup logic
}
}
```
Compile C++ Project
```php
class CompileGate extends \Sphp\tools\ConsoleGate {
public function onstart(){
//$this->disableStdout();
// print debug info
$this->enableStdout();
}
public function page_new(){
$this->proj = $this->consoleReadArgument("--proj");
if($this->proj != ""){
$this->compileproj($this->proj);
}else{
$this->sendMsg("--proj argument not exist",'e');
}
}
public function compileproj($proj){
$gccp = "";
$this->callf('which g++', 'Check G++', function($msg) use (&$gccp){
$gccp = $msg;
});
$str1 = $this->findAppendLib();
$compilecmd = 'g++ -o sbrowser.exe ./sbrowser/src/sbrowser.cpp -std=c++14 ' . $str1[0] . $str1[1] . $str1[2];
$this->sendMsg('compile ' . $compilecmd);
$this->calla($compilecmd, 'Compling', function($msg){
$this->sendMsg($msg);
},function($msg){
$this->sendMsg($msg);
});
}
private function findAppendLib(){
$libsrc = __DIR__ . '/' . $this->proj . '/lib';
$extralibflags = "";
$strinclude = "";
$strlink = "";
$dir = new DIR();
$liblist = $dir->directoryCount($libsrc);
//$total = count($filelist);
foreach ($liblist as $key => $value) {
$slib = json_decode(file_get_contents(realpath("{$libsrc}/$value/slib.json")),true);
$extralibflags .= " " . $slib[$this->os][$this->arch];
$strinclude .= " -I" . realpath("{$libsrc}/$value/include");
$strlink .= " -L" . realpath("{$libsrc}/$value/{$this->os}/{$this->arch}") . " -l{$value}";
}
return [$strinclude,$strlink,$extralibflags];
}
}
```
**Characteristics:**
- Runs from command line
- No web server required
- Outputs to console
- Can be scheduled via cron
## **2.4 Component Architecture**
Components are the building blocks of SartajPHP applications. They bridge the HTML presentation layer with PHP logic.
### **2.4.1 Component Anatomy**
Each Component consists of two parts:
1. **Component Object** (PHP class)
- Server-side logic
- Validation rules
- Database binding
- Lifecycle methods
2. **NodeTag** (HTML representation)
- Tag name and attributes
- Parent/child relationships
- Rendering control
### **2.4.2 Component Lifecycle**
```
Component Creation
├── HTML parsed, runat="server" detected
├── Component class instantiated
├── NodeTag bound to Component
↓
Parse Phase Events
├── oninit() - Component initializing
├── oncreate() - Component created
↓
Gate Interaction
├── Gate can modify Component via Fusion
├── Component processes posted values
↓
Render Phase Events
├── onprerender() - Before HTML generation
├── onrender() - Generating HTML
├── onpostrender() - After HTML generation
↓
HTML Output
├── Component may output multiple HTML elements
├── Children Components rendered recursively
```
### **2.4.3 Component Types**
**Built-in Components:**
- **Form Components**: TextField, TextArea, Select, CheckBox, Radio
- **File Components**: FileUploader, ImageUploader
- **Display Components**: Alert, Title, DataGrid, Pagination
- **Layout Components**: Include, ForLoop, IfCondition
**Custom Components:**
Use \Sphp\tools\Component class as parent class to create custom Component.
Developers can create reusable Components with custom behavior:
```php
namespace MyApp\Components;
class StarRating extends \Sphp\tools\Component {
public function onrender() {
$rating = $this->getValue();
$stars = str_repeat('★', $rating) . str_repeat('☆', 5 - $rating);
$this->element->setInnerHTML($stars);
}
}
```
## **2.5 FrontFile System Architecture**
The FrontFile system is where SartajPHP's "pure HTML" philosophy comes to life.
### **2.5.1 FrontFile Processing Stages**
```
FrontFile Loading
├── Read .front file
├── Parse HTML into DOM tree
↓
NodeTag Creation
├── Each HTML element becomes NodeTag
├── Attributes parsed and stored
↓
Component Detection
├── runat="server" tags identified
├── Component objects created
↓
Attribute Processing
├── Fusion attributes (fui-, fun-, fur-)
├── Runtime attributes (runas, runcb)
├── Helper attributes evaluated
↓
Expression Tag Resolution
├── ##{ }# tags processed
├── Execution timing based on context
↓
HTML Generation
├── NodeTags convert to HTML
├── Components inject their output
```
### **2.5.2 The Three Attribute Categories**
1. **Runtime Attributes** (`runat`, `runas`, `runcb`)
- Control how tags are processed
- Determine if Components are created
2. **Fusion Attributes** (`fui-*`, `fun-*`, `fur-*`)
- Call Component methods
- Control execution timing
3. **Helper Attributes** (`sphp-cb-*`, `dtable`, `dfield` , `id`, `path` custom attributes)
- Provide data to Components
- Used by Components for configuration
## **2.6 Event System**
SartajPHP's event system operates at multiple levels.
### **2.6.1 PageEvents**
URL-triggered events in Applications:
```php
// URL: gate.html
public function page_new() {
// Default Event
}
// URL: gate.html (POST with form)
public function page_submit() {
// Form submission
}
// URL: gate-action-param.html
public function page_event_action($evtp) {
// $evtp contains "param"
}
```
### **2.6.2 Lifecycle Events**
Gate's Life Cycle Events:
```php
public function onstart() {
// Gate initialization
}
public function onready() {
// Gate ready to process
}
public function onrun() {
// Gate execution starting
}
public function onrender() {
// Gate execution finished and ready to send output
}
```
### **2.6.3 Component Events**
Component-specific events:
```php
// In FrontFile: <comp runat="server" on-init="true">
public function comp_compname_on_init($evtp) {
// Component initialization
}
```
### **2.6.4 FrontFile Events**
```php
public function onfrontinit($frontobj) {
// Front File Initialized
}
public function onfrontprocess($frontobj) {
// Front File ready to process
}
```
### **2.6.5 WebSocket Events** (NativeGate only)
```php
public function onwscon($conobj) {
// WebSocket connection opened
}
public function onwsdiscon($conobj) {
// WebSocket connection closed
}
```
## **2.7 Data Flow Patterns**
Understanding data flow is crucial for building efficient applications.
### **2.7.1 Request Data Access**
**Never use superglobals directly:**
```php
// ❌ WRONG
$name = $_POST['name'];
// ✅ CORRECT
$name = $this->Client->post('name');
// or
$name = SphpBase::sphp_request()->post('name');
```
**Component values are automatic:**
```html
<!-- FrontFile -->
<input id="txtName" runat="server" type="text" />
```
```php
// Gate - value already available
$name = $this->front->getComponent('txtName')->value;
```
### **2.7.2 Database Operations**
SartajPHP provides multiple database interaction patterns:
**1. Component Binding (Automatic):**
```html
<input id="txtName" runat="server" dtable="users" dfield="username" type="text" />
```
```php
// Auto-generates SQL and Insert, based on Components binding children of form2
$this->page->insertData($form2);
```
**2. Direct Database Access:**
```php
$db = SphpBase::dbEngine();
$db->connect(); // use comp.php (Company) file settings
$result = $db->executeQuery("SELECT * FROM users");
```
**3. ORM-like Patterns:**
```php
$user = new UserModel();
$user->name = $this->Client->post('name');
$user->save();
```
### **2.7.3 Response Patterns**
**HTML Responses:**
```php
$this->setFrontFile($this->front); // Render FrontFile
```
**AJAX/JSON Responses:**
```php
$this->JSServer->addJSONReturnBlock(["status" => "success"]);
$this->JSServer->addJSONHTMLBlock("result", "<p>Updated</p>");
```
**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
<input id="user_email" runat="server" fui-setEmail="" fui-setRequired="">
```
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
<!-- Expression tags auto-escape for HTML context -->
<p>##{$userInput}#</p> <!-- HTML escaped -->
<!-- Raw output when explicitly requested -->
<p>##{raw:$trustedHtml}#</p> <!-- No escaping -->
```
**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
<!-- Script loads only if Component renders -->
<script runas="filelink" renderonce="true"
src="heavy-library.js"></script>
```
### **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
<!-- Basic form works without JavaScript -->
<form action="/submit" method="post">
<input type="text" name="email" id="email" />
</form>
<!-- Enhanced with SartajPHP -->
<form id="form1" runat="server" fun-setAJAX="">
<input id="email" type="text" runat="server" fui-setEmail="" />
</form>
```
## **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.*