Phalcon入门教程之模型

原文发表于: Phalcon入门教程之模型

Phalcon 提供了四种方式操作Mysql数据库:模型、PHQL、数据库抽象层以及原生SQL。不论何种方式,首先都需要在DI中注册 db 服务才能正常使用:

DI注册db服务

//  文件路径:app/core/services.php
$di -> setShared('db', function () use($config) {
    $dbconfig = $config -> database -> db;
    $dbconfig = $dbconfig -> toArray();
    if (!is_array($dbconfig) || count($dbconfig)==0) {
        throw new \Exception("the database config is error");
    }
    $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => $dbconfig['host'], "port" => $dbconfig['port'],
        "username" => $dbconfig['username'],
        "password" => $dbconfig['password'],
        "dbname" => $dbconfig['dbname'],
        "charset" => $dbconfig['charset'])
    );
    return $connection;
});

数据库连接信息配置如下:

// 文件路径:app/config/system.php
return array(
    //数据库表配置
    'database' => array(
        //数据库连接信息
        'db' => array(
            'host' => '127.0.0.1',
            'port' => 3306,
            'username' => 'admin',
            'password' => 'admin',
            'dbname' => 'test',
            'charset' => 'utf8',
        ),

        //表前缀
        'prefix' => 'test_',
    ),
);

记录底层SQL语句

在我们开发过程中,有时候需要通过SQL语句来分析定位问题。那么,我们需要将ORM生成的底层SQL记录到日志中。修改DI中注册的 db 服务如下:

//文件路径:app/core/services.php
$di -> setShared('db', function () use($config) {
    $dbconfig = $config -> database -> db;
    $dbconfig = $dbconfig -> toArray();
    if (!is_array($dbconfig) || count($dbconfig)==0) {
        throw new \Exception("the database config is error");
    }
    $eventsManager = new \Phalcon\Events\Manager();
    // 分析底层sql性能,并记录日志
    $profiler = new Phalcon\Db\Profiler();
    $eventsManager -> attach('db', function ($event, $connection) use ($profiler) {
        if($event -> getType() == 'beforeQuery'){
            //在sql发送到数据库前启动分析
            $profiler -> startProfile($connection -> getSQLStatement());
        }
        if($event -> getType() == 'afterQuery'){
            //在sql执行完毕后停止分析
            $profiler -> stopProfile();
            //获取分析结果
            $profile = $profiler -> getLastProfile();
            $sql = $profile->getSQLStatement();
            $params = $connection->getSqlVariables();
            (is_array($params) && count($params)) && $params = json_encode($params);
            $executeTime = $profile->getTotalElapsedSeconds();
            //日志记录
            $currentDay = date('Ymd');
            $logger = new \Phalcon\Logger\Adapter\File(ROOT_PATH . "/app/cache/logs/{$currentDay}.log");
            $logger -> debug("{$sql} {$params} {$executeTime}");
        }
    });

    $connection = new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => $dbconfig['host'], "port" => $dbconfig['port'],
        "username" => $dbconfig['username'],
        "password" => $dbconfig['password'],
        "dbname" => $dbconfig['dbname'],
        "charset" => $dbconfig['charset'])
    );

    / 注册监听事件 /
    $connection->setEventsManager($eventsManager);

    return $connection;
});

通过代码可以看到,不仅是底层SQL,还将SQL绑定的参数(PDO预处理)和SQL执行时间也记录到日志中了。日志记录demo如下:

SELECT `users`.`uid` AS `uid`, `users`.`mobile` AS `mobile` FROM `users` WHERE `users`.`uid` = :uid LIMIT :APL0 {"uid":1,"APL0":1} 0.034402132034302

花括号({})中的就是SQL预处理时绑定的参数,最后的浮点数就是SQL执行时间(单位为秒)。

创建模型

模型类的命名必须符合驼峰命名法,而且须继承自 Phalcon\Mvc\Model 类:

// 文件路径:app/frontend/models/ArticlesModel.php
class Articles extends \Marser\App\Frontend\Models\BaseModel {
    // \Marser\App\Frontend\Models\BaseModel继承自 \Phalcon\Mvc\Model 类。
    // 此处是再次封装一个基础模型类,  以方便后续的通用方法封装
    //...
}

数据库表映射

默认情况下,Articles 模型类对应的数据表名是 articles ;若是 ArticlesTags 模型类,则对应的数据库表名是 articles_tags , 即类名对应着表名。如果想映射到其他数据库表,可以使用 setSource() 方法设置:

// 文件路径:app/frontend/models/ArticlesModel.php
class Articles extends \Marser\App\Frontend\Models\BaseModel {
  public function initialize()
    {
        $this->setSource("articles_tags");
    }
}

在项目开发中,建议一个数据表对应着一个模型类。即使是关联表,也强烈建议创建其对应的模型类,因为 Phalcon 中提供的连表操作,都是基于模型类的(后续的教程会分享)。

设置表前缀

在进行数据库表设计的时候,有时会在表名前加上一段前缀,如 test_articles 。我们依然可以通过 setSource() 映射数据表:

// 文件路径:app/frontend/models/ArticlesModel.php
class Articles extends \Marser\App\Frontend\Models\BaseModel {
  public function initialize()
    {
        $this->setSource("test_articles");
    }
}

假设,我们的项目中有100张数据表,那么就意味着有100个模型类。此时我们在每个模型类中都必须调用 setSource() 来映射完整的表名。如果某天我们需要修改这100张表的前缀,那么将要修改这100个模型类,不仅耗时耗力还麻烦。我们尝试着将此处理过程提取出来进行封装:

// 文件路径: app/frontend/models/ArticlesModel.php
class ArticlesModel extends \Marser\App\Frontend\Models\BaseModel {

    /**
     * 表名
     */
    const TABLE_NAME = 'articles';

    public function initialize(){
        parent::initialize();
        //映射数据表(补上表前缀)
        $this->set_table_source(self::TABLE_NAME);
    }
}

BaseModel 模型基类中的 set_table_source() 方法定义如下:

// 文件路径: app/frontend/models/BaseModel.php
class BaseModel extends \Phalcon\Mvc\Model {

    public function initialize(){

    }

    /**
     * 映射数据表(补上表前缀)
     * @param string $tableName
     * @param null $prefix
     */
    protected function set_table_source($tableName, $prefix = null){
        //默认从配置中读取表前缀配置
        empty($prefix) && $prefix = $this->getDI()->get('config')->database->prefix;
        //拼接成完整表名之后,再通过setSource()映射数据表
        $this->setSource($prefix . $tableName);
    }
}

我们在每个模型类中定义一个 类常量 来存储无前缀的表名,再通过 set_table_source() 成员方法来拼接表前缀并映射。眼尖的读者,应该在上面的数据库连接信息配置中有看到 prefix 的表前缀配置。
还是以上面为例,此时我们就不需要修改100个模型类的代码,而只需修改配置文件中的 prefix 配置即可。

以上代码已托管在github:https://github.com/KevinJay/marser-phalcon-demo

最后,欢迎大家加入QQ群交流讨论:

  • 广州PHP高端交流群:158587573
  • Phalcon玩家群:150237524
时间: 2024-08-31 20:16:05

Phalcon入门教程之模型的相关文章

Phalcon入门教程之模型CURD(2)

原文发表于:Phalcon入门教程之模型CURD(2) 上一篇 Phalcon入门教程之模型CURD(1) 中介绍了 Phalcon 模型的 insert 和 select 操作,本篇将介绍 update 和 delete 的用法.文中所用的示例代码皆沿用上一篇的数据表,这里不在赘述. 更新记录 Phalcon 模型更新记录的示例代码如下: $articleModel = new ArticlesModel(); //先调用 findFirst() 获取一条记录,返回值是当前模型对象 $arti

Phalcon入门教程之模型CURD(1)

原文发表于:Phalcon入门教程之模型CURD(1) 上一篇<Phalcon入门教程之模型>中介绍了数据库模型操作的一些基础功能,本篇将介绍模型的 select 和 insert 用法.由于数据库模型操作的内容比较多和细,所以本篇只是粗略的介绍基础用法,以及补充文档中没有提及的一些用法和注意点.因此,强烈建议大家在熟读文档的前提下,再阅读此篇教程. 数据表 假设数据表名为 test_articles,数据结构及记录下: mysql> select * from test_article

Phalcon入门教程之目录结构

原文发表于:Phalcon入门教程之目录结构 很多初学Phalcon的朋友,对于以Phalcon框架为基础构建的项目,应该如何组织目录结构有点摸不着头脑.比如多模块的项目中,如何共用"libs"类库和"models"目录中模型类的情况,就有很多刚接触Phalcon朋友经常在群里问这种问题. 我们在翻阅Phalcon文档的时候,会看到"教程2:INVO简介"中有一个项目结构的demo,其中总结到" Phalcon不会强求应用程序使用特定的

Phalcon入门教程之控制器

原文发表于:Phalcon入门教程之控制器 控制器在MVC分层中的主要作用是处理请求与响应.Phalcon中的控制器类必须以" Controller "为后缀,action则以" Action "为后缀. " Phalcon\Mvc\Controller "是Phalcon中控制器的基类,我们写的控制器类通过继承此基类,可以调用在DI中注册的各种服务.一个简单的控制器类示例如下: namespace Marser\App\Frontend\Con

Phalcon入门教程之安装

Phalcon安装 # 下载安装包 wget https://github.com/phalcon/cphalcon/archive/v3.0.1.tar.gz # 重命名 mv v3.0.1.tar.gz cphalcon-3.0.1.tar.gz #解压 tar -zxvf cphalcon-3.0.1.tar.gz #切换目录(根据php版本和操作系统位数切换到相应的目录) cd cphalcon-3.0.1/build/php7/64bits/ #准备环境(通过find / -name

XHTML基础入门教程

html基础|xhtml|教程|入门教程 摘要 XHTML 1.0是作为XML1.0应用而重新制定的HTML4.本规范书定义XHTML 1.0以及其中与HTML 4对应的3种文档类型定义(DTDDocument Type Definition). 每个元素的语义和它们的属性已经在W3C Recommendation for HTML 4中定义它们是XHTML将来扩展的基础.只要遵循一小套指导方针XHTML文档就能和现存的HTML用户代理程序兼容. 本文档的状况 本节描述本文档发布时的状况.其它的

ReactiveCocoa入门教程:第二部分

翻译自:http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2 原文链接: ReactiveCocoa 是一个框架,它允许你在你的iOS程序中使用函数响应式(FRP)技术.加上第一部分的讲解,你将会学会如何使用信号量(对事件发出数据流)如何替代标准的动作和事件处理逻辑.你也会学到如何转换.分离和组合这些信号量. 在这里,也就是第二部分里,你将会学到更多先进的ReactiveCocoa特性,包括: 1.另外两个事件类型:error

Zend Framework教程之模型Model基本规则和使用方法_php实例

本文实例讲述了Zend Framework教程之模型Model基本规则和使用方法.分享给大家供大家参考,具体如下: 这里讲讲Zend中的model.其实Zend中的Model处理是相当简单的. 这主要得益于autoload功能.不像其它框架,为model定义复杂的基类. 如果要定义model,不得不要继承一个model的基类,才可以使用具体的功能. Zend中并没有对模型进行封装. 原因大概是Model主要是和具体业务逻辑相关的,进行过多的封装,只会画蛇添足. Zend使用了autoload和n

想了解递归神经网络?这里有一份入门教程

递归神经网络入门教程 引言 递归神经网络是一类人工神经网络,可用于识别诸如文本.基因组.手写字迹.语音等序列数据的模式,也可用于识别传感器.股票市场.政府机构产生的数值型时间序列数据.递归网络可以说是最强大的神经网络,甚至可以将图像分解为一系列图像块,作为序列加以处理.由于递归网络拥有一种特定的记忆模式,而记忆也是人类的基本能力之一,所以下文会时常将递归网络与人脑的记忆活动进行类比. 前馈网络回顾 要理解递归网络,首先需要了解前馈网络的基础知识.这两种网络的名字都来自于它们通过一系列网络节点数学