I am trying to learn slim framework and I am following the tutorial. What I would like is a detailed explanation of what the be low snippet of code is doing within the slim environment.
$app->get('/client/{name}'
The reason that I am asking is because in keep getting route not found. But I have yet to figure out why. The base route works. But when I added the twig and tried to route to that. It fails.
Now comes the code:
This part is in my webroot/public/index.php
<?php
use DI\Container;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
use Twig\Error\LoaderError;
require __DIR__ . '/../vendor/autoload.php';
$container = new Container;
$settings = require __DIR__ . '/../app/settings.php';
$settings($container);
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);
// Create Twig
$twigPath = __DIR__ . "/../templates";
$twig = '';
try {
$twig = Twig::create($twigPath, ['cache' => false]);
} catch (LoaderError $e) {
echo "Error " . $e->getMessage();
}
// Add Twig-View Middleware
$app->add(TwigMiddleware::create($app, $twig));
$routes = require __DIR__ . '/../app/routes.php';
$routes($app);
$app->run();
This part is in the routes.php:
<?php
use Slim\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
return function (App $app) {
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write("Hello world! Really?");
return $response;
});
$app->get('/client/{name}', function (Request $request, Response $response, $args) {
$view = Twig::fromRequest($request);
return $view->render($response, 'client_profiles.html', [
'name' => $args['name']
]);
})->setName('profile');
};
The first route works fine the second does not. According to what I am reading. It should work. https://www.slimframework.com/docs/v4/features/templates.html
I feel that if I knew what get is looking to do. I may be able to fix it and build a proper route.
When I dig into the $app->get which connects with the RouterCollecorProxy.php. There is the $pattern variable and $callable. The callable is the anonymous function that comes after the common in the
$app->get('/client/{name}', function <- this is the callable, right?
I see the map class which takes me to the createRoute which returns the $methods, $pattern, callable and a few other things.
I think the pattern is where my problem is.
Related
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...
I would like structure the API in order to separate both the routing organization from actions in separate files.
The current code does not return any errors, but the parameters are not collected correctly.
Is there a simple way to organize into functions without the need for classes, or __invoke?, the application does not require it.
public/index.php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
$app = new \Slim\App;
foreach (glob("../src/middleware/*.php") as $middleware) {
require $middleware;
}
require '../src/routes/routes.php';
$app->run();
src/routes/routes.php
$app->group('/v1', function () use ($app) {
$app->post('/register', 'registerParticipant');
});
src/middleware/registerParticipant.php
require '../lib/qrlib/vendor/qrlib.php';
function registerParticipant($request, $response, $args) {
// demo for testing
$foo= $request->post('foo');
echo "foo= ".$foo;
// more app logic
}
Replacing $foo= $request->post('foo'); with $foo= $request->getParam('foo'); did the trick.
src/middleware/registerParticipant.php
require '../lib/qrlib/vendor/qrlib.php';
function registerParticipant($request, $response, $args) {
// demo for testing
$foo= $request->getParam('foo');
echo "foo= ".$foo;
// more app logic
}
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 am completelly new to Slim. I have used php for the last 3-4 years but I have always done everything from scratch. I want to learn this frameworks for some rest services I have to do.
I have followed a tutorial on the slim webpage to get a simple rest service working but I want to add a log system to see what is happening when something goes wrong or wathever.
This is what I have right know:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../Slim/Slim.php';
\Slim\Slim::requisterAutoloader();
$application = new \Slim\App();
$logger = $application->log;
$logger->setEnabled(true);
$logger->setLevel(\Slim\Log::DEBUG);
$application->get(
'/hello/user',
function ()
{
GLOBAL $logger;
$logger->info("starting the handling function");
echo "<data>response</data>";
$logger->info("ending handling function");
});
$application->run();
?>
I also tried with monolog but I didn't get it working.
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
require '../vendor/autoload.php';
$logger = new \Flynsarmy\SlimMonolog\Log\MonologWriter(array(
'handlers' => array(
new \Monolog\Handler\StreamHandler('./logs/'.date('Y-m-d').'.log'),
),
));
$app = new Slim\App(array(
'log.writer' => $logger,
));
$app->get('/hello/{name}', function (Request $request, Response $response){
$name = $request->getAttribute('name');
$response->getBody()->write("Hello, $name");
//$app->log->writer("hola");
$this->logger->info("Slim-Skeleton '/' route");
return $response;
});
$app->run();
What I would really want is to have a daily log with warnings, debug, info... in the same file. Changing the file every day.
The slim-skeleton application shows how to integrate monolog.
Register the logger with the DI container:
$container['logger'] = function ($c) {
$settings = $c->get('settings')['logger'];
$logger = new \Monolog\Logger('test-app');
$logger->pushHandler(new Monolog\Handler\StreamHandler('php://stdout', \Monolog\Logger::DEBUG));
return $logger;
};
Use it in your closure:
$app->get('/hello/{name}', function (Request $request, Response $response){
$name = $request->getAttribute('name');
$response->getBody()->write("Hello, $name");
$this->get('logger')->info("Slim-Skeleton '/' route");
return $response;
});
The logs will out output to stdout, so you'll see the in your apache error log or if you're using the built-in PHP server, in the terminal.