入门 - 第3部分
这是一个系列的第三部分。由于文本是指一个运行的例子,你应该开始的前两部分。
管理依赖
到目前为止,我们已经使用了全局变量来保存我们的模型组件的访问。正如我已经提到的开始,这是不是一个好的做法。Konstrukt的设计的方式,以便它是可能的,用于管理共享组件在应用程序中使用的依赖注入容器。现在我们来看看应用程序可以转化为使用此。
为此,我们将使用简单的斗库。如果你喜欢用不同的容器,它是微不足道的,因为这样的容器-由它们的性质-介绍非常少的依赖。
您可以在一个共享的地方在你的机器上安装斗,但本教程中,我们将只把它的应用程序,我们正在努力。打开外壳,去您的网站的根文件夹(/ var / www下面/ foo的
),然后键入以下命令:
mkdir thirdparty git clone git://github.com/troelskn/bucket.git thirdparty/bucket
这将拉副本斗到该文件夹了第三方/桶
。
我们可以利用斗之前,我们需要配置我们的项目中使用它。打开/ development.inc.php
和替换的内容:
<?php
require_once 'applicationfactory.php';
require_once dirname(__FILE__).'/../thirdparty/bucket/lib/bucket.inc.php';
date_default_timezone_set('Europe/Paris');
function create_container() {
$factory = new ApplicationFactory();
$container = new bucket_Container($factory);
$factory->pdo_dsn = "sqlite:" . dirname(dirname(__FILE__)) . "/var/database.sqlite";
$factory->pdo_attributes = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
return $container;
}
功能create_container
创建了一个水桶容器和重视工厂(ApplicationFactory
),用于创建对象的。我们需要ApplicationFactory
这一点-在lib / applicationfactory.php中
打开一个新的文件,然后输入:
<?PHP
/ **
*此应用程序提供类依赖布线
*/
class ApplicationFactory {
public $pdo_dsn;
public $pdo_username;
public $pdo_password;
public $pdo_attributes = array();
function new_PDO($c) {
return new PDO($this->pdo_dsn, $this->pdo_username, $this->pdo_password, $this->pdo_attributes);
}
}
最后,打开WWW / index.php文件,
并改变它,以便它包含:
<?php
require_once dirname(__FILE__) . '/../config/global.inc.php';
k()
// Use container for wiring of components
->setComponentCreator(new k_InjectorAdapter(create_container()))
// Dispatch request
->run('components_Root')
->out();
在这一点上,依赖注入容器设置和配置,并且所有组件都将它们的依赖关系自动地填补实例。
利用这一点,我们现在可以编辑的组件。打开库/组件/联系我们/ list.php的,
并添加一个构造函数:
class components_contacts_List extends k_Component {
protected $contacts;
function __construct(ContactsGateway $contacts) {
$this->contacts = $contacts;
}
...
会看到components_contacts_List,
需要一个的ContactsGateway
实例,并为其提供的集装箱。然后我们就可以更换到全局变量的引用,像这样:
类别 components_contacts_List 扩展 k_Component {
...
function renderHtml() {
$this->document->setTitle("Contacts");
$t = new k_Template("templates/contacts-list.tpl.php");
return $t->render(
$this,
array(
'contacts' => $this->contacts->all()));
}
...
我们必须做同样的事情,与库/组件/接触/ entity.php,
class components_contacts_Entity extends k_Component {
protected $contact;
protected $contacts;
function __construct(ContactsGateway $contacts) {
$this->contacts = $contacts;
}
function dispatch() {
$this->contact = $this->contacts->fetchByName($this->name());
if (!$this->contact) {
throw new k_PageNotFound();
}
return parent::dispatch();
}
...
功能过程() {
...
try {
$this->contacts->save($this->contact);
} catch (Exception $ex) {
@$this->contact->errors[] = $ex->getMessage();
return false;
}
...
现在,您可以去验证应用程序的工作和以前完全一样。这可能看起来是一个很大的功夫,但结果是,现在,所有的组件都依赖注入容器管理的,为什么这是一个大问题是有点超出了本文的讨论范围,所以我建议其他来源。
默认情况下starterpack
每一个新的应用程序需要做的工作很多,我们做了以上的自举。这是为什么有一个starterpack的,更预先设定的。而不是使用starterpack_light
,的starterpack_default
包含一个更完整的设置,包括斗。
在我们继续之前,我们就拉在剩余的从starterpack_default
位:
cp -R starterpack_default/script script cp -R examples/starterpack_default/test test
这种“升级”我们的starterpack_light
,使我们的应用程序类似,它看起来会如何,如果我们开始与starterpack_default
(除的引导,我们将在后面)。该文件夹包含各种脚本/
命令行脚本的维护和代码生成。
测试
注意到,我们把车停在最后的目录吗?(提示:它是从吨,并结束美国东部时间)。是啊,默认Konstrukt的配置保存在一个目录测试/
测试。这是进一步分为单元测试,测试/单位/
文件夹中的功能测试,测试/功能/
文件夹中的。单元测试的测试最小的“单位”您参加办法-通常是一个单独的类。功能试验的互动。Konstrukt的,你通常会测试每个组件。
starterpack带有单一功能的测试开始。你可以试着运行它:
php test/functional/root.test.php
希望通过。
第一个测试是免费的,但我们要为我们自己的组件编写测试。另一个免费赠送时间:
script/generate_test_functional.php components_contacts_List
你可能会怀疑,这会产生一个功能测试用例的组件components_contacts_List
。或者更确切地说,它生成的文件和骨架-您还需要手动填写实际测试。打开新生成的文件:测试/功能/ contacts_list.test.php的
。正如你可以看到,它包含了网络的List组件的测试用例。
不同于一般的网络测试用例SimpleTest的中,这个使用一个k_VirtualSimpleBrowser的
。这是一个由Konstrukt的完全嘲笑满分的HTTP访问,从而使得有可能测试组件而不运行它通过Web服务器所提供的一个组件。这不仅是更快,更简单,但它可以模拟出依赖-这是不是真的有可能与常规的Web测试用例的东西。
的的骨架包含一个单一的测试,检查该组件来响应一个GET请求。让我们添加一个更有趣的测试,以:
function test_lists_contacts() {
$this->get('/');
$this->assertLink("Jabba the Hutt");
}
如果你没惹周围太多的数据,应该通过。然而,让测试依赖于数据库的状态是一个坏主意。让我们模拟出这种依赖是,我们应当:
function test_lists_contacts() {
Mock::Generate('ContactsGateway');
$contacts = new MockContactsGateway();
$jabba = new Contact(array('first_name' => "Jabba", 'last_name' => "the Hutt", 'short_name' => "jabba"));
$contacts->setReturnValue('all', array($jabba));
$this->container->set($contacts, 'ContactsGateway');
$this->get('/');
$this->assertLink("Jabba the Hutt");
}
首先,我们生成一个模拟的模型组件ContactsGateway
和设立的预期。然后,我们配置containier的使用我们的嘲弄对象的实打实的。运行测试时,容器将指定模拟对象的List组件,从而使测试独立的数据库。
这不是一个教程编写自动化测试,所以我们将离开这里,但我希望这说明Konstrukt的基本框架,提供的功能测试。
调试+日志
可以是一个有点令人生畏在第一Konstrukt的调度过程的内部工作。为了帮助了解每个请求的处理,你可以打开调试日志记录。这将记录执行链中的每个组件的信息。如果您使用的的默认starterpack,默认情况下启用了日志记录。否则,你可以把它添加一个单一的线,以引导(WWW /编辑
):
k()
...
->setLog(dirname(__FILE__) . '/../log/debug.log')
...
您可以按照流入的日志,因为它运行的尾巴
命令的输出:
tail -f log/debug.log
这将给你像下面这样:
(request (time "2009-10-18 23:15:46") (method "get") (request-uri "/foo/www/contacts") (headers (array (length 9) (host (string "localhost")) (user-agent (string "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.14) Gecko/2009090216 Ubuntu/9.04 (jaunty) Firefox/3.0.14")) (accept (string "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")) (accept-language (string "en-us,en;q=0.5")) (accept-encoding (string "gzip,deflate")) (accept-charset (string "ISO-8859-1,utf-8;q=0.7,*;q=0.7")) (keep-alive (string "300")) (connection (string "keep-alive")) (cookie (string "wp-settings-time-1=1234546590; re_ret=0")))) (dispatch (class-name "components_Root" (defined-in "/var/www/foo/lib/components/root.php")) (name *NULL*) (next contacts)) (dispatch (class-name "components_contacts_List" (defined-in "/var/www/foo/lib/components/contacts/list.php")) (name contacts) (next *NULL*)) (http-response (http-status 200) (content-type "text/html") (charset "utf-8") (headers))
有三种类型的条目在这一块的日志。请求
项记录解析HTTP请求。
之后,一些调度
项目-被调用链上的每个组件之一。总是会有在开始的根组件,但可以有任意数量的组件之后。记录每个组件的组件的类名与URL的名称,它上链和下一个名称。
最后有一个响应
的http响应被发送回给客户端显示的值的条目。
可以进一步自定义日志消息发送到调试日志中,从组件,通过调用$ - >调试()
。这通常是在开发过程中使用的,而不是后续代码var_dump
。
注:在调试日志的格式是S-表达式。您可以语法高亮显示Lisp代码。例如,如果你有安装在您的系统的源代码高亮
,您可以查看日志命令tail-f的日志/ debug.log中源的亮点-输出格式ESC - :SRC-LANG =俚语
。
如果你不喜欢命令行,您可能希望在浏览器中的日志输出,而不是使用。回到引导和添加下面一行:
k()
...
->setDebug()
...
如果你查看你的浏览器中的应用程序,你会发现一个绿框的右上角。试着点击它,你会得到相同的信息的日志文件格式整齐的表。
错误日志
除了 调试日志,默认的安装配置Apache的把一个自定义错误日志中的错误。这会发生,如果Apache配置错误,或者如果一个致命的错误发生在你的PHP应用程序。如果你有麻烦的东西的工作,尝试检查日志/ error.log中
,如果有什么。
配置应用程序的生产
在生产现场,你显然不希望显示在浏览器中还是有很多的调度信息在调试日志中的错误。你可以通过修改引导程序,并删除或注释掉调用setlog命令
和setDebug
后,已部署到生产现场“,但是这是一个有点繁琐和容易出错的。有些时候,你也想在各个站点进行其他配置更改。例如,你可能需要不同的连接详细信息的数据库(如果您使用)等。
你可以把不同的全球配置,在配置文件中的config /
下。引导将包括global.inc.php的
,这反过来将加载无论是local.inc.php
或回落至development.inc.php
。
我们的想法是,你创建一个单独的配置文件为每个目标网站(开发,分期,生产等),并将其命名(development.inc.php
,staging.inc.php
,production.inc.php
等)。在每个站点,你可以创建一个符号链接指向相关的配置文件。例如,在生产现场中,您将创建的链接local.inc.php - >“production.inc.php”
。您可以使这部分的部署脚本,如果您使用的自动化部署脚本。
为了使调试/日志记录配置,我们将不得不做一些小改变的index.php
:
<?php
require_once dirname(__FILE__) . '/../config/global.inc.php';
k()
->setComponentCreator(new k_InjectorAdapter(create_container()))
->setLog($debug_log_path)
->setDebug($debug_enabled)
->run('components_Root')
->out();
development.inc.php
我们添加两个配置参数:
...
$debug_log_path = dirname(dirname(__FILE__)) . "/var/debug.log";
$debug_enabled = true;
...
现在,让我们假设你想有一个生产基地(是不是太牵强,我希望)。首先副本的发展:
cp config/development.inc.php config/production.inc.php
并对其进行编辑,以满足您的需求。现在,我们就禁用调试日志记录,并在浏览器中调试。更换前与两行:
...
$debug_log_path = null;
$debug_enabled = false;
...
现在,您可以切换到使用的生产站点配置文件的一个符号链接:
ln -s config/production.inc.php config/local.inc.php
没有链接,加载的发展概况。因此,为您的开发网站,你将没有任何链接。
在实际部署过程是Konstrukt的,本教程的范围以外了一下,但你可以使用的工具,如斯特拉努或Phing。或者,你可以用一堆的shell脚本。
注:的的默认starterpack已经有一个自举以这 种方式配置,所以如果你从那里开始,所有你需要做的是使一个副本development.inc.php
生产(以及任何其他)的网站,并投入了。链接时,你部署到它。