ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 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)。