# **Chapter 9: Expression Tags - Safe Dynamic Content with Gate Integration**
## **9.1 The Strict Expression Tag Philosophy in SartajPHP v5**
SartajPHP version 5 introduces important restrictions on expression tag usage to ensure security, performance, and maintainability. The key principle is: **Expression tags are for simple output, not complex logic.**
### **9.1.1 What You CANNOT Do in Expression Tags v5**
1. **No Function Definitions:**
```html
<!-- ❌ NOT ALLOWED in v5 -->
#{
function formatPrice($price) {
return '$' . number_format($price, 2);
}
}#
```
2. **No Anonymous Functions via addProp:**
```php
// ❌ NOT ALLOWED in v5
$this->frtMain->addProp('formatPrice', function($price) {
return '$' . number_format($price, 2);
});
```
3. **No Complex Loops in Expression Tags:**
```html
<!-- ❌ NOT ALLOWED in v5 -->
#{
$output = '';
foreach ($products as $product) {
$output .= "<div>{$product->name}</div>";
}
echo $output;
}#
```
4. **No Component Generation from Expression Tags:**
```html
<!-- ❌ NOT ALLOWED in v5 -->
##{
// Cannot create or modify Components
$component = new \Sphp\Comp\Form\TextField();
echo $component->render();
}#
```
### **9.1.2 What You CAN Do in Expression Tags v5**
1. **Simple Variable Output:**
```html
<!-- ✅ ALLOWED -->
<p>Welcome, ##{$userName}#!</p>
<p>Price: $##{$productPrice}#</p>
```
2. **Basic Ternary Operations:**
```html
<!-- ✅ ALLOWED -->
<p class="##{$isActive ? 'active' : 'inactive'}#">
Status: ##{$isActive ? 'Online' : 'Offline'}#
</p>
```
3. **Simple String Concatenation:**
```html
<!-- ✅ ALLOWED -->
<p>##{'Hello ' . $firstName . ' ' . $lastName}#</p>
```
4. **Basic Arithmetic:**
```html
<!-- ✅ ALLOWED -->
<p>Total: $##{$price * $quantity}#</p>
<p>Discount: ##{$discountPercent}#%</p>
```
5. **Call Gate Methods for Complex Logic:**
```html
<!-- ✅ ALLOWED and RECOMMENDED -->
##{raw:$parentgate->generateProductGrid($products)}#
##{raw:$parentgate->formatCurrency($amount)}#
```
## **9.2 The Correct Pattern: Gate Methods for Complex Logic**
The proper way to handle complex presentation logic in SartajPHP v5 is to create methods in your Application class and call them from expression tags.
### **9.2.1 Basic Pattern**
**In App:**
```php
class MyGate extends \Sphp\tools\BasicGate {
public function generateProductList($products) {
$html = '<div class="product-list">';
foreach ($products as $product) {
$html .= $this->generateProductItem($product);
}
$html .= '</div>';
return $html;
}
private function generateProductItem($product) {
return sprintf(
'<div class="product-item">
<h3>%s</h3>
<p>%s</p>
<p class="price">$%.2f</p>
</div>',
htmlspecialchars($product['name']),
htmlspecialchars($product['description']),
$product['price']
);
}
}
```
**In FrontFile:**
```html
<div class="container">
##{raw:$parentgate->generateProductList($products)}#
</div>
```
### **9.2.2 Using Holder Tags with Gate Methods**
A cleaner approach is to use holder tags that call Gate methods:
**In App:**
```php
class MyGate extends \Sphp\tools\BasicGate {
// This method will be called by holder tag
public function onholder($element) {
if ($element->getAttribute('data-type') === 'product-grid') {
$products = $this->getProducts();
$html = $this->generateProductGrid($products);
$element->setInnerHTML($html);
}
}
private function generateProductGrid($products) {
$html = '<div class="row">';
foreach ($products as $product) {
$html .= $this->generateProductCard($product);
}
$html .= '</div>';
return $html;
}
private function generateProductCard($product) {
$onSale = $product['sale_price'] < $product['regular_price'];
$discount = $onSale ?
round((1 - $product['sale_price'] / $product['regular_price']) * 100) :
0;
return sprintf(
'<div class="col-md-4 mb-4">
<div class="card product-card">
%s
<div class="card-body">
<h5 class="card-title">%s</h5>
<div class="price-section">
%s
</div>
<button class="btn btn-primary">Add to Cart</button>
</div>
</div>
</div>',
$onSale ? '<span class="badge bg-danger sale-badge">Save ' . $discount . '%</span>' : '',
htmlspecialchars($product['name']),
$onSale ?
'<span class="text-muted"><s>$' . number_format($product['regular_price'], 2) . '</s></span> ' .
'<span class="text-danger">$' . number_format($product['sale_price'], 2) . '</span>' :
'<span>$' . number_format($product['regular_price'], 2) . '</span>'
);
}
}
```
**In FrontFile:**
```html
<div class="container">
<!-- Holder tag triggers App's onholder method -->
<div runas="holder" data-type="product-grid"></div>
</div>
```
## **9.3 Using Components for Loops Instead of Expression Tags**
When you need to repeat content, use Components instead of expression tag loops:
### **9.3.1 ForLoop Component**
**In FrontFile:**
```html
<div id="productLoop"
runat="server"
path="slibpath/comp/server/ForLoop.php"
fun-setLoopTo="##{$productCount}#">
<!-- Template for each item -->
<div class="col-md-4 mb-4">
<div class="card">
<!-- Use holder tags for dynamic content -->
<h5 runas="holder"
sphp-comp="productLoop"
dfield="name"></h5>
<p runas="holder"
sphp-comp="productLoop"
dfield="description"></p>
<p class="price">
$<span runas="holder"
sphp-comp="productLoop"
dfield="price"></span>
</p>
</div>
</div>
</div>
```
**In App:**
```php
public function onready() {
$products = $this->getProducts();
$loop = $this->frtMain->getComponent('productLoop');
// Set data for the loop
$loop->fu_setData($products);
}
```
### **9.3.2 DataGrid Component**
For tabular data:
**In FrontFile:**
```html
<div id="userGrid"
runat="server"
path="uikit/data/Pagination.php"
dtable="users"
fun-setColumns="name,email,role,created_at"
fun-setColumnNames="Name,Email,Role,Joined"
fun-setItemsPerPage="10">
</div>
```
## **9.4 Using Code Blocks for Layout Logic**
Code blocks (`runcb="true"`) are perfect for layout transformations without complex expression logic:
### **9.4.1 Define Code Blocks**
**In masters/sphpcodeblock.php:**
```php
SphpCodeBlock::addCodeBlock('product_card', function($element, $args, $context) {
// Extract product data from args
$product = $args[0] ?? [];
if (empty($product)) {
return;
}
// Generate card HTML
$html = '<div class="card product-card">';
if (!empty($product['image'])) {
$html .= '<img src="' . htmlspecialchars($product['image']) . '"
class="card-img-top"
alt="' . htmlspecialchars($product['name']) . '">';
}
$html .= '<div class="card-body">';
$html .= '<h5 class="card-title">' . htmlspecialchars($product['name']) . '</h5>';
if (!empty($product['description'])) {
$html .= '<p class="card-text">' . htmlspecialchars($product['description']) . '</p>';
}
$html .= '<p class="price">$' . number_format($product['price'], 2) . '</p>';
$html .= '</div></div>';
$element->setInnerHTML($html);
});
SphpCodeBlock::addCodeBlock('user_badge', function($element, $args, $context) {
$user = $args[0] ?? [];
$size = $args[1] ?? 'medium';
if (empty($user)) {
return;
}
$sizeClass = [
'small' => 'badge-sm',
'medium' => 'badge-md',
'large' => 'badge-lg'
][$size] ?? 'badge-md';
$roleClass = [
'admin' => 'badge-danger',
'moderator' => 'badge-warning',
'user' => 'badge-primary',
'guest' => 'badge-secondary'
][$user['role']] ?? 'badge-secondary';
$element->appendAttribute('class', 'user-badge ' . $sizeClass . ' ' . $roleClass);
$element->setInnerHTML(htmlspecialchars($user['name']));
});
```
### **9.4.2 Use Code Blocks in FrontFile**
```html
<!-- Simple container that code block will fill -->
<div runcb="true"
sphp-cb-product_card="##{$productData}#">
</div>
<!-- Multiple products using holder pattern -->
<div class="product-grid">
<div runas="holder" data-type="product_cards"></div>
</div>
```
**In App:**
```php
public function onholder($element) {
if ($element->getAttribute('data-type') === 'product_cards') {
$products = $this->getProducts();
$html = '';
foreach ($products as $product) {
// Pass product data to code block via data attribute
$html .= '<div runcb="true"
sphp-cb-product_card="' .
htmlspecialchars(json_encode($product)) . '"></div>';
}
$element->setInnerHTML($html);
}
}
```
## **9.5 Best Practices for SartajPHP v5 Expression Tags**
### **9.5.1 Do's and Don'ts**
**✅ DO:**
- Use simple variable output: `##{$variable}#`
- Use basic ternary operators: `##{$condition ? 'Yes' : 'No'}#`
- Use string concatenation: `##{'Hello ' . $name}#`
- Use arithmetic: `##{$price * $quantity}#`
- Call Gate methods for complex logic: `##{raw:$parentgate->method()}#`
**❌ DON'T:**
- Define functions in expression tags
- Create complex loops in expression tags
- Pass anonymous functions via `addProp()`
- Generate Components from expression tags
- Include business logic in expression tags
### **9.5.2 Recommended Architecture**
```
FrontFile (View Layer)
├── Simple Expression Tags (display only)
├── Holder Tags (for dynamic content)
├── Components (for reusable UI elements)
└── Code Blocks (for layout transformations)
Gate Class (Logic Layer)
├── Methods for complex HTML generation
├── Data preparation and processing
├── Component configuration
└── Business logic
Components (UI Layer)
├── ForLoop, DataGrid for repeating content
├── Custom Components for specialized UI
└── Built-in Components for forms, etc.
```
### **9.5.3 Performance Tips**
1. **Pre-generate HTML in App:** Complex HTML should be generated once in Gate methods
2. **Use Components for repeated content:** Components are optimized for loops
3. **Cache expensive operations:** Cache generated HTML in Gate if appropriate
4. **Minimize expression tag complexity:** Keep expressions simple and fast
## **9.6 Chapter Summary**
SartajPHP v5 expression tags follow a strict but sensible philosophy:
1. **Safety First:** No arbitrary code execution in templates
2. **Separation of Concerns:** Presentation logic in App, not in templates
3. **Performance Focus:** Pre-generated HTML for complex content
4. **Maintainability:** Clean, readable templates without embedded logic
**Key Takeaways:**
- Expression tags are for **simple output only**
- Complex logic belongs in **Gate methods**
- Use `##{raw:$parentgate->method()}#` for complex HTML
- Use **Components** for repeating content (not expression tag loops)
- Use **Code Blocks** for layout transformations
- Keep templates clean and focused on presentation
This approach ensures your SartajPHP applications are secure, maintainable, and performant. While it requires more upfront planning, it pays dividends in reduced bugs, better security, and easier maintenance.
---