Symfony 2 load different template depending on user agent properties
Ok, so I don't have a full solution but a little more than where to look for one :)
You can specify loaders (services) for templating item in app/config/config.yml
framework:
esi: { enabled: true }
#translator: { fallback: %locale% }
secret: %secret%
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: %kernel.debug%
form: true
csrf_protection: true
validation: { enable_annotations: true }
templating:
engines:
- twig
loaders: [moby.loader]
default_locale: %locale%
trust_proxy_headers: false
session: ~
Then define the mentioned loader service:
services:
moby.loader:
class: Acme\AppBundle\Twig\Loader\MobyFilesystemLoader
arguments: ["@templating.locator", "@service_container"]
After that define your loader service class:
namespace Acme\AppBundle\Twig\Loader;
use Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader;
use Symfony\Component\Templating\Storage\FileStorage;
class MobyFilesystemLoader extends FilesystemLoader
{
protected $container;
public function __construct($templatePathPatterns, $container)
{
parent::__construct($templatePathPatterns);
$this->container = $container;
}
public function load(\Symfony\Component\Templating\TemplateReferenceInterface $template)
{
// Here you can filter what you actually want to change from html
// to mob format
// ->get('controller') returns the name of a controller
// ->get('name') returns the name of the template
if($template->get('bundle') == 'AcmeAppBundle')
{
$request = $this->container->get('request');
$format = $this->isMobile($request) ? 'mob' : 'html';
$template->set('format', $format);
}
try {
$file = $this->locator->locate($template);
} catch (\InvalidArgumentException $e) {
return false;
}
return new FileStorage($file);
}
/**
* Implement your check to see if request is made from mobile platform
*/
private function isMobile($request)
{
return true;
}
}
As you can see this isn't the full solution, but I hope that this, at least, points you to the right direction.
EDIT: Just found out that there is a bundle with mobile detection capabilities, with custom twig engine that renders template file depending on a device that sent request
ZenstruckMobileBundle, although I never used it so... :)
Symfony2 twig mobile template fallback
You could create a service to handle it and then use it in the same way that you do the templating service like so..
Create a service with the templating and request service injected into it..
Service (YAML)
acme.templating:
class: Acme\AcmeBundle\Templating\TemplatingProvider
scope: request
arguments:
- @templating
- @request // I assume you use request in your platform decision logic,
// otherwise you don't needs this or the scope part
- 'html'
Class
class TemplatingProvider
{
private $fallback;
private $platform;
... __construct($templating, $request, $fallback) etc
private function setPlatform() ... Your platform decision logic
private function getPlatform()
{
if (null === $this->platform) {
$this->setPlatform();
}
return $this->platform;
}
private function getTemplateName($name, $platform)
{
if ($platform === 'html') {
return $name;
}
$template = explode('.', $name);
$template = array_merge(
array_slice($template, 0, -2),
array($platform),
array_slice($template, -2)
);
return implode('.', $template);
}
public function renderResponse($name, array $parameters = array())
{
$newname = $this->getTemplateName($name, $this->getPlatform());
if ($this->templating->exists($newname)) {
return $this->templating->render($newname);
}
return $this->templating->renderResponse($this->getTemplateName(
$name, $this->fallback));
}
And then you could just call your templating service instead of the current one..
return $this->container->get('acme.templating')
->renderResponse('<template_name>.html.twig', array());
Symfony2: Change rendered view with a listener
Here is the solution:
First I have to listen to kernel.view, not kernel.controller.
Then I use the "@templating" service (Thanks Marko Jovanovic for the hint)
So here is my new config.yml:
services:
controller.pre_execute_listener:
class: MyProject\MyBundle\Listener\ControllerListener
arguments: ["@templating"]
tags:
- { name: kernel.event_listener, event: kernel.view, method: preExecute }
Finally here is my listener preExecute function
public function preExecute(\Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event){
//result returned by the controller
$data = $event->getControllerResult();
/* @var $request \Symfony\Component\HttpFoundation\Request */
$request = $event->getRequest();
$template = $request->get('_template');
$route = $request->get('_route');
if(substr($route,0,7) == 'mobile_'){
$newTemplate = str_replace('html.twig','mobile.html.twig',$template);
//Overwrite original template with the mobile one
$response = $this->templating->renderResponse($newTemplate, $data);
$event->setResponse($response);
}
}
Hope this helps!
J.
Symfony2 - How to check if we are being called from a mobile device
I'm sure Symfony has some wrapped command to do this as well but:
$_SERVER['HTTP_USER_AGENT']
will give you the user-agent
string which tents to have a string "Android verNum".
Symfony set block content from controller
Since any parent Twig templates handle variables that are passed to their children templates, there's a simpler method to achieve what you want to do. In fact, this method is the basic equivalent of writing content into an entire block from the controller since we're essentially just inserting a passed render
variable directly into the contents using {% block %}{{ variable }}{% endblock %}
Start a base layout template with the title block
{# Resources/views/base.html.twig #}
<html>
<head>
<title>{% block title %}{{ page_title is defined ? page_title }}{% endblock %}</title>
{# ... Rest of your HTML base template #}
</html>
The {% block %}
part is not necessary but useful if you ever want to override or append to it (using parent()
)
You can also add a site-wide title so the page_title
can be appended if it exists:
<title>{% block title %}{{ page_title is defined ? page_title ~ ' | ' }}Acme Industries Inc.{% endblock %}</title>
Extend this base layout with every child template
{# Resources/views/Child/template.html.twig #}
{% extends '::base.html.twig' %}
{# You can even re-use the page_title for things like heading tags #}
{% block content %}
<h1>{{ page_title }}</h1>
{% endblock %}
Pass the page_title
into your render
function which references your child template
return $this->render('AcmeBundle:Child:template.html.twig', array(
'page_title' => 'Title goes here!',
));
Related Topics
How to Get Date from Excel Using PHPexcel Library
PHP Import Excel into Database (Xls & Xlsx)
How to Install Imagemagick to Use with PHP on Windows 7 (3)
Return One Value from Database with MySQL PHP Pdo
How to Allow Remote Access to My Wamp Server for Mobile(Android)
How to Call a Static Method from a Class If All I Have Is a String of the Class Name
Fix iOS Picture Orientation After Upload PHP
How to Use Laravel Passport with Password Grant Tokens
How to Determine Whether It's a Mobile Device with PHP
In PHP, How to Call a Function Interpolated in String
Wordpress Woocommerce - Use Update_Post_Meta to Add Product Attributes
Best Way to Check for Positive Integer (Php)
Add Column to Magento Admin Catolog > Manage Products
Codeigniter 2 on Iis with Web.Config File
How Does {} Affect a MySQL Query in PHP
Alternative to File_Get_Contents
Compile Error: "G++: Error Trying to Exec 'Cc1Plus': Execvp: No Such File or Directory"