Data Files
Data files separate data-binding logic from your main controller code.
They are PHP files executed within the template context —
$this refers to the template instance, giving full access
to all CandidTemplate methods.
1. How Data Files Work
addDataFile('page.data.php') — register data file
↓
render() — data file executes here
↓
$this->pick() calls inside — bindings queued
↓
final HTML output
CandidTemplateAdaptor::slot()
are resolved automatically — a page.data.php file
alongside page.html is loaded without any manual registration.
2. Basic Usage
Register a data file manually:
$tpl->addDataFile('/path/to/home.data.php');
home.data.php:
// $this = CandidTemplate instance
$this->pick('#pageTitle')->content('Welcome to our site');
$this->pick('.hero-text')->content('Latest Breaking News');
$this->pick('#publishDate')->content(date('d M Y'));
---
3. Automatic Resolution via Adaptor
When using CandidTemplateAdaptor, data files are
resolved automatically if they exist alongside the template file.
No manual registration needed.
views/
home.html — template
home.data.php — auto-loaded if exists
navbar.html
navbar.data.php — auto-loaded if exists
// home.data.php is auto-loaded — no addDataFile() needed
$view->slot('content', 'home');
// home.data.php
$this->pick('#pageTitle')->content('Home Page');
$this->pick('.subtitle')->content('Today\'s Top Stories');
---
4. Using PHP Logic
Data files are plain PHP — use any PHP logic to prepare values before binding:
// home.data.php
$today = date('l, d F Y');
$greeting = (date('H') < 12) ? 'Good Morning' : 'Good Evening';
$isWeekend = in_array(date('N'), [6, 7]);
$this->pick('#date')->content($today);
$this->pick('#greeting')->content($greeting);
$this->pick('.weekend-banner')->showIf($isWeekend);
---
5. Loop Handling Inside Data File
// news.data.php
$articles = NewsRepository::getLatest(10);
if ($articles->isEmpty()) {
$this->pick('#noResults')->showIf(true);
} else {
$this->pick('#noResults')->showIf(false);
foreach ($articles as $i => $article) {
$item = $this->addLoopItem('newsCard');
$item->pick('cardImage')
->src($article->thumbnail)
->attribute('alt', $article->title);
$item->pick('cardCategory')->content($article->category);
$item->pick('cardTitle')
->content($article->title)
->href($article->url);
$item->pick('newsCard')->toggleClass('featured', $i === 0);
}
}
---
6. Slot Handling Inside Data File
Register sub-slots from within a data file — useful for slots that always accompany a template:
// home.data.php
$slider = $this->slot('slider', 'slider');
$breaking = $this->slot('breaking', 'breaking');
$featured = $this->slot('featured', 'featured');
$slider->pick('.slide-title')->content('Top Stories Today');
---
7. Include Handling Inside Data File
// layout.data.php
$breadcrumb = $this->include('#breadcrumb', 'breadcrumb');
$breadcrumb->pick('current')->content('Home');
$breadcrumb->pick('parent')->content('News');
---
8. Passing Data from Controller
Use set() in the controller to pass data that
the data file reads with get():
index.php (controller):
$page = $view->slot('content', 'home');
$page->set('currentUser', $user);
$page->set('articles', $articles);
home.data.php:
$user = $this->get('currentUser');
$articles = $this->get('articles', []);
$this->pick('#username')->content($user->name);
$this->pick('#role')->content($user->role);
foreach ($articles as $article) {
$item = $this->addLoopItem('newsCard');
$item->pick('cardTitle')->content($article->title);
}
---
9. Multiple Data Files
Register multiple data files — executed in registration order:
$tpl->addDataFile('/data/meta.data.php'); // runs first
$tpl->addDataFile('/data/content.data.php'); // runs second
$tpl->addDataFile('/data/sidebar.data.php'); // runs third
10. Security — Forbidden Variables
Data files are validated before execution. The following superglobals are explicitly forbidden to prevent accidental data leaks or injection:
| Forbidden | Reason |
|---|---|
$_GET | User input — use controller layer |
$_POST | User input — use controller layer |
$_REQUEST | User input — use controller layer |
$_COOKIE | Session data — use controller layer |
$_SESSION | Session data — use controller layer |
$_FILES | Upload data — use controller layer |
$GLOBALS | Global scope — use share() instead |
// ❌ Throws InvalidArgumentException
$this->pick('name')->content($_GET['name']);
// ✅ Pass via controller instead
$this->pick('name')->content($this->get('name'));
---
11. Execution Order
- Data files registered via
addDataFile()run at render time - They run before loops, slots, and assignments are applied
- Multiple files run in registration order
- Auto-resolved data files (via adaptor) run before manually registered ones
12. Rules
$thisrefers to the owningCandidTemplateinstance- Data files must be valid, readable PHP files
- Superglobals are forbidden — pass data via
set()/get() - Data files run once per render — not cached between requests
- Data files can register slots, includes, and loops
- Later files can overwrite earlier bindings on the same element
13. Common Mistakes
$_GET, $_POST etc.) —
throws immediately❌ Using undefined variables — pass data via
set()/get()❌ Database queries inside data files — prepare data in controller
❌ Overwriting the same element across multiple data files unintentionally
❌ Registering sub-slots on root inside a data file — register on
$this (the correct parent)
14. Best Practices
- Keep data files focused — one data file per template
- Prepare and validate all data in the controller — data files are for view binding only
- Use
set()/get()to pass data cleanly from controller to data file - Use
share()for global data needed across all templates (app name, user, locale) - Avoid business logic — no calculations, no DB queries, no HTTP calls
- Name data files consistently —
page.data.phpalongsidepage.html
15. When to Use Data Files
| Use Data File | Use Controller Instead |
|---|---|
| Binding prepared data to elements | Fetching data from database |
| Registering sub-slots and includes | Business logic and calculations |
| Loop population from prepared arrays | Authentication and authorization |
| View-only conditional logic | API calls and external requests |
| Reusable template view logic | File uploads and processing |
Data Store API
The data store provides a clean way to pass data between controllers and data files, and to share data across the entire template tree.
---set(string $key, mixed $value)
Store data on the current template instance.
Accessible by the current template and its children via get().
// Controller / index.php
$page = $view->slot('content', 'home');
$page->set('user', $currentUser);
$page->set('articles', $latestArticles);
$page->set('pageTitle', 'Home — Latest News');
---
get(string $key, mixed $default = null)
Retrieve stored data. Walks the parent chain — child templates inherit data set on parents.
// home.data.php
$user = $this->get('user');
$articles = $this->get('articles', []);
$title = $this->get('pageTitle', 'News');
$this->pick('#username')->content($user->name);
$this->pick('#pageTitle')->content($title);
get() walks the parent template chain —
data set on a parent is accessible to all child templates
without re-passing it.
share(string $key, mixed $value)
Store data on the root template — accessible to every template in the entire tree regardless of nesting depth. Ideal for application-wide data.
// include.php — set once, available everywhere
$view->getTpl()->share('appName', 'Sony News');
$view->getTpl()->share('locale', 'en-IN');
$view->getTpl()->share('currentUser', $auth->user());
// Any data file at any depth
$appName = $this->get('appName'); // inherited via share()
$user = $this->get('currentUser');
$this->pick('#appName')->content($appName);
$this->pick('#navUser')->content($user->name);
---
Data Store Inheritance
root->share('appName', 'Sony News')
↓ accessible everywhere via get()
root->set('theme', 'dark')
├── content template → get('theme') ✅
│ ├── slider → get('theme') ✅ inherited
│ └── sidebar → get('theme') ✅ inherited
└── footer template → get('theme') ✅
// set() on child — parent cannot access
slider->set('slides', 5)
root → get('slides') ❌ not accessible upward
slider → get('slides') ✅
---
set(), and let the data file handle
all template binding. Use share() for anything
needed across the entire application.