Silex - Twig_Error_Syntax: The function "path" does not exist - php

According to the Silex documentation:
Symfony provides a Twig bridge that provides additional integration between some Symfony2 components and Twig. Add it as a dependency to your composer.json file.
I include the following in my composer.json file:
{
"require": {
"silex/silex": "1.*",
"twig/twig": ">=1.8,<2.0-dev",
"symfony/twig-bridge": "2.3.*"
}
}
I register the TwigServiceProvider() like so:
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__ . '/views'
));
I'm attempting to use the twig path() method like so:
Log out
The error I get is as follows:
Twig_Error_Syntax: The function "path" does not exist
Why am I getting this error?
I have tried switching around versions to check if it is a version issue
One google groups comment suggested 'registering' the twig bridge provider, but this doesn't exist
I don't want to have to use: app.url_generator.generate in all my templates instead
A temporary solution I have found:
Ensure The UrlGeneratorServiceProvider() is registered:
$app->register(new UrlGeneratorServiceProvider());
Create a new function for twig for path():
$app['twig']->addFunction(new \Twig_SimpleFunction('path', function($url) use ($app) {
return $app['url_generator']->generate($url);
}));
I shouldn't have to do this!! How can I get this working properly?

Hopefully this will help future viewers as many have posted this question without a solid answer, so here is one.
It is literally that you need UrlGeneratorServiceProvider() registered
$app->register(new UrlGeneratorServiceProvider());
Also, as umpirsky mentions in the comments, you need symfony/twig-bridge installed via composer.
You do not need to add your own function. You need both the TwigServiceProvider() and the UrlGeneratorServiceProvider() registered before loading your twig template. This isn't easily apparent from the documentation.

I too had to create a new function for twig for path(), but I improved it a bit to handle a variable number of arguments to allow passing arrays in the twig template:
$app['twig']->addFunction(new \Twig_SimpleFunction('path', function(...$url) use ($app) {
return call_user_func_array(array($app['url_generator'], 'generate'), $url);
}));

Four easy steps.
Create the loader
Create the twig object.
Create you custom function
Add to the Twig object.
use Twig\Environment;
use Twig\TwigFunction;
use Twig\Loader\FilesystemLoader;
$loader = new FilesystemLoader('/twig/templates');
$twig = new Environment($loader, []);
$function = new TwigFunction('url', function () { return 'MyURL'; });
$twig -> addFunction($function);

Related

How to Represent a PHP Closure in YAML?

I'm developing a PHP application using Silex and YAML.
Now I want to represent a PHP closure using the YAML language concept. What's the best way? There's a way to do that?
The following code is an example of what I want to "translate" to YAML.
'users' => function () use ($app) {
return new UserProvider();
}
Thanks!
This is what Symfony does: you first define your User Provider as a service. With Silex you can do it with:
$app['my_user_provider'] = function () use ($app) {
return new UserProvider();
};
Then, in your yaml configuration, you pass the service id that you want use. Something like:
security:
user_provider: my_user_provider

Slim Framework - splitting code into multiple files other than index.php

On the documentation for Slim Framework, it says
In this example application, all the routes are in index.php but in
practice this can make for a rather long and unwieldy file! It’s fine
to refactor your application to put routes into a different file or
files, or just register a set of routes with callbacks that are
actually declared elsewhere.
It doesn't say how to actually do this though. My only thought is that you could split code into multiple PHP files and then use include or require in index.php to reference these.
I'm also not sure what it means by "register a set of routes with callbacks that are actually declared elsewhere"
Does anyone have any thoughts on this, since the application I'm wanting to build might have quite a few routes?
Being a micro-framework, Slim does not enforce any specific method. You can either find a ready-to-use structure (Slim Skeleton Application comes to my mind) or write your own; unlike other frameworks, Slim does not try to protect you from PHP.
Route definitions can be something as simple as an array of strings:
<?php // routes.php
return [
'/' => ['Foo\\Home', 'index'],
'/about' => ['Foo\\Home', 'about'],
'/contact' => ['Foo\\Contact', 'form' ],
];
... which you then load and process in your index.php entry point:
$routes = require('/path/to/routes.php');
foreach ($routes as list($path, $handler)) {
$app->get($route, $handler);
}
And you can leverage the existing Composer set up to auto-load your classes by adding the appropriate directories to composer.json:
{
"require": {
"slim/slim": "^3.3",
"monolog/monolog": "^1.19"
},
"autoload": {
"psr-4": {"Foo\\": "./Foo/"}
}
}
From here, it can get as complex as required: define routes in a YAML file, auto-load from defined classes, etc.
(Code samples are shown for illustration purposes and might not even be valid.)
There're some thoughts on it in Slim documentation
Instead of require's you can use composer autoloading
"register a set of routes with callbacks that are actually declared elsewhere"
From docs:
Each routing method described above accepts a callback routine as its final argument. This argument can be any PHP callable...
So you can do:
$routeHandler = function ($request, $response) { echo 'My very cool handler'; };
$app->get('/my-very-cool-path', $routeHandler);
But usually people use classes instead of functions:
http://www.slimframework.com/docs/objects/router.html#container-resolution
I think you almost get the basic idea right. I recommend reading chapter on routing a couple of times. It covers everything pretty good.
Happy coding and let me know if you need any other help!

Symfony cannot find the template file

I have follow all the steps related to Symfony installation, and I try the examples of the Symfony book (provided by the Symfony web site). Currently I am on Controllers chapter (5) and I try the following code:
namespace MyBundle\FrontBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class HelloController extends Controller
{
public function indexAction($name, Request $request)
{
return $this->redirect($this->generateUrl('front_buy'), 301);
}
public function buyAction(Request $request)
{
return $this->render(
'Hello/buy.html.twig',
array(
'name' => 'Nikos'
)
);
}
}
but I get the following error:
INFO - Matched route "front_buy" (parameters: "_controller": "MyBundle\FrontBundle\Controller\HelloController::buyAction", "_route": "front_buy")
CRITICAL - Uncaught PHP Exception InvalidArgumentException: "Unable to find template "Hello/buy.html.twig"." at /var/www/projects/symfony/vendor/symfony/symfony/src/Symfony/Bridge/Twig/TwigEngine.php line 128
Context: {"exception":"Object(InvalidArgumentException)"}
I know is not something fancy, but I don't know how to fix the problem.
My view file is under the following path : ./src/MyBundle/FrontBundle/Resources/views/Hello/buy.html.twig.
You need to render it with the following syntax:
$this->render('AcmeBlogBundle:Blog:index.html.twig')
or with this syntax
$this->render('#BlogBundle/Blog/index.html.twig')
An Example:
$this->render('#FrontBundle/Hello/buy.html.twig)
More information can be found on the documentation, also refering to symfonys best practices templates should be stored in app/Ressources/views
in "app/config/config.yml" be sure to have this:
framework:
# ...
templating:
engines: ['twig']
In my case, the problem was really related to the specific version of Symfony.
My project used to be run with Symfony 2.8.19. I tried to migrate it to another Linux
evironment (uning symfony2.8.42) and then I got the very same error with the same code (very wierd).
I tried the solutions mentioned before and none worked like using :
$this->render('#BlogBundle/Blog/index.html.twig')
or
$this->render('AcmeBlogBundle:Blog:index.html.twig').
After several tries, I found the problem. In fact, in my old env, I had :
return $this->render('XxxxxBundle:Default:zzzz.html.twig';
But the problem was with Capitalized Default because the real path was with an uncapitalized default
so changing it to the following fixed the problem in my new env:
return $this->render('XxxxxBundle:default:zzzz.html.twig';

Adding a view to Slim Views Framework with composer

I am writing a PHP template system for Slim, I have it working fine, but it is necessary to install the view file Ets.php in the correct existing location:
vendor/slim/views/Slim/Views/Ets.php
Whilst I can do it manually of course this defeats the object of composer. I was wondering if I can do it with https://getcomposer.org/doc/articles/custom-installers.md but I am having trouble following the guide as it and others only really talk about installing outside of the vendor directory.
Why do you want the views to get installed in the same place?
Have a look into http://docs.slimframework.com/#Custom-Views
You just need to extend the Slim\View. An example taken from the docs
class CustomView extends \Slim\View
{
public function render($template)
{
return 'The final rendered template';
}
}
and integrate in to slim like
$app = new \Slim\Slim(array(
'view' => new CustomView()
));
NB : Don't forget to do the autoload the classes required.

PHP Silex Framework can't add Twig_Extension_StringLoader extension

I am trying to use template_from_string as stated on
http://twig.sensiolabs.org/doc/functions/template_from_string.html
How can I do that from Silex? I see that the Twig/Exteion/StringLoader.php file is there. Here is the code I've tried
$app['twig'] = $app->share($app->extend('twig', function($twig, $app) {
$twig->addExtension(new MarkdownExtension());
$twig->addExtension(new Twig_Extension_StringLoader());
return $twig;
}));
But when I try to use it like
return $app['twig']->template_from_string(
"The is the {{ title }}",
array('title' => 'Hello')
);
It generates following error
Fatal error: Call to undefined method Twig_Environment::template_from_string()
What I am trying to do is fetch the template content from DB or another file, then render it with Twig instead of using a template file, so I can combine several section templates into the main template. Or if there a better way?
Please note that I already know how to use insert within the template file like
{% include 'home-section.html.twig' %}
but this won't solve my problem because it can not fetch the content data to be parsed automatically.
Thank you.
Just had to create another twig object
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));

Categories