# DI容器扩展
Configurator不会生成代码本身,这是Nette \ DI \ Compiler和Nette \ DI \ ContainerBuilder类的任务。 第一个配置文件被加载并传递给编译器。 通过config.neon添加自己的扩展到编译器:
~~~
extensions:
blog: MyBlogExtension
~~~
每个编译器扩展必须扩展Nette \ DI \ CompilerExtension,并且可以实现在Container编译期间连续调用的三种不同方法。
## CompilerExtension::loadConfiguration()
首先调用此方法并加载其他配置文件,使用Nette \ DI \ ContainerBuilder创建方法,最重要的是处理应用程序的配置。
Config可以包含与扩展名具有相同名称的部分。 使用最后一个示例,以下行可以出现在您的配置文件中:
~~~
blog: # same name as your extension
postsPerPage: 10
comments: FALSE
~~~
在扩展中使用getConfig()方法列出其配置。
~~~
class MyBlogExtension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$config = $this->getConfig();
// [2] [ 'postsPerPage' => 10, 'comments' => FALSE ]
~~~
遵守约定的配置原则,我们可以设置默认值,并能够使用应用程序,而不明确设置任何东西。 getConfig()的第一个参数接受一个默认值数组,config部分(如上所述)将被合并到其中。
~~~
class MyBlogExtension extends Nette\DI\CompilerExtension
{
public $defaults = [
'postsPerPage' => 5,
'comments' => TRUE
];
public function loadConfiguration()
{
$config = $this->getConfig($this->defaults);
~~~
现在我们在$ config数组中有配置,并且可以在创建服务时使用它。 ContainerBuilder类允许您使用与配置文件中使用的NEON相同的服务描述方式。
~~~
$builder = $this->getContainerBuilder();
~~~
创建代表用于处理和加载文章的模型的blog_articles服务。
约定是以服务的名称为前缀,以避免冲突。 使用prefix()方法,我们可以通过$ container-> getService('blog.articles)访问服务。
~~~
$builder->addDefinition($this->prefix('articles'))
->setClass('MyBlog\ArticlesModel', ['@connection']);
~~~
您还可以创建组件工厂,传递blog_articles服务并设置每个页面的帖子数量选项。 如何使用组件工厂将很快显示。
~~~
$builder->addDefinition($this->prefix('articlesList'))
->setClass('MyBlog\Components\ArticlesList', [$this->prefix('@articles')])
->addSetup('setPostsPerPage', [$config['postsPerPage']])
->setShared(FALSE)->setAutowired(FALSE); // 将服务变成工厂
~~~
我们还需要一个blog_comment类,并将其连接到数据库和blog_articles实例。 如果注释被禁用,我们可以使用addSetup方法反映:
~~~
$comments = $builder->addDefinition($this->prefix('comments'))
->setClass('MyBlog\CommentsModel', ['@connection', $this->prefix('@articles')]);
if (!$config['comments']) { // 可选禁用注释
$comments->addSetup('disableComments');
}
~~~
当然,注释需要被写入和显示,所以我们添加一个组件工厂 - blog_commentsControl,这将允许我们列出注释和发布新的,除非他们已经关闭。
~~~
$builder->addDefinition($this->prefix('commentsControl'))
->setClass('MyBlog\Components\CommentsControl', [$this->prefix('@comments')])
->setShared(FALSE)->setAutowired(FALSE); // turns service into factory
~~~
## Loading additional configurations
如果您喜欢通过扩展的配置文件,可以将一些定义移动到单独的配置文件中。
~~~
services:
articles:
class: MyBlog\ArticlesModel(@connection)
comments:
class: MyBlog\CommentsModel(@connection, @blog_articles)
articlesList:
class: MyBlog\Components\ArticlesList(@blog_articles)
commentsControl:
class: MyBlog\Components\CommentsControl(@blog_comments)
~~~
加载文件并设置其他服务
~~~
public function loadConfiguration()
{
$config = $this->getConfig($this->defaults);
$builder = $this->getContainerBuilder();
//加载此扩展的附加配置文件
$this->compiler->parseServices($builder, $this->loadFromFile(__DIR__ . '/blog.neon'), $this->name);
// 设置组件中每页的文章数
$builder->getDefinition('blog_articlesList')
->addSetup('setPostsPerPage', [$config['postsPerPage']]);
// optional disabling of commenting
if (!$config['comments']) {
$builder->getDefinition('blog_comments')
->addSetup('disableComments');
}
}
~~~
感谢NEON语法,你现在有更清洁的容器扩展。
## CompilerExtension::beforeCompile()
在编译阶段之前,我们不应该添加任何更多的服务,但是您可以修改已有的服务或添加服务之间的关系(例如使用标签)。
## CompilerExtension::afterCompile(Nette\PhpGenerator\ClassType $class)
在这个阶段,Container实例已经生成并包含所有服务方法,并准备好存储到缓存中。 感谢Nette \ PhpGenerator \ ClassType,你可以添加自己的代码到容器来修改服务生成。
为了激发你自己看看Nette Framework的初始化方法,Nette添加它来处理一些用户设置。 此方法总是在容器实例化后调用。
下面是一段初始化代码,其中Nette添加了一个会话开始和标记有运行标签的服务的自动运行。
~~~
public function afterCompile(Nette\PhpGenerator\ClassType $class)
{
$container = $this->getContainerBuilder();
$config = $this->getConfig($this->defaults);
// initialize method
$initialize = $class->methods['initialize'];
// automatic session start
if ($config['session']['autoStart']) {
$initialize->addBody('$this->session->start();');
}
// services with run tag must be run after instantition of the container
foreach ($container->findByTag('run') as $name => $foo) {
$initialize->addBody('$this->getService(?);', [$name]);
}
}
~~~
方法'beforeCompile()和afterCompile()的区别是beforeCompile()可以访问容器和服务,而afterCompile()访问它的代码(通过Nette \ PhpGenerator)。
- Nette简介
- 快速开始
- 入门
- 主页
- 显示文章详细页
- 文章评论
- 创建和编辑帖子
- 权限验证
- 程序员指南
- MVC应用程序和控制器
- URL路由
- Tracy - PHP调试器
- 调试器扩展
- 增强PHP语言
- HTTP请求和响应
- 数据库
- 数据库:ActiveRow
- 数据库和表
- Sessions
- 用户授权和权限
- 配置
- 依赖注入
- 获取依赖关系
- DI容器扩展
- 组件
- 字符串处理
- 数组处理
- HTML元素
- 使用URL
- 表单
- 验证器
- 模板
- AJAX & Snippets
- 发送电子邮件
- 图像操作
- 缓存
- 本土化
- Nette Tester - 单元测试
- 与Travis CI的持续集成
- 分页
- 自动加载
- 文件搜索:Finder
- 原子操作