问题
I'm on a Silex project and I use classes to different treatments:
$connection = new Connection($app);
$app->match('/connection', function () use ($app, $connection) {
$connexion->connectMember();
return $app->redirect($app['url_generator']->generate('goHome'));
})->method('GET|POST')->bind('doConnection');
In the function 'connectMember()' of my class 'Connection', I have :
[...]
if($isMember){
[...]
}else{
return $this->_app['twig']->render(
'message.twig',
array('msg' => "This member does not exist.", 'class' => 'Warning'));
}
[...]
But the render () method is not working. The error message I want to display is not displayed and "$ app-> redirect (...)" is launched instead.
How to make my class uses the current object Silex\Application ? Is there a better method to bind a custom class to the instance of the Silex application?
Thank you very much for your answers !
Edition : Add informations
If I use :
return $connexion->connectMember();
The error message is displayed. But it's not a good solution. The 'connection' class calls other classes that also use this code:
$this->_app['twig']->render(...).
How to make $ this->_app (present in my classes) correspond to the variable $app created in my controller?
回答1:
Create a service for the Connection
(or Connexion
??) class and inject the application:
use Silex\Application;
class Connection
{
private $_app;
public function __construct(Application $app)
{
$this->_app = $app;
}
// ...
}
$app['connection'] = function () use ($app) {
return new Connection($app); // inject the app on initialization
};
$app->match('/connection', function () use ($app) {
// $app['connection'] executes the closure which creates a Connection instance (which is returned)
return $app['connection']->connectMember();
// seems useless now?
return $app->redirect($app['url_generator']->generate('goHome'));
})->method('GET|POST')->bind('doConnection');
Read more about it in the documentation of silex and pimple (pimple is the container used by silex).
回答2:
if you are using $app->share(...) for dependency injection you can setup something like this (it's pseudo code) :
<?php
namespace Foo;
use Silex\Application as ApplicationBase;
interface NeedAppInterface {
public function setApp(Application $app);
}
class Application extends ApplicationBase {
// from \Pimple
public static function share($callable)
{
if (!is_object($callable) || !method_exists($callable, '__invoke')) {
throw new InvalidArgumentException('Service definition is not a Closure or invokable object.');
}
return function ($c) use ($callable) {
static $object;
if (null === $object) {
$object = $callable($c);
if ($object instanceof NeedAppInterface) {
// runtime $app injection
$object->setApp($c); // setApp() comes from your NeedAppInterface
}
}
return $object;
};
}
}
Now doing this :
$app['mycontroller'] = $app->share(function() use ($app) {
return new ControllerImplementingNeedAppInterface();
});
will automatically set $app when calling $app['mycontroller'] !
PS : if you don't want to use ->share() try using __invoke($app) because \Pimple::offsetGet() calls it :p
来源:https://stackoverflow.com/questions/19565709/inject-silex-app-in-my-custom-class