Доступ к приложению в классе в Slim Framework 3

У меня возникли проблемы с пониманием того, как получить доступ к экземпляру Slim, когда маршрут находится в отдельном классе, чем index.php

При использовании Slim Framework 2 я всегда использовал следующее, но не работал в Slim 3:

$this->app = \Slim\Slim::getInstance(); 

Я пытаюсь получить доступ к соединению базы данных, которое у меня установлено в контейнере, но из отдельного класса. Это то, что я получил в моем index.php для запуска Slim-приложения:

 require_once("rdb/rdb.php"); $conn = r\connect('localhost'); $container = new \Slim\Container; $container['rdb'] = function ($c){return $conn;} $app = new \Slim\App($container); 

И вот мой маршрут:

 $app->get('/test','\mycontroller:test'); 

И это то, что я получил в моем классе mycontroller.php, на который указывает мой маршрут, который, очевидно, не работает как $ this-> app, не существует:

 class mycontroller{ public function test($request,$response){ $this->app->getContainer()->get('rdb'); } 

Сообщение об ошибке следующее: из-за того, что getinstance не является частью Slim 3 по сравнению с Slim 2:

 Call to undefined method Slim\App::getInstance() 

Благодарный за любую помощь,

С уважением Дэн

Посмотрите на Слайм 3 Скелет, созданный Робом Алленом.

Slim 3 сильно использует инъекцию зависимостей, поэтому вы также можете использовать его.

В вашем dependencies.php добавьте что-то вроде:

 $container = $app->getContainer(); $container['rdb'] = function ($c) { return $conn; }; $container['Your\Custom\Class'] = function ($c) { return new \Your\Custom\Class($c['rdb']); }; 

И в вашем Your\Custom\Class.php :

 class Class { private $rdb; function __construct($rdb) { $this->rdb = $rdb; } public function test($request, $response, $args) { $this->rdb->doSomething(); } } 

Надеюсь, это поможет, если у вас возникнут вопросы, вы можете спросить.

Обновить:

Когда вы определяете свой маршрут следующим образом

 $app->get('/test', '\mycontroller:test'); 

Slim смотрит вверх \mycontroller:test в вашем контейнере:

 $container['\mycontroller'] = function($c) { return new \mycontroller($c['rdb']); } 

Поэтому, когда вы открываете www.example.com/test в своем браузере, Slim автоматически создает новый экземпляр \mycontroller и выполняет test метода с аргументами $request , $response и $args . И поскольку вы принимаете соединение с базой данных в качестве аргумента для конструктора вашего класса mycontroller , вы также можете использовать его в методе 🙂

С Slim 3 RC2 и далее с учетом маршрута:

 $app->get('/test','MyController:test'); 

CallableResolver будет искать ключ в DIC под названием 'MyController' и ожидать, что он вернет контроллер, поэтому вы можете зарегистрироваться в DIC следующим образом:

 // 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 } } 

Кроме того, если вы не регистрируетесь в DIC, то CallableResolver передает контейнер вашему конструктору, поэтому вы можете просто создать контроллер следующим образом:

 class MyController { public function __construct($container) { $this->rdb = $container->get('rdb'); } public function test($request,$response){ // do something with $this->rdb } } 

Важный

Я поддержал @mgansler, и вы должны прочитать это сначала, если имеете дело с slim 3, и прочитайте это, только если заинтересованы в различиях с slim 2.

Обновить

Поэтому кажется, что эти обычаи были просто старым кодом, который никто не очищал.

Однако я оставляю этот пост здесь, поскольку он должен быть полезен любому, кто использует Slim 2 (поскольку slim 3 очень-очень бета-версия) и как ссылочный пункт, чтобы помочь увидеть различия.

Старое обновление (см. Выше)

После обновления OP я посмотрел на исходный код github и обнаружил, что getInstance все еще очень много, но с некоторыми небольшими отличиями возможно …

https://github.com/slimphp/Slim/search?utf8=%E2%9C%93&q=getInstance

Файлы тестов (которые могут быть устаревшими, но маловероятными) показывают что-то вроде этого:

 public function testGetCallableAsStaticMethod() { $route = new \Slim\Route('/bar', '\Slim\Slim::getInstance'); $callable = $route->getCallable(); $this->assertEquals('\Slim\Slim::getInstance', $callable); } 

Но в то же время мы видим такие вызовы в некоторых файлах, которые явно контекстуальны и возвращают объект diff ($ env) или находятся в одном статическом файле (Slim.php)

 $env = \Slim\Environment::getInstance(true); static::getInstance(); 

Но это показывает, что статическая функция все еще существует, поэтому используйте приведенные ниже примеры и попытайтесь выяснить, почему не работает для вас в текущей форме.

Кроме того, этот «может быть» интерес, как только очевидный пример использования slim3: https://github.com/akrabat/slim3-skeleton

Хотя существуют другие проекты, поиск с фильтрами github, если у вас все еще есть проблемы.

Исходный ответ

Пожалуйста, добавьте более подробную информацию о маршруте и другом классе, но вот 3 способа, с примерами выполнения, подробно описанными ниже.

Эта информация относится к Slim Framework 2, а не к Slim 3 beta, но slim 3 beta показывает похожий пример кода и не упоминает об изменениях в настройках, а на самом деле ссылки на документацию Slim 2: http://docs.slimframework.com / конфигурация / имена-и-прицелы /

 $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 имеет только один пример кода, который выглядит так:

 $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() 

Хотя очевидно, что это не подходит вне index.php, но совместимо с Slim2 doco, показывающим работу GetInstance.

Какой вам подходит?

У меня есть несколько файлов, которые используют эти разные подходы, хотя я не могу сказать, что лучше всего подходит, поскольку слишком мало контекста о том, как этот внешний класс подходит и каков его состав.

Например, мои контроллеры (которые являются конечными точками большинства моих маршрутов) используют один и тот же подход, используя базовый класс или просто прямой:

 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(); } //... } 

Мои вспомогательные файлы показывают код следующим образом:

 function get_permissions_options_list($context = null) { if(empty($context)) $context = 'user'; return App::config('permissions')[$context]; } 

Мое промежуточное ПО:

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

Вот пример того, как я получаю доступ к различным файлам, хотя код, который вы поделили, уже показывает, что вы уже использовали рекомендуемый подход

 $app = \Slim\Slim::getInstance(); 

Хотя снова нужно больше информации, чтобы точно сказать, как ваш внешний файл вписывается, но если он находится в конце маршрута или в «include ()», тогда он должен работать.

Вы сказали, что ваш старый подход не работает, но не дал информации о том, какой фактический результат и ожидаемый результат был (ошибка msg, ect), поэтому, если это не работает, обновите OP.

Это было тяжело. Ответ @mgansler был действительно полезен, но в его ответе он передал соединение с базой данных, а не точно $ app внутри контроллера

Следуя той же идее, можно отправить $ app.

Сначала внутри your dependencies.php вам нужно захватить $ приложение и выбросить его в контейнер, чтобы позже добавить его в контроллер.

 $container['slim'] = function ($c) { global $app; return $app; }; 

Тогда вы должны ввести его:

 // Generic Controller $container['App\Controllers\_Controller'] = function ($c) { return new _Controller($c->get('slim')); }; 

Теперь на вашем контроллере.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; } 

Теперь вам просто позвонили так:

 $this->slim->doSomething(); 

Я создал следующий базовый контроллер и расширил его. Только что начал играть с Slim, но он работает, если вам нужен доступ к DI в ваших контроллерах.

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

Затем в других контроллерах вы можете использовать его так.

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