How to use templates with Slim? - php

http://www.slimframework.com/docs/tutorial/first-app.html shows using "plain old PHP" (Composer package is php-view and class is PhpRenderer) for templates as follows:
<?php
// Create app
$app = new \Slim\App();
// Get container
$container = $app->getContainer();
$container['view'] = new \Slim\Views\PhpRenderer("../templates/");
$app->get('/tickets', function (Request $request, Response $response) {
$this->logger->addInfo("Ticket list");
$mapper = new TicketMapper($this->db);
$tickets = $mapper->getTickets();
$response = $this->view->render($response, "tickets.phtml", ["tickets" => $tickets]);
return $response;
});
// Run app
$app->run();
The above page states using Twig for templates is basically the same, but http://www.slimframework.com/docs/features/templates.html shows a very different approach. Which is the correct way to use templates, and specifically how should I use Twig for templates?
<?php
// Create app
$app = new \Slim\App();
// Get container
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('path/to/templates', [
'cache' => 'path/to/cache'
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
// Render Twig template in route
$app->get('/hello/{name}', function ($request, $response, $args) {
return $this->view->render($response, 'profile.html', [
'name' => $args['name']
]);
})->setName('profile');
// Run app
$app->run();

Related

Slim 4 assign twig parameters from middleware

I'm trying to upgrade my website's code from Slim v2 to v4. I'm not a hardcore programmer so I'm facing issues.
In Slim v2 I had some middleware where I was able to assign parameters to the Twig view before the route code executed.
Now I'm trying to manage the same with Slim v4 but without success.
I have a container:
$container = new \DI\Container();
I have the view:
$container->set('view', function(\Psr\Container\ContainerInterface $container) {
return Twig::create(__DIR__ . '/views');
});
I try to use this from middleware:
$this->get('view')->offsetSet('fbloginurl', $loginUrl);
But nothing append when the view rendered.
If I try to use the same from the route inside, its working fine.
Example route:
$app->get('/', function ($request, $response, $args) {
$params = array(...);
return $this->get('view')->render($response, 'index.html', $params);
});
There are two possible failures. First, the DI container may always return a new instance, thus it doesn't store the variables in the correct instance and they are not rendered in the twig template. Second, you use a different approach in your route sample. You pass the variables via your $params variable and they are given into the template by this way.
So you may store $this->get('view') in a variable or pass the variables as the third parameter of $params.
EDIT: You could also check, if your variable in your DI\Container already exists and then just return the instance.
So this is a test code:
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Routing\RouteContext;
require 'vendor/autoload.php';
require 'config.php';
lib\Cookie::init();
$container = new \DI\Container();
$container->set('view', function($container) {
return Twig::create(__DIR__ . '/views');
});
$container->set('flash', function ($container) {
return new \Slim\Flash\Messages();
});
$container->get('view')->getEnvironment()->addGlobal('flash', $container->get('flash'));
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->addErrorMiddleware(true, false, false);
$fb = new Facebook\Facebook([
'app_id' => '...',
'app_secret' => '...',
'default_graph_version' => '...',
]);
$beforeMiddleware = function (Request $request, RequestHandler $handler) use ($fb) {
$response = $handler->handle($request);
if (!isset($_SESSION['fbuser'])) {
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email'];
$loginUrl = $helper->getLoginUrl('...', $permissions);
$this->get('view')->offsetSet('fbloginurl', $loginUrl);
}
else {
$this->get('view')->offsetSet('fbuser', $_SESSION['fbuser']);
}
$uri = $request->getUri();
$this->get('view')->offsetSet('currenturl', $uri);
return $response;
};
$app->add($beforeMiddleware);
$app->get('/test', function (Request $request, Response $response, $args) {
$oViewParams = new \lib\ViewParams("home", "", "", "", "");
$oProfession = new \models\Profession();
$oBlogPost = new models\BlogPost();
$oBlogTopic = new models\BlogTopic();
$professions = $oProfession->getProfessionsWithLimit(14);
$posts = $oBlogPost->getMainPagePosts();
echo $this->get('view')->offsetGet('fbloginurl');
$params = array('professions' => $professions,
'posts' => $posts,
'viewp' => $oViewParams->getMassParams());
return $this->get('view')->render($response, 'index.html', $params);
});
$app->run();
When I use echo $this->get('view')->offsetGet('fbloginurl'); within the middleware it shows up. When I use the same within the route there is nothing show up...

Slim Twig View return $view as null when used in render function

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');
});

Slim v3 and twig ( View Page displays page not found error)

I have installed slim framework 3 and twig template following the composer.
When i call function http://localhost/elec/helloo/sandesh it displays Hello, Sandesh as followed on slim 3 documentation.
But when i try to call view page(inside templates folder).
It displays an error page Slim Application Error The application could not run because of the following error Error Description
Code Worked ( displays hello , {name} from function)
$app = new \Slim\App;
$app->get('/hello/{name}', function (Request $request, Response $response) {
$name = $request->getAttribute('name');
$response->getBody()->write("Hello, $name");
return $response;
});
Code error ( displays error when called view page from function)
$settings = [
'settings' => [
'displayErrorDetails' => true,
],
];
$app = new Slim\App($settings);
// Get container
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
return new \Slim\Views\PhpRenderer("templates/");
};
// Render Twig template in route
$app->get('/helloo/{name}', function ($request, $response, $args) {
return $this->view->render($response, 'view1.html', [
'name' => $args['name']
]);
})->setName('profile');
Path Detail
elec>
>>cache
>>templates
>>>view1.html
>>vender
>>.htaccess
>>composer.json
>>composer.lock
>>index.php
When passing the templates location, you have to provide a full path, (starting from the location of the running index.php file:
<?php
$container['view'] = function ($container) {
return new \Slim\Views\PhpRenderer(__DIR__ . "/../path/to/templates/");
};
try it out, and good luck.
Note: I'm using the same line but with Twig render:
<?php
$container['view'] = function ($container) {
return new \Slim\Views\Twig(__DIR__ . "/../path/to/templates/");
};
$app = new \Slim\App([
'settings' => [
'displayErrorDetails' => true,
]
]);
// Calling twigview from controller
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('templates/views',[
'cache' => false,
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container->router,
$container->request->getUri()
));
return $view;
};
$app->get('/home', function ($request, $response) {
return $this->view->render($response, 'home.twig');
});

Set template directory using Slim Framework 3

Using Slim Framework 2 you could set the template directory using this code:
// Views
$view = $app->view();
$view->setTemplateDirectory('../app/views');
How can I do this using Slim Framework 3?
Currently I'm getting this error:
Fatal error: Call to a member function setTemplateDirectory() on null
Does anybody know how to do this in Slim Framework 3?
You can do it using a \Slim\Container instance:
// Create container
$container = new \Slim\Container;
// Register component on container
$container['view'] = function ($c) {
$view = new \Slim\Views\Twig('your/path/to/templates');
$view->addExtension(new \Slim\Views\TwigExtension(
$c['router'],
$c['request']->getUri()
));
return $view;
};
Then you can use it:
$app = new \Slim\App($container);
// The route
$app->get('/foo', function (ServerRequestInterface $request, ResponseInterface $response) {
return $this->view->render($response, 'index.html', [
'name' => 'name'
]);
});
$app->run();
Check the official documentation (Mika Tuupola's suggestion).

Using a RouteCollectionProvider in Silex

I have a custom Silex\RouteCollection which I want to register...
class RouteCollectionProvider extends RouteCollection
{
public function __construct() {
$this->add(
'Index',
new Route('/', array(
'method' => 'get',
'controller' => 'index',
'action' => 'index'
)
));
}
}
...during the bootstrapping:
$app = new Silex\Application();
/** here **/
$app->run();
I could use:
$app = new Silex\Application();
$routes = new RouteCollectionProvider();
foreach ($routes->getIterator() as $route) {
$defaults = $route->getDefaults();
$pattern = $route->getPath();
$callback = 'Controller\\'
. ucfirst($defaults['controller'])
. 'Controller::'
. $defaults['action']
. 'Action';
$app->get($pattern, $callback);
}
$app->run();
I don't like having the initialization of those routes right in there.
Do you know any spot in Silex, where this does fit better?
I cannot use $app->register() because it's getting called too late and the routes won't get active in there.
Maybe there is an event I can use with
$app->on('beforeCompileRoutesOrSomething', function() use ($app) {
// initialize routes
}
Or a hook in the Dispatcher?
My aim is to not have a big collection of $app->get() or $app->post() in there. I also know I can ->mount() a controller but then still I have all my get definitions in my bootstrap and not in a Provider.
This post solves the problem: Scaling Silex pt. 2.
$app = new Application;
$app->extend('routes', function (RouteCollection $routes, Application $app) {
$routes->addCollection(new MyCustomRouteCollection);
return $routes;
});
$app->run();

Categories