I'm following the steps described here to use twig-view within Slim https://github.com/slimphp/Twig-View/tree/3.1.0#usage but I'm getting the following error on my screen when I try to use anyof the template functions used in TwigExtension
Fatal error: Uncaught Twig\Error\SyntaxError: Unknown "url_for" function.
I have run $ composer require slim/twig-view:^3.0 successfully, my composer.json file looks like this
"require": {
"slim/slim": "4.*",
"slim/psr7": "^1.2",
"league/container": "^3.3",
"slim/twig-view": "^3.0"
},
and this is my code
require_once __DIR__ . '/../vendor/autoload.php';
$container = new \Slim\Factory\Container();
\Slim\Factory\AppFactory::setContainer($container);
$container->add('view', function () {
return \Slim\Views\Twig::create(__DIR__ . '/views', [
'cache' => false,
]);
});
$app = \Slim\Factory\AppFactory::create();
$app->add(\Slim\Views\TwigMiddleware::createFromContainer($app));
require_once __DIR__ . '/../routes.php';
// routes.php
$app->get('/', function ($request, $response, $args) use ($container) {
return $container->get('view')->render($response, 'home.twig', ['foo' => 'test']);
})->setName('home');
// home.twig
...
<body>
Home {{ foo }}
<br>
About
</body>
...
If I remove the url_for from the twig template the page loads fine on the browser. I tried to search for TwigExtension in my codebase and the vendor folder, but can't find any file like that.
Am I doing something wrong here?
Looks like it's because of League container. It seems to be creating a new instance of Twig every time the function gets called $container->get('view') returns a new instance every time instead of referencing the same one. So a workaround would be
$twig = \Slim\Views\Twig::create(__DIR__ . '/views', [
'cache' => false,
]);
$container->add('view', function () use (&$twig) {
return $twig;
});
// Or this instead
$container->add(
'view',
\Slim\Views\Twig::create(__DIR__ . '/views', [
'cache' => false,
])
);
Related
I'm trying to add twig-view in slim v4
In slim v3, we add twig-view in container
$container['view'] = function ($c) {
$view = new \Slim\Views\Twig('path/to/templates', [
'cache' => 'path/to/cache'
]);
// Instantiate and add Slim specific extension
$router = $c->get('router');
$uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER));
$view->addExtension(new \Slim\Views\TwigExtension($router, $uri));
return $view;
};
but I can't add twig like that in slim v4
Update: Twig-View has reached a stable version and the docs are updated to address Slim 4 integration.
If you are still using an unstable version of Twig-View, please consider upgrading.
First, you need to add Twig-View package to your project:
composer require slim/twig-view
And assuming the following directory structure:
composer.json
cache/
public/
|--index.php
templates/
|--hello.twig
vendor/
|--autoload.php
The followings are two working examples:
If you use a container (which is optional according to Slim 4 docs), you can add Tiwg creation definition to the container and use it when required. (I'm using php-di/php-di in this example, but you can use any PSR compatible dependency container.)
index.php, using a container:
<?php
use DI\Container;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
require __DIR__ . '/../vendor/autoload.php';
// Create Container
$container = new Container();
AppFactory::setContainer($container);
// Set view in Container
$container->set('view', function() {
return Twig::create(__DIR__ . '/../templates',
['cache' => __DIR__ . '/../cache']);
});
// Create App
$app = AppFactory::create();
// Add Twig-View Middleware
$app->add(TwigMiddleware::createFromContainer($app));
// Example route
$app->get('/hello/{name}', function ($request, $response, $args) {
return $this->get('view')->render($response, 'hello.twig', [
'name' => $args['name']
]);
});
// Run the app
$app->run();
You can also skip the container creation, but in that case you need to create the Twig instance before trying to render a template.
index.php, without a container:
<?php
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
require __DIR__ . '/../vendor/autoload.php';
// Create App
$app = AppFactory::create();
// Create Twig
$twig = Twig::create(__DIR__ . '/../templates',
['cache' => __DIR__ . '/../cache']);
// Add Twig-View Middleware
$app->add(TwigMiddleware::create($app, $twig));
// Example route
// Please note how $view is created from the request
$app->get('/hello/{name}', function ($request, $response, $args) {
$view = Twig::fromRequest($request);
return $view->render($response, 'hello.twig', [
'name' => $args['name']
]);
});
// Run the app
$app->run();
hello.twig:
Hello {{ name }}
Now try visiting /hello/slim4 in your browser and the output will be:
Hello slim4
SlimTwigView is at 3.0.0 beta (at least as of October 12, 2019), and some things have changed. The few online tutorials I've seen, as well as the official documentation no longer work.
TwigMiddleware no longer takes an instance of the $container as an argument, so you must first put Twig on the Container manually such as:
$container->set('view', function() {
// Of course put correct path to your views here
return new Twig('../views', ['cache' => false]);
});
You then you can add TwigMiddleware to your Slim App using the class' new createFromContainer method, like so:
$app->add(TwigMiddleware::createFromContainer($app));
// which is equivalent to:
// $app->add(TwigMiddleware::createFromContainer($app, 'view'));
At that point, you can render a Twig view like so:
$app->get('/', function (Request $request, Response $response, $args) {
return $this->get('view')->render($response, 'home.twig');
});
When using the Slim specific middleware, you now have access to the additional Twig extensions:
url_for
full_url_for
is_current_url
current_url
get_uri
Well! In my case I was using Slim 4.0 and Twig ^2.5. All I added to my code was
$container->set('view', function () use ($container) {
$view = new \Slim\Views\Twig(
__DIR__ .'/Templates'
, [ 'cache' => false ] //you can turn on caching by providing string path to cache or set to false
);
return $view;
});
Hello I am having an issue while rendering the page, i hope someone can help me with it.
I have tried changing the directory structure as well creating a new project with similar code , but nothing works for me .
routes.php
<?php
$app->get('/home' , function() {
return $this->view->render($response,'home.twig');
});
app.php
<?php
session_start();
require __DIR__ . '/../vendor/autoload.php';
$app = new \Slim\App([
'settings'=> [
'displayErrorDetails' => true,
]
]);
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig(__DIR__.'/../resources/views', [
'cache' => __DIR__.'../cache',
]);
// Instantiate and add Slim specific extension
$view->addExtension(new Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
require __DIR__ . '/../app/routes.php';
index.php
<?php
require __DIR__ . '/../bootstrap/app.php';
$app->run();
See Slim templates section.
The closure needs extra parameters in routes.php:
// Render Twig template in route
$app->get('/home', function ($request, $response) {
return $this->view->render($response, 'home.twig');
});
I'm building a simple website in PHP with Slim Framework and Twig template engine.
I've installed Slim and Twig with Composer in the Command Line.
This is my index.php
<?php
require __DIR__ . '/vendor/autoload.php';
date_default_timezone_set('Europe/Copenhagen');
$app = new Slim\App( array (
'view' => new Slim\Views\Twig()
));
$view = $app->view();
$view->parserOptions = array(
'debug' => true
);
$view->parserExtensions = array(
new \Slim\Views\Twig(),
);
$app->get('/', function() use($app){
$app->render('about.twig');
});
$app->get('/contact', function() use($app){
$app->render('contact.twig');
});
$app->run();
?>
The error message is:
Fatal error: Class 'Slim\Views' not found in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\projects\simple-php-website\vendor\slim\views\Twig.php on line 46
It works without the Twig framework. So I guess the trouble is on loading the Twig. I've tried different variations of this line:
'view' => new Slim\Views\Twig()
But what confuses me is, that the error message is referring to line 46 in the Twig.php - which is in the core of slim.
I've tried reinstalling Twig and Slim several times.
Any suggestions what is wrong?
Much appreciated!
EDIT
This is from my composer.json
{
"name": "tyf5vl/simple-php-website",
"authors": [
{
"name": "My Name",
"email": "my#mail.com"
}
],
"require": {
"monolog/monolog": "^1.17",
"slim/slim": "^3.1",
"twig/twig": "^1.23",
"slim/views": "^0.1.3"
}
}
http://www.slimframework.com/docs/features/templates.html
states that ONLY view is this -> composer require slim/twig-view
you should have final file as
{
"require": {
"slim/slim": "^3.5",
"slim/twig-view": "^2.1"
}
}
In Silex I am able to use Twig templates but I want to use the PHP engine of Twig, instead of the Twig syntax. For example this guide describes how to do it for Symfony but not Silex.
My Silex index.php looks like:
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/views',
));
$app->get('/', function() use ($app) {
return $app['twig']->render('index.html.php', array(
'name' => 'Bob',
));
});
My index.html.php looks like:
<p>Welcome to the index <?php echo $view->name; ?></p>
When I run the app in the browser and view the source, I see the literal string <?php echo $view->name; ?> which hasn't been executed.
I suspect there may be a Twig config setting to tell it I want to use the PHP style templates. To clarify, if I use the Twig syntax instead, e.g.:
<p>Welcome to the index {{ name }} </p>
Then it works and I see the name Bob, therefore I know this is not a web server or PHP config problem.
If you want to mimic this behaviour in Silex, you would need to install the TwigBridge via Composer. Then build the templating service the same way Symfony does.
This solution works as I have tested it successfully.
<?php
require __DIR__.'/vendor/autoload.php';
use Silex\Application;
use Symfony\Component\Templating\PhpEngine;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Component\Templating\Loader\FilesystemLoader;
use Symfony\Component\Templating\DelegatingEngine;
use Symfony\Bridge\Twig\TwigEngine;
$app = new Application();
$app['debug'] = true;
// Register Twig
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/views',
));
// Build the templating service
$app['templating.engines'] = $app->share(function() {
return array(
'twig',
'php'
);
});
$app['templating.loader'] = $app->share(function() {
return new FilesystemLoader(__DIR__.'/views/%name%');
});
$app['templating.template_name_parser'] = $app->share(function() {
return new TemplateNameParser();
});
$app['templating.engine.php'] = $app->share(function() use ($app) {
return new PhpEngine($app['templating.template_name_parser'], $app['templating.loader']);
});
$app['templating.engine.twig'] = $app->share(function() use ($app) {
return new TwigEngine($app['twig'], $app['templating.template_name_parser']);
});
$app['templating'] = $app->share(function() use ($app) {
$engines = array();
foreach ($app['templating.engines'] as $i => $engine) {
if (is_string($engine)) {
$engines[$i] = $app[sprintf('templating.engine.%s', $engine)];
}
}
return new DelegatingEngine($engines);
});
// Render controllers
$app->get('/', function () use ($app) {
return $app['templating']->render('hello.html.twig', array('name' => 'Fabien'));
});
$app->get('/hello/{name}', function ($name) use ($app) {
return $app['templating']->render('hello.html.php', array('name' => $name));
});
$app->run();
You would need at least these dependencies to achieve this in your composer.json
"require": {
"silex/silex": "~1.0",
"symfony/twig-bridge": "~2.0",
"symfony/templating": "~2.0",
"twig/twig": "~1.0"
},
My question: How do I permit use of debug in Twig templates within Silex?
I'm playing around with the Silex micro-framework (a PHP framework that leverages Symfony).
When using the Twig template system with it I wanted to output a particular object. Normally I would do this with var_dump($app); and in Twig with {% debug app %}.
My problem is getting debug (and setting Silex's own debug to true does not help with Twig) to work with Silex. Out of the box a call to debug will result in an error message:
Twig_Error_Syntax: Unknown tag name "debug" in...
The call to debug looks like this:
{% debug app %}
I have found references to how to configure Twig's config.yml file to correctly use debug but Silex does not use a config file for Twig.
Silex does say you can set options via passing an associative array to twig.options and while Twig docs say you can pass an environment option like:
$twig = new Twig_Environment($loader, array('debug' => true));
Trying to pass it in Silex like:
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.options' => array('debug' => true),
));
Does not work. Is this the wrong sort of option? Simply incorrect formatting? I've no idea and nothing I have tried works.
I sense myself getting into "wheel spinning" mode so I am asking here on SO in hopes that I can move on to more productive work this morning. :)
(ugh... how's that for a hyper-specific StackOverflow question?)
Solution: (all this just to get var_dump like functionality... oh my): This was a bit of a pain in the butt, to be honest, and the Silex docs were of no help whatsoever in discovering this but here is what I had to do to get this to work.
First load the Twig autoloader:
$app['autoloader']->registerPrefixes(array(
'Twig_Extensions_' => array(__DIR__.'/vendor/Twig-extensions/lib')));
Why do you have to register it this way? No idea. How does it actually find the autoloader? No idea. But it works.
Register the provider and set the debug option:
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/views',
'twig.class_path' => __DIR__.'/vendor/Twig/lib',
'twig.options' => array('debug' => true), //<-- this is the key line to getting debug added to the options
));
And finally (the best part):
$oldTwigConfiguration = isset($app['twig.configure']) ? $app['twig.configure']: function(){};
$app['twig.configure'] = $app->protect(function($twig) use ($oldTwigConfiguration) {
$oldTwigConfiguration($twig);
$twig->addExtension(new Twig_Extensions_Extension_Debug());
});
To be honest, I think that's enough Silex for me.
Credit for this solution goes to Nerdpress.
*ninja edit: a year and a half later I have to say that Silex was a dud for me. I have been using Slim for all micro-framework needs and it is fantastic. Gets the job done quickly, cleanly, simply and easily.
I completely removed the old answer to show the output from a little example-app I built:
composer.json:
{
"require": {
"silex/silex": "1.*",
"twig/twig": "1.*",
"twig/extensions": "*"
}
}
app.php:
require_once __DIR__ . '/../vendor/.composer/autoload.php';
$app = new Silex\Application();
$app['debug'] = true;
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__ . '/views',
'twig.options' => array('debug' => true)
));
$app['twig']->addExtension(new Twig_Extensions_Extension_Debug());
$app->get('/', function () use ($app) {
return $app['twig']->render('debug_test.twig', array('app' => $app));
});
$app->run();
for silex ^2.2 using pimple 3 the share() has been removed so use:
$app->extend('twig', function($twig, $app) {
$twig->addExtension(new Twig_Extension_Debug());
return $twig;
});
It has been a while now so I did a small update to the accepted answer, you can use the new extend method of Pimple:
composer.json:
"silex/silex": "~1.3",
"twig/twig": "^1.23",
"symfony/twig-bridge": "^2.7",
"twig/extensions": "^1.3"
index.php (front controller)
/*
* config
*/
//...
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/../templets',
'twig.options' => array('debug' => true),
)
);
$app['twig'] = $app->share($app->extend('twig', function($twig, $app) {
$twig->addExtension(new Twig_Extension_Debug());
return $twig;
}));
//...
/*
* some static page
*/
$app->get('/', function () use($app) {
return $app['twig']->render('index.twig');
});
$app->run();