Hey everybody I am just trying to learn Twig and having a problem getting it to work at all. There are no errors returned in the web server or on the CLI but it just doesn't render the template at all. I installed twig using composer.
<?php
require_once 'vendor/autoload.php';
class xltwig {
private static $twig;
public static function twig() {
$templateDir = __DIR__.'/twig/en_us';
if ( ! isset(self::$twig) ) {
$loader = new Twig_Loader_Filesystem(array($templateDir));
self::$twig = new Twig_Environment($loader);
}
return self::$twig;
}
}
$twig = xltwig::twig();
$twig->render("index.html",array('pageTitle' => 'test'));`
index.html is simply:
<h1>{{ pageTitle }}</h1>
The Twig render method returns a string with the rendered template content, it doesn't output it. The documentation shows it used with echo, and points out:
The display() method is a shortcut to output the template directly.
Related
I have a PHP code to add a new class for my Twig template in my common controller in: "opencart\htdocs\catalog\controller\common\cart.php"
The code should check if the Device is Mobile or not.
function onStart()
{
// Anonymous Class only working on PHP7
$this['code'] = new class {
public function MobileDetect() {
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo
|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i"
, $_SERVER["HTTP_USER_AGENT"]);
}
};
}
But now I don´t know how to address that function correctly from my twig side at:
opencart\htdocs\catalog\view\theme\default\template\common\cart.twig
I tried something like this, but it didn´t seem to work:
{% if code.MobileDetect() is defined %}
If a device is mobile I want to use a completely different HTML construct.
What you need to do is create your own Twig function:
https://twig.symfony.com/doc/3.x/advanced.html#functions
So using their examples you should be able to do something like
$function = new \Twig\TwigFunction('MobileDetect', function () {
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo
|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i"
, $_SERVER["HTTP_USER_AGENT"]);
});
$twig->addFunction($filter);
Then call it like
{% if MobileDetect() %}
I am changing my assets from PNGs to SVGs, where appropriate, however I am having difficultly including these SVGs in my Twig templates.
I am trying to include the SVG like this:
{{ source('/assets/img/crmpicco-horizontal-logo.svg') }}
However, this results in the following error:
Unable to find template "/assets/img/crmpicco-horizontal-logo.svg"
(looked into:
/Library/WebServer/Documents/crmpicco/symfony/app/Resources/views,
/Library/WebServer/Documents/crmpicco/symfony/vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form).
Why can't I include this SVG in the same directory as my other assets? Specifically, i'm interested in finding out why a SVG can't be treated as an asset with Assetic.
Here is the solution I use (Twig with Symfony 4 and Webpack Encore) :
Inside your twig config, declare your public path :
twig:
paths:
"%kernel.project_dir%/public": public_path
Load your svg asset like that :
{{ source('#public_path'~asset('build/images/your_file.svg')) }}
You have to rename your svg file with a twig extension crmpicco-horizontal-logo.svg.twig and do this :
{% include ":svg:crmpicco-horizontal-logo.svg.twig" %}
The folder svg is in app/Ressources/views in this example
The #adrien-lamotte solution was working for inlining svg tag. However I also needed to dynamically add class(es) on the tag.
I ended up coding a specialized Twig extension for loading SVG and adding attributes, so you do:
{{ source(svg_asset('/images/front/connexion.svg'))|add_class('svg-picto') }}
The svg_asset function is just to limit boilerplate; whereas the add_class and add_html_attr filters allows for the SVG DOM manipulation.
The extension class:
<?php
namespace App\Twig\Extension;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Twig\TwigFilter;
class SvgExtension extends AbstractExtension
{
private $assetExt;
public function __construct(
\Symfony\Bridge\Twig\Extension\AssetExtension $assetExt
) {
$this->assetExt = $assetExt;
}
public function getFunctions(): array
{
// We could use a macro also, but this would need to be imported
// each time.
// https://twig.symfony.com/doc/3.x/tags/macro.html
return array(
new TwigFunction('svg_asset', [$this, 'svg_asset_url']),
);
}
public function getFilters(): array
{
return array(
new TwigFilter('add_html_attr', array($this, 'add_html_attr'), [
'is_safe' => ['html'],
]),
new TwigFilter('add_class', array($this, 'add_class'), [
'is_safe' => ['html'],
]),
);
}
public function svg_asset_url($path): string
{
$assetUrl = $this->assetExt->getAssetUrl($path);
return '#public_path/' . $assetUrl;
}
public function add_html_attr(string $html, $attr_name, $attr_value): string
{
// We assume a top level tag, on which will add an attribute
// value (without checking for a prior existence of the attribute key).
// We could use a naive Regex or a DOM library.
// https://github.com/scotteh/php-dom-wrapper#attr
// Or just the plain PHP DOMDocument() https://www.php.net/domdocument.loadhtml.
$doc = new \DOMWrap\Document();
$doc->setLibxmlOptions(LIBXML_HTML_NOIMPLIED);
return $doc
->html($html)
->children()->first()
->attr($attr_name, $attr_value);
}
public function add_class(string $html, $class_value): string
{
return $this->add_html_attr($html, 'class', $class_value);
}
public function getName()
{
return 'svg.extension';
}
}
#public_path is declared in config/packages/twig.yaml:
twig:
paths:
"%kernel.project_dir%/public": public_path
It is important to note you can have a near equivalent solution to target the SVG with CSS, without the overhead: just add an HTML tag wrapper. For eg.
<div class="svg-wrapper">
{{ source('#public_path'~asset('build/images/your_file.svg')) }}
</div>
I have an old project I'm working on using Slim version 2. I can not upgrade to 3.
I'm trying to integrate twig into slim 2 while also keeping the old default slim2 renderer.
Currently I have this.
class TwigView extends \Slim\View
{
public function rendertwig($template,$data = array()){
global $twig;
$twigResults = $twig->render($template,array('test' => '1'));
$data = array_merge($this->data->all(), $data);
return $this->render($twigResults, $data);
}
}
$view = new TwigView();
$config['view'] = $view; //#JA - This command overides the default render method.
//#JA - Intialize Slim
$app = new \Slim\Slim($config);
The idea is that I would call this saying $app->view->rendertwig('file.twig') when I need to render the twig templates and use $app->render('template.php') for all the other templates that use the default slim2 method of templating.
However, I get an error because in my rendertwig function $this->render() function requires a template name for the first parameter. Is there a way I can render directly the results from twig into the slim engine without needing a template file?
I'm aware this is bad form to have two templating engines but eventually I will switch everything to Twig but I need this as a temporary solution till I can patch everything over.
When I inspected slim's view object it has this defined as its render method which will explain the issue.
protected function render($template, $data = null)
{
$templatePathname = $this->getTemplatePathname($template);
if (!is_file($templatePathname)) {
throw new \RuntimeException("View cannot render `$template` because the template does not exist");
}
$data = array_merge($this->data->all(), (array) $data);
extract($data);
ob_start();
require $templatePathname;
return ob_get_clean();
}
I don't know if this is bad form but I did this as a temporary solution.
class TwigView extends \Slim\View
{
public function rendertwig($template,$data = array()){
global $twig;
$twigResults = $twig->render($template,array('test' => '1'));
echo $twigResults;
}
}
I saw that all the render method did was just require the template so I figured its safe to just echo the results from the twig templating engine? This seemed to work from my test.
Using Twig I render a particular view. I need this view to be translated into a language I choose. I display the view using:
return $this->setup->twig->display($view, $params);
Where $view is the name of the *.html.twig template and $params is an array with the parameters I need to pass.
However, if I want to translate the template before displaying it, how I have to do it?
Currently I have included .yml files for different languages and I have also replaced the text inside the views with the appropriate corresponding values from the yml file.
Apart from everything else, I have also loaded the Twig translator in a file separate from the rest of the project. It has the following code:
require dirname(__DIR__) . '/vendor/autoload.php';
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
class Translation
{
public $translator;
public function translator()
{
$this->translator = new Translator('fr_FR');
$this->translator->addLoader('array', new ArrayLoader());
$this->translator->addResource('array', array(
'Symfony is great!' => 'J\'aime Symfony!',
), 'fr_FR');
var_dump($this->translator->trans('Symfony is great!'));
}
}
$show = new Translation;
$show->translator();
And it really displays the translation.
Still, I have no idea how to connect everything together....
Did you try to set the locale before rendering your twig view?
public function exampleAction(Request $request) {
$locale = 'de'; // Set the language
$request->setLocale($locale);
$content = $this->renderView($view, $params);
// Maybe return to default locale....
}
NOTE: UPDATED MY QUESTION
I am using zend.I have the file "stylesettings.php" under css folder. Having the following line to convert php file to css.
header("Content-type: text/css");
stylesetting.php is under application/css/stylesettings.php
Now i want to get the color code from my DB in stylesettings.php.Here i can write basic DB connection code to get values from DB. I guess there might be another way to get all DB values by using zend. How can we connect DB like "Zend_Db_Table_Abstract" in stylesettings file ?
Is it possible to use zend component in that file ? Kindly advice on this.
I hope you understand.
You are breaking the basic separated model assumed in a MVC framework. For such color code, if it's only used in one place, I would suggest that you output the color in the "style="color: <color>"" in-line style in order to keep the dynamic part in HTML and your CSS file static.
If you really want to do this, then you should consider output your dynamic stylesheet in a URL path other than css, and use the controller/views etc to generate the stylesheet.
i am using the following way to apply color settings in layout.phtml
Use below code in bootstrap file
<?php
require_once 'plugins/StyleController.php';
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initRouter() {
$front = Zend_Controller_Front::getInstance ();
$front->setControllerDirectory ( dirname ( __FILE__ ) . '/controllers' );
$router = $front->getRouter ();
$front->registerPlugin ( new StyleController ( $router ) );
}
}
Created folder plugins under application and create a new file called stylecontroller.php
<?php
class StyleController extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
/* code for getting color settings */
$this->settings = new Admin_Model_DbTable_Settings();
$view->colorsettings = $this->settings->getStyleSettings();
//print_obj($view->colorsettings);
}
}
?>
Also to get color code,
<?php
class Admin_Model_DbTable_Settings extends Zend_Db_Table_Abstract
{
public function getStyleSettings()
{
$select = $this->_db->select()
->from('style_settings');
$result = $this->getAdapter()->fetchAll($select);
return $result['0'];
}
}
?>
By using above code i can able to use $this->colorsettings in layout page.
This one fix my dynamic color in layout but not in other template files.