Im having trouble understanding how to access the instance of Slim when a route is in a seperate class than index.php
When using Slim Framework 2 I always used the follo
With Slim 3 RC2 and onwards given a route of:
$app->get('/test','MyController:test');
The CallableResolver
will look for a key in the DIC called 'MyController'
and expect that to return the controller, so you can register with the DIC like this:
// Register controller with DIC
$container = $app->getContainer();
$container['MyController'] = function ($c) {
return new MyController($c->get('rdb'));
}
// Define controller as:
class MyController
{
public function __construct($rdb) {
$this->rdb = $rdb;
}
public function test($request,$response){
// do something with $this->rdb
}
}
Alternatively, if you don't register with the DIC, then the CallableResolver
will pass the container to your constructor, so you can just create a controller like this:
class MyController
{
public function __construct($container) {
$this->rdb = $container->get('rdb');
}
public function test($request,$response){
// do something with $this->rdb
}
}
This was a tough one. @mgansler answer was really helpful, but in his answer he passed a database connection, and not exactly $app inside the controller
Following the same idea it is possible to send $app though.
First inside your dependencies.php you need to grab the $app and throw it in a container to inject it to the Controller later.
$container['slim'] = function ($c) {
global $app;
return $app;
};
Then you got to inject it:
// Generic Controller
$container['App\Controllers\_Controller'] = function ($c) {
return new _Controller($c->get('slim'));
};
Now on your controller.php:
private $slim;
/**
* @param \Psr\Log\LoggerInterface $logger
* @param \App\DataAccess $dataaccess
* @param \App\$app $slim
*/
public function __construct(LoggerInterface $logger, _DataAccess $dataaccess, $slim)
{
$this->logger = $logger;
$this->dataaccess = $dataaccess;
$this->slim = $slim;
}
Now you just got call it like this:
$this->slim->doSomething();
Have a look at the Slim 3 Skeleton created by Rob Allen.
Slim 3 heavily uses dependency injection, so you might want to use it too.
In your dependencies.php
add something like:
$container = $app->getContainer();
$container['rdb'] = function ($c) {
return $conn;
};
$container['Your\Custom\Class'] = function ($c) {
return new \Your\Custom\Class($c['rdb']);
};
And in your Your\Custom\Class.php
:
class Class {
private $rdb;
function __construct($rdb) {
$this->rdb = $rdb;
}
public function test($request, $response, $args) {
$this->rdb->doSomething();
}
}
I hope this helps, if you have any more questions feel free to ask.
Update:
When you define your route like this
$app->get('/test', '\mycontroller:test');
Slim looks up \mycontroller:test
in your container:
$container['\mycontroller'] = function($c) {
return new \mycontroller($c['rdb']);
}
So when you open www.example.com/test
in your browser, Slim automatically creates a new instance of \mycontroller
and executes the method test
with the arguments $request
, $response
and $args
.
And because you accept the database connection as an argument for the constructor of your mycontroller
class, you can use it in the method as well :)
I created the following base controller and extended from that. Only just started playing with Slim but it works if you need access to to the DI in your controllers.
namespace App\Controllers;
use Interop\Container\ContainerInterface;
abstract class Controller
{
protected $ci;
/**
* Controller constructor.
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->ci = $container;
}
/**
* @param $name
* @return mixed
*/
public function __get($name)
{
if ($this->ci->has($name)) {
return $this->ci->get($name);
}
}
}
Then in your other controllers you can use it like this.
namespace App\Controllers;
/**
* Class HomeController
*
* @package App\Controllers
*/
class HomeController extends Controller
{
/**
* @param $request
* @param $response
* @param $args
* @return \Slim\Views\Twig
*/
public function index($request, $response, $args)
{
// Render index view
return $this->view->render($response, 'index.twig');
}
}
Important
I upvoted @mgansler and you should read that first if dealing with slim 3, and read this only if interested in differences to slim 2.
Update
So it seems those usages were just old code no one cleaned.
However im leaving this post here as it should be helpful to anyone using Slim 2 (as slim 3 is very much still beta) and as a referance point to help see differences.
Old Update (see above)
Following update of OP, i looked at github source code and found that getInstance is still very much there, but with some slight differences perhaps...
https://github.com/slimphp/Slim/search?utf8=%E2%9C%93&q=getInstance
Test files (which maybe outdated, but unlikely) show something like this:
public function testGetCallableAsStaticMethod()
{
$route = new \Slim\Route('/bar', '\Slim\Slim::getInstance');
$callable = $route->getCallable();
$this->assertEquals('\Slim\Slim::getInstance', $callable);
}
But at the same time we see calls like this in some files, which are obviously contextual and either return diff object ($env) or are in same static file (Slim.php)
$env = \Slim\Environment::getInstance(true);
static::getInstance();
But this does show the static function still exists, so use my examples below and try to figure out why not working for you in current form.
Also, this 'maybe' of interest, as only obvious example of slim3 in usage: https://github.com/akrabat/slim3-skeleton
Though other projects prob exist, search with github filters if still having issues.
Original Answer content
Please include more detail on the route and the other class, but here are 3 ways, with execution examples detailed further down.
This info does relate to Slim Framework 2, not the Slim 3 beta, but slim 3 beta shows similar example code and makes no mention of overhauling changes, and in fact links to the Slim 2 documentation: http://docs.slimframework.com/configuration/names-and-scopes/
$this->app->getContainer()->get('rdb');
// Recommended approach, can be used in any file loaded via route() or include()
$app = \Slim\Slim::getInstance();
Slim::getInstance();
App::config('filename');
Slim3 Beta has only one code example, which looks like this:
$app = new \Slim\App();
// which would by extension mean that this 'might' work too
$app = \Slim\App::getInstance();
// but be sure to try with slim2 naming just in case
$app = \Slim\Slim::getInstance()
Though obviously this doesnt fit outside of index.php, but is consistent with Slim2 doco showing GetInstance works.
Which one fits you?
I have multiple files that use these different approaches, though i cant say what fits best as too little context on how this external class fits in and what its composition is.
For example, my controllers (which are endpoints of most my routes) use the same approach, through a base class or just direct:
class ApiBaseController /// extends \BaseController
{
protected $app;
protected $data;
public function __construct()
{
$this->app = Slim\Slim::getInstance();
$this->data = array();
}
//...
}
class VideoApiController extends \ApiBaseController
{
// ...
public function embed($uid)
{
// trace($this->app->response->headers());
$vid = \R::findOne('videos'," uid = ? ",array($uid));
if(!empty($vid))
{
// embed logic
}else{
// see my baseclass
$this->app->render('api/404.html', array(), 404);
}
}
// ...
// Returns the video file, keeping actual location obscured
function video($uid)
{
require_once(APP_PATH.'helpers/player_helper.php');
$data = \R::findOne('videos'," uid = ? ",array($uid));
/// trace($_SERVER); die();
if($data)
{
stream_file($data['filename']);
}else{
$app = \Slim\Slim::getInstance();
$app->render('404.html');
}
/// NOTE - only same domain for direct /v/:uid call
header('Access-Control-Allow-Origin : '.$_SERVER['HTTP_HOST']);
// header('X-Frame-Options: SAMEORIGIN');
// Exit to be certain nothing else returned
exit();
}
//...
}
My helper files show code like this:
function get_permissions_options_list($context = null)
{
if(empty($context)) $context = 'user';
return App::config('permissions')[$context];
}
My middleware:
function checkAdminRoutePermissions($route)
{
$passed = runAdminRoutePermissionsCheck($route);
if($passed)
return true;
// App::notFound();
// App::halt(403, $route->getPattern());
if(!Sentry::check())
App::unauthorizedNoLogin();
else
App::unauthorized();
return false;
}
Thats example of how i access in the various files, though the code you shared already shows that you have used the recommended approach already
$app = \Slim\Slim::getInstance();
Though again, need more info to say for sure how your external file fits in, but if its at the end of a route or in an 'include()', then it should work.
You said your old approach didnt work though, but gave no info on what the actual result vs expected result was (error msg, ect), so if this doesnt work please update the OP.