# 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
- 原子操作