У меня возникли проблемы с пониманием того, как получить доступ к экземпляру 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'); } }