`
jackle_liu
  • 浏览: 148161 次
文章分类
社区版块
存档分类
最新评论

理解 Zend 框架(转)

阅读更多

Zend Framework发布了!虽然仍处于开发初期,这个教程仍突出讲解目前几个最好的功能,并指导你完成一个简单程序的构建。

 

Zend最早在社区里发布了ZF。基于同样的想法,这个教程写来用于展示ZF现有的功能。由于这个教程是在线发布,我将在ZF变化时对其进行更新,以便尽可能有效。

 

要求

 

Zend Framework要求PHP5。为了更好利用本教程的代码,你还需要Apache网页服务器。因为示范程序(一个新闻管理系统)用到了mod_rewrite

 

这个教程的代码可以自由下载,所以你可以自己试一下。你可以从Brain Buld的网站下载到代码:http://brainbulb.com/zend-framework-tutorial.tar.gz

 

下载ZF

 

当你开始这篇教程时,你需要下载ZF的最新版本。你可以用浏览器手工从http://framework.zend.com/download选择tar.gzzip文件进行下载,或者使用下列命令:

 

$ wget http://framework.zend.com/download/tgz
$ tar -xvzf ZendFramework-0.1.2.tar.gz

 

提示:Zend计划提供自有PEAR通道简化下载。

 

一旦你下载了预览版,把library目录放到方便的地方。在这个教程,我把library重命名为lib以便有个简洁的目录结构:

 

app/
    views/
    controllers/
www/
    .htaccess
    index.php
lib/

 

www目录是文档根目录,controllersviews目录是以后会用到的空目录,而lib目录来自你下载的预览版。

 

开始

 

我要介绍的第一个组件是Zend_Controller。从很多方面看,它为你开发的程序提供了基础,同时也部分决定了Zend Framework不只是个组件的集合。但是,你在用之前需要将所有的得到的请求都放到一个简单的PHP脚本。本教程用的是mod_rewrite

 

mod_rewrite自身是一种艺术,但幸运的是,这个特殊的任务特别简单。如果你对mod_rewrite或Apache的一般配置不熟悉,在文档根目录下创建一个.htaccess文件,并添加以下内容:

 

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

 

提示: Zend_Controller的一个TODO项目就是取消对mod_rewrite的依赖。为了提供一个预览版的范例,本教程用了mod_rewrite

 

如果你直接把这些内容添加到httpd.conf,你必须重启网页服务器。但如果你用.htaccess文件,则什么都不必做。你可以放一些具体的文本到index.php并访问任意路径如/foo/bar做一下快速测试。如你的域名为example.org,则访问http://example.org/foo/bar

 

你还要设置ZF库的路径到include_path。你可以在php.ini设置,也可以直接在你的.htaccess文件放下列内容:

 

php_value include_path "/path/to/lib"

 

Zend

 

Zend类包含了一些经常使用的静态方法的集合。下面是唯一一个你要手工添加的类:

 

<?php

include 'Zend.php';

?>

 

一旦你包含了Zend.php,你就已经包含了Zend类的所有的类方法。用loadClass()就可以简单地加载其它类。例如,加载Zend_Controller_Front类:

 

<?php

include 'Zend.php';

Zend::loadClass('Zend_Controller_Front');

?>

 

include_path能理解loadclass()及ZF的组织和目录结构。我用它加载所有其它类。   

Zend_Controller

 

使用这个controller非常直观。事实上,我写本教程时并没有用到它丰富的文档。

 

提示:文档目前已经可以在http://framework.zend.com/manual/zend.controller.html看到。

 

我一开始是用一个叫Zend_Controller_Front的front controller。为了理解它是怎么工作的,请把下列代码放在你的index.php文件:

 

<?php

include 'Zend.php';

Zend::loadClass('Zend_Controller_Front');

$controller Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('/path/to/controllers');
$controller->dispatch();

?>

 

如果你更喜欢对象链结,可以用以下代码代替:

 

<?php

include 'Zend.php';

Zend::loadClass('Zend_Controller_Front');

$controller Zend_Controller_Front::getInstance()
              ->
setControllerDirectory('/path/to/controllers')
              ->
dispatch();

?>

 

现在如果你访问/foo/bar,会有错误发生。没错!它让你知道发生了什么事。主要的问题是找不到IndexController.php文件。

 

在你创建这个文件之前,应先理解一下ZF想让你怎样组织这些事情。ZF把访问请求给拆分开来。假如访问的是/foo/bar,则foo是controller,而bar是action。它们的默认值都是index.

 

如果foo是controller,ZF就会去查找controllers目录下的FooController.php文件。因为这个文件不存在,ZF就退回到IndexController.php。结果都没有找到,就报错了。

 

接下来,在controllers目录创建IndexController.php文件(可以用setControllerDirectory()设置):

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
IndexController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        echo 
'IndexController::indexAction()';
    }
}

?>

 

就如刚才说明的,IndexController类处理来自index controller或controller不存在的请求。indexAction()方法处理action为index的访问。要记住的是index是controller和action的默认值。如果你访问//index/index/indexindexAction()方法就会被执行。 (最后面的斜杠并不会改变这个行为。) 而访问其他任何资源只会导致出错。

 

在继续做之前,还要在IndexController加上另外一个有用的类方法。不管什么时候访问一个不存在的控制器,都要调用noRouteAction()类方法。例如,在FooController.php不存在的条件下,访问/foo/bar就会执行noRouteAction()。但是访问/index/foo仍会出错,因为foo是action,而不是controller.

 

noRouteAction()添加到IndexController.php:

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
IndexController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        echo 
'IndexController::indexAction()';
    }

    public function 
noRouteAction()
    {
        
$this->_redirect('/');
    }
}

?>

 

例子中使用$this->_redirect('/')来描述执行noRouteAction()时,可能发生的行为。这会将对不存在controllers的访问重定向到根文档(首页)。

 

现在创建FooController.php

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
FooController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        echo 
'FooController::indexAction()';
    }

    public function 
barAction()
    {
        echo 
'FooController::barAction()';
    }
}

?>

 

如果你再次访问/foo/bar,你会发现执行了barAction(),因为bar是action。现在你不只支持了友好的URL,还可以只用几行代码就做得这么有条理。酷吧!

 

你也可以创建一个__call()类方法来处理像/foo/baz这样未定义的action。

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
FooController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        echo 
'FooController::indexAction()';
    }

    public function 
barAction()
    {
        echo 
'FooController::barAction()';
    }

    public function 
__call($action$arguments)
    {
        echo 
'FooController:__call()';
    }
}

?>

 

现在你只要几行代码就可以很好地处理用户的访问了,准备好继续。 

 

Zend_View

 

Zend_View是一个用来帮助你组织好你的view逻辑的类。这对于模板-系统是不可知的,为了简单起见,本教程不使用模板。如果你喜欢的话,不妨用一下。

 

记住,现在所有的访问都是由front controller进行处理。因此应用框架已经存在了,另外也必须遵守它。为了展示Zend_View的一个基本应用,将IndexController.php修改如下:

 

<?php

Zend
::loadClass('Zend_Controller_Action');
Zend::loadClass('Zend_View');

class 
IndexController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        
$view = new Zend_View();
        
$view->setScriptPath('/path/to/views');
        echo 
$view->render('example.php');
    }

    public function 
noRouteAction()
    {
        
$this->_redirect('/');
    }
}

?>

 

views目录创建example.php文件:

 

<html>
<head>
    <title>This Is an Example</title>
</head>
<body>
    <p>This is an example.</p>
</body>
</html>

 

现在,如果你访问自己网站的根资源,你会看到example.php的内容。这仍没什么用,但你要清楚你要在以一种结构和组织非常清楚的方式在开发网络应用。

 

为了让Zend_View的应用更清楚一点,,修改你的模板(example.php)包含以下内容:

 

<html>
<head>
    <title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
    <?php echo $this->escape($this->body); ?>
</body>
</html>

 

现在已经添加了两个功能。$this->escape()类方法用于所有的输出。即使你自己创建输出,就像这个例子一样。避开所有输出也是一个很好的习惯,它可以在默认情况下帮助你防止跨站脚本攻击(XSS)。

 

$this->title$this->body属性用来展示动态数据。这些也可以在controller中定义,所以我们修改IndexController.php以指定它们:

 

<?php

Zend
::loadClass('Zend_Controller_Action');
Zend::loadClass('Zend_View');

class 
IndexController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        
$view = new Zend_View();
        
$view->setScriptPath('/path/to/views');
        
$view->title 'Dynamic Title';
        
$view->body 'This is a dynamic body.';
        echo 
$view->render('example.php');
    }

    public function 
noRouteAction()
    {
        
$this->_redirect('/');
    }
}

?>

 

现在你再次访问根目录,应该就可以看到模板所使用的这些值了。因为你在模板中使用的$this就是在Zend_View范围内所执行的实例。

 

要记住example.php只是一个普通的PHP脚本,所以你完全可以做你想做的。只是应努力只在要求显示数据时才使用模板。你的controller (controller分发的模块)应处理你全部的业务逻辑。

 

在继续之前,我想做最后一个关于Zend_View的提示。在controller的每个类方法内初始化$view对象需要额外输入一些内容,而我们的主要目标是让快速开发网络应用更简单。如果所有模板都放在一个目录下,是否要在每个例子中都调用setScriptPath()也存在争议。

 

幸运的是,Zend类包含了一个寄存器来帮助减少工作量。你可以用register()方法把你的$view对象存储在寄存器:

 

<?php

Zend
::register('view'$view);

?>

 

registry()方法进行检索:

 

<?php

$view 
Zend::registry('view');

?>

 

基于这点,本教程使用寄存器。  

 

Zend_InputFilter

 

本教程讨论的最后一个组件是Zend_InputFilter。这个类提供了一种简单而有效的输入过滤方法。你可以通过提供一组待过滤数据来进行初始化。

 

<?php

$filterPost 
= new Zend_InputFilter($_POST);

?>

 

这会将($_POST)设置为NULL,所以就不能直接进入了。Zend_InputFilter提供了一个简单、集中的根据特定规则过滤数据的类方法集。例如,你可以用getAlpha()来获取$_POST['name']中的字母:

 

<?php

/* $_POST['name'] = 'John123Doe'; */

$filterPost = new Zend_InputFilter($_POST);

/* $_POST = NULL; */

$alphaName $filterPost->getAlpha('name');

/* $alphaName = 'JohnDoe'; */

?>

 

每一个类方法的参数都是对应要过滤的元素的关键词。对象(例子中的$filterPost)可以保护数据不被篡改,并能更好地控制对数据的操作及一致性。因此,当你操纵输入数据,应始终使用Zend_InputFilter

 

提示:Zend_Filter提供与Zend_InputFilter方法一样的静态方法。

 

构建新闻管理系统

 

虽然预览版提供了许多组件(甚至许多已经被开发),我们已经讨论了构建一个简单程序所需要的全部组件。在这里,你会对ZF的基本结构和设计有更清楚的理解。

 

每个人开发的程序都会有所不同,而Zend Framework试图包容这些差异。同样,这个教程是根据我的喜好写的,请根据自己的偏好自行调整。

 

当我开发程序时,我会先做界面。这并不意味着我把时间都花在标签、样式表和图片上,而是我从一个用户的角度去考虑问题。因此我把程序看成是页面的集合,每一页都是一个独立的网址。这个新闻系统就是由以下网址组成的:

 

/
/add/news
/add/comment
/admin
/admin/approve
/view/{id}

 

你可以直接把这些网址和controller联系起来。IndexController列出新闻,AddController添加新闻和评论,AdminController处理一些如批准新闻之类的管理,ViewController特定新闻和对应评论的显示。

 

如果你的FooController.php还在,把它删除。修改IndexController.php,为业务逻辑以添加相应的action和一些注释:

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
IndexController extends Zend_Controller_Action 
{
    public function 
indexAction()
    {
        
/* List the news. */
    
}

    public function 
noRouteAction()
    {
        
$this->_redirect('/');
    }
}

?>

 

接下来,创建AddController.php文件:

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
AddController extends Zend_Controller_Action
{
    function 
indexAction()
    {
        
$this->_redirect('/');
    }

    function 
commentAction()
    {
        
/* Add a comment. */
    
}

    function 
newsAction()
    {
        
/* Add news. */
    
}

    function 
__call($action$arguments)
    {
        
$this->_redirect('/');
    }
}

?>

 

记住AddControllerindexAction()方法不能调用。当访问/add时会执行这个类方法。因为用户可以手工访问这个网址,这是有可能的,所以你要把用户重定向到主页、显示错误或你认为合适的行为。

 

接下来,创建AdminController.php文件:

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
AdminController extends Zend_Controller_Action
{
    function 
indexAction()
    {
        
/* Display admin interface. */
    
}

    function 
approveAction()
    {
        
/* Approve news. */
    
}

    function 
__call($action$arguments)
    {
        
$this->_redirect('/');
    }
}

?>

 

最后,创建ViewController.php文件:

 

<?php

Zend
::loadClass('Zend_Controller_Action');

class 
ViewController extends Zend_Controller_Action
{
    function 
indexAction()
    {
        
$this->_redirect('/');
    }

    function 
__call($id$arguments)
    {
        
/* Display news and comments for $id. */
    
}
}

?>

 

AddController一样,index()方法不能调用,所以你可以使用你认为合适的action。ViewController和其它的有点不同,因为你不知道什么才是有效的action。为了支持像/view/23这样的网址,你要使用__call()来支持动态action。

  

数据库操作

 

因为Zend Framework的数据库组件还不稳定,而我希望这个演示可以做得简单一点。我使用了一个简单的类,用SQLite进行新闻条目和评论的存储和查询。

 

<?php

class Database
{
    private 
$_db;

    public function 
__construct($filename)
    {
        
$this->_db = new SQLiteDatabase($filename);
    }

    public function 
addComment($name$comment$newsId)
    {
        
$name sqlite_escape_string($name);
        
$comment sqlite_escape_string($comment);
        
$newsId sqlite_escape_string($newsId);

        
$sql "INSERT
                INTO   comments (name, comment, newsId)
                VALUES ('$name', '$comment', '$newsId')"
;

        return 
$this->_db->query($sql);
    }

    public function 
addNews($title$content)
    {
        
$title sqlite_escape_string($title);
        
$content sqlite_escape_string($content);

        
$sql "INSERT
                INTO   news (title, content)
                VALUES ('$title', '$content')"
;

        return 
$this->_db->query($sql);
    }

    public function 
approveNews($ids)
    {
        foreach (
$ids as $id) {
            
$id sqlite_escape_string($id);

            
$sql "UPDATE news
                    SET    approval = 'T'
                    WHERE  id = '$id'"
;

            if (!
$this->_db->query($sql)) {
                return 
FALSE;
            }
        }

        return 
TRUE;
    }

    public function 
getComments($newsId)
    {
        
$newsId sqlite_escape_string($newsId);

        
$sql "SELECT name, comment
                FROM   comments
                WHERE  newsId = '$newsId'"
;

        if (
$result $this->_db->query($sql)) {
            return 
$result->fetchAll();
        }

        return 
FALSE;
    }

    public function 
getNews($id 'ALL')
    {
        
$id sqlite_escape_string($id);

        switch (
$id) {
            case 
'ALL':
                
$sql "SELECT id,
                               title
                        FROM   news
                        WHERE  approval = 'T'"
;
                break;
            case 
'NEW':
                
$sql "SELECT *
                        FROM   news
                        WHERE  approval != 'T'"
;
                break;
            default:
                
$sql "SELECT *
                        FROM   news
                        WHERE  id = '$id'"
;
                break;
        }

        if (
$result $this->_db->query($sql)) {
            if (
$result->numRows() != 1) {
                return 
$result->fetchAll();
            } else {
                return 
$result->fetch();
            }
        }

        return 
FALSE;
    }
}

?>

 

(你可以用自己的解决方案随意替换这个类。这里只是为你提供一个完整示例的介绍,并非建议要这么实现。)

 

这个类的构造器需要SQLite数据库的完整路径和文件名,你必须自己进行创建。

 

<?php

$db 
= new SQLiteDatabase('/path/to/db.sqlite');

$db->query("CREATE TABLE news (
                id       INTEGER PRIMARY KEY,
                title    VARCHAR(255),
                content  TEXT,
                approval CHAR(1) DEFAULT 'F'
            )"
);

$db->query("CREATE TABLE comments (
                id       INTEGER PRIMARY KEY,
                name     VARCHAR(255),
                comment  TEXT,
                newsId   INTEGER
            )"
);

?>

 

你只需要做一次,以后直接给出Database类构造器的完整路径和文件名即可:

 

<?php

$db 
= new Database('/path/to/db.sqlite');

?>

  

整合

 

为了进行整合,在lib目录下创建Database.phploadClass()就可以找到它。你的index.php文件现在就会初始化$view$db并存储到寄存器。你也可以创建__autoload()函数自动加载你所需要的类:

 

<?php

include 'Zend.php
分享到:
评论

相关推荐

    理解 Zend 框架(IBM经典中文教程)

    ### 理解 Zend 框架:IBM 经典中文教程详解 #### 一、引言 在软件开发的世界里,程序员们总是希望能够通过工具和技术来提高工作效率,减少重复劳动。随着网络技术的发展和互联网应用的需求增加,PHP 作为一种流行...

    Zend框架入门教程

    ### Zend框架入门教程知识点解析 #### 一、简介与背景 **标题与描述解析:** - **标题**:“Zend...通过遵循文档中的指导,开发者能够更好地理解MVC架构,并学会如何利用Zend框架构建高效、可维护的Web应用程序。

    php框架,基于zend重构的框架

    压缩包中的“Lite”可能表示这个框架是轻量级的,相对于原始的Zend框架,它可能去除了部分高级功能或非核心组件,以保持简洁和高效。 **反馈机制** 开发者鼓励用户在使用过程中发现和报告问题,提供了一个邮箱地址...

    经典zend 框架入门教程

    ### 经典Zend框架入门教程知识点详解 #### 一、简介与目标 本教程旨在介绍如何使用Zend框架创建一个简单的基于数据库的应用程序,并遵循模型-视图-控制器(MVC)设计模式。通过本教程的学习,您将能够掌握Zend框架...

    zend完整框架Demo

    3. **MVC模式**:在Zend框架中,Model处理数据逻辑,View负责展示,Controller协调Model和View。开发者需要创建控制器类,定义模型类,并编写视图脚本来实现业务逻辑。 4. **路由与控制器**:`Bootstrap.php`文件是...

    zend框架里架构mysql主从

    在本教程中,我们将深入探讨如何在Zend框架中设置MySQL主从架构。 首先,理解MySQL主从复制的基本概念至关重要。主从复制是MySQL数据库的一种高可用性解决方案,其中一台服务器(主服务器)处理写操作,而其他...

    Zend开发手册 zend框架手册

    "Zend开发手册"包含了详细的API文档、教程和示例代码,是开发者快速上手和深入理解Zend Framework的重要参考。同时,社区和官方论坛提供了丰富的问答和最佳实践,可以帮助解决开发中遇到的问题。 总结, Zend ...

    基于Zend Framework 框架的CMS PHP 源代码

    **基于Zend Framework框架的CMS PHP源代码详解** 在IT领域,内容管理系统(CMS)是用于构建和管理网站的软件工具,而PHP作为一种流行的服务器端脚本语言,常被用于开发Web应用,包括CMS。本资源提供了基于Zend ...

    大道PHP:LAMP+Zend+开源框架整合开发与实战(随书光盘源码2).rar

    理解Zend框架的MVC(Model-View-Controller)模式,以及其服务、控制器、模型和视图的交互,有助于提高开发效率。 4. 开源框架整合:除了Zend,书中的实战部分还可能涵盖了其他如Symfony、Laravel、Yii等流行的PHP...

    php+mysql直销系统源码,含数据库 zend框架

    开发者可以通过深入研究源码,理解其数据库设计、PHP脚本逻辑以及Zend框架的应用,进一步提升自己的技能,并在此基础上进行二次开发或定制化服务。对于想要涉足直销系统开发的人员来说,这是一个宝贵的参考资料和...

    zend框架写的blog程序

    "zend框架写的blog程序"是一个使用 Zend Framework 构建的博客应用示例,它展示了如何利用该框架搭建功能齐全的 Web 应用。从描述中可以看出,这个程序可能需要 Apache 的 mod_rewrite 功能以提供友好的 URL。通过...

    理解ZEND框架

    作者简介: Nicholas Chase 曾经参与过许多公司网站的开发,包括 Lucent Technologies、Sun Microsystems、Oracle 及 Tampa Bay Buccaneers。他曾当过中学物理教师、低级放射性废弃设备管理员、在线科幻杂志编辑、...

    ZendFramework框架配置...

    首先,让我们理解 Zend Framework 的核心概念。框架的核心组件包括路由、控制器、模型、视图、服务管理器和依赖注入容器。每个组件都有其特定的角色,共同协作以实现Web应用的功能。 1. **配置文件结构**:在 Zend ...

    zendframework3.0框架

    Zend Framework 3.0(简称ZF3)是一个基于PHP编程语言的开源Web应用程序框架,它遵循模型-视图-控制器(MVC)架构模式,并提供了丰富的工具和组件来帮助开发者构建高质量的Web应用。这个框架的核心理念是模块化、可...

    zendframwork框架包

    这个框架包的资源包含了多个关键组件,对于深入理解和开发基于Zend Framework的应用程序至关重要。 首先,`.htaccess` 文件是Apache服务器的一个配置文件,用于控制目录级别的访问权限。在Zend Framework中,它通常...

    zend framework PHP框架一小时速成

    - **Django**:虽然Django是Python语言的Web框架,但这里提到它是作为一种对比,以便理解不同语言中的MVC框架的共同之处。 在Zend Framework中,MVC模式的实现非常灵活。开发者可以根据项目需求自由组合不同的组件...

    诗意的边缘:PHP顶级框架Zend Framework开发实战-代码

    ** Zend Framework 框架详解** Zend Framework 是一个开源、基于组件的 PHP 开发框架,专为构建可扩展且高性能的 Web 应用程序而设计。它的设计模式遵循了 Model-View-Controller(MVC)架构,使得开发者可以更加...

Global site tag (gtag.js) - Google Analytics