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
Data files registered via 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
Later data files can overwrite bindings made by earlier ones — be mindful of execution order when multiple files bind the same element.
---

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
$_GETUser input — use controller layer
$_POSTUser input — use controller layer
$_REQUESTUser input — use controller layer
$_COOKIESession data — use controller layer
$_SESSIONSession data — use controller layer
$_FILESUpload data — use controller layer
$GLOBALSGlobal 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

  1. Data files registered via addDataFile() run at render time
  2. They run before loops, slots, and assignments are applied
  3. Multiple files run in registration order
  4. Auto-resolved data files (via adaptor) run before manually registered ones
---

12. Rules

---

13. Common Mistakes

❌ Using superglobals ($_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

---

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')  ✅
---
Data files keep your controllers clean — prepare data in the controller, pass it via set(), and let the data file handle all template binding. Use share() for anything needed across the entire application.