web-dev-qa-db-fra.com

Accéder à l'application en classe dans Slim Framework 3

J'ai du mal à comprendre comment accéder à l'instance de Slim quand un itinéraire est dans une classe séparée que index.php

Lors de l'utilisation de Slim Framework 2, j'ai toujours utilisé les éléments suivants, mais cela ne fonctionne pas dans Slim 3:

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

J'essaie d'accéder à une connexion de base de données que j'ai configurée dans le conteneur, mais à partir d'une classe séparée. Voici ce que j'ai actuellement dans mon index.php pour lancer une application 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);

Et voici mon itinéraire:

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

Et c’est ce que j’ai eu dans ma classe mycontroller.php à laquelle mon itinéraire pointe, ce qui ne fonctionne évidemment pas en tant que $ this-> app n’existe pas: 

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

Le message d'erreur est le suivant, car getinstance ne fait pas partie de Slim 3 par rapport à Slim 2:

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

Reconnaissant pour toute aide,

Cordialement Dan

11
user3507740

Regardez le Slim 3 Skeleton créé par Rob Allen.

Slim 3 utilise beaucoup l'injection de dépendance, vous pouvez donc l'utiliser aussi.

Dans votre dependencies.php, ajoutez quelque chose comme:

$container = $app->getContainer();

$container['rdb'] = function ($c) {
    return $conn;
};

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

Et dans votre Your\Custom\Class.php:

class Class {
    private $rdb;
    function __construct($rdb) {
        $this->rdb = $rdb;
    }

    public function test($request, $response, $args) {
        $this->rdb->doSomething();
    }
}

J'espère que cela vous aidera si vous avez d'autres questions, n'hésitez pas à les poser.

Mettre à jour:

Quand vous définissez votre itinéraire comme ceci

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

Slim cherche \mycontroller:test dans votre conteneur:

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

Ainsi, lorsque vous ouvrez www.example.com/test dans votre navigateur, Slim crée automatiquement une nouvelle instance de \mycontroller et exécute la méthode test avec les arguments $request, $response et $args. Et parce que vous acceptez la connexion à la base de données comme argument pour le constructeur de votre mycontroller classe, vous pouvez aussi l’utiliser dans la méthode :)

13
Martin

Avec Slim 3 RC2 et les suivants, le parcours est le suivant:

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

La CallableResolver cherchera une clé dans le DIC appelée 'MyController' et attendra le retour du contrôleur afin que vous puissiez vous inscrire auprès du DIC comme ceci:

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

Sinon, si vous ne vous inscrivez pas auprès du DIC, la CallableResolver transmettra le conteneur à votre constructeur, vous pouvez donc créer un contrôleur comme celui-ci:

class MyController
{
    public function __construct($container) {
        $this->rdb = $container->get('rdb');
    }

    public function test($request,$response){
        // do something with $this->rdb
    }
}
6
Rob Allen

J'ai créé le contrôleur de base suivant et étendu à partir de cela. Je viens juste de commencer à jouer avec Slim mais cela fonctionne si vous avez besoin d’un accès à la DI de vos contrôleurs.

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

Ensuite, dans vos autres contrôleurs, vous pouvez l'utiliser comme ceci.

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

}
2
Lee

Important

J'ai voté @mgansler et vous devriez le lire en premier s'il s'agit de slim 3, et ne le lire que si vous êtes intéressé par les différences entre slim 2.


Mettre à jour

Il semble donc que ces utilisations étaient simplement du code ancien, personne n’a été nettoyé.

Cependant, je quitte ce post ici, car il devrait être utile à quiconque utilise Slim 2 (car slim 3 est encore très bêta) et comme point de référence pour aider à voir les différences.


Ancienne mise à jour (voir ci-dessus)

Après la mise à jour de OP, j’ai examiné le code source de github et découvert que getInstance était toujours là, mais avec quelques légères différences peut-être ...

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

Les fichiers de test (qui sont peut-être obsolètes, mais improbables) montrent quelque chose comme ceci:

public function testGetCallableAsStaticMethod()
{
    $route = new \Slim\Route('/bar', '\Slim\Slim::getInstance');

    $callable = $route->getCallable();
    $this->assertEquals('\Slim\Slim::getInstance', $callable);
}

Mais en même temps, nous voyons des appels comme celui-ci dans certains fichiers, qui sont évidemment contextuels et renvoient soit un objet diff ($ env), soit se trouvent dans le même fichier statique (Slim.php).

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

static::getInstance();

Mais cela montre que la fonction statique existe toujours, utilisez donc mes exemples ci-dessous et essayez de comprendre pourquoi vous ne travaillez pas pour vous sous la forme actuelle.

En outre, ce "peut-être" d'intérêt, en tant que seul exemple évident d'utilisation de slim3: https://github.com/akrabat/slim3-skeleton

Bien que d'autres projets existent, cherchez avec les filtres github si le problème persiste.



Contenu de la réponse originale

S'il vous plaît inclure plus de détails sur la route et l'autre classe, mais voici 3 façons, avec des exemples d'exécution détaillés plus bas.

Cette information ne concerne pas Slim Framework 2, ni Slim 3 beta, mais Slim 3 beta montre un exemple de code similaire et ne mentionne pas les modifications de révision. Il s'agit en fait de liens vers la documentation Slim 2: 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 n'a qu'un seul exemple de code, qui ressemble à ceci:

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

Bien évidemment, cela ne tient pas en dehors de index.php, mais est compatible avec le doco Slim2 montrant GetInstance fonctionne.


Lequel vous va?

J'ai plusieurs fichiers qui utilisent ces différentes approches, bien que je ne puisse pas dire ce qui convient le mieux car trop peu de contexte sur la place de cette classe externe et sur sa composition.


Par exemple, mes contrôleurs (qui sont les extrémités de la plupart de mes routes) utilisent la même approche, via une classe de base ou simplement:

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


    //...
}


Mes fichiers d'aide montrent le code comme ceci:

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


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


C’est un exemple de la façon dont j’accède aux différents fichiers, bien que le code que vous avez partagé montre déjà que vous avez déjà utilisé l’approche recommandée.

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

Encore une fois, vous avez besoin de plus d’informations pour savoir comment votre fichier externe s’intègre, mais si cela se trouve à la fin d’un itinéraire ou dans un "include ()", cela devrait fonctionner.

Vous avez dit que votre ancienne approche ne fonctionnait pas bien, mais ne donnait aucune information sur le résultat réel par rapport au résultat attendu (erreur, etc.), donc si cela ne fonctionne pas, veuillez mettre à jour le PO.

1
Daniel Brose

C'était difficile. La réponse de @mgansler a été très utile, mais dans sa réponse, il a transmis une connexion à une base de données et pas exactement $ app dans le contrôleur.

Suivant la même idée, il est toutefois possible d’envoyer $ app.

Tout d'abord dans votre dependencies.php, vous devez saisir l'application $ app et la jeter dans un conteneur pour l'injecter ultérieurement au contrôleur.

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

Ensuite, vous devez l'injecter:

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

Maintenant sur votre 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;
    }

Maintenant, tu viens de l'appeler comme ça:

$this->slim->doSomething();
1
Leo Leao