Skip to content

FragmentResponse

Viames Marino edited this page Jun 12, 2026 · 1 revision

Pair framework: FragmentResponse

Pair\Web\FragmentResponse is the explicit Pair v4 HTML fragment response for progressive, SPA-like regions inside server-rendered pages.

Use it from Pair\Web\Controller actions when a request asks for one page region through the X-Pair-Region header and the server should return only that region's markup.

Constructor

new FragmentResponse(string $templateFile, object $state, string $region, int $httpCode = 200)

Arguments:

  • templateFile: absolute path to the fragment layout file.
  • state: typed state object exposed to the fragment layout as $state.
  • region: non-empty region name normalized and sent back in the X-Pair-Region response header.
  • httpCode: optional HTTP status code.

Example:

use Pair\Web\FragmentResponse;

return new FragmentResponse(
    APPLICATION_PATH . '/modules/orders/layouts/_list.php',
    new OrdersPageState($orders),
    'orders-list'
);

Most application code should build it through Pair\Web\Controller::fragment() so the layout path is resolved from the current module:

use Pair\Http\ResponseInterface;
use Pair\Web\Controller;

require_once __DIR__ . '/classes/OrdersPageState.php';

/**
 * Orders controller with progressive region support.
 */
final class OrdersController extends Controller {

	/**
	 * Render the full page or only the requested orders list region.
	 */
	public function defaultAction(): ResponseInterface {

		$state = new OrdersPageState($this->loadOrders());

		return $this->pageOrFragment(
			'default',
			'_list',
			$state,
			'orders-list',
			'Orders'
		);

	}

}

Controller helpers

Pair\Web\Controller includes these helpers for fragment-aware actions:

  • fragment($layout, $state, $region, $httpCode = 200) builds a FragmentResponse.
  • pageOrFragment($pageLayout, $fragmentLayout, $state, $region, $title = null) returns a full PageResponse unless X-Pair-Region matches the given region.
  • pageOrFragments($pageLayout, $fragmentLayouts, $state, $title = null) chooses one fragment from a region-to-layout map.
  • requestedRegion() returns the normalized requested region name or null.
  • wantsRegion($region) checks whether the request explicitly asks for one region.

Layout contract

Fragment layouts receive only $state, just like PageResponse layouts.

<?php
/** @var OrdersPageState $state */
?>
<section data-pair-region="orders-list" data-pair-source="/orders">
	<?php foreach ($state->orders as $order): ?>
		<article><?= htmlspecialchars($order->number, ENT_QUOTES, 'UTF-8') ?></article>
	<?php endforeach; ?>
</section>

The response markup should include a matching data-pair-region element when it is meant to be consumed by PairUI.region.refresh().

Behavior

  • send() validates that the fragment template exists.
  • The constructor rejects empty region names after trimming and removing line breaks.
  • The response uses Content-Type: text/html; charset=utf-8.
  • The response sends X-Pair-Region with a single-line sanitized region value.
  • The fragment is not wrapped in the outer application template.
  • When Observability is enabled, send() records a fragment.response span with the template filename, region name, and state class.

Use PairUI.js for the client-side progressive helpers that request and replace these regions.

See also: Controller, PageResponse, ResponseInterface, PairUI.js, Observability.

Clone this wiki locally