从其他 classes 访问 Silex 应用程序 class;如何注射?
Accessing Silex Application class from other classes; how to inject?
我目前正在处理我的第一个 Silex (2.0) 项目。我定义了一些 Pheasant 模型,我可以从我的控制器中访问它们:
// it is used both static
$p = \Model\Post::oneById(3);
// .. and with an instance
$p = new \Model\Post;
$p->title = 'foobar';
$p->save();
现在,在某些情况下,我想在我的模型中访问应用程序 class。例如,检查我们是否 运行 处于调试模式(或不是)。现在:
public function beforeSave() {
global $app;
if($app['debug']) {
// ...
}
}
但这不像 Silex。所以我想我需要某种东西可以自动将 $app
class 注入我的模型:
class PheasantModelReflector {
protected $app;
public function __construct(\Silex\Application $app) {
$this->app = $app;
}
public function __get($className) {
$r = (new ReflectionClass(sprintf('Model\%s', $className)))->newInstance();
$r->__invoke($this->app);
return $r;
}
}
$app['model'] = function ($app) {
return new PheasantModelReflector($app);
};
这在一定程度上有效,但总是 returns Post 模型的新实例,如 $app['model']->Post
.
有什么办法可以解决这个问题吗?
在没有使用 Pheasant 的情况下,我可能会尝试创建一个服务工厂,将 $app(或 $debug 变量)注入到您的实体 class 中,就像这样(这里的一个问题是您的实体必须扩展 \Pheasant\DomainObject
并且您不能将构造函数重写为 it's marked as final):
<?php
// in the example below I inject the whole $app, if you only need the
// debug var, inject only that, injecting the whole $app may
// tempt you to use it as a service locator
// creating a new instance
$app['model_post_factory'] = $app->factory(function ($app) {
$post = new \Model\Post();
$post->setApp($app);
return $post;
});
$post = $app['model_post_factory'];
// getting an instance by ID, here it gets a little tricky
$app['model_post_static_factory'] = function($app, $id) {
$post = \Model\Post::oneById($id);
$post->setApp($app);
return $post;
}
$postById = $app->raw('model_post_static_factory');
$post = $postById($app, $id); // $id comes from somewhere else
// depending on the PHP version you may try directly:
// $post = $app->raw('model_post_static_factory')($app, $id);
静态方法的问题在于传递 id 参数。您可以使用 use 关键字从外部范围将 $id 导入工厂范围,但恕我直言,这太神奇了(尽管我也不太喜欢替代方案)。可能还有一些更优雅的方式,但我暂时想不到。
为了避免每次需要创建共享服务时都生成一个新的模型实例(http://silex.sensiolabs.org/doc/services.html)。
例如:
$app['model'] = $app->share(function () {
return new PheasantModelReflector();
});
无论如何注入$app
不一定是个好主意,也许你可以注入每个对象的依赖?类似于:
new \Model\Post($app['debug']);
我目前正在处理我的第一个 Silex (2.0) 项目。我定义了一些 Pheasant 模型,我可以从我的控制器中访问它们:
// it is used both static
$p = \Model\Post::oneById(3);
// .. and with an instance
$p = new \Model\Post;
$p->title = 'foobar';
$p->save();
现在,在某些情况下,我想在我的模型中访问应用程序 class。例如,检查我们是否 运行 处于调试模式(或不是)。现在:
public function beforeSave() {
global $app;
if($app['debug']) {
// ...
}
}
但这不像 Silex。所以我想我需要某种东西可以自动将 $app
class 注入我的模型:
class PheasantModelReflector {
protected $app;
public function __construct(\Silex\Application $app) {
$this->app = $app;
}
public function __get($className) {
$r = (new ReflectionClass(sprintf('Model\%s', $className)))->newInstance();
$r->__invoke($this->app);
return $r;
}
}
$app['model'] = function ($app) {
return new PheasantModelReflector($app);
};
这在一定程度上有效,但总是 returns Post 模型的新实例,如 $app['model']->Post
.
有什么办法可以解决这个问题吗?
在没有使用 Pheasant 的情况下,我可能会尝试创建一个服务工厂,将 $app(或 $debug 变量)注入到您的实体 class 中,就像这样(这里的一个问题是您的实体必须扩展 \Pheasant\DomainObject
并且您不能将构造函数重写为 it's marked as final):
<?php
// in the example below I inject the whole $app, if you only need the
// debug var, inject only that, injecting the whole $app may
// tempt you to use it as a service locator
// creating a new instance
$app['model_post_factory'] = $app->factory(function ($app) {
$post = new \Model\Post();
$post->setApp($app);
return $post;
});
$post = $app['model_post_factory'];
// getting an instance by ID, here it gets a little tricky
$app['model_post_static_factory'] = function($app, $id) {
$post = \Model\Post::oneById($id);
$post->setApp($app);
return $post;
}
$postById = $app->raw('model_post_static_factory');
$post = $postById($app, $id); // $id comes from somewhere else
// depending on the PHP version you may try directly:
// $post = $app->raw('model_post_static_factory')($app, $id);
静态方法的问题在于传递 id 参数。您可以使用 use 关键字从外部范围将 $id 导入工厂范围,但恕我直言,这太神奇了(尽管我也不太喜欢替代方案)。可能还有一些更优雅的方式,但我暂时想不到。
为了避免每次需要创建共享服务时都生成一个新的模型实例(http://silex.sensiolabs.org/doc/services.html)。 例如:
$app['model'] = $app->share(function () {
return new PheasantModelReflector();
});
无论如何注入$app
不一定是个好主意,也许你可以注入每个对象的依赖?类似于:
new \Model\Post($app['debug']);