Templates Customization
Learn how to customize the service documentation interface using Jinja templates.
Overviewβ
When you access your SOAP service URL without any query parameters, byjg/soap-server displays a modern, interactive HTML documentation page. This page is rendered using the byjg/jinja-php templating engine, and you can fully customize it.
Default Templateβ
The library includes a beautiful default template with:
- π¨ Modern, responsive design
- π± Mobile-friendly interface
- β‘ Interactive collapsible operations
- π Copy-to-clipboard functionality
- π― Smooth scrolling navigation
- π Syntax-highlighted code examples
Template Locationβ
The default template is located at:
templates/service-info.html.jinja
Template Variablesβ
The following variables are available in the template:
Service Informationβ
| Variable | Type | Description |
|---|---|---|
classname | string | Service name |
description | string | Service description |
selfUrl | string | Current URL (without query string) |
warningNamespace | boolean | Whether to show namespace warning |
Methods Arrayβ
The methods array contains operation information:
{% for method in methods %}
{{ method.name }} {# Operation name #}
{{ method.description }} {# Operation description #}
{{ method.returnTypesStr }} {# Return type as string #}
{{ method.signatureStr }} {# Full signature with parameters #}
{{ method.hasParams }} {# Boolean: has parameters? #}
{{ method.exampleRequest }} {# SOAP XML example #}
{# Parameters array #}
{% for param in method.params %}
{{ param.name }} {# Parameter name #}
{{ param.type }} {# Parameter type #}
{{ param.required }} {# "β
Yes" or "β No" #}
{% endfor %}
{% endfor %}
Jinja-PHP Syntaxβ
The template uses Jinja-PHP syntax, which is similar to Twig:
Variablesβ
{{ classname }}
{{ method.name }}
Control Structuresβ
{% if warningNamespace %}
<div class="warning">Namespace warning...</div>
{% endif %}
{% for method in methods %}
<div>{{ method.name }}</div>
{% endfor %}
Filtersβ
Note: Filters require spaces around the pipe |:
{# Correct - spaces around pipe #}
{{ text | upper }}
{# Wrong - no spaces #}
{{ text|upper }}
Available filters:
upper- Convert to uppercaselower- Convert to lowercasecapitalize- Capitalize wordstrim- Remove whitespacelength- Get lengthdefault- Default value
Filter Limitations
The jinja-php library has limited filter support. For complex formatting, prepare data in PHP before passing to the template.
Customizing the Templateβ
Method 1: Edit the Default Templateβ
Simply edit templates/service-info.html.jinja:
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ classname }} - My Custom Template</title>
<style>
/* Your custom CSS */
body {
font-family: Arial, sans-serif;
background: #f0f0f0;
}
</style>
</head>
<body>
<h1>{{ classname }}</h1>
<p>{{ description }}</p>
<h2>Operations</h2>
{% for method in methods %}
<div class="operation">
<h3>{{ method.name }}</h3>
{% if method.description %}
<p>{{ method.description }}</p>
{% endif %}
<pre>{{ method.signatureStr }}</pre>
{% if method.hasParams %}
<table>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Required</th>
</tr>
{% for param in method.params %}
<tr>
<td>{{ param.name }}</td>
<td>{{ param.type }}</td>
<td>{{ param.required }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
<h4>Returns</h4>
<p>{{ method.returnTypesStr }}</p>
<h4>Example Request</h4>
<pre>{{ method.exampleRequest }}</pre>
</div>
{% endfor %}
<footer>
<p>Powered by byjg/soap-server</p>
</footer>
</body>
</html>
Method 2: Create Multiple Templatesβ
You can create different templates for different services. The library currently uses a single template, but you can extend SoapHandler to support template selection:
class CustomSoapHandler extends SoapHandler
{
private string $templateName = 'service-info.html';
public function setTemplate(string $name): void
{
$this->templateName = $name;
}
protected function handleINFO(): void
{
// Use custom template name
$templatePath = __DIR__ . '/../templates';
$loader = new FileSystemLoader($templatePath);
$template = $loader->getTemplate($this->templateName);
// ... render template
}
}
Template Best Practicesβ
Best Practices
- Keep logic in PHP: Prepare complex data in PHP, not in templates
- Use semantic HTML: Proper HTML structure for accessibility
- Mobile-first CSS: Design for mobile, enhance for desktop
- Minimize JavaScript: Keep templates fast and simple
- Test with real data: Test with actual service operations
- Escape output: Data is already escaped, don't double-escape
Example: Minimal Templateβ
Here's a simple, minimal template:
<!DOCTYPE html>
<html>
<head>
<title>{{ classname }}</title>
<style>
body { font-family: sans-serif; max-width: 800px; margin: 40px auto; padding: 20px; }
h1 { color: #333; }
.op { border: 1px solid #ddd; padding: 15px; margin: 15px 0; }
pre { background: #f5f5f5; padding: 10px; overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }
</style>
</head>
<body>
<h1>{{ classname }}</h1>
<p>{{ description }}</p>
<p>
<a href="{{ selfUrl }}?WSDL">WSDL</a> |
<a href="{{ selfUrl }}?DISCO">DISCO</a>
</p>
<h2>Operations</h2>
{% for method in methods %}
<div class="op">
<h3>{{ method.name }}()</h3>
<p>{{ method.description }}</p>
<pre><code>{{ method.returnTypesStr }} {{ method.name }}({{ method.signatureStr }})</code></pre>
{% if method.hasParams %}
<h4>Parameters</h4>
<table>
<thead>
<tr><th>Name</th><th>Type</th><th>Required</th></tr>
</thead>
<tbody>
{% for param in method.params %}
<tr>
<td><code>{{ param.name }}</code></td>
<td>{{ param.type }}</td>
<td>{{ param.required }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% endfor %}
</body>
</html>
Adding JavaScript Interactivityβ
You can add custom JavaScript for interactive features:
<script>
// Toggle operation details
function toggleOperation(element) {
element.classList.toggle('expanded');
}
// Copy to clipboard
function copyCode(button) {
const code = button.nextElementSibling.textContent;
navigator.clipboard.writeText(code).then(() => {
button.textContent = 'Copied!';
setTimeout(() => {
button.textContent = 'Copy';
}, 2000);
});
}
</script>
Styling with CSS Frameworksβ
You can use CSS frameworks like Bootstrap or Tailwind:
<!DOCTYPE html>
<html>
<head>
<title>{{ classname }}</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1 class="display-4">{{ classname }}</h1>
<p class="lead">{{ description }}</p>
{% for method in methods %}
<div class="card mb-3">
<div class="card-header">
<h5>{{ method.name }}</h5>
</div>
<div class="card-body">
<p class="card-text">{{ method.description }}</p>
<!-- More content -->
</div>
</div>
{% endfor %}
</div>
</body>
</html>
Troubleshootingβ
Template Not Foundβ
If you get a "template not found" error:
- Check the template file exists at
templates/service-info.html.jinja - Verify the
.jinjaextension - Check file permissions
Variables Not Showingβ
If variables appear blank:
- Check variable names match exactly
- Verify data is being passed to
$template->render() - Use
{% if variable %}to check if variable exists
Filter Errorsβ
If filters cause errors:
- Ensure spaces around pipe:
{{ var | filter }} - Use only supported filters
- Prepare complex formatting in PHP instead
Next Stepsβ
- Getting Started - Create your first service
- Using Attributes - Configure services with attributes
- Complex Types - Work with custom classes