CodeIgnite-MVC-编程指南-全-

CodeIgnite MVC 编程指南(全)

原文:zh.annas-archive.org/md5/6c1b32f4c01c318b2fd0ab36939e9eb2

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

本书旨在教你如何使用 Ellis Labs 的 CodeIgniter 平台高效地开发 Web 应用程序。CodeIgniter 平台是一个面向对象模型-视图-控制器开发平台。有关 MVC 的更多信息,请参阅en.wikipedia.org/wiki/Model-view-controller。本书的读者应熟悉至少 PHP 编程语言,特别是 PHP 面向对象编程(OOP)及其用法,以及 MySQL。

CodeIgniter(本书中简称 CI)是一个应用程序开发框架,是使用 PHP 构建网站和 Web 应用程序的人的实用工具。CodeIgniter 是一个智能应用程序开发骨架框架,具有灵活且可扩展的核心,支持高性能和低资源占用。由 Ellis Labs 开发和维护的 CodeIgniter 框架(OSL 3.0 开源许可证)为全球的开发者生态系统提供动力。CodeIgniter 的第一个公开版本于 2006 年 2 月 28 日发布。它得到了 Web 应用程序专业开发者的极高评价。在 2010 年 11 月,CodeIgniter 开发项目被添加到知名的 GitHub 社区项目,并得到了全球开发者的日益关注和使用,以及越来越多的第三方提供更多附加组件,这些附加组件具有更好的成熟度和功能集。

基于面向对象编程(OOP)框架和MVC模型-视图-控制器)开发模式构建的 Web 应用程序呈上升趋势,这些模式将在下一节中描述。CodeIgniter 就是这样一种框架。似乎 CodeIgniter 的受欢迎程度持续上升,因为它拥有简单而高质量的 OOP 核心,这使它具有极大的创造力、可重用性和代码清晰性命名约定,这些都很容易扩展(用户类扩展 CI 类),同时越来越多的第三方应用程序插件(包括提供面向应用程序解决方案的视图/控制器/模型/库/辅助工具,如 CMS、购物车或表格网格导航器)和库/辅助工具的附加组件变得可用。

MVC 概念是一种开发模式或计算机用户界面的应用程序框架,它将信息的表示与与之交互的用户分离。MVC 已被采用作为 Web 应用程序开发的成功架构。模型由应用程序数据组成,并提供操作这些数据的服务。控制器处理业务规则,并执行对模型和视图的请求。控制器在输入和输出之间进行调解,输入主要来自与执行了渲染视图的 Web 浏览器交互的用户。浏览器通过 HTTP 协议运行控制器接收到的渲染视图。控制器是应用程序的核心。它执行模型/数据库更新、业务逻辑计算、将视图渲染给用户,并响应来自客户端的异步 AJAX (异步 JavaScript 和 XML) 请求。视图代码定义了控制器将作为 HTML 和 JavaScript 渲染到浏览器的表示和用户输入逻辑。浏览器通过 HTTP 响应接收渲染的视图以在本地执行。执行该内容的浏览器可以展示数据,例如文本、图表、图表和图像的混合。

有一些专注于 CMS 功能和维护的遗留 CMS (内容管理系统) Web 开发平台,例如成熟的平台 DRUPAL。对于以内容为导向的项目可能非常有用,但如果项目目标是开发一套新的丰富功能,即具有许多输入和定制 UI 操作的 Web 应用程序,则可能不太吸引人。如果项目需求涉及低占用空间和快速响应/高性能,CodeIgniter 被发现具有出色的结果。

总结来说,在灵活性、代码可重用性、轻量级基础设施、激发开发者创造力、代码清晰度、最高性能、最小占用空间和快速学习曲线方面,CodeIgniter 似乎是最好的选择。此外,由于全球开发者社区的不断发展,它也是主动改进过程的一部分。

本书涵盖的内容

第一章, 入门,介绍了 CodeIgniter 框架,同时初步了解基于 Web 的应用程序。

第二章, 配置和命名规范,回顾了 CI 命名规范规则、风格指南和精神,以及 CI 项目内的强制性和可选配置及其用法,并附有多个示例。还将回顾用户定义的配置实践。

第三章, 控制器,回顾了 CI 控制器和扩展 CI 控制器的用户定义控制器。将通过多个示例来回顾 CI 控制器类服务、角色、定义、使用和范围,以澄清。

第四章, ,回顾了 CI 框架中的用户定义库。它们的用途、角色、定义、使用范围将通过几个示例进行说明。将提供定义库和使用它们的几个示例。

第五章, 辅助函数,向您介绍 CI 辅助函数和用户定义辅助函数的可重用价值、定义规则、范围和使用。将提供定义辅助函数和使用它们的几个示例。

第六章, 模型,涵盖了 CI 模型和用户定义模型的可重用价值、定义规则、范围和使用。将提供定义模型、扩展 CI 模型和使用它们的几个示例。

第七章, 视图,解释了 CI 视图概念作为通过 HTTP 提供的客户端可视化和用户交互的生成器。将回顾 PHP 部分和范围、视觉内容(HTML/CSS)以及客户端浏览器中的程序(JavaScript/AJAX/jQuery)。本章将涵盖视图的范围、定义和控制器渲染指南,包括实际练习和技巧。

附录, 附录参考资料,指出了与 CodeIgniter 正式资源以及开发者社区 ECHO 系统相关的推荐外部资源。

您需要本书的内容

为了理解本书的内容,用户至少需要具备一些 PHP 编程语言经验,以及 PHP OOP(面向对象编程)和 MySQL 知识。

本书面向对象

本书面向对使用 OOP MVC 概念和特别是 CodeIgniter 平台开发应用程序感兴趣的 PHP 网络应用程序开发者。

惯例

在本书中,您将找到许多不同风格的文本,以区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码单词如下所示:"我们可以通过使用include指令来包含其他上下文"。

代码块如下设置:

[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)

当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:

[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)

任何命令行输入或输出如下所示:

# cp /usr/src/asterisk-addons/configs/cdr_mysql.conf.sample
 /etc/asterisk/cdr_mysql.conf

新术语和重要单词以粗体显示。您在屏幕上看到的单词,例如在菜单或对话框中,在文本中如下所示:"点击下一步按钮将您移动到下一屏幕"。

注意

警告或重要注意事项以如下框形式出现。

小贴士

技巧和窍门如下所示。

读者反馈

我们欢迎读者的反馈。请告诉我们您对本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们开发您真正能从中获得最大收益的标题非常重要。

要发送一般反馈,只需将电子邮件发送到链接feedback@packtpub.com,并在邮件主题中提及书名。

如果您在某个主题上具有专业知识,并且您有兴趣撰写或为书籍做出贡献,请参阅我们关于www.packtpub.com/authors的作者指南。

客户支持

现在您已经是 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助您从您的购买中获得最大收益。

下载示例代码

您可以从www.packtpub.com的账户下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便直接将文件通过电子邮件发送给您。

错误清单

尽管我们已经尽一切努力确保我们内容的准确性,但错误仍然可能发生。如果您在我们的某本书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以节省其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何错误清单,请通过访问www.packtpub.com/support,选择您的书籍,点击错误提交表单链接,并输入您的错误详细信息来报告它们。一旦您的错误清单得到验证,您的提交将被接受,错误清单将被上传到我们的网站,或添加到该标题的错误清单部分。

盗版

网络上对版权材料的盗版是一个持续存在的问题,所有媒体都存在。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现任何形式的我们作品的非法副本,请立即向我们提供位置地址或网站名称,以便我们可以追究补救措施。

请通过链接copyright@packtpub.com与我们联系,并提供疑似盗版材料的链接。

我们感谢您在保护我们的作者以及为我们提供有价值内容的能力方面的帮助。

询问

如果您在本书的任何方面遇到问题,可以通过链接questions@packtpub.com与我们联系,我们将尽力解决。

第一章. 入门

本章通过审查一些基本的 Web 应用程序示例,涵盖了 CI 开发框架的基本知识和其使用。我们将从一个基本的“你好,世界”示例开始,然后过渡到一个与数据库集成的交互式联系表单。我们将通过逐步方法构建 CI 应用程序。在整个章节中,我们需要记住 CI 开发框架是一个基于 MVC 的开发架构(更多信息,请参阅维基百科定义en.wikipedia.org/wiki/Model-view-controller)。

本章将主要关注以下主题:

  • CI 项目目录树框架

  • 配置(路由和自动加载在本章中介绍,其他问题在第二章配置和命名约定中介绍)

  • 示例 1:hello world

  • 示例 2:向视图传递参数

  • 示例 3:模型通过渲染结果到视图进行数据库查询

  • 示例 4:交互式联系表单

通过审查这些示例,我们将了解使用 CI 资源的基本知识。我们将首先简要回顾所使用的 CI 资源。然后,我们将审查一个加载静态视图页面的 Web 应用程序代码。接下来,我们将使用模型从数据库检索数据并在视图中显示它。最后,我们将添加一个带有联系表单的视图,通过调用控制器方法将输入保存到数据库中。

安装 CodeIgniter

首先,我们需要有一个托管 PHP 服务器(版本 5.3 或更高版本)和一个 MySQL 服务器(最新版本之一),我们知道数据库凭据。建议从 PHP 进行本地数据库访问以简化操作。

注意,服务器将以CGI通用网关接口)的方式运行,以便让持续集成(CI)操作。我们可以在我们的 PC 上有一个本地 Web 开发环境,或者一个托管和专用的远程服务器。

一旦我们设置了一个本地 Web 开发环境,我们需要下载 CI 的最新版本,本书撰写时为 2.1.2 版本。下载最新版本的链接是codeigniter.com/downloads/。现在,如果我们查看 CI 文件夹,我们应该看到以下目录树:

codeigniter/
  index.php
  application/
  cache/
  config/
  controllers/
  core/
  errors/
  helpers/
  hooks/
  language/
  libraries/
  logs/
  models/
  third_party/
  views/
  system/
  core/
  database/
  fonts/
  helpers/
  language/
  libraries/

文件夹概述

根目录包含index.php文件,该文件处理所有 URI 请求。index.php文件将使用 CI 核心处理它们,并使用控制器加载的模型、库和助手以及渲染的视图应用我们的应用程序控制器,license.txt是 CI 的许可文件。.htaccess用于配置 CI 路由并从 URL 中删除index.php。JavaScript、CSS 和 HTML 被纳入渲染的 PHP 输出中,它们的使用在第七章视图中详细说明。

让我们回顾文件夹及其内容应用。

应用程序目录文件夹是我们主要活动项目编码区域的根目录。这是 CI 开发应用程序项目的核心。

必选组件

让我们来看看必选组件。

  • application/config:此文件夹包含所有 CI 应用程序配置文件,这些配置文件在第二章配置和命名约定中有所介绍。

  • application/controllers:此文件夹包含 CI 应用程序项目中所有的应用程序控制器。正如在前言中提到的,控制器是 MVC 设计架构中的一个组件,它处理用户的请求并向用户展示数据。CI 中的控制器是一个扩展 CI 控制器基类的类。类方法可以通过适当的 URI 执行或调用。与控制器定义和使用相关的命名约定将在第二章配置和命名约定中介绍。

  • application/views:此文件夹包含所有视图文件。视图是由用户浏览器执行的 HTML 内容,用于展示和与用户交互。视图可以是网页或 RSS 页面。

以下组件不是必选的,但强烈推荐:

  • application/models:此文件夹包含所有项目模型文件。模型是 MVC 设计架构中的组件,负责处理存储在数据库中的数据。CI 中的模型是一个设计用来与数据库中的信息一起工作的 PHP 类。第六章模型将详细阐述 CI 模型的概念、定义和用法,并附上几个使用示例。

  • application/helpers:此文件夹包含 CI 辅助文件的附加文件。它们可以是第三方文件或由开发者创建。辅助文件是特定类别中独立过程函数的集合。每个辅助函数执行一个特定的任务,不依赖于其他函数。第五章辅助函数将详细阐述 CI 辅助函数的概念、定义和用法,并附上几个使用示例。

  • application/libraries:此文件夹包含由开发者创建的 CI 应用程序项目中的所有库。从技术上讲,CI 库是一个 PHP 类。库的范围可以是任何项目资源,例如辅助函数、模型、控制器和视图。例如,库可以提供 Facebook 库 API 服务,以简化 Facebook 集成应用程序的代码。第四章将详细阐述 CI 库的概念、定义和用法,并附上几个使用示例。

  • system:这是 CodeIgniter 核心目录的根目录。system 文件夹包含在子文件夹中的重要系统组件,例如核心、数据库、辅助程序(内置系统辅助程序)和库(内置系统库)。

    小贴士

    不要编辑这些文件!如果我们不这样做,升级会更容易。

示例 1 – Hello World

首先,我们将从一个简单的例子开始,该例子在渲染的网页上显示Hello World。这是一个不使用数据库的例子。

URI 将是http://ourdomain.com/index.php/hello

我们可以从路径中删除index.php文件以启用更短的 URI;也就是说,http://ourdomain.com/index.php/hello

为了启用这些更短的 URI,我们将按照第二章中描述的配置更改,在config.php中的index_page设置进行配置。

我们将构建以下两个脚本:

  • 控制器类:application/controllers/hello.php

  • 视图脚本:application/views/helloview.php

在这个例子中,我们使用默认配置。有关配置的更多信息,请参阅第二章,配置和命名约定。在这个例子中,控制器传递了在视图中显示的参数。

小贴士

从控制器传递参数到视图是可选的。

控制器文件

这是控制器的代码示例。控制器负责使用如巨标题和消息之类的参数渲染视图。关于控制器类的命名,请参阅第二章,配置和命名约定

<?php 
class Hello extends CI_Controller {
  * Index Page for this controller.
  * Maps to the following URLhttp://example.com/index.php/hello
  - or - http://example.com/index.php/hello/index- or -* since this controller is set as the default controller in config/routes.php, it's displayed at http://example.com/
  * So any other public methods not prefixed with an underscorewill map to /index.php/welcome/<method_name>
  @see http://codeigniter.com/user_guide/general/urls.html
  public function index(){	    
    // Note that $view_params is optional// we can use $this->load->view('helloview');as well.// if the view doesn't use php variables 
    // The $view_params is extracted in the view script to php// variables $key = $value
    // In this example three variables will be generated by CI in the // view page
    // helloview.php variable: $mega_title
    // value: 'Codeigniter - Hello World'		// variable: $title      value: 'Welcome to // Codegniter'// variable: $message    value: 'Hello World'
    $view_params = array(
    'mega_title' => 'Codeigniter - Hello World', 'title'      =>  'Welcome to Codegniter','message'    =>  'Hello World'                              );		
 $this->load->view('helloview', $view_params);		}
	} // closing the class definition
/* End of file welcome.php *//* Location: ./application/controllers/welcome.php */

小贴士

您可以从您在www.packtpub.com的账户中下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便直接将文件通过电子邮件发送给您。

视图文件

以下是对应的渲染视图,它使用控制器提供的参数将视图渲染到网页上,并将其返回给用户:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title><?php echo $mega_title ?></title>
</head>
<body>
  <div id="container">
  <h1><?php echo $title ?></h1>
  <div id="body">
  <p><?php echo $message ?></p>
</div></div>
</body>
</html>

示例 2 – 将复杂参数传递给视图

在这个例子中,我们将向您展示如何从 CI 控制器传递和使用复杂参数,例如数组和对象数组,以便在 CI 视图中使用。您可以将任意数量的数组作为参数传递给视图;您还可以传递对象,例如查询结果的行。

标准 GET 参数 URI 看起来像这样:http://ourdomain.com/index.php/example2/more/?a=1&b=2&c=3

然而,让我们记住在 CI 中,URI 以这种方式传递:http://ourdomain.com/index.php/example2/more/1/2/3。有关更多信息,请参阅第二章,配置和命名约定

观察 URI,我们将构建名为 more 的控制器 example2.php,并传递三个参数给它。

我们将构建以下两个脚本:

  • 控制器类:application/controllers/example2.php

  • 视图脚本:application/views/example2more.php

控制器文件

控制器负责使用如大标题和信息等参数渲染视图。

以下是对应的控制器代码示例:

<?php 
class Example2 extends CI_Controller {
  //This function gets parameters and passes them to the view//example2more
  //The example url//http://ourdomain.com/index.php/example2/more/1/2/3
  so $a = 1, $b = 2, $c = 3
  public function more($a, $b, $c)
  {
    // The parameters in $view_params are extracted in the view//example2more.php
    // In this example 2 variables will be generated by CI in the//view page example2more.php
    //variable: $mega_title, value: Codeigniter, Passing//url parameters to view
    variable: $rows, value: array('a' => $a, 'b' => $b, 'c' => $c);
    $rows = array('a' => $a, 'b' => $b, 'c' => $c);
    $view_params = array('mega_title' => 'Codeigniter -  Passing url parameters to view 'rows' => $rows);
 $this->load->view('example2more', $view_params);
    }	}// closing the class definition/* End of file welcome.php

视图文件

以下是对应的渲染视图:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title><?php echo $mega_title ?></title>
</head>
<body>
<table>
<tr>
  <td>Key</td>
  <td>Value</td>
</tr>
<?php foreach ($rows as $key => $value): ?>
<tr>
  <td><?php echo $key ; ?></td>
  <td><?php echo $value ; ?></td>
</tr> 
<?php endforeach; ?>
</table>
</body>
</html>

示例 3 – 模型通过渲染结果到视图执行数据库查询

在本例中,我们将向您展示 CI 控制器如何使用 CI 模型从数据库检索数据并将其渲染到 CI 视图中。

URL 将是http://ourdomain.com/index.php/user

首先,我们必须在配置文件 application/config/database.php 中配置数据库设置。

我们应保持默认数据库设置不变,只需更改以下配置参数:

$db['default']['hostname'] = '127.0.0.1';
//In many cases when the hostname's value is 'localhost' theconnection to the database fails.
//Setting the hostname to 127.0.0.1 solves the problem.
$db['default']['username'] = 'dbUser;
$db['default']['password'] = 'dbPassword';
$db['default']['database'] = 'dbDataAbse';
$db['default']['port']     = 'dbPort';

模型类将从 users 表中检索所有用户详细信息。

有关配置的更多信息,请参阅第二章,配置和命名约定

我们将构建以下三个脚本:

  • 控制器类:application/controllers/user.php

  • 模型文件:application/model/usermodel.php

  • 视图脚本:application/views/userview.php

控制器文件

控制器通过模型从数据库检索 users 列表,并与其一起渲染视图。

以下是对应的控制器代码示例:

<?php
class User extends CI_Controller {
  function users()
  {
    //Manually loading the database
 $this->load->database();
    //Loading the model class
 $this->load->model('Usermodel');
    $view_params['mega_title'] = 'Model Example';
    //Calling the model to retrieve the users from the database
    $view_params['users']= $this->Usermodel->get_users();
 $this->load->view('userview', $view_params);
  }
}
/* End of file welcome.php */
/* Location: /application/controllers/welcome.php */

模型文件

以下是对应的模型代码示例。

<?php
class Usermodel extends CI_Model {
  function __construct()
  {
    // Call the Model constructor	parent::__construct();
  }
  //This method retrieves the users list and returns an array of //objects each containing user details
  function get_users()
  {
    //Calling CI's database object's method for generating SQL//queries.
    $query = $this->db->get('users');
    //returns an array of users objects
    return $query->result();
  }
}

在本例中,CI 对象数据库的方法被调用以生成和执行 SQL 查询。

请参阅 CI 数据库库ellislab.com/codeigniter/user-guide/database/index.html

有关模型的信息,请参阅第六章,模型

视图文件

本例中的视图显示了从控制器接收的表格内容,其中包含数据库中定义的 users 列表。

以下是对应的渲染视图:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title><?php echo $mega_title ?></title>
</head>
<body>
<table>
<tr>
  <td>ID</td>
  <td>Name</td>
  <td>Email</td>
</tr>
<?php foreach ($users as $user): ?>
<tr>
  <td><?php echo $user->user_id ?></td>
  <td><?php echo $user->user_fname." ".$user->user_lname; ?></td>
  <td><?php echo $user->user_email ; ?></td>
</tr>
<?php endforeach; ?>
</body>
</html>

示例 4 – 交互式联系表单

本示例展示了如何使用 CI 表单辅助器和 form_validation 库编写联系表单。

关于库的更多信息,请参阅第四章,,以及关于辅助器的信息,请参阅第五章,辅助器

CI 控制器使用 form_validation 库定义表单验证设置,并渲染一个表单视图,该视图使用 form_validation 库设置来对用户提交的数据应用所需的验证。如果成功,CI 控制器将渲染显示成功消息的视图页面;否则,它将渲染包含表单的视图页面,并显示错误消息。

此示例的 URI 为 http://ourdomain.com/index.php/contact

为了执行此示例,我们需要构建以下三个脚本:

  • 联系表单控制器类:application/controllers/contact.php

  • 视图表单脚本:application/views/contactview.php

  • 查看成功页面脚本:application/views/contactsuccess.php

控制器文件

控制器创建了一个用于添加和编辑产品的表单。

更多信息,请参阅第七章,视图

以下是对应的控制器代码示例:

<?php
class Contact extends CI_Controller {
  public function index()
  {
    //Loading the form helper
    $this->load->helper('form');
    //Loading the form_validation library
    $this->load->library('form_validation');
    $view_params['form']['attributes'] = array('id' =>'myform');
    //contact name details
    $view_params['form']['contact_name']['label'] = array('text' => 'Your name:', 'for' => 'name');
    $view_params['form']['contact_name']['field']= array('name' => 'contact_name', 'id' => 'contact_name','value'=>isset($_POST['contact_name']) ?
    $_POST['contact_name'] : '',
    'maxlength' => '100', 'size' => '30', 'class' => 'input');
    //contact name details
    $view_params['form']['contact_email']['label'] = array('text' => 'Your email:', 'for' => 'email');
    $view_params['form']['contact_email']['field'] = array('name' => 'contact_email', 'id' => 'contact_email','value'=> isset($_POST['contact_email']) ?
    $_POST['contact_email'] : '',
    'maxlength'   => '100', 'size' => '30', 'class' => 'input');
    //contact message details
    $view_params['form']['contact_message']['label'] = array('text' => 'Your message:', 'for' => 'message');
    $view_params['form']['contact_message']['field'] = array('name' => 'contact_message', 'id' => 'contact_message','value' => isset($_POST['contact_message']) ?
    $_POST['contact_message'] : '',
    'rows' => '10',  'cols' => '100', 'class' => 'input');
    // Setting validation rules
    $config_rules = array(array('field' => 'contact_name','label' => 'Contact Name', 'rules' => 'trim|required'),
    array('field' => 'contact_email', 'label' => 'Contact Email','rules' => 'trim|required|valid_email'));
    $this->form_validation->set_rules($config_rules);
    $this->form_validation->set_rules('contact_message','Contact Message', 'trim|required');
    // Validating the form
    if ($this->form_validation->run() == FALSE)
    // failed 
    {
      for ($index = 0; $index < count($a_fields) $index++);
      {
        $s_field = $a_fields[$index];
        if (form_error($s_field))
        {
          $view_params['form'][$s_field]['field']['class'] .= 'error';
          }
        }
      $this->load->view('contactview', $view_params);
      }
      else // Validation succeeded
      {
      $success_params = array('message'=> 'Success');
      $this->load->view('contactsuccess', $success_params);
      }
    }
  }
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */

视图文件

视图文件显示用于从用户接收数据的联系表单。

以下是对应的渲染表单视图:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Form Example</title>
</head>
<body>
<?php if (validation_errors()) : ?>
  <?php echo validation_errors() ; ?>
  <?php endif; ?>
<?php echo form_open('contact', $form['attributes']) ; ?>
<table>
<tr>
  <td><?php echo form_label($form['contact_name']['label']['text'],
$form['contact_name']['label']['for']);?> 
  </td> 
  <td><?php echo form_input($form['contact_name']['field']); ?></td>
</tr>
<tr>
  <td><?php echo form_label($form['contact_email']['label']['text'],
$form['contact_email']['label']['for']);?>
  </td> 
  <td><?php echo form_input($form['contact_email']['field']);?>
  </td>
</tr>
<tr>
  <td><?php echo
  form_label($form['contact_message']['label']['text'],
  $form['contact_message']['label']['for']); ?>
  </td> 
  <td><?php echo form_textarea($form['contact_message']['field']);?>
  </td>
</tr>
<tr>
  <td colspan="3"><?php echo form_submit('mysubmit', 'Send'); ?></td>
</tr>
</table>
<?php echo form_close() ; ?>
</body>
</html>
The following is the corresponding rendered success view:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Contact sent</title>
</head>
<body>
<div id="container">
  <div id="body">
    <p><?php echo $message ?></p>
  </div>
</div>	
</body>
</html>

摘要

在本章中,我们回顾了 CI 目录树,特别是应用程序文件夹,它是任何 CI 项目的核心和灵魂。在下一章中,我们将回顾配置,例如数据库和命名约定,这些对于 CI 项目至关重要。

第二章. 配置和命名规范

本章最初介绍了 CI 命名规范。这些规范包括规则、风格指南和 CodeIgniter 命名精神。本章的第二部分将回顾 CI 项目配置,包括内置资源以及用户定义的或第三方附加库。请注意,我们实际上将在 第一章 中描述的子目录 application 中构建自己的项目代码,入门,可选地包含项目自制的资源的相关资源目录,例如 CSS / 媒体 / jQuery 库的资源或第三方附加组件,扩展从 Ellis Labs 网站或 GitHub 下载的基本 CI。

我们应该记住,开发 CI 项目是通过替换/扩展默认提供的控制器、视图、模型和其他资源,以良好的 OOP 风格完成的。我们应该扩展控制器、模型,添加额外的视图,以及使用定义的帮助器或库。我们可以从第三方库或帮助器中添加这些,或者为我们的特殊项目业务逻辑和需求开发新的。

安装 CI 后的初始步骤是为我们的项目需求进行适当的配置,例如数据库、会话、自动加载的帮助器以及我们想要的库。

CI 在项目目录中定义了一套配置文件,位于 application/config。这些配置在执行任何项目 CI 控制器时最初加载,无论是通过浏览器使用 URI 调用还是通过代码发出 HTTP 请求。主要的配置文件是:config.phpdatabase.phpautoload.phproutes.php

我们应该审查每个主要配置文件及其配置值,包括推荐值和可能的值。

CI 目录树

以下是 CodeIgniter 的经典目录树结构:

CI 目录树

注意,当我们添加新的插件和其他资源,如 bootstrap 时,可能会添加新的资源目录,您可以根据自己的选择命名,以便您可以从正在开发的特定资源中引用它们,使用 CI BASEPATH 定义参数作为 CI_PROJECT_ROOT 目录的路径。

如果我们在项目根目录下添加一个新目录,比如 bootstrap,则包含资源(如 CSS、JavaScript 或图像,例如 hello.png)的路径将是 $path = BASEPATH."bootstrap/hello.png"

config.php

CI 的主要配置文件具有以下主要配置:

$config['base_url'] = '';

默认为空字符串,以便 CI 可以计算项目根目录的基本 URL。在我们的代码中,我们将多次引用基本 URL,主要用于执行控制器。要获取基本 URL,我们应该调用:

$base_url = base_url();
// defined in the URL
// helper mentioned before.

URL 辅助函数中的 base_url() 函数返回 CI 项目基本 URI 字符串。例如,如果 CI 项目是在名为 example.com 的域名下名为 public_html 的目录中开发的,并且我们有一个名为 find 的控制器,一个名为 stock 的方法,以及一个名为 myprod 的目录,我们可以在 myprodmydev 项目中使用 base_url() 来调用 findstock 方法:

$url = base_url()."index.php/ find/stock";

mydev 项目中,我们将得到:

$url = "http://example.com/mydev/index.php/find/stock"

myprod 项目中,我们将得到:

$url = "http://example.com/myprod/index.php/find/stock"

因此,为了调用名为 my_class 的控制器类,我们使用:

$URL = base_url()."index.php/my_class/mymethod";

这将定义 $u rlhttp://example.com/ mydev/index.php/my_class

要将索引页面设置为 CI 控制器/方法的 URI 路径的一部分,我们使用:

$config['index_page'] = 'index.php';

index.php 文件是处理所有 URI 请求的 CI 根 PHP 服务。它用作资源路径 URI 的一部分,例如 http://mysite.com/fci/index.php/tables_management/show。然而,我们可以通过设置 CI 隐藏 URI 路径中的 index.php 文件来调用 CI 资源,如[http://mysite.com/fci/tables_management/show`]。为此,我们需要执行以下配置步骤:

  1. 在 CI index.php 文件所在的工程根目录中,添加了一个名为 .htaccess 的 HTACCESS 类型文件,其中包含以下配置行,它将不包含 index.php 的 URI 重定向到 CI 项目控制器路径:

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    RewriteRule ^(.*)$ index.php/$1 [L]
    
    <Files "index.php">
    AcceptPathInfo On
    </Files>
    

    更多信息请参阅en.wikipedia.org/wiki/Htaccess

  2. 我们应该将更改应用到 /config/config.php 文件中,以便在 URI 路径字符串中 index_page 为空,而不是默认的 index.php。 $config['index_page'] = '';

.htaccess 文件在这里通过在从浏览器接收 URI 请求并在执行之前将其添加到 URI 中,完成了这个任务。结果是,浏览的用户将看不到它,但它会正确地调用所需的资源,类似于我们使用 index.php 的方式:

语言设置如下:

$config['language'] = 'english';

建议您将其保留为默认设置。请注意,即使我们使用其他语言,如阿拉伯语或希伯来语,也没有问题。我们只需确保我们的 PHP 文件以 UTF-8 格式保存,不带 BOM(字节顺序标记是一个 Unicode 字符,用于标记支持多语言方案的文件编码方法;有关更多信息,请参阅en.wikipedia.org/wiki/Byte_order_mark,以通知接收渲染的 HTML 页面的浏览器将其处理为 UTF-8 文件)。

这个标签的确切含义超出了本书的范围,可以从 HTML 标准中学习。

$config['charset'] = 'UTF-8';

此外,为了支持多语言,我们强烈建议在视图文件的 HTML 头部添加以下行:

<meta http-equiv="Content-Type"
content="text/html; charset=utf-8" />

这些设置通知浏览器处理字符编码为 UTF-8 的渲染 HTML 页面,这是非英语语言(如希伯来语、阿拉伯语和中文)最常用的多语言标准。

不要修改这些设置;这对于支持多语言非常有用。

$config['enable_hooks'] = FALSE;

如果将前面的配置设置为 TRUE,将使我们能够定义 CI 事件的钩子,钩子定义在 application/hooks 目录中。除非你有针对 CI 事件钩子的特定计划,否则不要修改这些设置。请注意,将钩子添加到 CI 核心活动中的概念超出了本书的范围。

$config['subclass_prefix'] = 'MY_';

前面的配置将使我们能够为我们的库类名称的前缀定义命名角色,以便与其他默认库区分开来。

$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';

前面的代码定义了在调用 CI 资源(主要是控制器)的 URI 中的允许字符。建议不要修改此设置。

$config['allow_get_array'] = TRUE;

这将使我们能够以参数调用控制器类方法,例如在前面提供的示例中所示。

<?php echo base_url(); ?>index.php/my_handler/calc/5/7

以下代码将提供与 my_handler 类本身中的类方法相同的结果,格式如下:

$Val= $this->calc(5,7);

以下配置定义是否使用 GET URL 查询字符串:

$config['enable_query_strings'] = FALSE;

如果将此配置设置为 TRUE,将使我们能够通过 GET URL 查询表单调用控制器类方法:

<?php echo base_url();?>index.php/my_handler/calc.php?a=5&b=7

强烈建议将其保留为 FALSE,因为 CI 提供了在 URI 中传递参数的解决方案,如本章开头提供的 calc 示例所示。

对于严重级别的日志阈值,任何具有相同或更高严重级别的活动都将被记录到 CI 中。支持的阈值级别及其含义如下:

  • 0:禁用日志(错误日志关闭)

  • 1:错误消息(包括 PHP 错误)

  • 2:调试消息

  • 3:信息性消息

  • 4:所有消息

    $config['log_threshold'] = 4;
    // 4 is the highest level for all CI events from notice level 
    // events and worse
    

如果启用了错误日志,前面的配置将在 /application/logs 根据日志阈值 () 级别生成错误日志。

注意,启用错误日志会导致我们的 Web 应用程序性能降低。只有在必须用于调试时才使用它。否则将其设置为 0

$config['log_path'] = '';

CI 项目的默认日志文件路径为 application/logs。除非你有明确的原因,否则不要修改此配置。

日期时间格式:

$config['log_date_format'] = 'Y-m-d H:i:s';

默认的日期时间格式设置为 2012-06-18 14:54:11。建议不要修改此配置。

缓存文件路径:

$config['cache_path'] = '';

默认值为 application/cache。建议不要修改此配置。会话密钥:

$config['encryption_key'] = '';

encryption_key 必须设置为一个密钥,才能使用会话类服务。例如:

$config['encryption_key'] = 'cMGy4DSwGUvxYSar4279626HgOn2342efrwerr2TE2RF4G3reg4tF3etf';

在控制器内使用会话库并设置会话变量的示例如下:

$uid = 119; // where uid is the id of the loggeing user
$this->session->set_userdata ('this_user_id', $uid );

在另一个控制器中获取会话变量的方法如下:

$uid = $this->session->userdata('this_user_id');

会话数据存储机制如下:

$config['sess_use_database'] = FALSE;

如果将推荐配置设置为TRUE,我们将使用存储在相关默认数据库中的大量会话参数。

会话过期超时(秒):

$config['sess_expiration'] = 7200;
// The number of seconds the session will be kept

在 CI 用户手册中可以找到额外的会话配置参数。跨站脚本(XSS)过滤激活/停用:

$config['global_xss_filtering'] = FALSE;

这将启用对发送到应用程序的 URI 请求的 XSS 过滤。请注意,所有 URI 请求最初都由根index.php处理,以分析 URI 请求并发出适当的 CI 调用。如果设置为TRUE,它将保护 URI 请求免受 XSS 类型恶意攻击者的侵害。建议即使我们稍微降低应用程序性能,也应将其设置为TRUE

$config['csrf_protection'] = FALSE;

如果设置为TRUE,CI 将防止跨站请求伪造CSRF/XSRF)攻击。风险在于欺诈表单提交时。如果我们正在接受用户数据,强烈建议启用 CSRF 保护。请注意,当使用 AJAX 时,可能需要额外的代码来启用带有 AJAX 的 CSRF 保护。

database.php

数据库配置允许定义一个或多个数据库连接,这些连接可以被应用程序使用。数据库配置以下形式的二维数组:

$db['db_entry']['db_connection_param']

通过设置数据库默认条目的参数,我们将定义以下参数:

$db['default']['hostname'] = 'localhost';
// note: in some cases '127.0.0.1' must be used instead 
// localhost if the database server is in another server use
// URI such as: 'domain.db.NNNNNNN.hostedresource.com' or 
// similar – advise our system admin/service provider
// Optional configuration of DB server connection port

$db['default']['port'] = '4009';
// In case our DB server operates on another port
// otherwise we may drop the port config line!

$db['default']['username'] = 'mydefaultdb';
$db['default']['password'] = 'mypass1';
$db['default']['database'] = 'mydatabase1';
$db['default']['dbdriver'] = "mysql";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = TRUE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

通过设置名为dbentry2的另一个数据库的参数,我们将定义以下参数:

$db['dbentry2']['hostname'] = 'localhost';
$db['dbentry2']['username'] = 'mySecondDB';
$db['dbentry2']['password'] = 'mypass2';
$db['dbentry2']['database'] = 'mySecondDB';
$db['dbentry2']['dbdriver'] = "mysql";
$db['dbentry2']['dbprefix'] = "";
$db['dbentry2']['pconnect'] = TRUE;
$db['dbentry2']['db_debug'] = TRUE;
$db['dbentry2']['cache_on'] = TRUE;
$db['dbentry2']['cachedir'] = "";
$db['dbentry2']['char_set'] = "utf8";
$db['dbentry2']['dbcollat'] = "utf8_general_ci";

在加载数据库类时,无需连接和加载默认数据库,因为它会自动完成,但是调用如下:

$this->load->database();

或者,为了引用特定的数据库条目名称,它是:

$this->load->database('default');

为了连接和加载前面提到的dbentry2数据库设置,请使用以下代码:

$this->dbentry2= $this->load->database(dbentry2', TRUE); 

要使用数据库类库的默认数据库db,,请使用:

$q1 = $this->db->query ("select * from mytable");

要使用dbentry2数据库,请使用:

$q2 = $this->dbentry2->db->query ("select * from DB2table");

routes.php

定义默认控制器,当通过 URI 引用到项目的base_url时将执行此控制器——假设为http://mydomain.com/myapp,这样myapp就是服务器上public_html的子目录,并且我们有home_page_controller

$route['default_controller'] = "home_page_controller"

当用户发出http://mydomain.com/myapp时,由于对主页控制器的路由配置,CI 将发出的 URI 将好像用户正在引用http://mydomain.com/myapp/home_page_controller

$route['404_override'] = '';

在前面的示例中,如果用户引用不存在的项目控制器,如http://mydomain.com/myapp/sadfasdfsdfsdi,将执行默认的application/errors/error_404.php页面。

例如,我们可能决定为不存在的页面弹出消息并将路由到默认 URI,以最小化用户不便。

定义和使用自己的配置

CI 使我们能够定义自己的配置,并通过config类轻松访问它们。例如,使用application/config/my_config.php,假设我们在该config文件中定义了一个参数,如下所示:

$param1 = "value1";

我们可以轻松访问我们的配置文件参数,将所有参数加载到数组中:

$array = $this->config->load('my_config', TRUE);

第二个参数 TRUE 确保我们的配置参数将定义在一个以配置文件名作为前缀的数组中。

考虑以下代码:$param1 = $array['my_config']['param1'];

或者:$param1 = $this->config->item('param1', 'my_config');.

$param1 将具有我们在构建的配置文件中设置的 value1 的值。

理解和使用 CI 命名规范

CI 命名规范的理解和使用对于正确使用 CI 进行开发至关重要。它们使您能够使用严格且简洁的规则集编写最小化代码。

完整的 CI 命名规范和风格指南可以在codeigniter.com/user_guide/general/styleguide.html找到。

命名规范涉及参数、函数/方法、与类相关的 PHP 文件名存储代码、项目资源路径等的命名。以下是我们将审查的具体问题:

  • 在我们的项目资源中扩展 CI 资源,如 CI 控制器或模型(以类扩展类的方式——例如,扩展 CI_controllerCI_model;参见 控制器定义命名规则 部分中讨论的示例)

  • 定义视图并通过控制器渲染它们,无论是否提供视图代码可能用于其操作的参数

  • 使用 CI 辅助器和库中现有的通用可重用资源(可以从任何控制器或模型中加载,并由渲染的视图重用),以及定义新的 CI 辅助器和库

  • 定位文件和命名的如何做、应该做和不应该做,根据定义的控制器、模型、库和辅助器进行分类

  • 定义类资源名称、包含文件名、加载定义的类、辅助器或模型、通过 URI 实例化和调用调用方法以及调用带参数的类方法之间的关系

主要资源类型命名规则

CI 定义了“一类一个文件标准”,这样每个 CI 控制器扩展和库类 CI 模型扩展都位于一个文件中。这也适用于一组函数的辅助器。每个资源类别(控制器、库、模型和视图)都将位于特定的目录或其子目录中。最常用的资源类别如下:

  • 控制器:这些使客户端(例如,浏览器)能够操作

  • 视图:这些由控制器渲染并通过 HTTP 返回给浏览器

  • :这些由项目资源(如控制器、视图、模型和辅助器)调用

  • 模型:这些由项目资源(如控制器、视图、库和辅助器)调用

  • 辅助器:这些由项目资源(如控制器、视图、库和模型)调用

主要资源类型命名规则

控制器定义命名规则

让我们定义一个初始项目控制器来处理一些基本服务。注意,控制器类名为My_handler,必须位于我们 CI 项目目录中的/application/controllers下的一个名为my_handler.php(全部小写)的文件中。以下是用于回顾命名约定的代码示例:

class My_handler extends CI_Controller { 
function __construct(){
// Must Call Patent to get all its services inherited
parent::__construct();
}
  function index () {
// executed when referring to My_handlercontroller via URLecho "Hello World"; }

function calc  ($a = 2, $b=2) {// executed when referring to My_handler/calc via URL echo   " $a * $b = ".$a*$b;
}

functionAJAX_calc () {
// If the request is not an AJAX we shall abort!
//This is done by the
if (!$this->input->is_AJAX_request())  
exit ('none AJAX calls rejected!'); // see http://codeigniter.com/user_guide/libraries/input.html

$a = $this->input->post('a');// get the posted a parameter$b = $this->input->post('b');// get the posted b parameter
$result = (int) $a * (int) $b; 
$data = array('result'=> $result);// to add more array parameters: ,'p2' => $p2, 'p3'=>$p3,..
echojson_encode($data);// return the JSON encoded array
return;
}

} // closing the class definition

我们通过 HTTP 请求 URL 调用此控制器,作为 HTTP 或 HTTPS 请求。例如:http://mydomain.com/index.php/my_handler

让我们通过这个控制器类定义来回顾几个使用场景。注意,你可以启用 CodeIgniter 在路径中不使用index.php文件来操作;有关更多信息,请参阅本章后面讨论的index.php文件问题。在本节中,我们将回顾 CI 控制器及其相关的命名规则的不同用例。以下主要是用于调用控制器的用例:

  • 直接从浏览器中

  • 从使用 CI PHP 锚点辅助函数嵌入的 HTML 页面脚本中

  • 从使用嵌入页面的 JavaScript/jQuery AJAX 调用的 HTML 页面中

  • 从使用 cURL 调用的 crontab PHP 脚本中

控制器有其自己的命名规则和使用指南,我们现在将进行回顾。控制器最常见的是通过视图使用锚点标签来调用。然而,它也可以通过 AJAX 甚至使用 PHP 函数文件或基于 cURL 的请求的 crontab PHP 脚本来调用。

示例 1 – 调用控制器索引方法

控制器主要通过用户在客户端浏览器处理渲染视图的交互会话来调用。控制器方法被调用以发起另一个进程,例如 AJAX 请求或处理请求并将额外的视图或网页渲染回客户端浏览器。为了在视图定义(application/views)中定义控制器调用,我们定义一个由浏览器根据用户请求执行的锚点。注意,在这些示例中,我们使用了一个名为anchor()的其他 URL 辅助函数。

anchor( $uri, $text, $html_attributes);

注意,为了使用 CI 锚点辅助函数,我们最初将通过config/autoload.php加载辅助函数 URL。

$autoload['helper'] = array('url');

另一种方法是加载锚点辅助函数到渲染视图的控制器中,我们想在其中使用锚点:

$this->load->helper('url');
  • $URI:调用控制器或任何我们想要执行的 URI 路径

  • $text:显示给用户点击的锚点标签

  • $html_attributes:可以为 HTML 锚点元素定义的任何 HTML 属性

下面是一个客户端浏览器将要执行的 HTML 结果的示例:

<a href="myapps.com/myciapp/showme" class='mybutton'>
Press Me 
</a>
<!-- where 	$uri = 'myapps.com/myciapp/showme';
$text = 'Press Me';
$html_attributes = "class='mybutton'";-->

回到我们的例子——允许用户调用定义的控制器的视图代码部分将如下所示(PHP 部分在视图文件中的其他 HTML 标签中):

<?PHP 
echo anchor(ase_url().' index.php/my_handler ','Press Me A');
?>

注意

由于我们只引用了类名,其构造函数和(如果定义)索引方法将被执行。如果我们没有为这个 my_handler 控制器定义索引方法,前面的调用将仅使用其构造函数定义实例化类,如果定义了索引方法,它也将被调用。在我们的情况下,索引方法被定义了,所以它也将被调用。

示例 2 – 不带参数调用控制器和 calc 方法

在本例中,我们允许最终用户调用具有参数的特定类方法,但不需要参数,因此必须通过浏览器使用默认方法参数。

注意,为了使用任何 CI 辅助函数,我们需要确保它已被自动加载或已在控制器(用于控制器方法的用法或渲染的视图)、库或模型中特别加载。

<?PHP 
echo anchor(base_url().' index.php/my_handler/calc ' ,'Press Me B');
?>

注意,为了引用名为 calc 的特定 My_handler 类方法,我们在类名后拼接了 /calc。从浏览器发出此视图,我们将得到以下结果:2 * 2 = 4。为什么?

这仅仅是因为我们在接收控制器方法中定义了默认值。因此,如果没有发送参数,如本例所示,将使用这些默认值,它们都设置为 2,因此类 calc 方法将输出 4

示例 3 – 使用参数调用控制器和 calc 方法

在本例中,我们允许最终用户通过浏览器调用具有其参数的特定类方法。

<?PHP
echo anchor(base_url().' index.php/my_handler/calc/5/7', 'Press Me C',);
?>

从浏览器发出此请求,我们将得到:5 * 7 = 35。为什么?

由于我们提供了 5 作为第一个参数和 7 作为第二个参数,使用 CI URI 命名约定中的观察 / 将参数值传递给被调用的控制器类方法。由于我们将参数用作乘法整数,PHP 将它们转换为整数,因此我们有 5 * 7,结果是 35。

注意,为了使用参数调用特定控制器方法,我们在方法名后添加 / 分隔符,然后跟随着参数,每个参数也由 / 分隔。

要更好地理解这一点,请查看以下用例及其含义,CI 使用 URI 如下:

当发出 URI:

<?PHP base_url() ?>/controller_name/method_name/param1/param2/../paramN

命名为 controller_name 的控制器将由 CI 使用控制器构造函数实例化,然后调用 method_name 方法,使用第一个参数 param1,第二个参数 param2,依此类推。

在 PHP 控制器端,controller_name 方法原型将如下所示:

Publicfunction method_name($user, $name, $email, $phone) {

因此,$user = param1$name = param2,依此类推。

这是通过 URL 或获取数组的一种可能方式。在 CodeIgniter 中,我们不必获取数组,因此我们可以使用 URI 类来获取参数。有关参考,请参阅 ellislab.com/codeigniter/user-guide/libraries/uri.html

如果我们提供:

<?PHP base_url() ?>/controller_name

如果控制器有此类方法,CI 将仅执行控制器构造函数和 index() 方法。

如果我们提供:

<?PHP base_url() ?>/controller_name/method_name

以下代码将在调用特定方法method_name之后,而不调用index()方法之前执行。请记住,我们不应该在我们的参数中使用/,并且可能希望使用 URL 编码或其他可逆编码方法提供它们。我们也可以使用 POST/GET 调用我们的控制器方法,以便以以下方式检索在类方法中发布的参数值:

$param1_val = $this->input->post('param1');

例如,在类代码中,我们发出一个 AJAX 调用到函数,如下一个示例所示。

示例 4 – 带参数调用面向 AJAX 的方法

在这个例子中,我们允许最终用户通过 HTTP POST向特定的类方法发出 AJAX 调用,并传递其参数。

<script src="img/jquery.min.js"></script>
<script type="text/javascript">

function AJAX_call () {
a_val  = $('[name="a"]').val();
b_val  = $('[name="b"]').val();
AJAX_url = '<?PHP echo base_url()."index.php/my_handler/AJAX_calc";?>';
$.AJAX({
type: "POST",url : AJAX_url,data:  {a : a_val,  b : b_val },dataType: "json",success: function(data) {$('#result').html (data.result); }
}); // AJAX Call end
}</script>

<form onsubmit="AJAX_call();"><label>Enter A</label><input type="text" name="a" /><label>Enter B</label><input type="text" name="b" />Result:<div id='result'>The Result Will Be Shown Here</div><input type="submit" value="Calculate" /></form>

AB输入两个数值并点击计算按钮。我们将在div部分中,id='result'将得到将整数A转换为整数并乘以将整数B转换为整数的结果。

加载库、模型和辅助函数

为了在我们的控制器中重用其他库、模型和辅助函数的能力,我们可能还想将库和辅助函数加载到我们的控制器或模型类中,以便为我们的需求重用它们。如果我们决定某些辅助函数、库或模型是有用的,我们将自动加载它们。我们可以在名为autoload.php的自动加载配置文件中这样做,该文件位于我们的项目中的application/config/autoload.php

以下是一个自动加载配置示例:

$autoload['libraries'] = array('template','database','session');

$autoload['helper'] = 
array('url', 'utilities');
// Note: url helper provide base_url() service

请记住,如果我们想在某个控制器或模型中加载我们的辅助函数或库,我们可以按照以下示例启用它:

classMy_handler extends CI_Controller { 
function __construct(){
// see previous explanation on this parent call 
parent::__construct();

// Loadingspecific helperto enable calling 
// its functions in all this 
// controller class methods as well as in all 
// rendered views.
// Note how the full name and path is abbreviated:

$this->load->helper('ssl_helper');

//Loading and instantiatinga library s
// application/librarues/smart_handler.php to 
// enable calling all its class methods as from // this controller as well from all the rendered 
// by this controller.
$this->load->library('smart_handler' );
}
function enforce_ssl () {
force_ssl();
// A function in the ssl_helper for more see 
// helpers chapter
}
function smarty () {
//call a method smart_service in the loaded //smart_handler library
//for more see Libraries chapter
$this->smart_handler->smart_service($param1, $param2); 
} 
}//End Controller My_handler

我们将按照以下方式调用使用辅助函数的方法:

<?php echo base_url(); ?>index.php/my_handler/enforce_ssl

对于加载库中的 smarty 方法调用,我们使用以下代码:

<?php echo base_url(); ?>index.php/my_handler/smarty

将参数传递到控制器中的视图,application/controllers/my_controller.php如下所示:

$array = array ('a' =>100,'b' =>200);
$view_params = array 
('param1' => 'hello world', 'param2' =>$array
);
$this->load_view('my_view', $view_params);

在视图文件application/views中的my_view.php,视图可以使用以下方法使用提供的参数:

<?PHP 
echo $param1;// will echo hello world

注意,在控制器中,它被定义为param1键数组元素,其中数组被发送到视图。

// To get the param2 values we shall perform :

foreach ( $params2 as param ){
echo param;  
// will echo 100 and 200 as $params2['a'] and 
// $params2['b'] values
}
?>

杂项命名约定

CI 指南有一些通用的命名约定,如下所示:

  • 您的类、函数和参数应该有简短的名字,如果由多个单词组成,它们应该使用下划线分隔符,如下所示:

    // several lowercase words naming with under score
    get_file_properties();
    
  • 当定义一个字符串值时,如果字符串没有参数要评估,我们应该使用单个逗号,如下所示:

    $my_string   = 'the string';
    
  • 如果我们想让字符串具有一个如$name这样的参数,我们使用双引号来编写我们的字符串:

    $name = 'big string parameter';
    $my_string = "This is a $name ";
    
  • 布尔值和联系人名称都应该使用大写:

    $this_vale = FALSE;
    // While in javascript we shall use true / false 
    // to distinguish
    

对于更一般的 CI PHP 风格指南,请参阅codeigniter.com/user_guide/general/styleguide.html

摘要

在本章中,我们通过一系列关于参数、类、控制器、模型、辅助函数、库和视图的示例,审查并实践了 CI 的命名规范、规则和用法。

遵循我们已审查的命名规范,我们审查了主要的配置文件,例如config.phpdatabase.phpautoload.phproutes.php的深度。我们还审查了在配置用于我们项目的多个数据库时如何使用配置参数。除此之外,我们还看到了如何添加更多针对特定项目的配置。

第三章:控制器使用和作用域

本章涵盖了 CI 控制器的作用域和不同的控制器使用类别,并提供了几个 Web 应用程序的代码示例。控制器是处理或路由请求以及如何响应操作(如将渲染的视图作为 HTML 页面发送回浏览器,AJAX 响应以允许当前请求页面通过响应更新某些选择器区域,或者甚至只是无缝更新数据库)的前线决策者。控制器使用可用的模型、帮助器、库和视图来响应用户,无论是 Web 浏览器 URL 还是自动发出 cURL 类型POST/GET请求的 cron 进程。

CI 内置控制器在项目范围内表现得像一个抽象类,因此我们的任何项目控制器都必须是内置 CI 控制器的扩展。我们开发的控制器将继承 CI 内置控制器的功能和内置资源,例如自动加载的帮助器、库和模型,并允许我们编写任何特定的服务作为控制器方法来满足我们的项目需求,并满足视图的渲染需求。

如前所述,控制器是 MVC 开发框架的一部分,该框架与模型一起运行,并应用业务逻辑,通常将视图渲染回客户端 Web 浏览器以进行用户交互。

Web 用户通过浏览器引用一个 URL。在 CI 中,视图是通过调用 CI 控制器方法实现的。CI 控制器方法处理浏览器请求,并发送回一个渲染的视图,该视图成为浏览用户的可视化网页。

从 CI 控制器接收到的网页被称为渲染的控制器视图;它可能包括用户与控制器交互的锚点和按钮。当用户在浏览器中点击一个锚点时,会调用一个控制器(锚点通过 HTTP 请求激活控制器调用)。如果用户发出事件,如按钮点击、操作滚动条等,以便此用户事件将触发使用 jQuery 激活的操作,例如 jQuery 回调函数。jQuery 回调函数可能调用另一个渲染控制器,例如:

$(location).attr('href',controller_url_to_call);

另一个选项是激活对 AJAX 控制器的异步 AJAX 调用。此类控制器函数处理我们将在后面讨论的 AJAX 请求。当从服务器返回的 AJAX 调用返回时,其返回的数据可以由客户端 JavaScript 用于更新网页的某些区域/(HTML 选择器/),例如,在输入搜索字符串并发出搜索按钮时,AJAX 响应将提供要可视化的搜索结果,或者将跳转到另一个页面。

更多关于控制器的一般信息可以在en.wikipedia.org/wiki/Model-view-controller找到。

以下是我们将涵盖的章节主题和子主题:

  • CI 控制器的范围

  • 使用类别:

    • 渲染视图

    • 服务器端浏览器 AJAX 请求的控制器

    • 服务器端浏览器 AJAX 请求的 Linux 计划cron执行请求

  • CI 控制器扩展和使用()(有关更多信息,请参阅第二章,配置和命名约定

    • 加载模型、助手和库的资源

    • 使用加载的资源

    • 调用 CI 控制器方法

  • 示例 1:默认主页控制器

  • 示例 2:发送带附件的电子邮件

  • 示例 3:管理员和普通用户登录

我们将首先简要回顾 CI 框架中应用程序控制器的范围和使用案例,以及我们如何使用它们来满足项目需求。

CI 控制器的范围

CI 控制器是 CI MVC 的中心和大脑,处理 HTTP 请求,如来自浏览器的请求,并与其他 CI 资源一起操作以响应。CI 控制器的范围在以下图中描述,并与其他 CI 资源一起操作以响应请求:

CI 控制器的范围

CI 控制器的一般流程如图所示。用户的浏览器将 HTTP 请求发送到 CI 项目的 URL。最初,请求的 URL 通过基于路由配置/conf/routes.php的路由进行处理。有关更多信息,请参阅第二章,配置和命名约定。特定的 CI 控制器被实例化,并调用特定的方法。CI 方法可能由项目资源(如模型、库和操作助手)协助,如业务逻辑和数据库查询。CI 控制器通常使用定义要响应 HTTP 响应的网页的视图。

用户定义的 CI 控制器

每个 CI 项目必须有一个或多个用户定义的控制器才能运行。用户定义的控制器是任何 CI 用户交互的起点。可以通过多种方式调用控制器及其方法。可以通过向浏览器提交项目根 URI 来调用控制器(将调用项目默认控制器),通过从渲染的视图中发出用户锚点,通过客户端 AJAX 请求执行操作(更新页面选择器),或者甚至通过crontab(Linux 已知调度服务)计划执行的动作,该动作作为某个控制器方法的 URI 重复执行。

我们可以看到,控制器范围是所有其他项目资源(如模型、视图、助手和库)的通用管理者,管理所有资源以处理来自用户或计划请求的执行请求。

任何应用程序控制器都将位于project目录下的application/controller/中。

控制器可以加载其他 CI 项目代码资源,包括库、模型和辅助工具,以便它们可以直接由渲染的视图访问。这意味着,如果控制器加载了一个库,渲染的视图 PHP 文件可以以与控制器完全相同的方式调用库函数。以下是可以由控制器加载的代码资源:

  • application/helpers:辅助工具是内置的 CI 第三方库或用户自定义的。

  • application/models:模型通常是针对特定数据库和特定项目的表用户定义的,扩展了内置的 CI 模型。为特定定义的数据库和表提供 CRUD 服务,也可以是第三方(例如,可以与任何数据库通用使用的通用数据映射扩展)。

  • application/libraries:库可以是内置的、第三方的或用户自定义的。库是一个基于面向对象 PHP 类的服务,可以提供与特定项目相关的或跨多个项目的一些可重用服务。例如,作为 Flickr、Facebook 或 LinkedIn 包装 API 库。一个好的做法是,除了我们可能决定使用的第三方库之外,我们还定义面向项目库以增强我们的项目简单性和可维护性。

扩展 CI 控制器

正如我们所言,我们的应用程序控制器扩展了内置的 CI 控制器,这在开发范围内类似于一个抽象类,因此为了满足我们的需求使用控制器,我们必须构建一个扩展基本类的控制器。我们可以以几种方式扩展 CI 控制器。

  • 加载辅助工具、模型和库的资源:

    • 这些可以来自 CI 内置仓库、第三方开发或自行开发。有关如何自行开发模型的更多信息,请参阅第六章,模型;有关如何自行开发库的更多信息,请参阅第四章,;有关如何自行开发辅助工具的更多信息,请参阅第五章,辅助工具

    • 控制器可以在其任何方法中以以下方式加载任何外部资源,通常在构造函数中,以及在资源需要通过autoload.php配置文件( )在所有控制器中(请参阅第三章,配置和命名约定以获取更多信息)。然而,为了实现最佳资源优化,以最小化占用空间和开销,资源将仅在需要其服务的控制器方法中加载。

    下面是一些如何加载所提及资源的示例:

    $this->load->model('some_model');
    $this->load->library('some_library', $keyed_array);
    $this->load->helper('some_helper');
    
  • 添加公共和私有方法:

    • 这是一种常见的 PHP OOP 指南,你应熟悉(尽管有关此内容的详细说明可以在php.net找到)。以下是一个公共方法如何调用私有方法以获取数据的简单示例:

      public function get_something () {
        $some_data= $this->_get_it ();
        }
      private function _get_it () {
        return= 'hello';
        }
      
  • 使用加载的资源:

    加载的资源可以在加载后使用如下:

    • 使用加载的模型方法:

      $status= $this->some_model->save_data($table, $row);$rows= $this->some_model->get_table($table_name);
      
    • 使用加载的库方法:

      $another_data = $this->some_library->method($some_data);
      
    • 使用加载的辅助函数:

      $your_ip =get_your_ip();  // myhtml_helper function
      // NOTE: a helper defines regular functions!
      
      
  • 调用控制器:

    • 控制器由 CI 核心自动实例化,其方法通过 HTTP URI 调用。有关更多信息,请参阅第二章,配置和命名约定

    • 调用控制器的方法:

      仅调用构造函数,然后调用(如果定义如下)索引方法:$URI = "base_url().'/mycontroller'; mycontroller';

      不带参数调用mycontroller类的mymethod方法:$URI = "base_url.'/mycontroller/mymethod';

      使用两个参数 a 和 b 调用mycontroller类的mymethod方法:$URI = "base_url.'/mycontroller/mymethod/a/b';

CI 控制器使用案例

CI 用户自定义控制器有几种不同的使用场景。通常,CI 控制器将处理启动/渲染 HTML 页面,使我们能够让用户浏览和查看我们定义的不同 Web 应用页面。然而,控制器也可能提供其他服务,例如 AJAX 服务器端控制器,异步处理客户端浏览器请求,并通常返回 JSON 格式的数据而不是渲染的视图。AJAX 的确切范围和用途不是 CI 框架的一部分,但它是一种非常有用的标准事实技术。要了解更多关于 AJAX 的信息,请参考维基百科上的 AJAX(异步 JavaScript 和 XML)en.wikipedia.org

在 CI 框架中,我们控制器的主体使用类别如下:

  • 渲染视图:这类控制器主要对数据进行一些准备,并将请求的视图以及准备好的数据渲染给用户,以便在下一个用户会话状态中显示 Web 应用。

  • 一种特殊情况是主页视图渲染。因此,用户通过 URI 引用项目根目录,如下所示:

    http://mydomain.com/my_ci_project.
    
    
  • CI 路由将在项目根目录下的application/config/routes.php中将maincontroller定义为主页或默认控制器,如下所示。这样,默认控制器将被定义为以下内容:

    $route ['default_controller'] = "maincontroller";
    
    
  • 然后调用

    http://mydomain.com/my_ci_project will be routed by the CI routes 
    

    http://mydomain.com/my_ci_project/maincontroller
    

    对于用户导航请求到另一个页面,我们在渲染的视图中应有 HTML 锚点,用于导航到另一个页面,如下所示视图代码:

    <?PHP echo anchor 
        'Navigate me to page B'); ?>
    
    
  • 服务器端控制器服务于浏览器 AJAX 请求。这些控制器响应 AJAX 客户端请求,并且通常将 JSON 数据返回给调用 jQuery 脚本的脚本如下:

    <script type="text/javascript">
    function autocomplete(clue_val) {
      varurl = '<?php echo site_url(); ?>/AJAX_controller/autocomplete_name';
      $AJAX ({type: "POST", url: url, data: {clue: clue_val},
        dataType: "json", success: function(data) {
          // show the data of matching names
          }
        return;
        });
    
  • 服务器 Linux 计划任务 cron 请求:我们发现 CI 的一个非常强大的用法是服务 Linux cron 计划请求,这些请求是在 Linux cron 中定义的(有关 Linux cron 计划的更多信息,请参阅en.wikipedia.org/wiki/Cron)。

    我们可以在 DirectAdmin apache 管理工具中找到一个 UI 编辑器来定义服务器要执行的计划 crontab 可重复操作。

    对于每个请求,我们将定义 PHP 处理器路径;例如,/user/local/bin/php,以及要执行的 PHP 脚本;例如,/home/mysite.com/public_html/crontabs/ci_crontab.php

    ci_crontab.php 可以执行 CI 控制器方法。

    http://myCIproject/mycontroller/mymethod 例如,将扫描数据库并更新一个名为 sums_table 的表,该表包含所有表在每次执行后添加的行数。让我们看看如何从 PHP 脚本中调用该 CI 控制器的示例。

    为了通过 HTTP 请求调用 CI 控制器,ci_crontab.php 将使用 cURL 服务来调用 CI 控制器,类似于我们从浏览器中发出请求的方式(cURL客户端 URL),php.net/manual/en/ref.curl.php)。

    让我们在 /home/mysite.com/public_html/crontabs/ci_crontab.php 中构建。

    Linux crontab 将重复调用每个定义的操作。

    ci_crontab.php 的代码将类似于以下代码:

    <?PHP
    function file_get_contents_curl($url) {
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_URL, $url);
      $data = curl_exec($ch);
      curl_close($ch);
      return $data;
      }
    $http_to_execut='http://myCIproject/mycontroller/mymethod';
    $result = file_get_contents_curl ($http_to_execute);
    

    $result 将是控制器生成的输出,主要是简单的 echo 消息,例如 Processed 127 entries。当然,我们可以每次记录结果并将其附加到操作日志的日志文件中。

    我们刚刚看到了如何使用 CI 控制器来服务 Linux cron 服务,这在许多业务场景中具有非常强大的功能。

示例 1 – 默认主页控制器

初始时,我们将从一个简单的控制器示例开始,该示例打开一个带有导航选项来回切换到另一个页面 B 的主页,以及类似地返回主页。我们将这样做,同时在视图中渲染一些控制器计算的数据。

此示例不使用数据库。此示例将从以下 CI 框架组件配置、控制器和视图文件构建。

让我们定义默认控制器文件名为 controller/home_page.php,主页视图为 views/home_page_view.php

假设项目根 URI 为 http://mydomain.com/myproject

控制器文件

控制器文件 /home_page.php 将准备一些要在视图中显示的数据,并将允许用户导航到页面 B,以及类似地返回主页。

所使用的辅助工具由本书提供的示例源代码提供。

以下是对应的代码:

<?php
class Home_page extends CI_Controller
{
  function __construct() {
    parent::__construct();
    $this->load->helper ('validators_helper');
    $this->load->helper ('dates_time_helper');
    }
  public function index() {
    $data = array ();
    $data ['email'] = $email = "the@email.com";
    // validators_helpercalls
    $data ['email_valid'] = isValidEmail($email);
    $data ['url'] = $url = "http://cnn.com";
    $data ['url_valid'] = isValidURL($url);
    $data ['url_exist'] = isURLExists($url);
    $this->load->view('home_page_view', $data);
    }
  publicfunction page_b () {
    $data = array ();
    $myqsl_date = "1970-01-01";
    // dates_time_helper calls
    $data ['since'] = ui_date ($myqsl_date);
    $data ['past'] = getAgeAccurate ($myqsl_date, $percision = 2);
    $this->load->view ('page_b_view', $data);
    }
  }
// End controller

视图文件

控制器文件将为显示在主页视图 views/home_page_view.php 中的当前日期和时间进行准备。

<!DOCTYPE html>
<meta content="text/html; charset=utf-8"/>
<?PHP
/* data from controller
$email, $email_valid, $url, $url_valid , $url_exist
*/
$validation_text = ($email_valid) ? "Is Valid ": "Is Not Valid!";
$validation_url = ($url_valid) ? "Is Valid ": "Is Not Valid!";
$exist_url = ($url_exist) ? "Exist ": "Not exist!"; ?>
<body style="text-align: left; color: blue;">
<H1>Main Page</H1>
<HR></HR>
<div style = "float: left">
The Email: <? = $email; ?><? = $validation_text; ?>
</div>
<div style = "clear: both;"></div>
<HR></HR>
<div>
The url: <? = $url; ?><? = $validation_url; ?> and <? = $exist_url; ?>
<? = anchor ($url, '[visit the url]', array ("target" => "_blank", "title" => "opens a new Tab")); ?>
</div>
<div style = "clear: both;"></div>
<HR></HR>
<?php echo anchor ('home_page/page_b', 'Navigate me to page B') ?>
</body>
</html>

控制器有一个page_b()方法来渲染以下视图文件。它将为该页面准备$since$past参数,以便在渲染的视图page_b_view中内联使用,如下所示:

视图文件是views/page_b_view.php

<!DOCTYPE html>
<meta content="text/html; charset=utf-8" />
<?PHP
/* data from controller $since, $past */ ?>
<body style = "text-align: left; color: blue;">
<H1>Page B</H1>
<HR></HR>
<div style = "float: left">
<!We render the provided controller parameters $since & $past>
Since: <? = $since; ?> past<? = $past; ?> years</div>
<div style = "clear: both;"></div>
<HR></HR>
<?php echo anchor ('home_page', 'Back to Home Page') ?>
</body>
</html>

配置文件

首先,我们应在 application/config/routes.php 中定义要调用的默认控制器。

For example, $route['default_controller'] = "home_page";.

因此,如果你在浏览器中输入项目根部的 URI,比如说:

http://mydomain.com/myproject

http://mydomain.com/myproject/home_page将被调用。

可选地,我们可以配置 CI 以消除在 URI 路径中需要使用index.php来调用我们的 CI 项目控制器/的需求(有关信息,请参阅第二章,配置和命名约定)。

示例 2 – 发送带附件的电子邮件

在此示例中,我们将看到控制器如何加载邮件服务库并使用它来发送邮件附件。

CI 邮件库不是自动加载的库,因此,将由我们为发送电子邮件构建的控制器来加载。

CI 邮件库使得发送非英语语言的邮件主题和正文变得简单,支持 UTF-8 编码。使用 CI 邮件库添加附件变得轻而易举。我们只需要在我们的服务器上有一个已知的目录路径的文件,并引用它们来附加到邮件中。

我们可以附加一个或多个文件来创建邮件正文。HTML/TEXT 通过 CI 邮件库的简单配置设置来定义。

此示例将仅从邮件控制器构建;你可以在以后添加渲染的视图,以添加到示例报告,发送电子邮件目的地列表的报告,而不是仅发送一到两个目的地的报告。

让我们指定默认控制器文件名为controller/mail

假设项目根部的 URI 是http://mydomain.com/myproject。因此,执行发送邮件的控制器 URI 将是http://mydomain.com/myproject/mail

我们应该记住,在 CodeIgniter 中,如果你只引用控制器 URI 路径,CI 将操作功能控制器类index()函数,如果有的话。实际上在任何情况下,都会调用控制器构造函数来创建类实例。

控制器文件

控制器文件controller/email.php将首先加载 CI 邮件库,然后配置邮件服务属性,如发件人/收件人电子邮件地址、主题、HTML 正文和附件文件。最后,控制器将发出库的电子邮件发送服务,获取操作完成状态以报告给网络用户。如果失败,控制器将渲染一个报告,说明失败的原因,并提供 CI 邮件库提供的调试信息。

注意

使用的辅助工具由本书提供的示例源代码提供。

由于这个控制器示例有几个函数,我们将在以下代码审查之前先审查它们的用法:

  • __construct():这个构造函数加载 CI 电子邮件库,供其他函数使用

  • index():这构建电子邮件消息并发送到目的地

  • doc_root_path():这提供了查找要发送的电子邮件附件的目录路径

关于加载资源(如库、辅助工具和模型)的需求,最佳实践是在我们的控制器中使用它们的数量。例如,假设我们拥有 40 个控制器,其中 39 个需要相同的库。我们应该将该库添加到自动加载列表中,/config/autoload.php。如果我们添加了资源,如库、模型或辅助工具到项目的自动加载中,我们可以通过以下方式消除在需要资源服务的类中加载它:

class Email extends CI_Controller
// The controller/email.php file will contain this class
{
  function __construct()
  {
 // call the parent constructor to inherit all its services
    parent::__construct();
 // Loads the CI e-mail library, so that it will be instantiated // and its methods will be accessed, as $this->mail->METHOD_NAME.
    $this->load->library('email');
    }
 // Define the controller methodindex (the default method), so that referring to the URI mydomain.com/myproject/email will execute the index method call
  function index() {
 // Configure the library to work with UTF-8 strings // multi-language support, as well as enable HTML content body.
    $config['charset'] = 'utf-8';
    $config['mailtype'] = 'html';

 // Loads the configuration settings by initialize method
    $this->email->initialize($config);
 // Since the mail body is HTML, define CR/LF to be // replaced with HTML <BR/>
    $this->email->set_newline("<BR/>");
 // Define the 'From' Email address
    $this->email->from('eliorr@phpmyqsl.com', 'Eli Orr');

 // Define the 'To' Email/s
    $this->email->to (array('"Name 1" <name1@name.com>', '"Name 2" <name2@name.com>'));
 // Set the e-mail subject
    $this->email->subject ("This is the Subject – can be ANY UTF-8 chars");
 // Define the e-mail body in HTML format, as we set the message to be HTML typed
    $this->email->message
    ('<H1>Hello there!<H1/>
    <p>
    This Email is sent from CI via its cool e-mail library)<BR/>
    <font color=green size=3><b>See Attached Files</b></font><BR/>
    Attachedfiles: <BR/>
    <ul>
    <li> 1 - File One.</li>
    <li> 2 - Second File </li>
    </p>
    );

 // Load the attachments
    $path = $this->doc_root_path ();
 // Doc root For example, /home/yourdomain.com/public_html
 // Let say attachment under public_html as /attachments
    $attachment_path1 = $path."/attachments/file1.jpg";
    $attachment_path2 = $path."/attachments/file2.php";

 // Set the two attachment file paths
    $this->email->attach($attachment_path1);
    $this->email->attach($attachment_path2);

 // We have the e-mail object ready! Let us send it!
 // execute send and check the result status
    if ($this->email->send())
    {
 // The e-mail was sent successfully.
      echo 'Your email was sent!';
      }
    else {
 // We had some problems, let's show what was wrong
      echo $this->email->print_debugger();
      }
    }
  functiondoc_root_path () {
    // An auxiliary method for calculating attachment // file path in our server 
    return $doc_root = $_SERVER["DOCUMENT_ROOT"];
    }
  }

示例 3 – 管理员和普通用户登录

在本例中,我们将看到控制器如何使用模型和视图来协调普通用户和超级管理员用户的登录会话,以便每个用户都有一个独特的菜单。为了使用提供的数据库文件并成功登录,请按照以下步骤操作:

  • 对于普通用户登录:

    • 用户:reg_user

    • 密码:111111111(9 个 1)

  • 对于管理员用户登录:

    • 用户:admin_user

    • 密码:111111111(9 个 1)

此示例将由以下控制器、模型和视图构建:

  • application/controller/auth.php:此控制器用于控制认证检查并重定向每个用户类别到其视图或通知登录失败。普通用户和管理员用户将具有不同的视图菜单、消息和注销选项。

  • application/models/users_model.php:这是验证提交的用户名和密码(通过 MD5 存储在数据库中)与预定义的用户数据库表的模型。

  • application/views/login_view.php:这是显示给未登录用户的视图,以便他们登录。

  • application/views/logged_in_view.php:这是显示给成功登录并执行reg_user/管理员用户角色的用户的视图。

  • MySQL 数据库-USERS_DB.sql:这是我们将会上传到数据库中的数据库表。

假设项目根的 URI 是http://mydomain.com/myproject

因此,执行登录的认证控制器的 URI 将是http://mydomain.com/myproject/auth

控制器文件

控制器文件,controller/auth.php,最初将加载 CI 表单辅助工具;这个辅助工具将用于构建和操作登录表单。有关辅助工具的使用和作用域的更多信息,请参阅第五章,辅助工具

users_model,专门编写以服务于验证用户凭据的控制器,将被加载。auth/index控制器将从初始阶段以及login_view提交后调用。

会话是 PHP 中众所周知的问题,但超出了本书的范围。然而,CI 允许通过名为ci_sessions的表将操作会话存储在数据库中供客户端使用。

这样,会话对项目来说就更有序了,可以用来搜索会话和加载会话参数。为了使用数据库存储的会话,我们需要编辑/config/config.php

$config['sess_use_database'] = TRUE;
/* Enforce storing sessions data in the database */

此外,我们还将添加一个会话库,因为我们想在这个示例中使用它,以及其他常用的/config/autoload.php库。

$autoload['libraries'] = array('database', 'session', 'xmlrpc');

如果有提交,密码的输入 post 将不会为空,控制器将使用users_model模型进行凭据检查。如果成功,用户记录字段将保留在会话中,并且将根据模型返回的用户角色调用auth/admin_main_menuauth/user_main_menu控制器方法。如果已登录用户点击注销链接,将调用auth/logout来销毁会话并将用户重定向到登录表单。

以下是对应的代码:

class Auth extends CI_Controller {
  function __construct() {
    parent::__construct
    $this->load->helper ('form');
    $this->load->model ('users_model');
    }
  // called with auth is called with no specific method and // simply calls the login method
  function index() {
    $this->login();
    }
  functionlogin()
  {
    // The message to user in case of login failure
    $msg = "";
    if ($this->input->post('password'))
    {
      // The caller is from the form submission 
      // we will check credentials validity using the local method // check_login.
      $stat = $this->check_login();
      // Extract failure message to user if any
      $msg = $stat ['msg' ];
      if($stat['result'] == 'ok')
      {
        // Successful login!
        // See what We have
        // admin_user or regular user?
        if ($this->session->userdata ('role') == 'admin_user')
        // Issue the controller for admin user main menu
        redirect('auth/admin_main_menu');
        else
        // Issue regular user main menu controller
        redirect('auth/user_main_menu');
        return;
        }
      }
    else {
      // rendered with no submission 
      // let's destroy any previous session and challenge again // the user
      $this->session->sess_destroy();
      }
    // We can get here due to login failure or referring to auth // controller without any active submission.
    // Keep the msg return from the model into view view_setup
    ['msg'] = $msg; 
    // render the login view to challenge the user
    $this->load->view('login_view.php', $view_setup);
    }
  functioncheck_login() {
    // Extract the credentials from the submitted login_viewform
    $user_name = $this->input->post('user_name');
    $password = $this->input->post('password');
    // init an array to return
    $ret = array ();
    // Check if login is ok and get the $row using the loaded // users_model model.
    $user_record = $this->users_model->check_login ($user_name, $password);
    if ($user_record) {
      // User passed credentials checkup successfully
      // We have the user record. Let's use it to extract info // for the logged session buildup
      $this->session->set_userdata ('user_id', $user_record->id);
      $this->session->set_userdata ('user_name', $user_record->user_name);
      $this->session->set_userdata ('role', $user_record->role);
      $ret ['result'] = 'ok'; $ret ['msg' ] = 'Logged-in!';
      }
    else {
    // login failed!
    $ret ['result'] = 'notok';
    // inform the login form to alert user for the failure
    $ret ['msg' ] = 'Invalid User/Pass - Try Again!';
    }
  return $ret;
  }
// logout method called auth/logout
function logout() {
  // destroy the current session
  $this->session->sess_destroy();
  redirect('auth');
  }
functionadmin_main_menu() {
  // Shall render an admin main menu page
  $view_setup ['uid'] = $this->session->userdata ('user_id');
  $view_setup ['user_name'] = $this->session->userdata ('user_name');
  $view_setup ['role'] = $this->session->userdata ('role');
  $view_setup ['menu'] = "Add User/Modify User/Delete User";
  $this->load->view ('logged_in_view.php', $view_setup);
  }

functionuser_main_menu() {
  // Shall render a regular user
  $view_setup ['uid'] = $this->session->userdata ('user_id');
  $view_setup ['user_name']= $this->session->userdata ('user_name');
  $view_setup ['role']= $this->session->userdata ('role');
  $view_setup ['menu']= "View Content/Modify Your Account/Logout";
  $this->load->view ('logged_in_view.php', $view_setup);
  }
}

模型文件

模型文件application/models/users_model.php将为验证用户凭据的用户表提供控制器。如果成功,模型将返回用户数据库行给调用者。

根据auth/admin_main_menuauth/user_main_menu返回的用户角色调用。如果已登录用户点击注销链接,将调用auth/logout来销毁会话并将用户重定向到登录表单。

以下是对应的代码:

class Users_model extends CI_Model {
  function __construct()
  {
    parent::__construct();
    }
  functioncheck_login ($user, $pass)
  {
 // Important notice.
 // Since the model extends the base CI model, it already got the // instance. However, we can use the $ci = &get_instance(); instead // $this-> anywhere in helpers, libraries, and so on.
  // convert the typed password in the login form to md5, same as // we do, when opening a user account.
  $md5_pass = md5($pass);
  // build up the query 
  $sql = "SELECT * FROM users WHERE user_name = '$user' AND password = '$md5_pass' ";
  $q = $this->db->query($sql);
  if ($q->num_rows()) {
    foreach ($q->result() as $row)
    return $row;
    }
  // In case no num_rows: return NULL;
  }
}

为此示例上传的数据库文件

我们将上传作为本书资源一部分的数据库文件到与 CI 连接的数据库中。

用户表包括两个用户,即reg_useradmin_user。他们的密码以文本密码的 md5 存储,其中111111111222222222reg_useradmin_user用户的密码。

以下是对应的代码:

-- phpMyAdmin SQL Dump
-- http://www.phpmyadmin.net
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(128) NOT NULL,
  `password` varchar(128) NOT NULL,
  `role` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
  ) ENGINE=MyISAM DEFAULT CHARSET = utf8 AUTO_INCREMENT = 3;
--
-- Dumping data for table users
--
INSERT INTO `users` (`id`, `user_name`, `password`, `role`)
VALUES (1, 'reg_user', 'bbb8aae57c104cda40c93843ad5e6db8', 'regular_user'), (2, 'admin_user', '0d777e9e30b918e9034ab610712c90cf', 'admin_user');

login_view视图文件

login_view视图由application/auth/index索引方法渲染,以向未登录的网站访客显示登录页面,以便在登录阶段挑战他们。

用户输入用户名和密码并提交login_view视图表单后,将调用application/auth/login,并使用用户模型检查凭据。如果登录成功,并且基于从用户模型获取的已登录用户类别,将调用以下auth方法之一:

  • auth/admin_main_menu:如果用户具有管理员角色,将渲染成功登录视图供管理员用户使用

  • auth/user_main_menu:如果用户具有管理员角色,则用于渲染普通用户的成功登录视图

视图位于 application/views/login_view.php。此视图使用了由 auth 控制器加载的许多 CI 表单辅助函数。当用户提交表单时,输入首先在客户端进行检查,然后再向 application/auth 发出提交调用。

以下为代码:

<!DOCTYPE html">
<meta http-equiv = "Content-type" content = "text/html; charset=utf-8"/>
<html>
<head>
<script src = http://code.jquery.com/jquery-latest.js type = 'text/javascript'></script>
</head>
<body>
<H1>Login Here</H1>
<!—Building the login form using the form helper-->
<?php
// Define the form attributes
// We will use the 'form' helper 'auth' will // be called on submission only, if check_if_valid()// will return true!
$submit_attributes = array('onsubmit' =>"return check_if_valid();", 'id' => 'auth');
echoform_open('auth', $submit_attributes);
echo "<table><tr><td>";
// The attributes of the <input tag>
echoform_label("User Name");
echo "</td><td>";
echoform_input(array('name' => 'user_name', 'value' => ''));
echo "</td><td>";

// The error message holders – hidden by default echo
<label id='user_name_err' style = 'color:red; display:none'>name is too short </label>";
echo "</td></tr><tr><td>';
echoform_label("Password");
echo "</td><td>";
echoform_password("password","");
echo "</td><td>";
// The error message holders – hidden by default echo
<label id='password_err' style = 'color: red; display: none'> password is too short </label>";
echo "</td></tr>";
echo "</table>";
// The submit button echo
form_input(array('type' => 'submit', 'value' =>'Login'));
echoform_close(); ?>
<HR></HR>
<!-- Server Credentials failure message -->
<p style = "color: red"><?php echo $msg; ?></p>
</body>
<!-- Local JavaScript service -->
<script type='text/javascript'>
functioncheck_if_valid() {
  var submit = true;
  varuser_name = $('[name="user_name"]').val();
  var password = $('[name="password"]').val();
  if (user_name.length< 2) {
    $('#user_name_err').show();
    submit = false;
    }
  else $('#user_name_err').hide();
  if (password.length< 6) {
    $('#password_err').show();
    submit = false;
    }
  else $('#password_err').hide();
  return submit;
  }
</script>
</html>

登录视图文件

login_in_view 视图是在成功登录后由 application/auth/admin_main_menu 控制器方法或基于用户类别的 application/auth/user_main_menu 方法渲染的。该视图根据登录用户的详细信息显示给登录用户。

两个控制器都使用 users_model 模型来验证登录尝试并获取登录用户。视图向登录用户显示有关其账户的一些信息,例如用户名和角色以及其用户类别可用的菜单。

视图位于 application/views/login_in_view.php。此视图使用 $user_nam$uid$role$menu 控制器提供的参数显示给登录用户。从该视图,用户可以发出注销锚点,调用 auth/logout 来销毁会话并将登录用户重定向到登录视图。

许多 CI 表单辅助函数都是由 auth 控制器加载的。当用户提交时,输入首先在客户端进行检查,然后再向 application/auth 发出提交调用。

以下为代码:

<!DOCTYPE html">
<meta http-equiv = "Content-type" content = "text/html; charset<!DOCTYPE html">
<meta http-equiv = "Content-type" content = "text/html; charset=utf-8"/>
<html>
<body>
<H1>Welcome <? = $user_name; ?>!</H1>
<H1>You are logged in!</H1>
<HR></HR>
<H3>Your User ID is: <? = $uid; ?></H3>
<H3>Your System Role is:<? = $role; ?></H3>
<H3>Your Menu options: <? = $menu; ?></H3>
<?php echo anchor ('auth/logout', 'Logout') ?>
</body>
</html>

摘要

在本章中,我们回顾了 CI 控制器的作用域以及针对视图渲染、服务 AJAX 客户端请求或 Apache crontab 定时处理请求的不同控制器使用类别。我们回顾了控制器可以辅助的各种资源,例如辅助函数、库和模型。最终,我们提供了以下使用示例:

  • 示例 1:默认主页控制器

  • 示例 2:发送带附件的电子邮件

  • 示例 3:管理员和普通用户登录

第四章:库

本章涵盖了 CI 库的主题,以及不同类型的库及其不同的使用类别,并提供了几个 Web 应用程序的代码示例。CI 开发平台为我们提供了内置库,使我们能够通过简单的程序集成第三方库,还允许我们开发自己的库并与社区共享,如果我们愿意的话。

CI 库正在推动效率、代码重用性、分离和简单性。所获得的好处如下:

  • 效率:意味着以最少的资源负载。这一特性是通过以下事实实现的,即 CI 库可能只由特定的 CI 项目控制器(或甚至只由特定的方法)加载,在这些方法中需要库的服务。因此,在执行时间中,库资源(内存)的负载在每个控制器操作状态下都最小化了。

  • 重用性:重用性意味着编写一次函数代码并在项目资源中重复使用它。任何项目控制器、模型或辅助程序(在辅助程序中,我们将使用之前讨论多次的&get_instance()方法)都可以加载库以在 CI 项目的任何地方重复使用其代码。不仅如此,控制器渲染的视图还可以调用这些已加载的库方法。因此,实现了极高的代码重用性。

  • 分离:分离防止了与项目其他地方相同名称的参数或函数的意外重叠。库类方法和参数有自己的命名空间,这样它们就不会在库外部被错误地覆盖,如果开发者在服务模块(如控制器/视图)中使用相同的参数。

  • 简单性:这使得代码文本尽可能简单,易于理解和维护。从服务资源(如控制器、模型和辅助程序)调用的库方法使代码看起来更加简单,并使其易于维护和导航。因此,这简化了代码的扩展和维护。

这些库为我们提供了开发力量和效率,在特定项目方面具有丰富的功能,还使我们能够通过调用库方法而不是在控制器中本地放置服务代码,以简单和简洁的方式在服务控制器中编写代码。库应该由使用它们的代码(如控制器、模型或辅助程序)初始化,或者如果几乎所有的控制器都使用它,可以使用自动加载机制来加载模型。第二章配置和命名约定讨论了如何自动加载库。

一旦通过自动加载或控制器构造函数实例化,库就可以通过控制器方法或渲染的视图使用。此外,任何模型、辅助程序或其他库都可以使用 &get_instance(),如前几章所述,来使用我们项目安装的库。

这些库为 CI 模型-视图-控制器实例化组件的代码提供支持(有关功能扩展和项目控制器、模型、辅助程序和视图的可重用性更多信息,请访问网站 en.wikipedia.org/wiki/Model-view-controller)。

本章将主要关注以下主题:

  • CI 库的作用域和用法:

    • 使用类别

    • 使用库

    • 将库添加到项目中

    • 实例化一个库

    • 使用库方法

  • 可用的 CI 库

  • 示例:

    • 示例 1:使用内置库

    • 示例 2:使用第三方库,例如 Google Maps CI 库包装器

    • 示例 3:构建自己的库,例如 Flickr API 包装器

    • 示例 4:构建自己的库,例如 LinkedIn API 包装器

我们将首先简要回顾 CI 框架中的库是什么,以及我们如何在我们项目的代码资源中用它来满足我们的需求。

CI 库的作用域和用法

CI 库默认情况下无法访问控制器资源,除非调用 CI $ci = &get_instance() 并使用 $ci 而不是 $this 来访问 CI 资源,例如,而不是 $this->db->query ($sql),我们应该使用 $ci->db->query ($sql),依此类推。我们可以通过 CI echo 系统(全球 CI 开发者社区分享代码和开放问题的知识、资源和解决方案)使用第三方库来扩展 CI 库,或者从头开始开发自己的库或扩展其他库。

任何应用程序库都将位于项目目录下的 application/libraries/ 目录中。此外,可选资源,如库配置文件,这些文件对于库配置是必需的,可以放置在项目根目录或其他位置。一个良好的做法是将它们放置在项目根目录下,以增强 CI 提供的安全性。例如,<PROJECT_ROOT>application/config/<LIB_NAME>_config.php,或者甚至可能还需要在另一个 application/<LIB_ADDITIONAL_RESOURCES> 目录下添加额外的资源,例如 application/assets 下的 images/CSS/HTML/additional 类库。

库集成和 CI 项目中的使用方法如下:

  • 将库代码资源添加到 application/libraries/my_lib.php,如果有的话,还可以添加相关的资源,例如库配置文件,以及/或其他库资产到之前提到的位置。

  • 通过配置自动加载或控制器实例化库类。

    • 自动加载整个 CI 项目的库 my_lib

      $autoload['libraries'] = array('database','my_lib');
      
    • 特别是在某些控制器(s)、构造函数(s)或方法(s)中:

      $this->load->library('my_lib');
      
  • 使用库方法:

    $result=$this->my_lib->called_method ($param1, $param2);
    
  • 我们可以将库范围视为整个项目代码资源模型、视图、辅助工具和库的终极面向对象重用启用器,它们共同处理所有执行请求,或计划请求。

如前所述,CI 库为我们提供了极大的分离和简单性。例如,以下代码:

// Library class
class my_handler {
  private $my_lib_param;
  // Can't be accessed outside the class directly
  // but we can provide the read only service as follows:

  public function get_my_lib_param () {
    return $this->my_lib_param;}
  // The following is a library function that can't 
  // be called from outside the class!

  private function my_private_function () { }
  }

可用的 CI 库

CI 和 CI 开发者回声系统提供了许多涵盖丰富主题的库。我们将回顾 CI 库以及已知的第三方 CI 库资源。

我们还鼓励构建自己的库,供他人使用,并与社区分享,例如:

要调用内置库,例如,调用名为 CI_Xxxx 的内置库,如下所示:$this->load->library (xxxx);这样,就不使用 CI_ 前缀,而是使用大写库名称 Xxxx 的小写库名称 xxxx。在库 CI_Xxxx 内调用库函数 yyyy 时,应编写 $this->xxxx->yyyy();。

以下是一个内置和常用 CI 库的列表(截至版本 2.1.4):

CI_Benchmark CI_Encrypt CI_Migration CI_Unit_test
CI_Cache CI_Exceptions CI_Model CI_Upload
CI_Cache_apc CI_Form_validation CI_Output CI_URI
CI_Cache_dummy CI_FTP CI_Pagination CI_User_agent
CI_Cache_file CI_Hooks CI_Parser CI_Utf8
CI_Cache_memcached CI_Image_lib CI_Profiler CI_Xmlrpc
CI_Calendar CI_Input CI_Router CI_Xmlrpcs
CI_Cart CI_Javascript CI_Security CI_Zip
CI_Config CI_Jquery CI_Session
CI_Controller CI_Lang CI_SHA1
CI_Driver CI_Loader CI_Table
CI_Driver_Library CI_Log CI_Trackback

在本章中,我们将提供一个 Google Maps 第三方库包装器的使用示例,可在 github.com/ianckc/CodeIgniter-Google-Maps-Library 找到。

在 CI 论坛 codeigniter.com/forums 可以找到更多第三方库。

示例 1 – 使用内置库

在这个初始示例中,我们将看到如何使用 CI 内置库。在这里,我们将使用 CI 库CI_Table以及CI_db库,对于给定的数据库表/视图和一些可选的 CSS 设置,它将使我们能够在单行代码中渲染出所有 HTML 表格标签和 CSS 设置。在本例中,我们将使用与第三章中控制器示例相同的用户表,控制器使用和范围

本示例将由以下控制器和视图构建:

  • application/controllers/builtins.php:此控制器加载内置 CI 库table以及db库,它是自动加载的(更多信息,请参阅第二章,配置和命名约定),以获取用户的表内容,并设置表格以使用table库渲染。

    $this->load->library('table');
    
    

    控制器准备地图设置的向量以及每个地点和可能的控制器列表,以缩放进入每个地点,并渲染一个名为google_map_view的视图。

  • application/views/users_view.php:此视图将使用table库服务渲染从db加载的格式良好的表格,并由控制器配置。

    注意

    让我们假设项目根 URL 为http://mydomain.com/myprojecthttp://mydomain.com/myproject/builtins

    (源代码通过 URL 提供。)

控制器文件

以下是对每个操作控制器代码的逐步示例:

<?php 
/** Use CI built In libraries
class Builtins extends CI_Controller{
  function __construct(){
    parent::__construct();
    // Load the table library that generates the HTML tags for// showing the table structure within a view
    $this->load->library('table');
    }
  public function index(){
    // Load the users list from DB into the view 
    $data['users'] = $this->db->get('users');
    // Create custom header for the table 
    $header = array
    ('id', 'User Name', 'Hashed Password', 'Position' );
    // Set the headings
    $this->table->set_heading($header);
    // Set table formatting 
    $table_format = array ( 'table_open'  => '<table border="1"cellpadding="2" cellspacing="1" class="mytable">' );
    $this->table->set_template($table_format);
    // Load the view and send the results
    $this->load->view('users_view', $data);
    }
  }

视图文件

为了完成操作,我们将完成视图文件的工作。

<!DOCTYPE html">
<meta http-equiv="Content-type" content="text/html;charset=utf-8"/>
<html>
<head>
<title>
  Showing Users Table Using CI Build-In table Library
</title>
</head>
<body>
  <div id='results'>
  <!—All The Formatted Table is rendered by the table libraryinstance using the controller defined settings and the tableof users we have fetched from the DB >
  <?php echo $this->table->generate($users); ?>
  </div>
</body>
</html>

示例 2 – 使用第三方库,如 Google Maps CI 库包装器

在本例中,我们将看到如何安装和使用 Google Maps CI 库以及一些酷炫的服务。首先,我们需要从biostall.com/codeigniter-google-maps-v3-api-library下载库文件。

在下载的 TAR 文件中,我们将找到以下库:

  • Googlemaps.php:这是 CI 的 Google Maps API 库。我们将将其放置在application/libraries/

  • Jsmin.php:这是库的辅助代码,用于生成启用智能 Google Maps UI 交互的 JavaScript 生成代码。我们也将将其放置在application/libraries/

  • Google Maps V3 API:这是一个 PDF 文件,用于深入了解可能的库设置和使用。

在本例中,我们将提供一个初始页面,在创建的应用程序中,我们将在这个 Google 地图窗口上一起显示几个标记的地点。在那个可视视图中,我们将启用用户使用 CI 锚点 URL 助手缩放进入我们在地图上标记的预定义选定地点。

本示例将由以下库、控制器和视图构建:

  • application/libraries/:这是我们下载的 Google Maps CI 包装器库。请参阅 CI 库贡献者网站biostall.com

  • application/controllers/gmaps.php:此控制器加载googlemaps库,并为 Google 地图上显示的几个地点构建几个视图,并放大到每个地点。

    $this->load->library('googlemaps');
    

    控制器准备地图设置向量、地点列表以及可能的控制器,以便放大到每个地点,并渲染名为google_map_view的视图。

  • application/views/google_map_view.php:这是最初显示 Google 地图上所有地点的渲染视图,并允许用户通过菜单选项放大到列出的放大位置,或者回到放大地图上所有地点的视图。

假设项目根 URI 为http://mydomain.com/myprojecthttp://mydomain.com/myproject/gmaps

小贴士

本书通过 URL 提供源代码。

控制器文件

控制器文件controllers/gmaps.php最初将加载 CI Google Maps 库,然后设置地图设置和要标记并显示在不同视图中的地点,控制器将具有__construct()index()方法,并设置在定义的地点上放大。

<?php
/** Use The Google Maps CI Library Wrapper for severalmarked places altogether and zoom-in*/
class Gmaps extends CI_Controller {
  function __construct()
  {  parent::__construct();
    $this->load->library('googlemaps');
    // Set the map window sizes:
    $config['map_width']	= "1000px";
    // map window width
    $config['map_height'] = "1000px";
    // map window height
    $this->googlemaps->initialize($config);
  }
  function index() {
    /* Initialize and setup Google Maps for our App startingwith 3 marked places
    London, UK, Bombai, India, Rehovot, Israel
    */
    // Initialize our map for this use case of show 3// places altogether.
    // let the zoom be automatically decided by Google for showing// the several places on one view.
    $config['zoom'] = "auto";
    $this->googlemaps->initialize($config);
    //Define the places we want to see marked on Google Map!
    $this->add_visual_flag ('London, UK');
    $this->add_visual_flag ('Bombai, India');
    $this->add_visual_flag ('Rehovot, Israel');
    $data = $this->load_map_setting ();
    // Load our view, passing the map data that has just been//created.
    $this->load->view('google_map_view', $data);
  }
  //The class Gmaps continued with several more functions as//follows:
  function london() {
    // Initialize our map
    //Here you can also pass in additional parameters for// customizing the map (see the following code:)
    // Define the address we want to be on the map center
    $config['center'] = 'London, UK'; to be on the map center
    // Set Zoom Level - Zoom 0: World – 18 Street Level
    $config['zoom'] = "16";
    $this->googlemaps->initialize($config);
    // Add visual flag
    $this->add_visual_flag ($config['center']);
    $data = $this->load_map_setting ();
    // Load our view passing the map data that has just been//created
    $this->load->view('google_map_view', $data);
  }
  functionBombay() {
  //Initialize our map.
  //Here you can also pass in additional parameters for//customizing the map (see the following code)
  //Define the address we want to see as the map center
  $config['center'] = 'Bombay, India';
  $config['zoom'] = "16";  // City Level Zoom 
  $this->googlemaps->initialize($config);
  // Add visual flag
  $this->add_visual_flag ($config['center']);
  $data = $this->load_map_setting ();
  // Load our view passing the map data that has just been created
  $this->load->view('google_map_view', $data);
}

Gmaps继续添加以下几个函数:

function rehovot()
{
  // Initialize our map.
  //Here you can also pass in additional parameters for //customizing the map (see the following code)
  $config['center'] = 'Rehovot, Israel';
  $config['zoom'] = "16";
  // City Level Zoom
  $this->googlemaps->initialize($config);
  // Add visual flag
  $this->add_visual_flag ($config['center']);
  $data = $this->load_map_setting ();
  // Load our view, passing the map data that has just been//created.
  $this->load->view('google_map_view', $data);
}
function load_map_setting ( ) {
  $data = array();
  $locations = array();
  $controllers = array();
  // Set controllers list for zoom in
  $locations[] = 'London, UK';
  $locations[] = 'Bombai, India';
  $locations[] = 'Rehovot, Israel';
  // Set controllers list for zoom in 
  $controllers[] = "london";
  $controllers[] = "bombai";
  $controllers[] = "rehovot";
  $data['map'] = $this->googlemaps->create_map();
  $data['locations'] = $locations;
  $data['controllers'] = $controllers;
  $data['map'] = $this->googlemaps->create_map();
  return $data;
}

Gmaps继续添加以下几个函数:

function add_visual_flag ( $place ) {
  $marker = array();
  // Setup Marker for the place and the title as the place name
  $marker['position'] = $place;
  $marker['title'] = $place;
  $this->googlemaps->add_marker($marker);
  }
}

视图文件

视图文件将渲染提供的 Google Maps JavaScript 和 HTML 部分,以及渲染地点列表。它还提供控制器支持的地点的放大和缩小导航选项。

<!DOCTYPE html">
<meta http-equiv="Content-type"
content="text/html; charset=utf-8" />
<html>
<head>
  <script src = http://code.jquery.com/jquery-latest.js ></script>
  <!--Render all the map JS provided by rendering controller-->
  <?php echo $map['js']; ?>
</head>
<body>
<H3>CodeIgniter Powered CI Google Maps Library : <H3>
<HR/><ul>
<!—Let the User Always Get Back to the default Zoom out -->
<li><?php  echo anchor("index.php/gmaps",
'<B>See All Locations</B>' ); ?>
</li>
<?PHP 
$i=0;
foreach ($locations as $location ) {
  // Show to the user all the possible Zoom Ins defined places by//the controller, so that user may zoom in by issuing the// anchor.
  $controller = $controllers["$i"];
  $i++; ?>
  <li>
  <?php echo anchor
  ("index.php/gmaps/$controller", "Zoom-In to ".$location ) ?>
  </li>
  <?PHP } ?>
  }
</ul>
<HR></HR>
<?php echo $map['html']; ?>
</body>
</html>

示例 3 – 构建如 Flickr API 包装器之类的库

Yahoo!提供的flickr.com网站为社区上传的公共照片库提供 API 访问。该 API 非常丰富,其文档可在www.flickr.com/services/api/找到,被称为应用花园

该 API 支持多种编程语言和访问方法。我们将构建一个包装器解决方案,使其能够扩展以获取任何 Flickr API 服务,使用 PHP REST 访问方法。

本示例将由以下库、控制器和视图构建:

  • application/libraries/flickr_wrapper.php:这是一个 CI 包装器库,它通过 CI 实现流畅的 Flickr API 访问。这个基本服务库可以扩展以支持整个 Flickr 应用花园。

  • application/controllers/flickr_recent.php:这是使用我们编写的flickr_wrapper库的控制器,它抓取了带有 EXIF 照片信息和摄影师相关信息的最近上传的公共照片。

  • application/views/flickr_recent_view.php:这是显示最近照片和摄影师收集信息的视图。

假设项目根 URI 为 http://mydomain.com/myproject,因此执行自动登录控制器的 URI 将是 http://mydomain.com/myproject/flickr_recent

flickr_wrapper.php 库文件

application/libraries/flickr_wrapper.php 库文件包含我们正在构建并用于访问 Flickr App Garden API 的 flickr_wrapper 类库。必须使用有效的 Flickr api_key 加载此库,您可以通过遵循 Flickr App Garden 文档来获取该 api_key。库将使用 PHP REST API 访问,这样我们就可以在以后将任何 Flickr API 服务扩展到我们的库中。库的每个方法都返回一个多维键数组的结果数据。

以下是对应的代码:

/**
* CodeIgniter Flickr API wrapper Library Class
*
* Enable Simple Flickr API usage 
*
* @package        CodeIgniter
* @category    Libraries
* @author        Eli Orr
* Usage:
* Via CI controller: 
* $this->load->library( 'flickr_wrapper',
* array(   'api_key'     => '<YOUR_FLICKR_API_KEY>',
* 'DEFAULT_RES' => '3000',
// filter 3000 pix 
* 'GPS_ENABLED' => FALSE ));
* $this->flickr_wrapper->set_params ( $keyed_array );
* $recent_photos = 
* $this->flickr_wrapper->flickrPhotosGetRecent ();
* $filter_photos = 
* $this->flickr_handler->
* filter_photos ($photos_to_filter);
* $user_info        = 
* $this->flickr_wrapper->flickrUserInfo ($uid);
* // $uid e.g. 72095130@N00
//.PRIVATE 
//We will use the following private functions:
private function _file_get_contents_curl($url);
private function _flickrRestAPI ($params);
private function _is_filtered_photo ($photo_rec );
*/

以下是我们正在构建的 Flickr_wrapper 类:

class Flickr_wrapper {
  // parameters as part of the library instance
  private $DEFAULT_RES = 2000;
  // Width in Pixels 
  private $GPS_ENABLED = TRUE;
  // total shown photos 
  private $RECENT_PHOTOS = 500;
  // how many photos in each poll ?
  // CI instance 
  private $CI;
  // Flickr api_key to use 
  private $api_key = "" ;
  function __construct( $params = array())
  {
    // Make sure we got the api_key – otherwise exit!
    if (!isset ($params['api_key']))
    exit ('FATAL - must be constructed with api_key!');
    $this->set_params ($params);
    // Just for debugging needs, we may drop those later
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
  }
  // change settings on the fly
  function set_params ( $key_array ) {
    // sets array of instance parameters 
    foreach ($key_array as $key => $val ){ 
      switch ($key) {
        case 'DEFAULT_RES': $this->DEFAULT_RES 	= $val; break;
        case 'GPS_ENABLED': $this->GPS_ENABLED 	= $val; break;
        case 'RECENT_PHOTOS': $this->RECENT_PHOTOS = $val; break;
       case 'api_key' : $this->api_key = $val; break;
       // We can add many more here.
       default: exit ("FATAL! - set_params invalid param: $key");
     }
  }
}

类代码继续,同时将我们的重点转向访问最新的公开照片。

// Pulls recent public photos as multi-dimensional array
function flickrPhotosGetRecent () {
  #
  # build the Params for API
  #
  $params = array(
    'api_key' => $this->api_key,
    'method' => 'flickr.photos.getRecent',
    'extras' => 'o_dims,owner_name,date_taken,media,
    path_alias,url_sq,geo',
    'per_page' => $this->RECENT_PHOTOS,
    'format' => 'php_serial'
  );
  $rsp_obj = $this->_flickrRestAPI ($params);
  #
  # check if ok or successful result :
  #
  if ($rsp_obj['stat'] == 'ok') {
    # Get the array of all the photo records in this cycle 
    return $recent_photos = $rsp_obj['photos']['photo'];
  }
  else 
  # Query failed we shall return NULL to the caller 
  return NULL;
}
// Get the Photo EXIF that has a lot of info related to the// photo for a given photo id

类代码继续,我们将看到如何访问与图像相关的附加信息。

function GetPhotoExif ($photo_id) {
  #
  # build the API URL to call
  #
  $params = array(
    'api_key' => $this->api_key,
    'method' => 'flickr.photos.getExif',
    'photo_id' => $photo_id,
    'format' => 'php_serial',
  );
  $rsp_obj = $this->_flickrRestAPI ($params);
  #
  # display the photo title (or an error if it failed)
  #
  if ($rsp_obj['stat'] == 'ok') {
    /*
    Array ([photo] => Array ([id] => 8002716747 [secret] => 559f87aea0
    [server] => 8030
    [farm] => 9
    [camera] => Casio EX-H20G
    [exif] => ... A LOT OF EXTRA INFO
    */

    $photo_camera = $rsp_obj['photo']['camera'];
    // We can add more interesting items for our app here
    $params = array
    ( 'camera'    => $photo_camera,
    'full_exif' => $rsp_obj
    // All EXIF info for the photo_id
  );
  return $params;
  }
  else // Request Failed We shall return error:
  return NULL;
}

让我们看看如何使用以下代码应用照片过滤:

// apply photos filtering on a provided photos array
// based on the current settings
function filter_photos ($photos) {
  $filtered_photos = array();
  foreach ($photos  as $photo) {
    if ($this->_is_filtered_photo ($photo) )
    $filtered_photos[] = $photo;
  }
  return $filtered_photos;
}
function flickrUserInfo ($uid) {
  // UID e.g. : 72095130@N00
  // find info for this User
  #
  # build the API URL to call
  #
  $params = array(
    'api_key'	=> $this->api_key,
    'method'	=> 'flickr.people.getInfo',
    'user_id' 	=> $uid,
    'extras'  	=> 'contact,friend,family',
    'format'	=> 'php_serial',
  );
  $rsp_obj = $this-> _flickrRestAPI ($params);
  #
  # Check if response is OK
  #
  if ($rsp_obj['stat'] == 'ok'){ 
    // Yes! We have a good result .. let's load it to the // keyed array structure
    $real_name = @urlencode($rsp_obj['person']['realname']['_content']);
    $location = @urlencode (strtolower ($rsp_obj['person']['location']['_content']));
    $photos = @$rsp_obj['person']['photos']['count']['_content'];
    // more can be added

类代码继续如下:

    $params = array ( 
      'name' => $real_name,
      'uid' => $uid,
      'photos' => $photos,
      'location' => $location,
      'full_info' => $rsp_obj
    );
    return $params;
  }
  else // Response failed return NULL
  return NULL;
}
// PRIVATE SECTION OF ALL PRIVATE LIBRARY METHODS 
// THAT CANNOT BE CALLED DIRECTLY FROM THE LIBRARY USER 
// This is the heart of our wrapper library that makes it easy to get 
// The Flickr API access via simple keyed array based calls and response
private function _flickrRestAPI ($params) {
  $encoded_params = array();
  foreach ($params as $k => $v){
    $encoded_params[] = urlencode($k).'='.urlencode($v);
  }
  #
  # call the API and decode the response
  #
  $url = "http://api.flickr.com/services/rest/?".implode('&', $encoded_params);
  // This will create get query URI …?param1=val1&param2=val2// and so on
  $rsp = $this->_file_get_contents_curl($url);
  return $rsp_obj = unserialize($rsp);
}

类代码继续如下:

// This function assure we can get a url content into a buffer// it requires that a PHP curl library is installed!
private function _file_get_contents_curl($url) {
  if (! function_exists('curl_init') )
  exit ('PHP curl library is not enabled please fix!');
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
}
private function _is_filtered_photo ($photo_rec ) {
  /*
  [o_width]   => 4416
  [latitude] => 0
  //More can be added 
  */
  // Photo width  shall be larger than  $this->DEFAULT_RES ?
  if ( 	(int) (@$photo_rec['o_width'] )  <
  (int)  $this->DEFAULT_RES  )	 return FALSE;
  // GPS info required & Found ?
  if (( $this->GPS_ENABLED && ! @$photo_rec['latitude'] ))
  return FALSE;
  // if we are here the filtered photo passed successfully
  return TRUE;
  }
}

flickr_recent.php 控制器文件

application/controllers/flickr_recent.php 控制器文件将加载 flickr_wrapper API,调用其服务以获取新上传的公开照片和摄影师,并渲染一个视图来显示结果。

为了执行控制器,您应该将浏览器指向以下 URI:http://mydomain.com/myproject/flickr_recent

以下是对应的控制器代码:

<?php
/**
 * Flickr Recent Controller
 *
 * Provide recent uploaded public photos in flickr community
 * Enable to apply several settings and filtering
 * Enable to get photographer user profile for each photo
 * 
 * @author Eli Orr
*/
class Flickr_recent extends CI_Controller{
  function __construct()
  {
    parent::__construct();
    /* 
    Standard Libraries, database, & helper url are included in theconfigs/autoload.php
    */
    // This lines are only for debugging needs we may drop them// if things are going good
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    /* ------Loading User Defined Library------------ */
    $this->load->library
    ( 'flickr_wrapper',
    array('api_key' => '<YOUR_FLICKR_API>',
    'DEFAULT_RES' => '3000',
    // filter 3000 pix
    'GPS_ENABLED' => FALSE
  )
  );
}

类代码继续如下:

function index () {
  $settings = array(
    'DEFAULT_RES' => '4000',  // Only 4000 pix and better
    'GPS_ENABLED' => FALSE,  // GPS Info is not mandatory
    'RECENT_PHOTOS' => 50,  // Latest 100 photo uploads
  );
  $this->flickr_wrapper->set_params ( $settings );
  $photos_to_filter = 
  $this->flickr_wrapper->flickrPhotosGetRecent ();
  $filter_photos = 
  $this->flickr_wrapper->filter_photos ($photos_to_filter);
  $data = Array();
  $data['photos'] = $filter_photos;
  $data['settings'] = $settings;
  $this->load->view('flickr_recent_view.php',$data );
  }
}

flickr_recent_view.php 视图文件

flickr_recent_view.php 视图文件由我们之前定义的 Flickr_recent 控制器渲染。此控制器使用我们开发的 flickr_wrapper 库来获取带有相关信息的最新 Flickr 上传照片。

视图文件位于 application/views/flickr_recent_view.php。此视图使用 CI 解析器通过 <?=$param ?> 符号插入 PHP 参数。

以下是对应的代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<div>
<H1>Flickr Recent Uploads</H1>
<p>
<!--  Show the applied filter settings first -->
<table border="1" style='background-color:#b0c4de;' >
<tr>
  <td>Photos in Poll</td><td><?=$settings['RECENT_PHOTOS'];?></td>
</tr>
<tr>
  <td>Min. Width Filter</td><td><?=$settings['DEFAULT_RES'];?>Px</td>
</tr>
<tr>
  <td>GPS Filter</td><td><?=$settings['GPS_ENABLED'] ? "With GPS" : "With/Without GPS"; ?></td>
</tr>
</p>
<!--  For each photo show the User name, how many photos they took till now, the original size in MP (Mega Pixels) of the photos and the Time stamp when the photo was taken by the camera (mostly loaded days or even weeks/months later)
<table border="1"  style='background-color:#009900;'  >
<tr>
  <th>User Uploaded</th><th>User photos Count</th>
  <th>Photo ID</th><th>Original Size MP</th><th>Was Taken</th>
</tr>

类代码继续如下:

<?PHP foreach($photos as $photo )
{
  // get the owner id
  $uid = $photo['owner'];
  // Get User Info
  $user_info = $this->flickr_wrapper->flickrUserInfo ($uid);
  $photos = number_format ($user_info["photos"]);
  $mp_res = (int) ((( $photo['o_width' ] * $photo['o_height'] )/ 1000000)  +  1);
  ?> 
  <tr>
    <td> <?=$photo['ownername'] ?></td>
    <td> <?=$photos ?></td>
    <td> <?=$photo['id'] ?></td>
    <td> <?=$mp_res ?></td>
    <td> <?=$photo['datetaken'] ?></td>
  </tr>
  <?PHP      } ?>
  </table>
</div>
</body>
</html>

示例 4 – LinkedIn API 包装器

在本例中,我们将构建 CI 库包装器以与 LinkedIn API 集成,以便从其中查询 LinkedIn 信息。

在这样做时存在几个挑战,其中之一是获取访问 LinkedIn 资源的令牌并访问如下数据对象:

  • LinkedIn 用户的详细信息

  • LinkedIn 用户的连接

  • LinkedIn 公司的详细信息

  • LinkedIn 公司的更新

要求

  • PHP 扩展 oauth 库必须从 il1.php.net/manual/en/book.oauth.php 安装。

  • 我们应在 LinkedIn 开发者网络主页注册应用程序以接收 API 密钥,developer.linkedin.com。此唯一的 API 密钥用于识别我们的应用程序,以便从 LinkedIn 授权对我们的 API 调用进行访问。一旦我们注册了 LinkedIn 应用程序,我们将获得一个 API 密钥和一个密钥。为了我们应用程序的安全,我们不共享我们的密钥。有关更多信息,请参阅developer.linkedin.com/

身份验证流程图

为了认证我们的 LinkedIn 应用程序以授予访问权限,需要以下步骤。我们将把这个项目称为 LinkedIn 应用程序。

  1. LinkedIn API 客户端向 LinkedIn 发送请求。客户端通过oauth对象将请求发送到 LinkedIn 请求令牌 URL api.linkedin.com/uas/oauth/requestToken,其中callback URL作为 LinkedIn API 的参数。callback URL参数是从 LinkedIn 授权 URL 返回的 URL,LinkedIn 用户应在其中确认 LinkedIn 应用程序所需的权限。LinkedIn 服务器响应并返回oauth令牌(公钥)和oauth令牌密钥。

    Client > Server request token URL
    parameter: callback URL < Server returns oauth token, ouath token secret
    
  2. 客户端使用从api.linkedin.com/uas/oauth/authorize ?oauth_token = oauth_token服务器在第一阶段返回的oauth_token令牌,向 LinkedIn 服务器身份验证 URL 发送请求。

    Client > Server auth URL
    $_GET parameter: oauth token
    
  3. LinkedIn 服务器将 oauth 令牌、oauth 令牌密钥和oauth_verifier返回给客户端。

    Client < Server
    oauth token, oauth token secret, oauth_verifier
    
  4. 客户端向 LinkedIn 服务器访问令牌路径api.linkedin.com/uas/oauth/accessToken发送请求。

    Client > Server access token path
    parameter: oauth_verifier (from phase 2) < Server returns oauth token, ouath token secret
    

此示例将由以下控制器、库和视图构建:

  • application/controllers/linkedinfo.php: 使用 LinkedIn 库进行身份验证并显示库返回输出的控制器

  • application/libraries/linkedin_handeler.php: linkedin_handler库,它使访问 LinkedIn 资源成为可能,例如 LinkedIn 用户的详情和连接,以及公司的详情

  • application/views/linkedin-me.php: 显示 LinkedIn 用户详情的视图

  • application/views/linked-connections.php: 显示 LinkedIn 用户的连接的视图

  • application/views/linked-company.php: 显示公司详情的视图

  • application/views/linked-company-updates.php: 显示公司更新的视图

假设项目根的 URI 是http://mydomain.com/myproject

因此,执行登录身份验证控制器的 URI 将是http://mydomain.com/myproject/linkedinfo

linkedin_handler.php 库文件

库文件application/libraries/linkedin_handler.php包含类库linkedin_handler

该库包含用于验证应用程序和访问 LinkedIn 资源的函数。

以下是对应的代码:

<?php

if (!defined('BASEPATH')) exit('No direct script access allowed');

// The php oauth extension is required
// For more information refer to 
// http://il1.php.net/manual/en/book.oauth.php
if(!extension_loaded('oauth')) {
  throw new Exception('Simple-LinkedIn: library not compatible with installed PECL oauth extension. Please disable this extension to use the Simple-LinkedIn library.');
  }
/*
 *   CodeIgniter LinkedIn API
 *
 *   @package CodeIgniter
 *
 *   @author  Yehuda Zadik
 *
 *
 *   Enable Simple LinkedIn API usage
 */
class Linkedin_handler {
  const LINKEDIN_API_URL = 'https://api.linkedin.com';

  private $api_key;
  private $secret_key;
  private $on_failure_url;

  // Oauth class
  public $oauth_consumer;

  // The url to return to from LinkedIn
  // authorize url in our case is// http://mydomain.com/return_from_provider
  private $callback_url;

  // The request token URL
  private $request_token_url;

  // LinkedIn authorize URL for getting the LinkedIn user // confirmation for required permissions
  private $authorize_path;

  // LinkedIn URL for getting the tokens to access // the LinkedIn URL resources
  private $access_token_path;

  // accessory variable for accessing the LinkedIn resources
  private $api_url;

  // CI instance
  private $CI;

  /*
   *  Set the class variables
   */
  private function set_varaiables() {
    $this->request_token_url = self::LINKEDIN_API_URL . '/uas/oauth/requestToken';
    $this->authorize_path = self::LINKEDIN_API_URL . '/uas/oauth/authorize';
    $this->access_token_path = self::LINKEDIN_API_URL . '/uas/oauth/accessToken';

    $this->api_url = array('people' => 'http://api.linkedin.com/v1/people/~' , 'connections' => 'http://api.linkedin.com/v1/people/~/connections', 'companies' => 'http://api.linkedin.com/v1/companies/');

    $this->CI = &get_instance();
    }
  /*
   *  Library constructor
   *
   *  Initializes the library variables
   *  and initializes oauth consumer object
   *
   *  @param $config array of the Linked configuration variables
   */
  public function __construct($config) {
    // Setting the handler's variables;
    foreach ($config as $k => $v) {
      $this->$k = $v;
      }

    // Setting all the class variables
    $this->set_varaiables();

    // Initializing the oauth consumer object
    $this->oauth_consumer = new oauth($this->api_key, $this->secret_key);

    // Enabling Oauth debug
    $this->oauth_consumer->enableDebug();

    // Checking if returned from the LinkedIn UI permission // conformation window
    if ($this->CI->input->get('oauth_verifier') || $this->CI->input->get('oauth_problem')) {
      $this->on_success();
      } elseif (!$this->CI->session->userdata('oauth_token') && !$this->CI->session->userdata('oauth_token_secret')) {
      // if session variables are not set: oauth_token, // oauth_token_secret
      // call auth to start the process of getting the tokens from // LinkedIn via the oauth consumer object
      $this->auth();
      } elseif ($this->CI->session->userdata('oauth_token') && $this->CI->session->userdata('oauth_token_secret')) {
      // if session variables are set: oauth_token, // oauth_token_secret initialize the oauth consumer with // $oauth_token, $oauth_token_secret
      $oauth_token = $this->CI->session->userdata('oauth_token');
      $oauth_token_secret = $this->CI->session->userdata('oauth_token_secret');

      // initialize oauth consumer with $oauth_token, // $oauth_token_secret
      $this->setToken($oauth_token, $oauth_token_secret);
      }
    }
  /*
   * Start the process of getting oauth token & oauth token * secret so that the user
   * redirects to a LinkedIn UI permission conformation window
   */
  public function auth()  {
    // Start communication with the LinkedIn server
    $request_token_response = $this->getRequestToken();

    $this->CI->session->set_userdata('oauth_token_secret', $request_token_response['oauth_token_secret']);

    // Get the token for the LinkedIn authorization url
    $oauth_token = $request_token_response['oauth_token'];

    $log_message = 'yuda auth getRequestToken oauth_token: : ' . $oauth_token;
    $log_message = "oauth_token_secret: " . $request_token_response['oauth_token_secret'] . "\n";
    log_message('debug', $log_message) ;

    // Redirect to the LinkedIn authorization url for getting // permissions for the app
    header("Location: " . $this->generateAuthorizeUrl($oauth_token));
    }
  /*
   * This is the method called after returning
   * from the LinkedIn authorization URL
   * The returned values from the LinkedIn authorization URL are: * oauth_token, oauth_token_secret, oauth_verifier
   * Those values are used to retrieve oauth_token, * oauth_token_secret for accessing the LinkedIn resources
   *
   */
  public function on_success() {
    if ($this->CI->input->get('oauth_problem')) {
      redirect($this->on_failure_url);
      }

    // Set the oauth consumer tokens
    $this->setToken($this->CI->input->get('oauth_token'), $this->CI->session->userdata('oauth_token_secret'));

    // Sending request to the LinkedIn access_token_path to // receive the array, which it's keys are tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $access_token_reponse = $this->getAccessToken($this->CI->input->get('oauth_verifier'));

    // Setting the session variables with the tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $this->CI->session->set_userdata('oauth_token', $access_token_reponse['oauth_token']);
    $this->CI->session->set_userdata('oauth_token_secret',$access_token_reponse ['oauth_token_secret']);

    // Redirecting to the main page
    redirect('');
    }

  /*
   * This method sends the request token to LinkedIn
   *
   * @return array keys: oauth_token, oauth_token_secret
   */
  public function getRequestToken() {
    // The LinkedIn request token url
    $request_token_url = $this->request_token_url;

    // The LinkedIn app permissions
    $request_token_url = "?scope = r_basicprofile+r_emailaddress+r_network";

    // Getting the response from the LinkedIn request token URL.
    // The method returns the response, which is an array// with the following keys: oauth_token, oauth_token_secret
    return $this->oauth_consumer->getRequestToken($request_token_url, $this->callback_url);
    }
  /*
   * This method returns the LinkedIn authorize URL
   *
   * @param $oauth_token string oauth token for the LinkedIn * authorzation URL
   *
   * @return string URL of the LinkedIn authorization URL
   */
  public  function generateAuthorizeUrl($oauth_token) {
    return $this->authorize_path . "?oauth_token = " . $oauth_token;
    }
  /*
   * This method sets the token and secret keys of
   * the oauth object of the oauth protocol
   *
   * @param $oauth_token string oauth token
   * @param $oauth_token_secret oauth_token_secret
   *
   */
  public function setToken($oauth_token, $oauth_token_secret) {
    $this->oauth_consumer->setToken($oauth_token, $oauth_token_secret);
    }
  /*
   * This method requests the LinkedIn tokens for
   * accessing the LinkedIn resources
   * It returns an array with the following keys: oauth_token, * oauth_token_secret
   *
   * @param $oauth_verifier string
   *
   * @return array Array with the following keys: *  oauth_token, oauth_token_secret,
   * which are used to access the LinkedIn resources URL
   */
  public function getAccessToken($oauth_verifier) {
    try {
      // Returns an array with the following keys: // oauth_token, oauth_token_secret
      // These keys are used to access the LinkedIn // resources URL
      return $this->oauth_consumer->getAccessToken($this->access_token_path, '', $oauth_verifier);
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn user's details
   * It returns a JSON string containing these values
   *
   * @return $json string String containing user's details
   */
  public function me() {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['people'] . '?format = json';

    try {
      // Request for a LinkedIn user's details
      $this->oauth_consumer->fetch ($api_url, $params, $method, $headers);

      // Receiving the last response with json // containing the user's details
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn user's connections
   * It returns a JSON string containing these values
   *
   * @return $json string String containing user's connections
   */
  public function connections() {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['connections'] . '?count = 10&format = json';

    try {
      // Request for a LinkedIn user's connections
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);

      // Receiving the last response with json containing the user's // connections
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn company' details
   * It returns a JSON string containing these values
   *
   * @param Integer $company_id - company id
   *
   * @return $json string String containing a company' details
   */
  public function company($company_id) {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url['companies'] . $company_id;

    // The following company's details are required: // company_id, number of employees, foundation year, // number of the company's followers
    $api_url = ':(id, name, website-url, twitter-id, employee-count-range, specialties, founded-year, num-followers)?format = json';

    try {
      // Request for a LinkedIn company's details
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);

      // Receiving the last response with json containing the // company's details
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>";var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  /*
   * This function returns a LinkedIn company' three updates
   * It returns a JSON string containing these values
   *
   * @param Integer $company_id - company id
   *
   * @return $json string String containing company's three updates
   */
  public function company_updates($company_id) {
    $params = array();
    $headers = array();
    $method = OAUTH_HTTP_METHOD_GET;
    $api_url = $this->api_url[ 'companies'] . $company_id . '/updates?start = 0 & count = 3 & format = json';

    try {
      // Request for a LinkedIn company's three updates
      $this->oauth_consumer->fetch($api_url, $params, $method, $headers);

      // Receiving the last response with json // containing company's three updates
      $s_json = $this->oauth_consumer->getLastResponse();
      return $s_json;
      } catch(OAuthException $E) {
      echo "<pre>"; var_dump($this->oauth_consumer);
      echo "</pre><br><br>";
      echo "Response: ". $E->lastResponse;
      exit();
      }
    }
  }
// Class closing tags
/*  End of file linkedin.php */
/* Location: ./application/libraries/linkedin_handler.php */

链接 info.php 控制器文件

控制器文件application/controllers/linkedinfo.php将加载 LinkedIn API,调用其服务,并渲染视图以显示结果。

以下是对应的控制器代码:

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * *
 * The controller is loading our developed library * LinkedIn (wrapper)
 * Next, the following process will occur in the loaded library.
 * 1 – get oauth token & oauth token secret so that the user * will be redirected to a LinkedIn UI permission conformation * window to approve our requested permission.
 * 2 – If user confirms the permissions we requested, * the method onSuccess is called with the * oauth token & oauth token secret as $_GET parameters.* The tokens will be stored as session parameters. * Else we cannot proceed querying LinkedIn and the onFailure.
 *
 * Now we can access the LinkedIn resources using the retrieved .*.tokens.
 * Here are the methods that query LinkedIn resources: * me() – Get the Info of the User who confirmed the permissions
 * connections() - Get the preceding user connection records JSON * formatted
 * company() – We just gave an example how to retrieve any company * by company id we got from the results or query company * id by company id or search criteria
 * company_updates() – Let us get the latest updates of this * company
 */
class Linkedinfo extends CI_Controller {
  // array of LinkedIn configuration variables
  private $linkedin_config;

  // callback url from the LinkedIn authorization URL
  private $callback_url;
  /*
   * Controller constructor
   *
   * Checks if session variables are set: oauth_token, * oauth_token_secret
   * If they are set, then it initializes the oauth consumer
   * else it will call the method auth() to start the * process of setting the token
   * It also loads the LinkedIn library
   */
  public function __construct() {

    parent::__construct();

    $linked_config = array(
      // Application keys registered in the // LinkedIn developer app
      ‹api_key› => ‹esq76cosbm9x›, ‹secret_key› => ‹TyUQ2FzRRzWz9bHk›,// The url to return from the // LinkedIn confirmation URL
        ‹callback_url› => base_url() . ‹linkedinfo/on_success›,// The URL when the failure occurs
          ‹on_failure_url› => ‹linkedinfo/on_failure›);

    // Load the LinkedIn library
    $this->load->library(‹linkedin_handler›, $linked_config);
    }
  /*
   * Load the main menu of the application
   */
  public function index() {
    $this->load->view(‹linkedin-menu›);
    }
  /*
   * This is the method called after returning* from the LinkedIn authorization URL
   * The returned values from the LinkedIn authorization URL are: * oauth_token, oauth_token_secret, oauth_verifier
   * Those values are used to retrieve oauth_token, * oauth_token_secret for accessing the LinkedIn resources
   *
   *
   */
  public function onSucess() {
    // Set the oauth consumer tokens
    $this->linkedin->setToken($this->input->get(‹oauth_token›), $this->session->userdata(‹oauth_token_secret›));

    // Sending the request to the LinkedIn access_token_path to 
    // receive the array, which it's keys
    // are tokens: oauth_token, oauth_token_secret for // accessing the LinkedIn resources
    $access_token_reponse = $this->linkedin->getAccessToken($this->input->get('oauth_verifier'));

    // Setting the session variables with the tokens: oauth_token, // oauth_token_secret for accessing the LinkedIn resources
    $this->session->set_userdata(‹oauth_token›, $access_token_reponse[‹oauth_token›]);
    $this->session->set_userdata(‹oauth_token_secret›, $access_token_reponse[‹oauth_token_secret›]);

    // Redirecting to the main page
    redirect(‹›);
    }
  /*
   *
   */
  /*
   * This function calls the library method me to get
   * the LinkedIn user›s details
   */
  public function me() {
    // Get the LinkedIn user›s details
    $s_json = $this->linkedin->me();
    $o_my_details = json_decode($s_json);
    $prodile_url = $o_my_details->siteStandardProfileRequest->url;

    $view_params[‹my_details›] = $o_my_details;
    $view_params[‹profile_url›] = $prodile_url;

    // Load the view for displaying the LinkedIn user›s details
    $this->load->view(‹linkedin-me›, $view_params);
    }
  /*
   * This function calls the library method me to get
   * the LinkedIn user›s connections
   */
  public function connections() {
    // Get the LinkedIn user›s connections
    $s_json = $this->linkedin->connections();
    $o_json = json_decode($s_json);

    // Processing data received from the LinkedIn library
    $a_connections = array();
    for ($index = 0; $index < $o_json->_count; $index++) {
      if ($o_json->values[$index]->id == ‹private›) {
        continue;
        }

      if (isset($o_json->values[$index]->pictureUrl)) {
        $picture_url = $o_json->values[$index]->pictureUrl;
        } else {
        $picture_url = ‹› ;
        }

      $a_connections[] = array(‹picture_url› => $picture_url, ‹name› => $o_json->values[$index]->firstName . « «. $o_json->values[$index]->lastName, ‹headline› => $o_json->values[$index]->headline, ‹industry› => $o_json->values[$index]->industry, ‹url› => $o_json->values[$index]->siteStandardProfileRequest->url);
      }

    $view_params[‹connections_count›] = $o_json->_total;
    $view_params[‹connections›] = $a_connections;

    // Load the view for displaying the LinkedIn user›s // connections
    $this->load->view(‹linked-connections›, $view_params);
    }
  /*
   * This function the calls library method me to get
   * the LinkedIn company›s details
   *
   * @param $company_id integer - Linkedin company id
   */
  public function companies($company_id) {
    // Get the LinkedIn company›s details
    $s_json = $this->linkedin->company($company_id);
    $o_company_details = json_decode( $s_json);

    $a_company_details = array (‹id› => $company_id, ‹name› => $o_company_details->name, ‹specialties› => $o_company_details->specialties->values, ‹websiteUrl› => $o_company_details->websiteUrl, ‹employeeCountRange› => $o_company_details->employeeCountRange->name, ‹foundedYear› => $o_company_details->foundedYear, ‹numFollowers› => $o_company_details->numFollowers);

    // Load the view for displaying the LinkedIn company›s // details
    $view_params = $a_company_details;
    $this->load->view(‹linked-company›, $view_params);
    }
  /*
   * This function calls the library method me to get
   * the LinkedIn company›s updates
   *
   *  @param $company_id integer - Linkedin company id
   */
  public function company_updates($company_id) {
    // Get the LinkedIn company›s updates
    $s_json = $this->linkedin->company_updates($company_id);
    $o_company_updates = json_decode( $s_json);

    // Processing the data received from the LinkedIn library
    $a_updates = array();
    $a_json_updates = $o_company_updates->values;
    for ($index = 0; $index < count($a_json_updates);$index++) {
        $o_update = $a_json_updates[$index];

        if (isset($o_update->updateContent->companyJobUpdate)) {
          $a_updates[] = array(‹type› => ‹Job Update›, ‹position› => $o_update->updateContent->companyJobUpdate->job->position->title, ‹url› => $o_update->updateContent->companyJobUpdate->job->siteJobRequest->url);
        }
      }

    // Load the view for displaying the LinkedIn // company›s updates
    $view_params[‹updates›] = $a_updates;
    $this->load->view(‹linked-company-updates›, $view_params);
    }
  } // class closing tags
/* End of the file linkedinfo.php */
/* Location: ./application/controllers/linkedinfo.php */

链接 linkedin-me.php 视图文件

此视图文件显示 LinkedIn 用户的详细信息。

以下是对应的视图代码:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>My Details</title>
</head>
<body>
<table>
<tr>
  <td>Full Name:</td>
  <td><?php echo $my_details->firstName . « « . $my_details->lastName ; ?></td>
</tr>
<tr>
  <td>Title</td>
  <td><?php echo $my_details->headline ; ?></td>
</tr>
<tr>
  <td>My LinkedIn profile</td>
  <td><a href = «<?php echo $profile_url ?>» target = «_blank»>Link</a> </td>
</tr>
</table>

<div>
  <p><a href = «<?php echo site_url(‹›) ; ?>»>Back to Menu</a> </p>
</div>
</body>
</html>

视图文件 linked-connections.php

此视图文件显示 LinkedIn 用户的联系。

以下是对应的视图代码:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>My Connections</title>
</head>
<body>
<h1>My Total connections: <?php echo $connections_count ; ?></h1>
<div>
  <p><a href = «<?php echo site_url(‹›) ; ?>»>Back to Menu</a> </p></div>
<table>
<tr>
  <td>Picture</td>
  <td>Name</td>
  <td>Headline</td>
  <td>Industry</td>
</tr>
  <?php foreach ($connections as $connection): ?>
<tr>
  <td><img src = «<?php echo $connection[‹picture_url›]; ?>»> </td>
  <td><a href = «<?php echo $connection[‹url›];?>» target = «_blank»><?php echo $connection[‹name›] ?></a></td>
  <td><?php echo $connection[‹headline›]; ?></td>
  <td><?php echo $connection[‹industry›]; ?></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>

视图文件 linked-company.php

此视图文件显示 LinkedIn 公司的详细信息。

以下是对应的视图代码:

<!DOCTYPE html>
<html lang = "en">
<head>
  <meta charset = "utf-8">
  <title>Company</title>
</head>
<body>

<div>
  <p><a href = «<?php echo site_url(‹›); ?>»>Back to Menu</a></p>
</div>

<table>
<tr>
  <td>Name</td>
  <td><?php echo $name; ?></td>
</tr>
<tr>
  <td>Founded</td>
  <td><?php echo $foundedYear; ?></td>
</tr>
<tr>
  <td>employeeCountRange</td>
  <td><?php echo $employeeCountRange; ?></td>
</tr>
<tr>
  <td>Specialties<td>
  <td>
    <ul>
      <?php foreach ($specialties as $specialty): ?>
      <li><?php echo $specialty; ?></li>
      <?php endforeach; ?>
    </ul>
  </td>
</tr>
<tr>
  <td>Website</td>
  <td><a href = «<?php echo $websiteUrl; ?>»>Website</a></td>
</tr>
<tr>
  <td>numFollowers</td>
  <td><?php echo $numFollowers; ?></td>
</tr>
</table>
<div style = «margin-top: 10px;»>
  <a href = «<?php echo site_url(‹linkedinfo/company_updates/7919›); ?>»>Updates</a>
</div>
</body>
</html>

视图文件 linked-company-updates.php

此视图文件显示 LinkedIn 公司的三个更新。

以下是对应的视图代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset = "utf-8">
    <title>Company</title>
</head>
<body>
<div>
  <p><a href = "<?php echo site_url('') ; ?>">Back to Menu</a> </p>
</div>
<table>
  <?php foreach ($updates as $update): ?>
  <tr>
    <td>
      <ul>
        <?php foreach ($update as $key => $val): ?>
        <li><?php echo $key; ?>: <?php echo $val; ?></li>
        <?php endforeach; ?>
      </ul>
    </td>
  </tr>
  <?php endforeach; ?>
</table>
</body>
</html>

摘要

在本章中,我们回顾了 CI 库的作用域、不同类型的内置 CI 输出系统第三方库,以及如何在我们的项目中构建自己的库。我们还回顾了在项目中加载和使用库资源的方法。最终,我们创建了几个使用示例。

第五章。助手

本章涵盖了 CI 助手主题,不同类型的助手及其不同的使用类别,并提供了几个网络应用程序的代码示例。CI 为我们提供了内置助手,使我们能够集成第三方助手,并允许我们开发新的助手,如果愿意,还可以与社区分享。CI 助手通过允许所有其他 CI 控制器使用相同的代码而不是在本地定义助手函数,从而提高了 CI 的效率和代码的可重用性。

助手文件是一组特定类别的独立过程函数集合。每个助手函数执行一个特定的任务,不依赖于其他函数。本章将通过几个示例详细阐述 CI 助手的理念、定义和用法。

文件夹 system/helpers 包含 CI 系统的内置助手。文件夹 application/helpers 包含 CI 助手的所有附加文件。它们可以是第三方助手或由开发者创建。

本章将主要关注:

  • CI 助手的范围和用法

    • 使用类别

    • 使用助手

    • 将助手添加到项目中

    • 加载助手

    • 使用助手方法

  • 可用的 CI 助手

  • 示例

    • 示例 1:使用内置助手

    • 示例 2:使用第三方助手——SSL 助手

    • 示例 3:构建我们自己的助手——my_download 助手

我们将首先简要回顾 CI 框架中助手的定义,以及我们如何在整个项目代码资源中利用它。

CI 助手的范围和用法

CI 助手默认情况下无法访问控制器资源,除非调用并使用 CI 和 get_instance() 来访问 CI 资源。

我们可以使用 CI 系统的第三方助手扩展 CI 助手,或者我们可以开发自己的助手。

任何应用程序助手都应位于项目目录下的 application/helpers/ 下。

助手文件必须采用以下格式:

  application/helpers/<HELPER_NAME>_helper.php

例如,SSL 助手文件应显示为 application/helpers/ssl_helper.php

在 CI 项目中,助手集成和使用的如下:

  • 将助手代码资源添加到 application/helpers/myhelper_helper.php

  • 自动加载助手或通过控制器加载

    • 自动为所有 CI 项目加载助手 myhelper 如下:

      $autoload['helper'] = array('url','myhelper');
      
      
    • 对于加载特定控制器、构造函数或方法,请使用以下方法:

      $this->load->helper('myhelper'); 
      
      
  • 使用以下助手方法:

    $result = $this->myhelper->called_method($param1, aram2);
    
    

可用的 CI 助手

CI 和 CI 开发者社区网络提供了许多助手,覆盖了丰富的主题。我们将回顾 CI 助手以及第三方 CI 助手的常用资源。

我们还被鼓励构建自己的助手,供他人使用,并与以下社区分享:

CI 系统助手

CI 内置助手的列表如下(它们可以在 CI 目录树 中找到,通过访问 system/helpers/):

  • 数组助手

  • 验证码助手

  • Cookie 助手

  • 日期助手

  • 目录助手

  • 下载助手

  • 邮件助手

  • 文件助手

  • 表单助手

  • HTML 助手

  • 变词助手

  • 语言助手

  • 数字助手

  • 路径助手

  • 安全助手

  • 表情符号助手

  • 字符串助手

  • 文本助手

  • 字体助手

  • URL 助手

  • XML 助手

CI 第三方助手

  • ssl_helper.php

  • html_manipulator_helper.php

示例 1 – 使用内置助手

在本例中,我们将看到如何使用 CI 内置助手。对于本例,我们将使用 URL 助手来生成链接。URL 助手文件包含辅助处理 URL 的函数。我们将使用 URL 助手函数 site_url(),它返回在配置文件中指定的站点 URL。

本例将由以下任一控制器构建:

  • application/controllers/ helperexample1.php

    此控制器加载了内置的 CI URL 助手。

    $this->load->helper('url'); 
    
    

    控制器渲染了一个名为 helper-example1-view 的视图

  • application/views/helper-example1-view.php

    此视图将使用 URL 助手在视图文件中生成链接

    假设项目根目录的 URL 如下所示:http://mydomain.com/myprojecthttp://mydomain.com/myproject/helperexample1

    小贴士

    本书通过 URL 提供源代码。

控制器文件

现在,我们将看到控制器如何加载内置的 CI URL 助手,以便视图文件能够使用 URL 助手函数 site_url,该函数生成链接。

class Helperexample1 extends CI_Controller {
  /**
   * Index Page for this controller.
   *
   * Maps to the following URL
   *     http://example.com/index.php/welcome
   *  - or -  
   *     http://example.com/index.php/welcome/index
   *  - or -
   * Since this controller is set as the default controller in 
   * config/routes.php, it's displayed at http://example.com/
   *
   * So any other public methods not prefixed with an underscore
       *  will
   * map to /index.php/welcome/<method_name>
   * @see http://codeigniter.com/user_guide/general/urls.html
   */
    public function index()
    {
  	      	  // Loading the url helper
  	      	  $this->load->helper('url');
         $this->load->view('helper-example1-view');
    }
  }
/* End of file helperexample1.php */
/* Location: ./application/controllers/helperexample1 */

视图文件

视图文件调用 URL 助手函数 site_url。由于控制器已加载 URL 助手,因此它被视图识别。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
  <title>Menu</title>
</head>
<body>
<table>
<tr>
<td><a href="<?php echo site_url('welcome'); ?>">Welcome</a></td>
</tr>
<tr>
<td><a href="<?php echo site_url('example2/more/1/2/3');      ?>">Example2</a></td>
</tr>
</table>
</body>
</html>

示例 2 – SSL 助手

在本例中,我们将使用 CI 第三方 SSL 助手来强制 CI 和浏览器之间的 https 或 HTTP URI 请求和响应。本例将由以下助手构建:

  • application/helpers/ssl_helper.php:实现 SSL 的 CI 助手。

  • application/controllers/helpersslexample.php:此控制器加载助手并在链接上实现 SSL。助手在构造函数中加载。

    $this->load->helper('ssl'); 
    
    
  • application/views/helper-ssl-view.php:这是实现了 SSL 的渲染视图。

假设项目根目录的 URI 为 http://mydomain.com/myprojecthttp://mydomain.com/myproject/helpersslexample

小贴士

本书通过 URL 提供源代码。

助手文件

此 CI 助手文件实现了前面章节中描述的服务。此助手使用内置的 CI URL 库和 URL 助手,通过使用重定向 CI URL 助手函数。

  <?php if ( ! defined('BASEPATH')) exit('No direct script access  allowed');
  if (!function_exists('force_ssl')) {function force_ssl(){ // get the CI instance to access the CI resources  $CI =& get_instance();// Change the base_url to have https prefix  
      $CI->config->config['base_url'] =str_replace('http://', 'https://',$CI->config->config['base_url']);
            if ($_SERVER['SERVER_PORT'] != 443){     // redirect CI to use https URI
        // so that ($CI->uri->uri_string() return 
        // the current URI with https prefix
              redirect($CI->uri->uri_string());}}}
  if (!function_exists('remove_ssl')) {function remove_ssl(){$CI =& get_instance();
      // Change the base_url to have http prefix  
      $CI->config->config['base_url'] =str_replace('https://', 'http://',$CI->config->config['base_url']);
      if ($_SERVER['SERVER_PORT'] != 80){// redirect CI to use http URI
        // so that ($CI->uri->uri_string() return 
        // the current URI with http prefix
              redirect($CI->uri->uri_string());}}}

控制器文件

现在,我们将看到控制器如何加载 SSL 助手并调用其函数 force_ssl 以强制浏览器进行 HTTPS URI 请求和响应。

class Helpersslexample extends CI_Controller {
    public function __construct() {
      parent::__construct();
      // Loading the ssl helper
      $this->load->helper('ssl');		
      // Enforce URI request of https 
      force_ssl();
    }  
    /**
      * Index Page for this controller.
      *
      */
    public function index()
    {
      $this->load->helper('url');
      $this->load->view('helper-ssl-view');
    }
  }
/* End of file helpersslexample.php */
/* Location: ./application/controllers/helpersslexample */

视图文件

视图文件代码如下:

  <!DOCTYPE html>
  <html lang="en">
  <head>
  <meta charset="utf-8">
    <title>Menu</title>
  </head>
  <body>
  <table>
  <tr>
    <td>
    <a href="<?php echo site_url('welcome'); ?>">
    Welcome - You are using https
    </a>
    </td>
  </tr>
  <tr>
     <td><a href="<?php echo site_url('example2/more/1/2/3'); 	   
           ?>">Example2</a></td>
  </tr>
  </table>
  </body>
  </html>

示例 3 – 创建自己的助手

此示例使用辅助函数下载一个非常大的文件,大小为 200 MB,该文件无法一次性读取。

此示例将由以下辅助函数构建:

  • application/helpers/my_download_helper.php:这是用于下载一个非常大文件的 CI 辅助函数

  • application/controllers/classg2.php:这是使用 my_download 辅助函数的控制文件

  • application/views/classg2view.php:这是包含文件下载链接的视图

假设项目根目录的 URI 为 http://mydomain.com/myproject。因此,执行登录的 auth 控制器的 URI 将是 http://mydomain.com/myproject/classg2

小贴士

本书通过 URL 提供了源代码。

辅助函数文件

此辅助函数用于下载非常大的文件,这些文件无法一次性读取。其函数 download_large_files 在每次循环中读取 1 MB,直到下载整个文件。

  <?php  if ( ! defined('BASEPATH')) exit('No direct script access           allowed');
  /*** CodeIgniter Download Helpers** @package  CodeIgniter* @subpackage Helpers* @category	Helpers* @author Yehuda Zadik*/ 
    // --------------------------------------------------------------
  	/*** Download large files** Generates headers that force a download to happen** @access  public* @param	string	$fullPath* @return	void*/ 
    function download_large_files($fullPath){
    // File Exists? if( file_exists($fullPath) ){ 
      // Parse Info / Get Extension $fsize = filesize($fullPath); $path_parts = pathinfo($fullPath); $ext = strtolower($path_parts["extension"]); 
      // Determine Content Type 
      switch ($ext) { 
        case "pdf": $ctype = "application/pdf"; break; 
        case "exe": $ctype = "application/octet-stream";
         break; 
        case "zip": $ctype = "application/zip";
          break; 
        case "doc": $ctype = "application/msword"; break; 

        case "xls":$ctyp = "application/vnd.ms-excel";
             break;
        case "ppt": $ctype = "application/vnd.ms-powerpoint";
           break; 

        case "wmv": $ctype = "video/x-ms-wmv";
             break;
               case "gif": $ctype = "image/gif";
             break;
               case "png": $ctype = "image/png";
               break;

        case "jpeg":case "jpg": $ctype = "image/jpg"; 
                break;

        default: $ctype = "application/force-download"; 
      } 
      $file_handle = fopen($fullPath, "rb");          
      header('Content-Description: File Transfer');
        header("Content-Type: " . $ctype);            header('Content-Length: ' . $fsize);

        header('Content-Disposition: attachment; filename=' .
                 basename($fullPath));
      while(!feof($file_handle)) {$buffer = fread($file_handle, 1*(1024*1024));
        echo $buffer;          ob_flush();flush();    //These two flush commands seem to             have helped with performance
      }    
      fclose($file_handle);
    } else{die('File Not Found');
    } 
  }
  /* End of file my_download_helper.php *//* Location: ./application/helpers/my_download_helper.php */

控制器文件

控制器加载了辅助函数 my_download 并调用其函数 download_large_files, 以便用户能够使用 my_download 辅助函数下载原本无法下载的大文件。

  <?php 
  class Classg2 extends CI_Controller {
    public function index()
    {
      $this->load->helper('url');  
      $this->load->view('classg2view');
      }  
    function download(){
      // Loading the helpers url, my_download
      $this->load->helper(array('url', 'my_download'));        // FCPATH is a constant that Codeigniter sets which       // contains the absolute path to index.php 
      $fullPath = FCPATH . 'files/movie-classg2.wmv';
      // Using the helper my_download function to download       // a very large filedownload_large_files($fullPath);
    }
  }  
  /* End of file classg2.php *//* Location: ./application/controllers/classg2.php */

视图文件

视图文件显示包含下载非常大型文件链接的数据。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="utf-8">
 <title>Download large file</title>
</head>
<body>
<div id="container">
 <a href="<?php echo base_url("classg2/download")              ?>">Download large file</a>
</div>
</body>
</html>

摘要

在本章中,我们回顾了 CI 辅助函数、作用域、不同类型的内置 CI 系统辅助函数、第三方辅助函数以及如何在我们的项目中构建自己的辅助函数。我们还回顾了在项目中加载和使用辅助函数的步骤。最后,我们看到了几个相关使用示例,如下:

  • 示例 1:使用内置辅助函数

  • 示例 2:使用第三方辅助函数— SSL 辅助函数

  • 示例 3:构建我们自己的辅助函数—my_download 辅助函数

第六章:模型

本章涵盖了 CI 模型、它们的作用以及它们在多个 Web 应用程序代码示例中的使用。该模型负责处理它存储和检索的数据库对象,并包含应用程序实现的逻辑。

大部分数据都是应用程序持久状态的一部分(无论这种持久状态是存储在文件中还是数据库中),在数据加载到应用程序后应位于模型对象中。因为模型对象代表与特定主题相关的知识和专业知识,它们可以在应用程序中重复使用。

模型代表应用程序数据服务,也可以服务于应用程序逻辑(通常称为业务逻辑)。通常,模型负责以下操作:

  • 添加、修改、删除和搜索应用程序数据库对象:通常,这包括数据库操作,但实现相同的操作并调用外部 Web 服务或 API 并不罕见。

  • 封装应用程序逻辑:例如,模型可以在存储数据对象之前进行数据验证,并可以向调用应用程序模块报告问题。

CI 数据库类的最常见误用是直接从控制器、视图或辅助程序中使用它。一个好的做法是开发模型类来处理所有应用程序的数据库服务。

因此,所有其他应用程序模块都可以从中受益,并重用这些模型。

CI 模型是专门设计来处理数据库或外部信息资源(如 Facebook)的特殊类(我们将在本章中看到一个示例)。

CI 模型是为与数据库中的信息一起工作而设计的 PHP 类。

本章将主要关注以下主题:

  • CI 模型的作用范围:

    • 模型资源路径

    • 加载模型

    • 使用模型方法

    • 连接到数据库

    • 业务逻辑

  • 对象关系映射(ORM)

  • 示例 1:CRUD 示例

  • 示例 2:业务逻辑示例

  • 示例 3:从 Facebook 检索数据

我们将首先简要回顾 CI 模型的作用范围,然后通过几个使用示例继续,涵盖在真实项目中结合的不同用例。

CI 模型的作用范围

CI 模型为所有应用程序模块提供了一种面向对象的方式,以访问应用程序数据库(或外部信息资源)。通常,模型类将包含帮助我们检索、插入和更新数据库中的信息的函数。

本节将专注于 CI 模型语法和用法指南,作为以下使用代码示例的序言。

模型资源路径

模型文件位于文件夹application/models/中,遵循模式application/models/<MODEL_NAME>.php

加载模型

加载模型可以是自动的,也可以通过控制器完成。更具体地说,可以在特定控制器的构造函数或任何控制器方法中完成。

  • 如果模型只在少数控制器方法中使用,建议在这些方法中加载模型。在这种情况下,模型的范围仅限于那些方法的项目,并将引用application/models/mymodel.php

  • 如果模型在大多数控制器方法中使用,建议在控制器构造函数中加载模型。在这种情况下,模型的范围是所有控制器方法的项目,并将引用application/models/mymodel.php

    $this->load->model('mymodel');
    

    它自动为所有 CI 项目加载模型mymodel

  • 如果模型在 CI 项目的大部分控制器中使用,建议在application/config/autoload.php中自动加载它。在这种情况下,模型的范围是所有 CI 项目,并将引用application/models/mymodel.php

    $autoload['model'] = array('users', 'mymodel');

使用模型方法

一旦 CI 模型被加载,我们将使用以模型名称作为类的对象来访问模型函数。模型的函数被调用以执行数据库操作,例如从数据库检索、插入和更新数据。

// Loading the model mymodel in the controller's method
$this->load->model('mymodel');
// Calling the model's method my_function 
$this->mymodel->my_function();

例如,让我们加载模型users并访问其函数get_users

// Loading the model class
$this->load->model('usermodel');
// Calling the model to retrieve the users from the database
$view_params['users'] = $this->usermodel->get_users();

连接到数据库

更多信息,请参阅第二章,配置和命名约定

在此示例中,我们将手动连接到数据库。以下设置在application/config/database.php中完成:

$config['hostname'] = '127.0.0.1';
$config['username'] = 'db_username';
$config['password'] = 'db_password';
$config['database'] = 'db_database';
$config['port'] = 'db_port';
$config['dbdriver'] = 'mysql';
$config['dbprefix'] = '';
$config['pconnect'] = TRUE;
$config['db_debug'] = TRUE;
$config['cache_on'] = FALSE;
$config['cachedir'] = '';
$config['char_set'] = 'utf8';
$config['dbcollat'] = 'utf8_general_ci';
$config['swap_pre'] = '';
$config['autoinit'] = TRUE;
$config['stricton'] = FALSE;
// Loading the database with the configuration manually
this->load->database($config);

业务逻辑

业务逻辑是为特定信息对象主题或数据库对象定义的一组验证规则和决策标准。

模型可以对它处理的数据库和信息对象应用业务逻辑。

在社交网络的情况下,模型层将负责诸如保存用户数据、保存朋友关联、存储和检索用户照片、寻找新朋友以供推荐等任务。

对象关系映射 (ORM)

当 CI 为开发者提供模型类以扩展面向对象的数据库CRUD创建、读取、更新和删除)验证,并为定义的项目数据库提供业务逻辑时,还有一个选项可以启用自动模型服务。在本节中,我们将讨论对象关系映射ORM)。ORM 是将数据库模式定义转换为面向对象数据库类 API 的新概念。它为给定数据库提供数据库 CRUD 服务,因此所需的代码量最小,而不是完整的模型开发。更重要的是,还启用了对 CRUD 操作的定制验证。使用 ORM 插件可以减少我们自行开发 CI 模型的需求,这样只剩下特殊业务逻辑活动需要实现。

今天,ORM 插件提供了预定义的验证服务,以及用户定义的服务,以强制执行来自请求数据库 CRUD 服务的应用程序控制器、库或助手中的 CRUD 请求的验证。

使用 ORM 既有优点也有缺点。一方面,它大大简化了数据库模型开发。另一方面,它对数据库模式定义施加了各种规则,例如为 ORM 对象用户定义用户表,或者定义自动递增主键字段名,如 ID 等。

CI 有几个 ORM 插件;最著名和最完善的,拥有庞大的社区开发者网络,如下所示:

ORM 插件还提供了对处理数据库字段进行验证和操作的服务,例如在将字符串字段保存到数据库之前对其进行修剪。

验证服务包括内置验证,如有效的电子邮件字段,或者必须与另一个字段具有相同值的字段,例如具有账户创建密码重输要求的字段。ORM 的完整范围和用法超出了本 CI 书籍的范围。然而,强烈建议您了解更多关于 ORM 的信息,并尝试使用所提到的 ORM 插件,并考虑在 CI 项目中使用它们。

当然,我们在下一节中提供了一个简单的使用示例,演示如何使用 ORM 向数据库添加记录,以及如何使用 ORM 检索数据库记录:

ORM 简单操作示例

例如,假设我们有一个以 ID 作为主键自动递增的用户数据库表。用户名、电子邮件和密码是其他字段,如果我们想向数据库添加一个新的用户记录,我们可以使用以下代码来完成:

<?PHP
// We shall define the database table named users// with ID as auto-increment, username, password, and e-mail as // the other fields.
// ORM will create an user objet based on the users // table scheme. We can set the variable to this object, and use // the operational services provided by ORM for actions, such // as save, delete, update, and add.
$u = new User();
$u->username = 'A new User';
$u->password = 'shhnew1';
$u->email = 'user@mail.com';
// To add a new user record
if ($u->save()) {
  // if saved we have a new echo 'New User Id Opened having'$u->id. 'User Id <br/>';
  }
else {// Show why we failed to save echo
  $u->error->string;
  }
// Getting the first three users from the database
$u = new User();
$u->limit(3)->get();
// Showing the fetched users
foreach ($u as $user_rec)
{
  echo 'User Id: '. $user_rec->id . '<br/>';
  echo 'User Name: '. $user_rec->username . '<br />';
  echo 'User Email: '. $user_rec->email. '<br/>';
  }
// Get the user with Uid = 10 if any
$u = new user();
$seek_uid = 10;

$u->where('id', $seek_uid)->get();
// Check if found
if (exist ($u)){
  echo 'User Id:'.$u->id.' Name is'.$u->username. '<br />';
  }
else echo 'No user found for user ID'. $seek_uid. '<br />';

这只是一个非常简单的使用示例,而 ORM 今天提供了丰富的 CRUD 和验证服务。请参阅提供的 ORM 插件链接以获取更多信息。

示例 1 – CRUD 示例

在这个示例中,我们将看到如何使用 CI 模型。对于这个示例,我们将使用一个在数据库上执行以下操作的模型:SELECTINSERTUPDATE

示例显示,在数据库主页中由模型productmodel检索的所有产品。

假设项目根 URI 为http://mydomain.com/myprojecthttp://mydomain.com/myproject/product

注意

源代码通过 URL 提供。

主页有添加和编辑产品的链接。这些链接会生成用于编辑和添加产品的表单。

假设项目根 URI 为http://mydomain.com/myprojecthttp://mydomain.com/myproject/product/add

假设我们想编辑并更新product_id 1的产品,链接将是http://mydomain.com/myproject/product/edit/1。此示例将由以下控制器、模型和视图构建:

  • application/controllers/product.php:此控制器加载模型 product。

    $this->load->model('productmodel');
    

    此控制器渲染以下视图:

    • productsview:此视图显示所有产品,并提供编辑和添加产品的链接

    • productform:此视图包含添加和编辑产品的表单

  • application/models/productmodel.php:此模型包含执行以下数据库操作的函数:SELECTINSERTUPDATE

  • application/views/productsview.php:显示产品的视图。

  • application/views/productform.php:包含表单的视图。

控制器文件

控制器 PHP 文件位于application/controllers/product.php。控制器处理产品的操作,如添加、编辑、更新和显示产品表。

控制器创建用于添加和编辑产品的表单。

更多信息请参阅第七章,视图

以下为代码和内联说明:

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
class Product extends CI_Controller {
// Accessory method for generating forms called by the methods add // and edit.
private function load_form($form_action, $a_values = array())
{
  // Loading the form helper
  $this->load->helper('form');
  // Loading the form_validation library
  $this->load->library('form_validation');
  $view_params['form']['attributes'] = array('id' => 'productform');
  $view_params['form']['action'] = $form_action;
  $product_id = isset($a_values['product_id']) ?
  $a_values['product_id']: 0;
  $view_params['form']['hidden_fields'] = array('product_id' => $product_id);
  // product name details
  $view_params['form']['product_name']['label'] = array('text' => 'Product name:', 'for' => 'product_name');
  $view_params['form']['product_name']['field'] = array('name' => 'product_name', 'id' => 'product_name', 'value' => isset($a_values['product_name']) ? $a_values['product_name']: '', 'maxlength' => '100', size' => '30', 'class' => 'input');
  // product sku details
  $view_params['form']['product_sku']['label'] = array('text' => 'Product SKU:', 'for' => 'product_sku');
  $view_params['form']['product_sku']['field'] = array('name' => 'product_sku', 'id' => 'product_sku', 'value' => isset($a_values['product_sku']) ? $a_values['product_sku']: '', 'maxlength' => '100', 'size' => '30', 'class' => 'input');
  // product quantity details
  $view_params['form']['product_quantity']['label'] = array('text' => 'Product Quantity:', 'for' => 'product_quantity');
  $view_params['form']['product_quantity']['field'] = array('name' => 'product_quantity', 'id' => 'product_quantity', 'value' => isset($a_values['product_quantity']) ? $a_values['product_quantity']: '', 'maxlength' => '100', 'size' => '30', 'class' => 'input');
  // Form attributes validation rules
  $config_form_rules = array(array('field' => 'product_name', 'label' => 'Product Name','rules' => 'trim|required'), array('field' => 'product_sku', 'label' => 'Product SKU', 'rules' => 'trim|required'), array('field' => 'product_quantity', 'label' => 'Product Quantity', 'rules' => 'trim|required|integer'));
  $this->form_validation->set_rules($config_form_rules);
  return $view_params;
  }
// This controller method retrieves the products list calling the // model productmodel's method get_products() renders the results // in the view productsview.
public function index()
{
  // Loading the url helper
  $this->load->helper('url');

  // Manually loading the database
  $this->load->database();

  // Loading the model class
  $this->load->model('productmodel');

  // Calling the model productmodel's method get_products()to // retrieve the products from the database.
  $view_params['products'] = $this->productmodel->get_products();
  // Rendering the products list in the view productsview.
  $this->load->view('productsview', $view_params);
  }
// This method handles the operation of adding a product to the // database.
public function add()
{
  // Loading the url helper
  $this->load->helper('url');

  // Manually loading the database
  $this->load->database();

  // Loading the model class
  $this->load->model('productmodel');

  $a_post_values = $this->input->post();
  $view_params = $this->load_form('product/add', $a_post_values);

  // Validating the form
  if ($this->form_validation->run() == FALSE) {
    // Validation failed
    $this->load->view('productform', $view_params);
    } else {
    $data = $a_post_values;
    array_pop($data);
    $this->productmodel->addProduct($data);

    redirect('product');
    }
  }
// This method handles the operation of editing a product
public function edit($product_id)
{
  // Loading the url helper
  $this->load->helper('url');
  // Manually loading the database
  $this->load->database();

  // Loading the model class
  $this->load->model('productmodel');

  $a_post_values = $this->input->post();
  // Checking if a form was submitted
  if ($a_post_values) {
    $a_form_values = $a_post_values;
    } else {
    // Get the values of the database
    $a_db_values = $this->productmodel->get_product($product_id);
    $a_form_values = array('product_id' => $a_db_values[0]->product_id, 'product_name' => $a_db_values[0]->product_name, product_sku' => $a_db_values[0]->product_sku, 'product_quantity' => $a_db_values[0]->product_quantity);
    }

  $view_params = $this->load_form('product/edit/' . $product_id, $a_form_values);
  // Validating the form
  if ($this->form_validation->run() == FALSE) {
    // Validation failed
    $this->load->view('productform', $view_params);
    } else {
    $a_fields = array('product_name', 'product_sku', 'product_quantity');
    for ($index = 0; $index < count($a_fields); $index++)
    {
      $s_field = $a_fields[$index];
      $data[$s_field] = $this->input->post($s_field)
      }
    $this->productmodel->updateProduct($product_id, $data);
    redirect('product');
    }
  }
}
/* End of file product.php */
/* Location: /application/controllers/product.php */

模型文件

模型 PHP 文件位于application/models/productmodel.php

在此示例中,调用 CI 对象db的方法来生成和执行 SQL 查询。

请参阅 CI 数据库库ellislab.com/codeigniter/user-guide/database/index.html

以下为代码和内联说明:

<?php
class Productmodel extends CI_Model {
  // The model's constructor method
  public function __construct()
  {
    // Call the Model's parent constructor
    parent::__construct();
    }
  // This method retrieves the products list and returns an array of // objects each containing product details.
  public function get_products()
  {
    // Calling the CI's db object's method for generating SQL // queries.
    $query = $this->db->get('products');
    // returns an array of products objects
    return $query->result();
    }
  // This method retrieves a specific product's details identified by // $product_id as a parameter
  public function get_product($product_id)
  {
    // Calling the CI's db object's methods for generating SQL // queries.
    $this->db->select('*');
    $this->db->from('products');
    $this->db->where('product_id', $product_id);

    // Calling the CI's db object method for executing the query
    $query = $this->db->get();
    // Returning array of one object element containing product // details.
    return $query->result();
    }

  // This method adds a product to the products table Parameters // $data - The data to insert into the table
  public function addProduct($data)
  {
    // Calling the CI's db object method for inserting a product data // into the products table.
    $this->db->insert('products', $data);
    }
  // This method updates a product row in the products table // parameters $product_id - The product id, $data - The updated // data
  public function updateProduct($product_id, $data)
  {
  // Calling the CI's db object's methods for generating SQL queries
  $this->db->where('product_id', $product_id);
  // Calling the CI's db object method for updating the product data // in the products table
  $this->db->update('products', $data);
  }
}

视图文件

视图 PHP 文件位于application/views/productsview.php

此视图文件显示包含产品列表的表格。以下为代码和内联说明:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Products List</title>
</head>
<body>
<table>
<tr>
  <td>ID</td>
  <td>Name</td>
  <td>SKU</td>
  <td>Quantity</td>
  <td>Actions</td>
</tr>

<?php foreach ($products as $product): ?>
<tr>
  <td><?php echo $product->product_id; ?></td>
  <td><?php echo $product->product_name; ?></td>
  <td><?php echo $product->product_sku ; ?></td>
  <td><?php echo $product->product_quantity ; ?></td>
  <td><a href="<?php echo site_url("product/edit/" . $product->product_id); ?>">Edit Product</a></td>
</tr>
<?php endforeach; ?>
</table>

<p>
  <a href="<?php echo site_url('product/add'); ?>">Add Product</a>
</p>
</body>
</html>

示例 2 - 业务逻辑示例

在此示例中,我们将演示业务逻辑。订购产品将触发模型更新产品的数量并检查是否小于某个数量。

此示例将由以下控制器、模型和视图构建:

  • application/controllers/order.php:此控制器加载模型productmodel

  • $this->load->model('productmodel'):此控制器渲染视图orderview,显示所有产品,并且每个产品都有订购产品的链接

  • application/models/productmodel.php: 此模型包含检索产品、更新其数量和检查其数量的函数

  • application/views/orderview.php: 视图以表格形式显示所有产品,其中每行都有一个订购产品的链接

假设项目根目录的 URI 为 http://mydomain.com/myprojecthttp://mydomain.com/myproject/order

注意

代码源文件通过 URL 提供。

控制器文件

控制器 PHP 文件位于 application/controllers/order.php

此控制器负责显示产品并更新每个产品。如果产品的数量达到限制,它将生成错误消息。

代码和内联说明如下:

<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
class Order extends CI_Controller
{
  // This method retrieves the products list and returns an array // of objects each containing product details
  public function index()
  {
    // Loading the url helper
    $this->load->helper('url');

    // Manually loading the database
    $this->load->database();

    // Loading the model class
    $this->load->model('productmodel');

    $view_params['products'] = $this->productmodel->get_products();

    $this->load->view('orderview', $view_params);
    }
  // This method checks the product's quantity.
  // It updates the product row in the database or generates an // error message
  public function product($product_id)
  {
    // Loading the url helper
    $this->load->helper('url');

    // Manually loading the database
    $this->load->database();

    // Loading the model class
    $this->load->model('productmodel');

    if (!$this->productmodel->update_quantity($product_id)) {
      mail($user_mail, 'product' . $product_id . "reached it's limit", 'Order product' . $product_id);
      }
    redirect('product');
  }
}

模型文件

模型 PHP 文件位于 application/models/productmodel.php

在此示例中,调用 CI 对象 db 的方法来生成和执行 SQL 查询。

请参阅 CI 数据库库,可在ellislab.com/codeigniter/user-guide/database/index.html找到。

代码和内联说明如下:

<?php
class Productmodel extends CI_Model
{
  // The model's constructor method
  public function __construct()
  {
    // Call the model constructor
    parent::__construct();
    }
  // This method retrieves the products list and returns an array of // objects each containing product details.
  public function get_products()
  {
    // Calling the CI's db object's method for generating the // SQL queries.
    $query = $this->db->get('products');
    // returns an array of products objects
    return $query->result();
    }
  // This method retrieves a specific product's details // identified by $product_id as a parameter.
  public function get_product($product_id)
  {
  // Calling the CI's db object's methods for generating the // SQL queries.
  $this->db->select('*');
  $this->db->from('products');
  $this->db->where('product_id', $product_id);
  // Calling the CI's db object method for executing the query
  $query = $this->db->get();
  // Returning array of one object element containing the product // details.
  return $query->result();
  }
// This method adds a product to the products table parameters.
// $data - The data to insert into the table
public function addProduct($data)
{
  // Calling the CI's db object method for inserting a product data // into the products table.
  $this->db->insert('products', $data);
  }
// This method updates a product row in the products table // parameters.
// $product_id - The product id
// $data - The updated data
public function updateProduct($product_id, $data)
{
  // Calling the CI's db object's methods for generating the // SQL queries.
  $this->db->where('product_id', $product_id);
  // Calling the CI's db object method for updating the product data // in the products table.
  $this->db->update('products', $data);
  }

// This method checks whether the quantity exceeds it's limit.
private function check_quantity($product_id) {
  // Calling the CI's db object's methods for generating the // SQL queries.
  $this->db->select('product_quantity');
  $this->db->from('products');
  $this->db->where('product_id', $product_id);
  // Calling the CI's db object method for executing the query.
  $query = $this->db->get();
  // Calling the result's method row, which returns the SQL query // result row.
  $row = $query->row();
  if ($row->product_quantity < 7) {
    return false;
    } else {
    return true;
    }
  }

// This method updates a product quantity and return true or false, // if quantity reaches it's limit.
public function update_quantity($product_id)
{
  $sql = "UPDATE products SET product_quantity = product_quantity - 1 WHERE product_id=" $product_id;

  $this->db->query($sql);

  // Checking if the quantity reached it's limit.
  if ($this->check_quantity($product_id)) {
    return true;
    } else {
    return false;
    }
  }
}

视图文件

PHP 视图文件位于 application/views/orderview.php。此视图文件显示一个包含产品列表的表格。

以下为代码和内联说明:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Products List</title>
</head>
<body>
<table>
<tr>
  <th>ID</th>
  <th>Name</th>
  <th>SKU</th>
  <th>Quantity</th>
  <th>Actions</th>
</tr>
<?php foreach ($products as $product): ?>
<tr>
  <td><?php echo $product->product_id; ?></td>
  <td><?php echo $product->product_name;  ?></td>
  <td><?php echo $product->product_sku ; ?></td>
  <td><?php echo $product->product_quantity ; ?></td>
  <td><a href="<?php echo site_url("order/product/" . $product->product_id); ?>">Order Product</a></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>

示例 3 – 从 Facebook 获取数据

在此示例中,我们将使用 CI 内置模型从 Facebook 获取数据。

此示例将显示 Facebook 用户名和图片,并显示用户的 Facebook 朋友。

此示例使用 Facebook PHP SDK 作为 CI 库。可以从github.com/facebook/php-sdk下载。更多信息,请参阅第四章,

此示例将由以下控制器、模型和视图构建:

  • application/controllers/fbpage.php: 此控制器加载模型 fbmodel

  • $this->load->model('fbmodel'): 此控制器渲染视图 fbview,显示用户的 Facebook 图片和姓名,以及包含用户朋友姓名和其个人资料链接的表格

  • application/models/fbmodel.php: 此模型包含从 Facebook 检索数据的函数

  • application/views/fbview.php: 此视图显示 Facebook 数据

假设项目根目录的 URI 为 http://mydomain.com/myprojecthttp://mydomain.com/myproject/fbpage

注意

代码源文件通过 URL 提供。

控制器文件

控制器 PHP 文件位于 application/controllers/fbpage.php

控制器负责从 Facebook 获取访问令牌,并将 Facebook 用户重定向到 Facebook 登录页面以确认 Facebook 应用的权限。

控制器还负责通过模型获取 Facebook 用户的详细信息和朋友,并相应地渲染视图页面。

如需了解更多关于 Facebook API 使用和开发的信息,请参阅位于developers.facebook.com/的 Facebook 开发者页面。

以下为代码和内联解释:

<?php
class Fbpage extends CI_Controller {
  public function __construct() {
    parent::__construct();
    // Extremely important!!!
    // Due to the fact that the CI handles classes for // $_GET, $_POST, and $_COOKIE parse_str is called to // copy the variables sent by Facebook to the $_REQUEST var, // so that the Facebook SDK can do its checks.
    // This is done in order to avoid infinite redirect loop.
    parse_str($_SERVER['QUERY_STRING'], $_REQUEST);
    }
  // This method retrieves Facebook data of a Facebook user and // displays personal details and some of his  friends.
  // It checks if a Facebook token is valid, if it's valid, // then it displays his details, otherwise it produces // the token.
  public function index() {
    $a_config = array('appId' => $fb_API, 'secret'=> $fb_secret, 'cookie' => true);
    $this->load->library('facebook', $a_config);
    // Checking if the user is logged in and confirms // the app's permissions.
    if ($user = $this->facebook->getUser()) {
      // Get the Facebook token
      $access_token = $this->facebook->getAccessToken();
      // Loading the fbmodel
      $this->load->model('fbmodel');
      // Updating the token
      $this->fbmodel->set_token($access_token);
      // Get a Facebook user's profile details
      $user_profile = $this->fbmodel->get_user_profile();
      // Getting the Facebook user ID
      $uid = $user_profile['id'];

      // Retrieving a Facebook user's details
      $me = $this->fbmodel->get_me_by_fql($uid);
      // Get a Facebook user's friends
      $friends = $this->fbmodel->get_friends();
      $view_params = array('me' => $me, 'friends' => $friends);
      // Loading the view
      $this->load->view("fbview", $view_params);
      } else {
      // The Facebook parameters for the Facebook login URL, // where scope consists the Facebook app's permissions.
      $a_params = array ('fbconnect' => 0, 'scope' => offline_access, publish_stream', 'cookie' => true);
      // The Facebook login URL page
      $login_url= $this->facebook->getLoginUrl($a_params);
      // Redirecting the Facebook user to the login URL.
      // After the Facebook user confirms the permissions // required by the app; he is redirected back to the // index page.
      header('Location:'. $login_url);
      }
    }
  }

模型文件

模型 PHP 文件位于application/models/fbmodel.php

模型负责与 Facebook SDK 交互,并检索 Facebook 用户的详细信息和朋友列表。该模型使用 Facebook FQL 机制。

如需了解更多关于 Facebook API 使用和开发的信息,请参阅位于developers.facebook.com/的 Facebook 开发者页面。

代码和内联解释如下:

<?php
class fbmodel extends CI_Model {
  // The Facebook app's token
  private $token;
  public function __construct() {
    // Call the model constructor
    parent::__construct();
    }

  // This method sets the model class's private token value
  public function set_token($token) {
    $this->token = $token;
    }

  // This method returns an array, which contains the Facebook user // profile.
  public function get_user_profile() {
    // Getting the CI main class to get access to the Facebook // library.
    $ci =& get_instance();

    // Getting the Facebook user's profile
    $user_profile = $ci->facebook->api('/me');
    return $user_profile;
    }

  // This method returns an array, which contains a Facebook user's // details.
  public function get_me_by_fql($uid) {
    // Getting the CI main class to get access to the Facebook // library.
    $ci =& get_instance();
    // The SQL query to send to Facebook $fql = SELECT uid, name, // pic_big FROM user WHERE uid=" $uid;
    $param = array('method' => 'fql.query', 'query' => $fql, 'callback' => '');

    // Getting the Facebook user's details
    $fqlResult = $ci->facebook->api($param);
    // Returning an array, which contains the required details
    return $fqlResult;
    }

  // This method returns an array of a Facebook user's friend.
  public function get_friends() {
    // Getting the CI main class to get access to the Facebook // library
    $ci =& get_instance();
    // Getting the Facebook user's friends
    $friends = $ci->facebook->api('/me/friends');

    // Returning an array, which contains a Facebook user's friend
    return $friends;
    }
  }

视图文件

视图 PHP 文件位于application/views/fbview.php

此视图文件显示了一个 Facebook 用户的详细信息以及他们的朋友详情表格。

代码和内联解释如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My facebook details</title>
</head>
<body>

<div id="my_details">
  <div id="picture"><img src="img/<?=$me[0]['pic_big'] ?>"></div>
  <div id="my_name"><?=$me[0]['name'] ?></div>
</div>
<table>
<tr>
  <th>Name</th>
  <th>Link to friend</th>
</tr>
<?php foreach ($friends['data'] as $friend): ?>
<tr>
  <td><?=$friend['name']?></td>
  <td><a href='http://www.facebook.com/<?=$friend["id"]?>'>To friend</a></td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>

摘要

在本章中,我们回顾了 CodeIgniter 模型的作用域、业务逻辑和 ORM。在本章中,我们制作了以下示例:

  • 示例 1:一个 CRUD 示例

  • 示例 2:一个业务逻辑示例

  • 示例 3:从 Facebook 检索数据

第七章。视图

本章涵盖了渲染视图的过程流程、视图文件内的过程流程、不同类型的视图及其与几个网络应用程序代码示例的角色和用法。

视图是程序性部分,为浏览器提供内容,在客户端(即用户的 PC)上执行,以在本地计算机上创建用户界面会话。

PHP 视图文件渲染的输出作为 HTTP 响应内容从服务器返回给请求的浏览器应用程序(即通过在浏览器导航区域提交 URI 来请求)。

初始时,浏览器发送一个 URI 请求,即用户输入的 URI,到默认或特定的控制器方法,例如 http://mysite.com/myapp/helloworld

被调用的控制器方法处理请求,执行其决策,并可能使用其他 CI 资源,如辅助函数、库、模型,最终将视图作为 HTTP 响应渲染回浏览器,该响应是浏览器对控制器操作的初始 HTTP 请求。返回给浏览器的 HTML 文件包括 HTML、CSS 和 JavaScript。浏览器执行从服务器接收到的渲染视图,并使用它来执行用户界面会话(视觉元素和 UI 元素,如按钮、滚动条和导航元素);我们通过浏览器看到并操作,以导航到其他页面视图或通过发出页面锚点、按钮、点击图标等方式获取特定信息或媒体。所描述的操作会导致另一个 HTTP 请求(s),要么是同步的(主要是锚点),要么是由嵌入网页中的 JavaScript 处理的异步 AJAX 请求(s)。

CI 视图是一个 PHP 文件,可能包含以下部分或全部内容:PHP 语句、HTML 标签、CSS、JavaScript 程序、Flash、图片和媒体源。在 CI 中,视图文件可能包含使用控制器提供的参数的 PHP 代码,甚至可以直接调用 CI 辅助函数、库或模型来生成作为生成 HTML 文件响应一部分的输出。生成的 PHP 输出可以是字符串或数值,它们被整合到 HTML 标签中,甚至可以是一个完整的 HTML 页面。

本章将主要关注以下主题:

  • CI 视图作用域:

    • CI 视图资源路径

    • 渲染流程

    • 客户端灵活性

    • 在视图中访问库/辅助函数

    • 表单

    • 使用 AJAX

    • 视图解析器配置问题

    • 集成 jQuery 或其他客户端库

  • 视图渲染插件(视图模板插件示例)

  • 示例 1:由 Google Maps 驱动的 HTML5 位置

  • 示例 2:由 AJAX 和 jQuery UI 驱动的用户反馈

我们将首先简要回顾 CI 视图的作用域,然后通过几个使用示例来涵盖可以在实际项目中组合的不同用例。

CI 视图的作用域

CI 视图具有极大的灵活性,可以集成客户端第三方资源,以及访问 CI 库、辅助函数和模型的 CI 资源。

本节将重点介绍 CI 视图语法和用法指南,作为即将到来的使用代码示例的序言。

我们可以使用 CI echo 系统中的第三方库来扩展 CI 库,或者开发我们自己的库。

CI 视图资源路径

在 CI 项目中,视图文件位于 application/views/ 目录或此路径的任何子目录下。例如,我们可以在 application/views/ 子目录下构建,比如两个不同的视图类别,以提高我们项目中文件结构的清晰度。以下截图显示了 CI 项目目录树中的视图位置:

CI 视图资源路径

例如,要渲染位于 Application/views/templates/ 的模板文件 home.php,我们应该编写以下代码:

$this->load->view('templates/home');
//The following load view call, render a view using all its optional parameters
$this->load->view('view_file', // PHP view file to render
$view_params,  // parameters array for view
FALSE  //  FALSE - default. to output
//   TRUE – back as string
  );

在此示例中,view_file 指的是 CI 资源 PHP 视图文件 application/views/view_file.php

$view_params 是视图文件的参数数组(每个条目为标量/数组),正如我们在几个地方之前所展示的,因此每个数组键,比如 name,成为视图中的 $name PHP 变量以供使用。

如果我们希望将处理过的视图放入缓冲区,用于特殊处理、缓存或其他处理目的,例如,你可以调用以下示例:

$view_buffer=$this->load->view('sectionA/view_file', $params, TRUE);

注意,第三个参数的值设置为 TRUE(默认值设置为 FALSE,并将视图输出到标准输出;在控制器渲染的情况下,这意味着它将作为 HTTP 响应返回给浏览器,由控制器发起请求)。

上述示例引用以下视图文件:application/views/sectionA/view_file.php

渲染流程

视图是由控制器渲染的。控制器提供了参数给渲染的 PHP 视图文件以供使用。

控制器使用以下内置 CI load 库:$this->load->view('my_view',$data);

否则,控制器将使用第三方渲染服务库。在本章中,我们将使用此类库。CI 控制器渲染是通过 CI load view 库完成的,该库可选地接受渲染的 PHP 视图文件可以使用的 $data 参数和对象。以下代码为例:

$data['myval'] = 'Hello';
$this->load->view('my_view',$data);

渲染的 PHP 视图文件 application/views/my_view.php 如下使用通过加载库提供的 $data 参数:

<H1><?PHP echo $myval; ?></H1>

注意,控制器如下定义数据:

$data['myval'] = 'Hello';

当在 PHP 视图文件中使用的用法如下:

<H1><?PHP echo $myval; ?></H1>

之后,PHP 视图文件将被执行,因此生成的 HTML 代码将如下所示:

<H1>Hello</H1>

渲染的整个 PHP 视图文件,包括 PHP 执行,将生成将被通过 HTTP 返回给浏览器的视图 HTML 文件,并在本地执行。

视图灵活性

CI 为 PHP 视图文件代码使用任何客户端 JavaScript/CSS/HTML 或其他 JavaScript 库提供了灵活性,而无需在服务器端控制器中声明它们,这在某些其他平台上是常见的。

此外,CI 视图可以访问任何其他 CI 资源,例如 CI 库、CI 模型或 CI 辅助函数,就像它是视图的渲染控制器一样;例如,直接访问会话参数。

$param = $this->session->userdata('param1' );

此外,CI 视图可以直接调用 CI 库方法,就像渲染控制器一样(假设渲染控制器加载了这个库)。

$calc = $this->my_lib->my_lib_calc( $param);
<H1><?PHP echo $calc; ?></H1>

访问库/辅助函数

如前所述,CI PHP 视图文件可以访问 CI 的任何资源,例如以与控制器相同的方式调用 CI 辅助函数、库或模型。

以下是一个更详细和完整的 PHP CI 视图文件示例,访问 CI 资源,如库/模型/辅助函数:

<HTML>
<?PHP
// URI is a built-in CI library
// if the rendering controller for this view was// http://mysite/myproject/mycontroller/test3
// the segment(1) = mycontroller – the controller name
// the segment(2) = test3 - the controller method
$the_controller = $this->uri->segment(1);
$the_method = $this->uri->segment(2);
?>
<H1>This View Rendered by Controller
<?=$the_controller; ?> </H1>
<H1>Using its method named <?=$the_method; ?></H1>

表单

CI PHP 视图文件可以包含任何数量的 HTML 数据输入表单,以接受浏览用户的输入数据。我们可以使用 CI 表单辅助服务来简化数据输入构建并启用验证服务。

CI 表单辅助函数提供了一套有用且全面的 PHP 函数,用于多种数据输入和输入方式。其中我们可以找到文本字段的数据输入、区域文本字段、单选按钮、复选框、组合框和菜单选项。

以下是最常见的 CI 表单辅助函数列表:

  • form_open()

  • form_input()

  • form_dropdown()

  • form_password()

  • form_upload()

  • form_textarea()

  • form_multiselect()

  • form_checkbox()

  • form_radio()

  • form_close()

CI 表单辅助函数生成一个 HTML 部分,该部分作为返回给浏览器的 HTML 文件的一部分进行渲染。

例如,让我们看看一个颜色拾取的下拉选择示例。

<HTML>
<?PHP
$attr = ' class="nice_field" ';
$options = array();
$options[0] = 'Blue';
$options[1] = 'Green';
$options[2] = 'Yellow';
$default    = 1;
echo form_dropdown("color", $options, $default, $attr);
?>

form_dropdown 辅助函数将生成以下代码:

<select class="nice_field" name="color">
<option value="0»>Blue</option>
<option selected=»selected» value=»1»>Green</option>
<option value=»2»>Yellow</option>
</select>

更多信息,请参阅 CI 表单帮助用户手册。

AJAX

异步 JavaScript 和 XML 服务(AJAX)en.wikipedia.org/wiki/Ajax 在视图中的 JavaScript/jQuery 集成对于今天几乎任何 Web 应用程序都是至关重要的。它通过异步并行于用户操作来提供高级用户体验,并且只更新某些 HTML 选择器部分,而不是整个页面,就像非 AJAX 更新操作一样。

AJAX 有许多用例示例,可以增强用户体验。以下是一些常见的使用示例:

  • 当用户在字段中输入时,自动完成功能会显示所有匹配项,并在弹出列表中供用户选择。如果没有 AJAX 自动完成,UI 服务几乎是不可能的。

  • 当使用 AJAX 提交表单数据条目时,可以发出服务器提交以存储或处理数据,并在特定的选择器(通知消息)中显示结果,而不是像需要表单操作的提交那样刷新整个页面。(格式:项目符号)

  • 当浏览许多信息页面(称为分页)并点击某个页码以查看时。AJAX 允许在整页 HTML 中不刷新整个页面,在选择的 DIV 内渲染所选页面。(格式:项目符号结束)

目前,AJAX 正成为必不可少的视图组件,主要通过流行的 jQuery 库实现,这使得它很容易使用。AJAX 是构建智能和交互式视图的极其宝贵的 UI 资产。例如,以下是一个 AJAX 服务的示例,对于给定的SSN社会保险号),如果找到,在定义的选择器中提供个人的姓名和电话号码,否则发出警报。每当用户点击获取信息按钮时,就会触发 AJAX 调用,并发送一个异步 AJAX 调用到 AJAX 控制器,以 SSN 获取个人的记录。当响应返回时,如果找到 SSN,个人的电话和姓名将被更新。否则,将提供通知,表示未找到 SSN 个人的记录。

以下是实现之前描述的过程的代码,其中 AJAX 调用是操作的核心:

<script type="text/javascript">
function get_person_info (SSN_val, name_sel, phone_sel, err_sel) {
  /*
  //SSN_val –the value of the SSN user typed in to search 
  //name_sel–the name input that the Ajax will update if SSN found
..//phone_sel-the phone selector to be update if SSN found as well
  //err_sel-the error message area, to explain error such as SSN //not found or some other error occurred.
  */
  varajax_url = '<?php echo base_url();?>ajax/get_person_info';
  $.ajax({
    type: "POST",    //Very important POST is the best
    url: ajax_url,
    // the URI of the AJAX server side controller method that will processes this request
    data: {SSN: SSN_val},
    // SSN is the parameter name
    // SSN_val is the value
    dataType: "json",
    //the retuned data expected to be JSON
    success: function(data) { 
      // the data is the array conversion of the JSON data// retuned to ease our usage in the JavaScript!
      if(data.result=='found') {
        // Let's show the name and phone of the person with the//given SSN
        $(name_sel).val(data.name);
        $(phone_sel).val(data.phone);
      } else{
        // SSN Not found in the database!
        // Let's notify SSN has no person match
        $(err_sel).css ('color', 'red');
        $(err_sel).text('No person found with SSN' + SSN_val );
      }
    },
    error : //Ajax error occurred such as Ajax server not found//and so on
    function ( msg ) { alert ('Error:' + msg )
    $(err_sel).css ('color', 'red');
    $(err_sel).text ('Error:' + msg);
  }
});
// Wait for the document to be ready and bind the user click// on the #get id selector to call the AJAX search service// with the user typed SSN
$(function(){
  $('#get').click( function(){ 
    get_person_info ($('#SSN').val(),
    '#name',
    '#Phone',
    '#err_sel'
  );
  });
});
</script>

以下是从 HTML 表单本身的部分:

<form>
<label>Enter SSN</label>
<input type='text' name="SSN" id="SSN">
<button id='get'>Get Info</button>
<BR/>
<label>Name</label><B id='name'></B><BR/>
<label>phone</label><B id='phone'></B>
</form>
<B id='err_sel'></B>

解析器配置问题

视图在渲染回请求的浏览器之前由 CI 解析器解析。在 HTML 标签内输出 PHP 参数/计算表达式值的默认语法是<?PHP echo trim($param); ?>

然而,CI 在application/config/config.php和配置参数$config['rewrite_short_tags'] = TRUE;中提供了自动 PHP 短标签解析支持的配置。

如果rewrite_short_tags设置为TRUE,我们可以使用<?=trim($param)?>的短标签。

关于这一点的重要提示是,在调试方面,非短/常规 PHP echo 格式更受欢迎,因为短形式错误可能更难以这种方式追踪。然而,由于这种格式在许多我们看到的代码项目中都被使用,我们也提到了它。

集成 jQuery 或其他客户端库

CI 提供了集成任何客户端库的自由,因此 CI 不需要特别配置,或者我们不需要执行任何特殊的 CI 声明。

客户端集成以相同的方式进行,就像没有使用任何平台一样;它们是完全透明的。然而,CI 通过 PHP 提供客户端 jQuery 代码生成服务,例如构建 JavaScript 库以创建 jQuery 代码,作为控制器编码的一部分。

$this->load->library('javascript');

然而,对于当今最新的 jQuery 和许多其他基于 JavaScript 的解决方案,没有必要使用这种渲染 JavaScript 片段的方式,但我们可以使用视图本身的 JavaScript A-Z。关于 JavaScript 库的(哇级)资源,可以在我们迄今为止找到的最大的 JavaScript 库资源www.jsdb.io中找到。

delicious.com/eliorr1961可以找到更多关于客户端平台的酷链接。

注意,CI 视图中源目录路径的计算,就像视图文件在项目根目录一样。

例如,假设 JavaScript 库位于<Project_root>/javascript/myjs.js

视图位于<Project_root>/application/views/view1.php<Project_root>/application/views/topicB/view2.php视图路径下的views

在使用内置 CI URL 助手<base href="<?php echo base_url() ?>"/>提供根路径后,两者都将加载myjs.js如下:

<script type='text/javascript'src="img/myjs.js" ></script>

它们加载时就像它们位于项目根目录一样。这是因为 CI 将请求和视图渲染作为根目录index.php的一部分进行处理。因此,所有从视图 PHP 部分来的 SRC 或 INCLUDE 目录路径都被视为来自项目根目录。这是由于所有指向项目的 URI 都是由index.php执行的。所以对于所有项目代码,目录路径就像你的代码在index.php的同一目录或 CI 项目根目录一样。

视图渲染插件

如本章开头所述,我们可以使用第三方库来使我们能够在模板布局方式中创建更高级的渲染服务。

例如,由Colin Williams提供的 CodeIgniter 模板类,可在www.williamsconcepts.com/ci/libraries/template/index.html找到。

此插件使我们能够将渲染的页面定义为一种乐高风格的布局,具有预定义的页面区域,这样我们就可以为每个区域使用不同的 PHP CI 视图来渲染。

这样我们可以有很好的可重用性和统一的风格,并填充整个应用程序页面,这在许多情况下是一种好的UX(用户体验)实践。在这种情况下,用户,比如说,将知道在顶部他们将有一个特定的主要导航区域,在右侧有某些状态信息和操作快捷方式,等等。

我们可以定义一个或多个布局,这样每个页面布局模板都将有其区域组织。每个区域通常定义在一个 DIV 内。

有多个模板布局,我们最初可以选择我们想要使用的适当布局,然后我们将使用为每个区域定义的 CI 视图来加载其区域内容。例如,假设我们想要一个名为default的布局。

default 模板的主体布局将被命名为 template,例如,使用视图文件 main_template.php,因此 main_template.php 将包含以下区域:

  • header

  • upper_navigation

  • content

  • footer

我们将在 application/config/template.php 执行以下配置。

注意

这不是 CI 内置插件,而是一个附加插件,包括库和配置文件,以及我们安装到 CI 项目的其他资产。

//The default template shall be defined as follow:
//Note, more templates can be defined in the same fashion
$template['default']['template'] = 'main_template';
$template['default']['regions'] = array ('header', 'upper_navigation', 'content', 'footer');

main_template 指的是 application/views/main_template.php

main_template.php 的内容将包括所有定义的模板区域的渲染,如下所示:

<html>
<body>
<div><?=$header;?></div>
<div ><?= $upper_navigation;?></div>
<div><!--main content area -->
<?= $content; ?>
</div>
<!-- #footer -->
<?=$footer;?>
</body>
</html>

为了使用前面的模板插件,我们将执行以下操作:

首先,在 CI 控制器构造函数/s 中加载模板库,我们希望使用模板。请记住,模板库位于 <Project_root>/application/libraries/Template.php

我们将按照以下方式加载模板库:

$this->load->library('template');

<Project_root>/application/libraries/Template.php

$this->load->library('template');

然后,我们将加载我们已配置的特定模板文件(我们可以定义多个以供选择),例如,在控制器构造函数中,我们还将假设所有控制器方法使用相同的模板。

//set the selected template from the template config we want//to use
$this->template->set_template('default');

现在,为了使用预定义的视图将模板区域渲染为已渲染的视图,我们将按照以下方式操作:

对于每个模板区域,例如在 <Project_root>/application/views/,我们将按照以下方式将其加载到相应的区域:

$this->template->write_view ('header', 'header_view', $data);.
$this->template->write_view('upper_navigation', 'upper_navigation_view', $data );
$this->template->write_view ('content', 'content_view', $data);
$this->template->write_view ('footer', 'footer_view', $data);

现在模板区域已使用它们的区域视图文件进行渲染。我们可以按照以下方式渲染整个模板及其所有区域:

// Now, we have all the regions rendered into the
// template instance buffer, we can render them all to
// the desired template base page.
$this->template->render();

需要记住的是,模板有很好的优点,但也存在一些缺点。模板强制执行一种非常严格的渲染模板基础页面的方式,这种方式并不总是具有所需的灵活性,因此我们可能会发现自己需要编写多个模板并在它们之间切换,根据 UI 情况而定。

示例 1 – 由 Google Maps 提供支持的 HTML5 位置

在本例中,我们将扩展来自 第四章 的 Google Maps 集成示例,,以便将有一个新的选项显示用户在 Google 地图上的位置。为此,我们将使用 HTML5 navigator.geolocation 服务请求浏览用户与应用程序共享其位置。如果用户同意,并且使用支持此服务的先进浏览器,例如最新的 Firefox、Chrome 构建。一旦我们获取了值,我们将收集地理位置,并调用控制器方法来准备该区域的 Google 地图,以使用 navigator 选项渲染 Google 地图视图。我们将按照以下方式使用 HTML5 navigator.geolocation 服务:

navigator.geolocation.getCurrentPosition(getLocation, locationFail);

在这里,如果位置成功获取,则调用 getLocation,如果失败,则调用 locationFail

我们将从控制器开始。

控制器文件

控制器 PHP 文件位于application/controllers/gmaps.php。以下是基于第四章的扩展 Google Maps API 集成示例的控制器代码,其中新代码部分被突出显示:

class Gmaps extends CI_Controller
{
// Extends the CI controller to be our Gmaps controller powered by 
// the Google API wrapper library.
 // Setting the initialization parameters of Google Maps 
 // Library Mapper for the window size where the 
 // user interaction with Google Maps created window will occur
 private $user_lon = 0;
 private $user_lat = 0;
  function __construct()
  {parent::__construct();
    $this->load->library('googlemaps');
    // Set the map window sizes:
    $config['map_width'] = "1000px";  // map window width
    $config['map_height'] = "1000px";  // map window height
    $this->googlemaps->initialize($config);
  }
  function index()
  {
  /*Initialize and setup Google Maps for our App starting with 3 marked places: London, UK, Bombai, India, Rehovot, Israel */
  // Initialize our map for this use case of show 3 places // altogether.
  // let the zoom be automatically decided by Google for// showing the several places in one view
  $config['zoom'] = "auto";
  $this->googlemaps->initialize($config);
  //Define the places we want to see marked on Google Map!
  $this->add_visual_flag ('London, UK');
  $this->add_visual_flag ('Bombai, India');
  $this->add_visual_flag ('Rehovot, Israel');

 // **NEW CODE ** 
 // optional user location if user allow it and was fetched// successfully
 if ( $this->is_user_location_defined () ) {
 $this->add_visual_flag ($this->get_user_location ());
 }

  $data = $this->load_map_setting ();
  // Load our view, passing the map data that has just been //created.
  $this->load->view('google_map_view', $data);
}
// ** NEW CODE **
function user_location ($lat=0, $lon=0)
{
 // This is a new code we add for showing the //Geolocation fetched from the view base HTML5 Geolocation//service.
 //Initialize our map with it if it is set.
 if (! $lat&& ! $lon ) $this->index();

 // They are ok - let's keep them 
 $this->user_lat = $lat;
 $this->user_lon = $lon;
 $config['center'] = $this->get_user_location ();
 // Define the address we want to be on the map center
 $config['zoom'] = "5";
 // since its approximate location is country level
 $this->googlemaps->initialize($config);
 //Add visual flag
 $this->add_visual_flag ($config['center']);
 $data = $this->load_map_setting ();
 // Load our view, passing the map data that has just been //created.
 $this->load->view('google_map_view', $data);
 }
// ** NEW CODE
functionis_user_location_defined ( ) {
 return ( $this->user_lat != 0 ) || ( $this->user_lon!= 0 );
 }
// ** NEW CODE
functionget_user_location ( ) {
 return $this->user_lat.", ".$this->user_lon;
 }

functionlondon() 
{
  // as before
  }

functionbombai()
{
  // as before
  }
functionrehovot()
{
  // as before
  }
functionload_map_setting ( ) {
  // as before
  }
functionadd_visual_flag ( $place ) {
  // as before
  }
}
//End class Gmaps

视图文件

视图 PHP 文件位于application/views/google_map_view.php。以下是基于第四章的扩展 Google Maps API 使用示例视图的视图文件代码,其中新代码部分被突出显示。

在这里,我们通过 JavaScript 添加一个 HTML5 服务来收集用户的地理位置,并调用控制器方法user_location ($lat=0, $lon=0)

<!DOCTYPE html">
<meta http-equiv="Content-type" content="text/html;charset=utf-8" />
<html>
<head>
<script src="img/jquery-latest.js" type ='text/javascript'></script>
<script>
// New Code to get the user Geolocation and ask the controller to// render a Google Map for it.
var latitude = 0;
var longitude = 0;
functionshow_on_map () {
 var DIRECTORY_SEPARATOR = '/';

 // Prepare the URL path of calling the Gmaps controller method// user_location with latitude and longitude coordinates as// parameters using the CI naming convention of
 // ControllerName/methodName/Param1/Param2
 Var url_to_show = 
 '<?php echo base_url(); ?>index.php/gmaps/user_location/' +
 longitude + DIRECTORY_SEPARATOR + latitude;
 // Use jQuery to issue the HTTP controller call and rendering// request
 $(location).attr('href', url_to_show );
 }
$(document).ready(function() {
 // if user clicks on the <li> for getting its Geolocation
 $('#getmylocation').click(checkLocation);
 functioncheckLocation() {
 // Check if the browser supports the HTML5 Geolocation
 // Note that navigator.geolocation will pop a request from// the user to allow getting its location (Privacy)
 if (navigator.geolocation) {
 // It does so let the user be notified
 $('#notifications').html ( 'fetching your location, wait...' );
 $('#notifications').css ( 'color', 'blue' );

 // Try to fetch the latitude/longitude of the browsing user//and provides the callbacks
 // Success: getLocation
 // Failure: locationFail
 navigator.geolocation.getCurrentPosition(getLocation, locationFail);
 }

else {
 $('#notifications').html( 'Sorry, your browser settings does not enable fetching yourGeolocation');
 } // ends checkLocation()
 //this is what happens if getCurrentPosition is successful
 functiongetLocation(position) { 
 latitude = position.coords.latitude;
 longitude = position.coords.longitude;
 // Notify user for its location:
 $('#notifications').html
 ( 'Your approx. position : (' + latitude + ',' + longitude + ')' );
 $('#notifications').css ( 'color', 'green' );
 // Two seconds after the notification to user we have the// location issue call to the controller to show it on// the Google Map
 setTimeout ( show_on_map, 2000);
 }
 //this is what happens if getCurrentPosition is unsuccessful//(getCurrentPositionerrorCallback)
 functionlocationFail() {
 $('#notifications').html('Sorry, your browser could not fetch your location ...');
 $('#notifications').css ('color', 'red');
 }
 });
 </script>
    <!—As Before..  -->
 <!—Notification selector  -->
 <HR></HR>
 <DIV style='background:lightgreen;width:300px;'>
 <span id='notifications'>...</span>
    </DIV>
    <HR></HR>
    <ul>
    <!-- Let the User Always Get Back to the default Zoom out withall places marked>
    <li><?php echo anchor("index.php/gmaps", '<B>See All Locations</B>' ) ?></li>
 <!—If user clicks this one the Geo Location service will start -->
 <li id = 'getmylocation' style = 'cursor: pointer;color: blue; decoration: underline'> Show Me My Location</li>
    <!—As Before..  -->

示例 2 – 由 AJAX 和 jQuery UI 驱动的用户反馈

在本例中,我们将展示如何使用 jQuery UI 和 AJAX 调用 CI AJAX 控制器方法来收集用户反馈,并在不刷新/渲染页面的情况下提交。

我们将重用并扩展第三章中的登录示例,即控制器的使用和范围,因此如果用户已登录,我们将使用会话中保存的用户 ID 记录反馈,如果没有,我们将将其记录为匿名用户反馈。

记住以下事项:

  • 用户名: reg_user,

  • 密码: 111111111 (9 个 1)用于普通用户登录

重用和扩展的资源如下:

  • auth.php: 这里没有变化

  • ajax_handler.php: 这是新的 AJAX 处理器控制器

  • users_model.php: 这是扩展的用户模型

  • logged_in_view.php: 这是扩展的普通用户登录视图

我们扩展代码以包括新的Ajax_handler,以保持 jQuery UI 对话框提交的浏览用户反馈,并通过 AJAX 异步接口获取用户登录消息。注意,我们在Ajax_handler中检查请求是否为 AJAX。如果不是,我们在浏览器中发出以下 URL:

photographersnav.com/ci_utils/index.php/ajax_handler.

我们将在浏览器中收到通知,这是一个错误的请求。

users_model资源被扩展以提供更多服务,具体如下:

  • get_logged_in_user(): 此函数用于在用户登录时返回登录用户记录,否则返回 NULL。get_user_rec ( $uid )根据其 ID 获取特定用户记录。

  • keep_user_feedback ($feedback): 此函数用于将用户反馈及其用户 ID 存储在数据库中,如果用户已登录。

  • get_user_feedbacks ($uid): 此函数获取迄今为止保存在数据库中的所有用户反馈消息,以数据库对象数组的形式。每个反馈数据库行返回的反馈消息及其时间戳格式化为 HTML,并通过 JSON 格式返回给 AJAX 调用者,以便通过 jQuery 选择器基于 HTML 渲染显示给最终用户(例如,$(selector).html (从服务器返回的 _html_item))。

logged_in_view 资源已扩展,为用户提供以下新服务:

  • 添加一个新的反馈按钮,点击后会弹出用于此目的的 jQuery UI 对话框

  • 显示反馈日志按钮,点击后会显示一个可滚动的用户反馈列表

现在我们来回顾源代码本身。

ajax_handler.php 控制器文件

控制器 PHP 文件位于 application/controllers/ajax_handler.php。代码和内联说明如下:

<?php if (!defined('BASEPATH'))exit('No direct script access allowed');
class Ajax_handler extends CI_Controller {
  function __construct()
  {parent::__construct();
    /* Standard libraries, database & helper URL loaded via theauto load
    */
    if (!$this->input->is_ajax_request())
    {exit( "Bad Request ignored! - Your info has been logged forfurther investigation of attacking the site!");
    }
  /* ------ Our Users Model ---------- */
  $this->load->model ( 'users_model' );
}

functionsave_user_feedback () {
  // Get the feedback content
  $feedback = $this->input->post('feedback');
  // Get if the user is logged in keep the user id
  $this->users_model->keep_user_feedback($feedback);
  }
functionget_user_feedback_log () {
  $user = $this->users_model->get_logged_in_user ();
  if ( $user ) $uid = $user->id;
  $user_feedback_rows = $this->users_model->get_user_feedbacks( $uid );
  $html = '';
  foreach ($user_feedback_rows as $row )
  $html.= $row->timestamp.' -  <B>'.$row->feedback.'</B><BR/>';
  $result = array ('result' => $html);
  echojson_encode ($result);
  return;
  }
} // End Ajax_handler

users_model.php 模型文件

模型 PHP 文件位于 application/models/users_model.php。代码和内联说明如下:

<?php if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Users_model extends CI_Model {
  function __construct()
  {parent::__construct();
  }
  functioncheck_login ($user, $pass)
  {
    /* No change here
    */ 
    }
  functionget_logged_in_user (  )
  {
    // Will check if there's a login user session and if so will// fetch its record
    $ci = &get_instance();

    //get the login in user ID, if any
    $uid = $this->session->userdata('user_id');
    if (! $uid ) return NULL;
    $sql = "SELECT *
    FROMusers
    WHERE id = '$uid' ";

    $q = $ci->db->query($sql);
    if ($q->num_rows())
    {foreach ($q->result() as $row )
      return $row;
      }
    return NULL;
    }
    Function get_user_rec ( $uid ){
      // Will check if there's a login user session and if so will// fetch its record
      $ci = &get_instance();
      // get the login in user ID, if any
      if (! $uid ) return NULL;
      $sql = "SELECT *FROM users WHERE id = '$uid' ";
      $q = $ci->db->query($sql);
      if($q->num_rows())
      {foreach ($q->result() as $row ) return $row;
        }
      return NULL;
      }
    Function keep_user_feedback ($feedback) {
      $ci = &get_instance();
      $uid_rec = $this->get_logged_in_user ();
      $uid = $uid_rec ? $uid_rec->id: 0;
      /* id email uid feedback timestamp
      */
      $table = 'user_feedback';
      $data = array ( 'feedback'  =>urldecode ($feedback),'uid'=>  $uid);
      $ci->db->insert($table, $data);
      }
      Function  get_user_feedbacks ( $uid ) {
        $ci = &get_instance();
        if (! $uid ) return NULL;
        $feedbacks = array();
        $table = 'user_feedback';
        $sql = "SELECT * FROM  $tableWHERE  uid = '$uid'
        ORDER BY timestamp DESC";
        $q = $ci->db->query($sql);
        if ( $q->num_rows() ) {
          foreach ($q->result() as $row)
          $feedbacks[] = $row;
          }
        return $feedbacks;
        }
      } // End Users_model

logged_in_view.php 视图文件

PHP 视图文件位于 application/views/logged_in_view.php。此文件扩展了几个更多服务,如前例所述。代码和内联说明如下:

<!DOCTYPE html">
<meta http-equiv="Content-type" content="text/html;charset=utf-8" />
<html>
<head>
<script src="img/jquery-latest.js" type='text/javascript'></script>
<scriptsrc="img/jquery-1.8.2.js"></script>
<script src="img/jquery-ui.js">
</script>
<link rel="stylesheet" type="text/css" href="<?=base_url(); ?>/css/my_style.css" media="screen" />
<script type='text/javascript'>
// The AJAX handler controller method URLs
varsave_user_feedback_submitter = '<?=site_url()?>'+'index.php/ajax_handler/save_user_feedback';
varget_user_feedbacks = '<?=site_url()?>' +'index.php/ajax_handler/get_user_feedback_log';
functionajax_save_user_feedback (feedback) {
  $.ajax({
    type : "POST",
    url : save_user_feedback_submitter,
    data : {feedback: feedback},
    dataType: "json",
    success: function(data) {
      // When AJAX return back alert // ('Your feedback Updated - Thanks!');
      }
    });
  }

functionajax_get_user_feedback_log() {
  $.ajax({
    type: "POST",
    url: get_user_feedbacks,
    dataType: "json",
    success: function(data) {
      $('#feedback_log_view').show();
      $('#feedback_log_view').html(data.result);
      }
    });
  }
$(document).ready(function() {
  // Set up the jQuery UI feedback dialog
  $("#ideas-form").dialog({
    autoOpen: false,
    height: 270,
    width: 700,
    modal: true,
    resizable: false,
    effect: 'drop',
    direction: "up",
    show: "slide",
    buttons: {
      "Send Us Your Feedback": function() {
        varuser_feedback = $('#user_feedback').val();
        ajax_save_user_feedback(user_feedback);
        // clean feedback entry for next one
        $('#user_feedback').val('');
        // Show user all its feedback so far
        ajax_get_user_feedback_log();
        $(this).dialog("close");
        },
      "Cancel": function() {
        $(this).dialog("close");
        }
      }
    });

  // When user clicks on for a popup feedback window
  $('#user_ideas').button().click(function() {
    $("#ideas-form").dialog("open");
    });

  $('#feedback_log').button().click(function() {
    ajax_get_user_feedback_log();
    });
  });// Document ready section
</script >
</head>
<body>
<H1>Welcome <?=$user_name; ?>! </H1>
<H1>You are logged in! </H1>
<HR></HR>
  <H3>Your User ID is: <?=$uid; ?></H3>
  <H3>Your System Role is: <?=$role; ?></H3>
  <H3>Your Menu options: <?=$menu; ?></H3>
<DIV>
  <button id='user_ideas' style="cursor: pointer; position: relative; top:0px" title='Share your feedback/ideas'> Add A New Feedback </button><BR/>
  <button id="feedback_log" style= "cursor: pointer; position: relative; top:0px" title="Your feedback log"> See Your Feedback Log </button>
</DIV>
  <div id='feedback_log_view' style= "display: none; width: 800 px; border-style: solid;border-color: black; overflow-x: auto; height: 200 px; overflow-y: auto;">
</DIV>
<H2><?php echo anchor ('index.php/auth/logout', 'Logout')?></H2>

  <div id= "ideas-form", title= "Your Feedback To Improve">
<form>
<fieldset>
<span id= "user_name" class= "text ui-widget-content ui-corner-all"> Thanks <? = $user_name; ?>, Please share your feedback with us</span>
<textarea name= "idea_desc", id = "user_feedback", rows = "10" cols = "83", placeholder = 'Your ideas'></textarea>
</fieldset>
</form>
</div>
</body>
</html>

摘要

在本章中,我们回顾了 CI 视图、作用域以及它们的通用 MVC 作用域,以及不同类型的视图和用法。此外,我们展示了如何将我们的 CodeIgniter 代码与第三方模板插件(CI 库、配置和额外的代码资源)集成,为应用程序控制器提供视图模板服务。

我们还学习了在 CI 视图中集成 jQuery UI 和 AJAX 的示例,与 CI 控制器/模型一起使用。

附录 A. 附录

在本附录中,我们将提供一组关于 CodeIgniter 社区及其特色 CI 网站的主动更新和网页资源。

CI 正式资源如下:

特色 CI 插件如下:

支持 CodeIgniter 的网站和文章如下:

以下是由 CodeIgniter 驱动的特色网站:

如需更多信息,请参阅 ellislab.com/codeigniter 上的 基于 CodeIgniter 构建 部分。

posted @ 2025-09-05 09:26  绝不原创的飞龙  阅读(4)  评论(0)    收藏  举报